mikesmithgh/kitty-scrollback.nvim

github github
terminal-integration
stars 172
issues 15
subscribers 2
forks 3
CREATED

2023-03-08

UPDATED

5 hours ago


😽 kitty-scrollback.nvim

Navigate your Kitty scrollback buffer to quickly search, copy, and execute commands in Neovim.

neovim: v0.9+ kitty v0.29+ semantic-release: angular test status

[!NOTE]
👀 Check out Advanced Configuration for more demos! 🎥

⚡️ Neovim Conf 2023: Developing kitty-scrollback.nvim

Check out my lighting talk on Dec 8th at Neovim Conf 2023 about kitty-scrollback.nvim!

🚀 Migrating to v2.0.0

[!IMPORTANT]
v2.0.0 has breaking changes and requires steps to properly migrate from v1.X.X.

You can ignore this section if you have not previously installed any version of kitty-scrollback.nvim

  • If you are using the lazy.nvim or packer.nvim package manager, then add the custom User event KittyScrollbackLaunch as a trigger for lazy loading. See Installation for additional details.

    event = { 'User KittyScrollbackLaunch' }
    
  • Regenerate default Kitten mappings and add to kitty.conf

    nvim --headless +'KittyScrollbackGenerateKittens' +'set nonumber' +'set norelativenumber' +'%print' +'quit!' 2>&1
    
  • Remove previous kitty-scrollback.nvim Kitten mappings in kitty.conf

  • The default mapping keys changed from ctrl+shift to kitty_mod. The default values for kitty_mod in Kitty is ctrl+shift.

    • If you are using the default value for kitty_mod of ctrl+shift, then no change is needed.
    • If you are using a different value for kitty_mod, then you should correct any potential mapping conflicts that may occur now that kitty-scrollback.nvim is using kitty_mod.
  • Migrate any customized configurations to the new format

    • When you define your kitty-scrollback.nvim Kitten configuration, do not use --config-file yourconfigfile.lua. Instead, move the contents of yourconfigfile.lua to an entry in the configuration passed to the kitty-scrollback.nvim setup function.
      require('kitty-scrollback').setup({ 
        yourconfig = function() 
          ...
        end, 
      })
      
      Update your Kitten to use the name of the configuration defined in the setup function. In this example, --config-file yourconfigfile.lua changes to --config yourconfig
  • [!NOTE]
    The configuration to view the last command output now references a builtin configuration instead of a file. The new configuration can be viewed by running :KittyScrollbackGenerateKittens.

  • Old configuration

    • The Kitten defined in kitty.conf references the configuration file get_text_last_cmd_output.lua
    # Browse output of the last shell command in nvim
    map kitty_mod+g kitty_scrollback_nvim --config-file get_text_last_cmd_output.lua
    -- get_text_last_cmd_output.lua
    local M = {}
    M.config = function()
      return {
        kitty_get_text = {
          extent = 'last_visited_cmd_output',
          ansi = true,
        },
      }
    end
    
    return M
  • New configuration
    • The Kitten defined in kitty.conf references the builtin configuration name ksb_builtin_last_cmd_output
    # Browse output of the last shell command in nvim
    map kitty_mod+g kitty_scrollback_nvim --config ksb_builtin_last_cmd_output
    require('kitty-scrollback').setup({ 
      ksb_builtin_last_cmd_output = function()
        return {
          kitty_get_text = {
            extent = 'last_visited_cmd_output',
            ansi = true,
          },
        }
      end
    })

✨ Features

  • 😻 Navigate Kitty's scrollback buffer with Neovim
  • 🐱 Copy contents from Neovim to system clipboard
  • 😺 Send contents from Neovim to Kitty shell
  • 🙀 Execute shell command from Neovim to Kitty shell

🤯 Example use cases

  • Open Kitty's scrollback history (default mapping <C-S-h>)
  • Search backward for a pattern in Neovim ?{pattern}<CR>
  • Enter Visual mode v and select desired text
  • Copy selection to clipboard (default mapping <leader>y)
  • kitty-scrollback.nvim automatically closes and returns to Kitty
  • Open Kitty's scrollback history (default mapping <C-S-h>)
  • Copy desired selection to clipboard (e.g., yy)
    • Alternatively, you could just enter Insert mode (i or a) to open an empty floating window (similar to <C-x><C-e> in Bash)
  • kitty-scrollback.nvim opens a floating window in Neovim with the contents of the selection
  • Modify the content
  • Execute the command (default mapping <C-CR>)
  • kitty-scrollback.nvim automatically closes and executes the command in Kitty
  • Open Kitty's scrollback history (default mapping <C-S-h>)
  • Copy desired selection to clipboard (e.g., yy)
  • kitty-scrollback.nvim opens a floating window in Neovim with the contents of the selection
  • Modify the content
    • Note: you can close (default mapping <ESC>) and reopen (yank or enter Insert mode) the floating window multiple times
  • Paste the content (default mapping <S-CR> or :w)
  • kitty-scrollback.nvim automatically closes and paste the contents in Kitty for further editing

