编辑:
我已经简化了功能并澄清了问题。
原始问题在页面下方仍然可用。交叉发布到 vim_dev 邮件列表: https ://groups.google.com/forum/#!topic/vim_dev/_Rz3uVXbwsQ
作为错误报告给 Neovim:
https ://github.com/neovim/neovim/issues/6276
为什么光标在以下两个示例中的位置不同:
[CORRECT CURSOR POSITION] 替换的结果加入到缓冲区中的先前更改(添加第 3 行),光标位置正确恢复到缓冲区中的第二行。
normal ggiline one is full of aaaa set undolevels=10 " splits the change into separate undo blocks normal Goline two is full of bbbb set undolevels=10 normal Goline three is full of cccc set undolevels=10 undojoin keepjumps %s/aaaa/zzzz/ normal u
[INCORRECT CURSOR POSITION] 替换的结果加入到缓冲区中的先前更改(第 4 行的添加),光标位置错误地恢复到缓冲区的第一行(应该是第 3 行)。
normal ggiline one is bull of aaaa set undolevels=10 " splits the change into separate undo blocks normal Goline two is full of bbbb set undolevels=10 normal Goline three is full of cccc set undolevels=10 normal Goline four is full of aaaa's again set undolevels=10 undojoin keepjumps %s/aaaa/zzzz/ normal u
原始问题
我的 VIM 设置方式,将缓冲区保存到文件会触发自定义 StripTrailingSpaces() 函数(附在问题的末尾):
autocmd BufWritePre,FileWritePre,FileAppendPre,FilterWritePre <buffer>
\ :keepjumps call StripTrailingSpaces(0)
在看到撤消脚本所做的文本更改后恢复光标位置后,我想到了通过将函数创建的撤消记录合并到先前更改的末尾来从撤消历史记录中排除我的 StripTrailingSpaces() 函数所做的更改缓冲区。
这样,当撤消更改时,该函数似乎根本没有创建它自己的撤消记录。
为了验证我的想法,我使用了一个简单的测试用例:创建一个干净的缓冲区并手动输入以下命令,或者将以下块保存为文件并通过以下方式获取它:
vim +"source <saved-filename-here>"
normal ggiline one is full of aaaa
set undolevels=10 " splits the change into separate undo blocks
normal Goline two is full of bbbb
set undolevels=10
normal Goline three is full of cccc
set undolevels=10
undojoin
keepjumps %s/aaaa/zzzz/
normal u
如您所见,在撤消缓冲区中的最后一次更改后,即创建第三行,光标正确返回到文件中的第二行。
由于我的测试有效,我undojoin
在我的 StripTrailingSpaces() 中实现了几乎相同的。但是,当我在函数运行后撤消最后一次更改时,光标将返回到文件中最顶部的更改。这通常是一个被剥离的空间,而不是我修改的位置undojoin
。
谁能想到为什么会这样?更好的是,有人可以建议修复吗?
function! StripTrailingSpaces(number_of_allowed_spaces)
" Match all trailing spaces in a file
let l:regex = [
\ '\^\zs\s\{1,\}\$',
\ '\S\s\{' . a:number_of_allowed_spaces . '\}\zs\s\{1,\}\$',
\ ]
" Join trailing spaces regex into a single, non-magic string
let l:regex_str = '\V\(' . join(l:regex, '\|') . '\)'
" Save current window state
let l:last_search=@/
let l:winview = winsaveview()
try
" Append the comming change onto the end of the previous change
" NOTE: Fails if previous change doesn't exist
undojoin
catch
endtry
" Substitute all trailing spaces
if v:version > 704 || v:version == 704 && has('patch155')
execute 'keepjumps keeppatterns %s/' . l:regex_str . '//e'
else
execute 'keepjumps %s/' . l:regex_str . '//e'
call histdel('search', -1)
endif
" Restore current window state
call winrestview(l:winview)
let @/=l:last_search
endfunction