-
-
Save galaxia4Eva/9e91c4f275554b4bd844b6feece16b3d to your computer and use it in GitHub Desktop.
return function(INPUT_LINE_NUMBER, CURSOR_LINE, CURSOR_COLUMN) | |
print('kitty sent:', INPUT_LINE_NUMBER, CURSOR_LINE, CURSOR_COLUMN) | |
vim.opt.encoding='utf-8' | |
vim.opt.clipboard = 'unnamed' | |
vim.opt.compatible = false | |
vim.opt.number = false | |
vim.opt.relativenumber = false | |
vim.opt.termguicolors = true | |
vim.opt.showmode = false | |
vim.opt.ruler = false | |
vim.opt.laststatus = 0 | |
vim.o.cmdheight = 0 | |
vim.opt.showcmd = false | |
vim.opt.scrollback = INPUT_LINE_NUMBER + CURSOR_LINE | |
local term_buf = vim.api.nvim_create_buf(true, false); | |
local term_io = vim.api.nvim_open_term(term_buf, {}) | |
vim.api.nvim_buf_set_keymap(term_buf, 'n', 'q', '<Cmd>q<CR>', { }) | |
vim.api.nvim_buf_set_keymap(term_buf, 'n', '<ESC>', '<Cmd>q<CR>', { }) | |
local group = vim.api.nvim_create_augroup('kitty+page', {}) | |
local setCursor = function() | |
vim.api.nvim_feedkeys(tostring(INPUT_LINE_NUMBER) .. [[ggzt]], 'n', true) | |
local line = vim.api.nvim_buf_line_count(term_buf) | |
if (CURSOR_LINE <= line) then | |
line = CURSOR_LINE | |
end | |
vim.api.nvim_feedkeys(tostring(line - 1) .. [[j]], 'n', true) | |
vim.api.nvim_feedkeys([[0]], 'n', true) | |
vim.api.nvim_feedkeys(tostring(CURSOR_COLUMN - 1) .. [[l]], 'n', true) | |
end | |
vim.api.nvim_create_autocmd('ModeChanged', { | |
group = group, | |
buffer = term_buf, | |
callback = function() | |
local mode = vim.fn.mode() | |
if mode == 't' then | |
vim.cmd.stopinsert() | |
vim.schedule(setCursor) | |
end | |
end, | |
}) | |
vim.api.nvim_create_autocmd('VimEnter', { | |
group = group, | |
pattern = '*', | |
once = true, | |
callback = function(ev) | |
local current_win = vim.fn.win_getid() | |
for _, line in ipairs(vim.api.nvim_buf_get_lines(ev.buf, 0, -2, false)) do | |
vim.api.nvim_chan_send(term_io, line) | |
vim.api.nvim_chan_send(term_io, '\r\n') | |
end | |
for _, line in ipairs(vim.api.nvim_buf_get_lines(ev.buf, -2, -1, false)) do | |
vim.api.nvim_chan_send(term_io, line) | |
end | |
vim.api.nvim_win_set_buf(current_win, term_buf) | |
vim.api.nvim_buf_delete(ev.buf, { force = true } ) | |
vim.schedule(setCursor) | |
end | |
}) | |
end |
# ... | |
scrollback_pager nvim -u NONE -R -M -c 'lua require("kitty+page")(INPUT_LINE_NUMBER, CURSOR_LINE, CURSOR_COLUMN)' - | |
# ... |
@mikesmithgh @jackielii @SmartFinn @Ssnnee
I have updated kitty+page.lua
now, while still problematic with codepages that take more bytes that display length, it should place cursor properly. Pay attention to detail:
vim.api.nvim_create_autocmd('ModeChanged', {
group = group,
buffer = term_buf,
callback = function()
local mode = vim.fn.mode()
if mode == 't' then
vim.cmd.stopinsert()
vim.schedule(setCursor)
end
end,
})
maybe you would like to remove vim.schedule(setCursor)
on ModeChanged
for *:t
Error detected while processing command line:
E5108: Error executing lua vim/_options.lua:0: E474: Invalid argument
stack traceback:
[C]: in function 'nvim_set_option_value'
vim/_options.lua: in function '_set'
vim/_options.lua: in function '__newindex'
/home/sl/.config/nvim/lua/kitty+page.lua:17: in function </home/sl/.config/nvim/lua/kitty+page.lua
:4>
[string ":lua"]:1: in main chunk
Press ENTER or type command to continue
This error sometimes occurs when the output of the scollback buffer becomes rather large?! I don't know what is causing this. It seems to work great most of the time
Any pointers would be helpful thanks!
Solved it by handling the error when it occurs. I am using fish shell. This is the code:
return function(INPUT_LINE_NUMBER, CURSOR_LINE, CURSOR_COLUMN)
print('kitty sent:', INPUT_LINE_NUMBER, CURSOR_LINE, CURSOR_COLUMN)
local function setOptions()
vim.opt.encoding='utf-8'
vim.opt.clipboard = 'unnamedplus'
vim.opt.compatible = false
vim.opt.number = false
vim.opt.relativenumber = false
vim.opt.termguicolors = true
vim.opt.showmode = false
vim.opt.ruler = false
vim.opt.laststatus = 0
vim.o.cmdheight = 0
vim.opt.showcmd = false
vim.opt.scrollback = INPUT_LINE_NUMBER + CURSOR_LINE
end
-- Use pcall to execute setOptions and catch any errors
local success, errorMessage = pcall(setOptions)
-- If an error occurred, substitute INPUT_LINE_NUMBER, CURSOR_LINE, CURSOR_COLUMN with 0,0,0
if not success then
-- print("Error setting options:", errorMessage)
INPUT_LINE_NUMBER, CURSOR_LINE, CURSOR_COLUMN = 0, 0, 0
end
local term_buf = vim.api.nvim_create_buf(true, false);
local term_io = vim.api.nvim_open_term(term_buf, {})
vim.api.nvim_buf_set_keymap(term_buf, 'n', 'i', '<Cmd>q<CR>', { })
vim.api.nvim_buf_set_keymap(term_buf, 'n', 'q', '<Nop>', { })
-- vim.api.nvim_buf_set_keymap(term_buf, 'n', '<ESC>', '<Cmd>q<CR>', { })
local group = vim.api.nvim_create_augroup('kitty+page', {})
local setCursor = function()
vim.api.nvim_feedkeys(tostring(INPUT_LINE_NUMBER) .. [[ggzt]], 'n', true)
local line = vim.api.nvim_buf_line_count(term_buf)
if (CURSOR_LINE <= line) then
line = CURSOR_LINE
end
vim.api.nvim_feedkeys(tostring(line - 1) .. [[j]], 'n', true)
vim.api.nvim_feedkeys([[0]], 'n', true)
vim.api.nvim_feedkeys(tostring(CURSOR_COLUMN - 1) .. [[l]], 'n', true)
end
vim.api.nvim_create_autocmd('ModeChanged', {
group = group,
buffer = term_buf,
callback = function()
local mode = vim.fn.mode()
if mode == 't' then
vim.cmd.stopinsert()
end
end,
})
vim.api.nvim_create_autocmd('VimEnter', {
group = group,
pattern = '*',
once = true,
callback = function(ev)
local current_win = vim.fn.win_getid()
for _, line in ipairs(vim.api.nvim_buf_get_lines(ev.buf, 0, -2, false)) do
vim.api.nvim_chan_send(term_io, line)
vim.api.nvim_chan_send(term_io, '\r\n')
end
for _, line in ipairs(vim.api.nvim_buf_get_lines(ev.buf, -2, -1, false)) do
vim.api.nvim_chan_send(term_io, line)
end
vim.api.nvim_win_set_buf(current_win, term_buf)
vim.api.nvim_buf_delete(ev.buf, { force = true } )
vim.schedule(setCursor)
end
})
end
FYI If anyone is interested. I developed the plugin kitty-scrollback.nvim to navigate your Kitty scrollback buffer to quickly search, copy, and execute commands in Neovim. Feel free to check it out 😺!
I'm using this gist but I'm finding that if the setCursor
function is called in the VimEnter autocommand callback it doesnt work properly because the buffer isn't fully written when we try to set the cursor. INPUT_LINE_NUMBER is usually greater than the number of lines in the buffer at that point resulting in the cursor being placed at the very bottom of the buffer.
My hacky solution was to take out the vim.schedule(setCursor)
line from the VimEnter callback and put vim.defer_fn(setCursor, 10)
at the bottom of the returned function. I basically want to synchronously invoke setCursor AFTER the VimEnter autocommand is complete, and 10ms seems to be enough time for the VimEnter autocommand to finish writing the contents of the buffer. Has anyone else has encountered this? Looking for some guidance on a less hacky approach.
This is my modified attempt, using @yusufshalaby solution with vim.defer_fn(setCursor, 10)
to make sure the terminal has time to process the content and the buffer is ready.
/home/YOUR_USER/.config/nvim/lua/kitty+page.lua:
return function(INPUT_LINE_NUMBER)
vim.opt.encoding='utf-8'
-- Prevent auto-centering on click
vim.opt.scrolloff = 0
vim.opt.compatible = false
vim.opt.number = false
vim.opt.relativenumber = false
vim.opt.termguicolors = true
vim.opt.showmode = false
vim.opt.ruler = false
vim.opt.signcolumn=no
vim.opt.showtabline=0
vim.opt.laststatus = 0
vim.o.cmdheight = 0
vim.opt.showcmd = false
vim.opt.scrollback = 100000
vim.opt.clipboard:append('unnamedplus')
local term_buf = vim.api.nvim_create_buf(true, false)
local term_io = vim.api.nvim_open_term(term_buf, {})
-- Map 'q' to first yank the visual selection (if any), which makes the copy selection work, and then quit.
vim.api.nvim_buf_set_keymap(term_buf, 'v', 'q', 'y<Cmd>qa!<CR>', { })
-- Regular quit mapping for normal mode
vim.api.nvim_buf_set_keymap(term_buf, 'n', 'q', '<Cmd>qa!<CR>', { })
local group = vim.api.nvim_create_augroup('kitty+page', {clear = true})
local setCursor = function()
local max_line_nr = vim.api.nvim_buf_line_count(term_buf)
local input_line_nr = math.max(1, math.min(tonumber(INPUT_LINE_NUMBER), max_line_nr))
-- It seems that both the view (view.topline) and the cursor (nvim_win_set_cursor) must be set
-- for scrolling and cursor positioning to work reliably with terminal buffers.
vim.fn.winrestview({topline = input_line_nr})
vim.api.nvim_win_set_cursor(0, {input_line_nr, 0})
end
vim.api.nvim_create_autocmd('ModeChanged', {
group = group,
buffer = term_buf,
callback = function()
local mode = vim.fn.mode()
if mode == 't' then
vim.cmd.stopinsert()
vim.schedule(setCursor)
end
end,
})
vim.api.nvim_create_autocmd('VimEnter', {
group = group,
pattern = '*',
once = true,
callback = function(ev)
local current_win = vim.fn.win_getid()
-- Instead of sending lines individually, concatenate them.
local main_lines = vim.api.nvim_buf_get_lines(ev.buf, 0, -2, false)
local content = table.concat(main_lines, '\r\n')
vim.api.nvim_chan_send(term_io, content .. '\r\n')
-- Process the last line separately (without trailing \r\n)
local last_line = vim.api.nvim_buf_get_lines(ev.buf, -2, -1, false)[1]
if last_line then
vim.api.nvim_chan_send(term_io, last_line)
end
vim.api.nvim_win_set_buf(current_win, term_buf)
vim.api.nvim_buf_delete(ev.buf, { force = true } )
-- Use vim.defer_fn to make sure the terminal has time to process the content and the buffer is ready.
vim.defer_fn(setCursor, 10)
end
})
end
On my kitty.conf
:
scrollback_pager nvim -u NONE -R -M -c 'lua require("kitty+page")(INPUT_LINE_NUMBER)' -
Dear @jackielii,
From my observations, kitty sometimes replaces
INPUT_LINE_NUMBER, CURSOR_LINE, CURSOR_COLUMN
with not incorrect values when there was output to stderr in one of the scripts (kitty and fish shell on MacBook)Maybe there's a more precise way that would also account for stderr lines, but I'm not aware of it.