📚 Prerequisites

🏃 Quickstart

To quickly test this plugin without changing your configuration run the command:

sh -c "$(curl -s https://raw.githubusercontent.com/mikesmithgh/kitty-scrollback.nvim/main/scripts/mini.sh)"

[!NOTE]
It is good practice to first read the script before running sh -c directly from the web

📦 Installation

  {
    'mikesmithgh/kitty-scrollback.nvim',
    enabled = true,
    lazy = true,
    cmd = { 'KittyScrollbackGenerateKittens', 'KittyScrollbackCheckHealth' },
    event = { 'User KittyScrollbackLaunch' },
    -- version = '*', -- latest stable version, may have breaking changes if major version changed
    -- version = '^2.0.0', -- pin major version, include fixes and features that do not have breaking changes
    config = function()
      require('kitty-scrollback').setup()
    end,
  }
  use({
    'mikesmithgh/kitty-scrollback.nvim',
    disable = false,
    opt = true,
    cmd = { 'KittyScrollbackGenerateKittens', 'KittyScrollbackCheckHealth' },
    event = { 'User KittyScrollbackLaunch' },
    -- tag = '*', -- latest stable version, may have breaking changes if major version changed
    -- tag = 'v2.0.0', -- pin specific tag
    config = function()
      require('kitty-scrollback').setup()
    end,
  })
mkdir -p "$HOME/.local/share/nvim/site/pack/mikesmithgh/start/"
cd $HOME/.local/share/nvim/site/pack/mikesmithgh/start
git clone git@github.com:mikesmithgh/kitty-scrollback.nvim.git
nvim -u NONE -c "helptags kitty-scrollback.nvim/doc" -c q
mkdir -p "$HOME/.config/nvim"
echo "require('kitty-scrollback').setup()" >> "$HOME/.config/nvim/init.lua"

✍️ Configuration

[!NOTE]
The Advanced Configuration section of the Wiki provides detailed demos of each configuration option.

Kitty

The following steps outline how to properly configure kitty.conf

  • Valid values are yes, socket, socket-only
  • If kitty-scrollback.nvim is the only application controlling Kitty then socket-only is preferred to continue denying TTY requests.
  • For example, listen_on unix:/tmp/kitty
  • Set shell_integration to enabled
  • Do not add the option no-prompt-mark
  • Generate default Kitten mappings and add to kitty.conf
nvim --headless +'KittyScrollbackGenerateKittens' +'set nonumber' +'set norelativenumber' +'%print' +'quit!' 2>&1
nvim +'KittyScrollbackCheckHealth'
  • Follow the instructions of any ERROR or WARNINGS reported during the healthcheck

kitty_mod is a special modifier key alias for default shortcuts. You can change the value of this option to alter all default shortcuts that use kitty_mod. See Kitty documentation #opt-kitty.kitty_mod.

The default value of kitty_mod is ctrl+shift. In this example, kitty_mod+h represents ctrl+shift+h.

allow_remote_control yes
listen_on unix:/tmp/kitty
shell_integration enabled

# kitty-scrollback.nvim Kitten alias
action_alias kitty_scrollback_nvim kitten /Users/mike/gitrepos/kitty-scrollback.nvim/python/kitty_scrollback_nvim.py

# Browse scrollback buffer in nvim
map kitty_mod+h kitty_scrollback_nvim
# Browse output of the last shell command in nvim
map kitty_mod+g kitty_scrollback_nvim --config ksb_builtin_last_cmd_output
# Show clicked command output in nvim
mouse_map kitty_mod+right press ungrabbed combine : mouse_select_command_output : kitty_scrollback_nvim --config ksb_builtin_last_visited_cmd_output

Kitten arguments

Arguments that can be passed to the kitty_scrollback_nvim Kitten defined in kitty.conf.

