Reputation: 155
I have made a custom command, and I tried to use mark
to save the cursor position. But the mark is set in the position where the file is inserted on the 6th line(using the r
command).
vim.cmd [[ command! -nargs=1 Include call feedkeys("mx") | 6r <args> | call feedkeys("`x")]]
I think 6r <args>
is getting executed before feedkeys("mx")
.Is there any way we can fix this?? or if there are other ways to restore cursor position
Upvotes: 3
Views: 2997
Reputation: 532
This is converted from Vim defaults - https://github.com/vim/vim/blob/master/runtime/defaults.vim#L105-L116
-- When editing a file, always jump to the last known cursor position.
-- Don't do it when the position is invalid, when inside an event handler,
-- for a commit or rebase message
-- (likely a different one than last time), and when using xxd(1) to filter
-- and edit binary files (it transforms input files back and forth, causing
-- them to have dual nature, so to speak)
function RestoreCursorPosition()
local line = vim.fn.line("'\"")
if line > 1 and line <= vim.fn.line("$") and vim.bo.filetype ~= 'commit' and vim.fn.index({'xxd', 'gitrebase'}, vim.bo.filetype) == -1 then
vim.cmd('normal! g`"')
end
end
if vim.fn.has("autocmd") then
vim.cmd([[
autocmd BufReadPost * lua RestoreCursorPosition()
]])
end
Upvotes: 1
Reputation: 2318
For some read if you call vim.fn.winsaveview()
immediately, it seems like it happens before the do things
and the position is restored, well that's my theory.
To get winrestview
to work, you have to delay it, either by using feed keys (yuck) or call it deferred with a small (e.g. 0) delay asynchronously:
vim.g.cursor_position = vim.fn.winsaveview()
-- do things
-- Now we restore the cursor position with a delay of 0ms
vim.defer_fn(function() vim.fn.winrestview(vim.g.cursor_position) end, 0)
Deferred keys version (not recommended, press <ctrl+v>then escape to insert a escape at the start of the string, and a CR at the end of the string (those sepcial chars were removed by stackoverflow):
vim.fn.feedkeys([[:lua vim.fn.winrestview(vim.g.cursor_position)]])
Upvotes: 0
Reputation: 11800
I have a "preserve cursor position" function in lua (neovim), it is in my utils.lua file, it goes like this:
M.preserve = function(arguments)
local arguments = string.format("keepjumps keeppatterns execute %q", arguments)
-- local original_cursor = vim.fn.winsaveview()
local line, col = unpack(vim.api.nvim_win_get_cursor(0))
vim.api.nvim_command(arguments)
local lastline = vim.fn.line("$")
-- vim.fn.winrestview(original_cursor)
if line > lastline then
line = lastline
end
vim.api.nvim_win_set_cursor({ 0 }, { line, col })
end
The above function encapsules any give command, for example, if I want to reindent the whole file I create a Reindent command:
vim.cmd([[command! Reindent lua require('utils').preserve("sil keepj normal! gg=G")]])
And run:
:Reindent
To remove blank spaces at the end of any line:
vim.cmd([[cnoreab cls Cls]])
vim.cmd([[command! Cls lua require("utils").preserve('%s/\\s\\+$//ge')]])
Vimscript version of it:
" preserve function
if !exists('*Preserve')
function! Preserve(command)
try
let l:win_view = winsaveview()
"silent! keepjumps keeppatterns execute a:command
silent! execute 'keeppatterns keepjumps ' . a:command
finally
call winrestview(l:win_view)
endtry
endfunction
endif
In my case I have another function to squeeze blank lines (if I have more than one consecutive blank like they become one), so, I have this function:
M.squeeze_blank_lines = function()
-- references: https://vi.stackexchange.com/posts/26304/revisions
if vim.bo.binary == false and vim.opt.filetype:get() ~= "diff" then
local old_query = vim.fn.getreg("/") -- save search register
M.preserve("sil! 1,.s/^\\n\\{2,}/\\r/gn") -- set current search count number
local result = vim.fn.searchcount({ maxcount = 1000, timeout = 500 }).current
local line, col = unpack(vim.api.nvim_win_get_cursor(0))
M.preserve("sil! keepp keepj %s/^\\n\\{2,}/\\r/ge")
M.preserve("sil! keepp keepj %s/\\v($\\n\\s*)+%$/\\r/e")
if result > 0 then
vim.api.nvim_win_set_cursor({ 0 }, { (line - result), col })
end
vim.fn.setreg("/", old_query) -- restore search register
end
end
Then I have the consecutive blank lines remove but the cursor remains where it is:
:nnoremap <leader>d :lua require('utils').squeeze_blank_lines()<cr>
Or if you are, by any chance using init.lua
-- map helper
local function map(mode, lhs, rhs, opts)
local options = { noremap = true }
if opts then
options = vim.tbl_extend("force", options, opts)
end
vim.api.nvim_set_keymap(mode, lhs, rhs, options)
end
map("n", "<leader>d", '<cmd>lua require("utils").squeeze_blank_lines()<cr>')
I hope these ideas can help you to figure out a solution to your problem
A final tip: If you are using the proposed utils.lua you have to insert at the beginning of it:
local M = {}
and at the end of it:
return M
Upvotes: 3