Argument Description
--config The name of the kitty-scrollback.nvim plugin configuration. The configuration can be defined during plugin setup (i.e., require('kitty-scrollback').setup({ ... })).
--no-nvim-args Do not provide any arguments to the Neovim instance that displays the scrollback buffer. The default arguments passed to Neovim are --clean --noplugin -n. This flag removes those options.
--nvim-args All arguments after this flag are passed to the Neovim instance that displays the scrollback buffer. This must be the last of the kitty-scrollback.nvim Kitten arguments that are configured. Otherwise, you may unintentionally send the wrong arguments to Neovim. The default arguments passed to Neovim are --clean --noplugin -n. This flag removes those options.
--env Environment variable that is passed to the Neovim instance that displays the scrollback buffer. Format is --env var_name=var_value. You may specify multiple config files that will merge all configuration options. Useful for setting NVIM_APPNAME
--cwd The current working directory of the Neovim instance that displays the scrollback buffer.

kitty-scrollback.nvim configuration file

Options Type Description
callbacks KsbCallbacks? fire and forget callback functions
callbacks.after_setup fun(kitty_data: KsbKittyData, opts: KsbOpts)? callback executed after initializing kitty-scrollback.nvim
callbacks.after_launch fun(kitty_data: KsbKittyData, opts: KsbOpts)? callback executed after launch started to process the scrollback buffer
callbacks.after_ready fun(kitty_data: KsbKittyData, opts: KsbOpts)? callback executed after scrollback buffer is loaded and cursor is positioned
keymaps_enabled boolean? if true, enabled all default keymaps
restore_options boolean? if true, restore options that were modified while processing the scrollback buffer
highlight_overrides KsbHighlights? kitty-scrollback.nvim highlight overrides
highlight_overrides.KittyScrollbackNvimNormal table? status window Normal highlight group
highlight_overrides.KittyScrollbackNvimHeart table? status window heart icon highlight group
highlight_overrides.KittyScrollbackNvimSpinner table? status window spinner icon highlight group
highlight_overrides.KittyScrollbackNvimReady table? status window ready icon highlight group
highlight_overrides.KittyScrollbackNvimKitty table? status window kitty icon highlight group
highlight_overrides.KittyScrollbackNvimVim table? status window vim icon highlight group
highlight_overrides.KittyScrollbackNvimPasteWinNormal table? paste window Normal highlight group
highlight_overrides.KittyScrollbackNvimPasteWinFloatBorder table? paste window FloatBorder highlight group
highlight_overrides.KittyScrollbackNvimPasteWinFloatTitle table? paste window FloatTitle highlight group
highlight_overrides.KittyScrollbackNvimVisual table? scrollback buffer window visual selection highlight group
status_window KsbStatusWindowOpts? options for status window indicating that kitty-scrollback.nvim is ready
status_window.enabled boolean If true, show status window in upper right corner of the screen
status_window.style_simple boolean If true, use plaintext instead of nerd font icons
status_window.autoclose boolean If true, close the status window after kitty-scrollback.nvim is ready
status_window.show_timer boolean If true, show a timer in the status window while kitty-scrollback.nvim is loading
status_window.icons KsbStatusWindowIcons? Icons displayed in the status window
status_window.icons.kitty string kitty status window icon
status_window.icons.heart string heart string heart status window icon
status_window.icons.nvim string nvim status window icon
paste_window KsbPasteWindowOpts? options for paste window that sends commands to Kitty
paste_window.highlight_as_normal_win fun(): boolean? If function returns true, use Normal highlight group. If false, use NormalFloat
paste_window.filetype string? The filetype of the paste window
paste_window.hide_footer boolean? If true, hide mappings in the footer when the paste window is initially opened
paste_window.winblend integer? The winblend setting of the window, see :help winblend
paste_window.winopts_overrides fun(paste_winopts: KsbWinOpts): table<string,any>? Paste float window overrides, see nvim_open_win() for configuration
paste_window.footer_winopts_overrides fun(footer_winopts: KsbWinOpts, paste_winopts: KsbWinOpts): table<string,any>? Paste footer window overrides, see nvim_open_win() for configuration
paste_window.yank_register string? register used during yanks to paste window, see :h registers
paste_window.yank_register_enabled boolean? If true, the yank_register copies content to the paste window. If false, disable yank to paste window
kitty_get_text KsbKittyGetText? options passed to get-text when reading scrollback buffer, see kitty @ get-text --help
kitty_get_text.ansi boolean If true, the text will include the ANSI formatting escape codes for colors, bold, italic, etc.
kitty_get_text.clear_selection boolean If true, clear the selection in the matched window, if any.
kitty_get_text.extent string What text to get. The default of screen means all text currently on the screen. all means all the screen+scrollback and selection means the currently selected text. first_cmd_output_on_screen means the output of the first command that was run in the window on screen. last_cmd_output means the output of the last command that was run in the window. last_visited_cmd_output means the first command output below the last scrolled position via scroll_to_prompt. last_non_empty_output is the output from the last command run in the window that had some non empty output. The last four require shell_integration to be enabled. Choices: screen, all, first_cmd_output_on_screen, last_cmd_output, last_non_empty_output, last_visited_cmd_output, selection
checkhealth boolean? if true execute :checkhealth kitty-scrollback and skip setup
visual_selection_highlight_mode string? Sets the mode for coloring the Visual highlight group in the scrollback buffer window. darken uses a darkened version of the Normal highlight group to improve readability. kitty uses the colors defined for selection_foreground and selection_background in your Kitty configuration. nvim uses the default colors defined in the Visual highlight group. reverse reverses the foreground and background colors of the visual selection.

Nerd Fonts

By default, kitty-scrollback.nvim uses Nerd Fonts in the status window. If you would like to use ASCII instead, set the option status_window.style_simple to true.

[!NOTE]
Nerd Fonts release v3.1.0 added the Neovim icon! See ksb_example_status_win_nvim in Advanced Configuration for a demo and example configuration.

The following example configuration sets a global kitty-scrollback.nvim configuration to use the neovim icon instead of vim icon

kitty.conf

action_alias kitty_scrollback_nvim kitten /Users/mike/gitrepos/kitty-scrollback.nvim/python/kitty_scrollback_nvim.py --nvim-args -u kitty-scrollback-nvim-kitten-config.lua

kitty-scrollback-nvim-kitten-config.lua

-- I am still working on a better experience for configuring kitty-scrollback.nvim, but this works for now
vim.opt.runtimepath:append(vim.fn.stdpath('data') .. '/lazy/kitty-scrollback.nvim') -- assuming lazy.nvim setup
require('kitty-scrollback').setup({
  global = function()
    return {
      status_window = {
        icons = {
          nvim = '',
        },
      },
    }
  end,
})
  • Status window with Nerd Fonts v3.1.0+ opts.status_window.icons.nvim = '' opts.status_window.style_simple = false

  • Status window with Nerd Fonts < v3.1.0 opts.status_window.icons.nvim = '' opts.status_window.style_simple = false

  • Status window with ASCII text opts.status_window.style_simple = true

🫡 Commands and Lua API

The API is available via the kitty-scrollback.api module. e.g., require('kitty-scrollback.api')

Command API Description
:KittyScrollbackGenerateKittens[!] [generate_modes] generate_kittens(boolean?, table<string|'commands'|'maps'>)? Generate Kitten commands used as reference for configuring kitty.conf
:KittyScrollbackCheckHealth checkhealth() Run :checkhealth kitty-scrollback in the context of Kitty

⌨️ Keymaps and Lua API

The API is available via the kitty-scrollback.api module. e.g., require('kitty-scrollback.api')

<Plug> Mapping Default Mapping Mode API Description
<Plug>(KsbExecuteCmd) <C-CR> n,i execute_command() Execute the contents of the paste window in Kitty
<Plug>(KsbPasteCmd) <S-CR> n,i paste_command() Paste the contents of the paste window to Kitty without executing
<Plug>(KsbToggleFooter) g? n toggle_footer() Toggle the paste window footer that displays mappings
<Plug>(KsbCloseOrQuitAll) <Esc> n close_or_quit_all() If the current buffer is the paste buffer, then close the window. Otherwise quit Neovim
<Plug>(KsbQuitAll) <C-c> n,i,t quit_all() Quit Neovim
<Plug>(KsbVisualYankLine) <Leader>Y v Maps to "+Y
<Plug>(KsbVisualYank) <Leader>y v Maps to "+y
<Plug>(KsbNormalYankEnd) <Leader>Y n Maps to "+y$
<Plug>(KsbNormalYank) <Leader>y n Maps to "+y
<Plug>(KsbNormalYankLine) <Leader>yy n Maps to "+yy

👏 Recommendations

The following plugins are nice additions to your Neovim and Kitty setup.

  • vim-kitty - Syntax highlighting for Kitty terminal config files
  • smart-splits.nvim - Seamless navigation between Neovim and Kitty split panes

🤝 Acknowledgements

🐶 Alternatives