VIM:撤消功能后恢复位置

时间:2018-09-12 17:11:27

标签: vim

在vim中进行LaTeX编辑时,我记录了一些有用的宏并将它们包装到函数/命令中。我有一个可以更改Latex环境的类型,例如,当我有以下情况时:

\begin{itemize}
     \item First
     \item Second
\end{itemize}

我只需在环境中某处的光标处输入:ChangeEnv enumerate,即可从逐项更改为枚举。

我的ftplugin / tex.vim中的代码如下:

function! ChangeEnv(newenv)
    let l:save = @e
    let @e = a:newenv

    let l:line = getline('.')

    " Fake change to restore undo
    normal ix
    normal x

    if match(l:line, '\\begin{') != -1
        normal mz_%f{lci}e'zf{l.`z:delma   z
    else
        normal my?\\begin{^M_mz%f{lci}^Re^['zf{l.`y:delma    yz
    endif

    let @e = l:save
endfunction

command -nargs=1 ChangeEnv :silent call ChangeEnv(<f-args>)

到目前为止,如果光标位于环境的if match(...部分上,则第一部分(在\begin{...}之后)到目前为止可以正常工作,我可以进行更改并撤消它,光标停留在应有的位置。

第二部分,专门用于环境内部,也可以很好地工作,但是当撤消更改时,光标跳到\ begin行的第一个字符。

normal ixnormal x部分的目的是确保在und之后恢复光标位置(我在这里有Restor Cursor Position

我的问题是,为什么它不能用于第二个宏?有什么错误吗?

为避免破坏宏,请执行以下步骤:

  • my-在当前位置设置y标记
  • ?\\begin{^M-向后搜索环境的起点,然后跳到那里
  • _mz-转到该行的第一个字符并设置z标记
  • %-跳转到匹配的环境\end{...(这是matchit vim插件的一部分,随vim一起提供,但默认情况下不处于活动状态)。
  • f{l-跳至{并向右一个字符
  • ci}-更改内部{...}
  • ^Re^[-插入存储新环境名称的e寄存器的内容,并返回普通模式
  • 'z'-跳至z标记(\begin{...)的开头
  • f{l.-转发至{,向右移一步,然后重复上一次更改
  • `y-跳至y标记,即初始位置
  • :delma yz-删除yz标记

尽管如此,撤消行为并不是破坏交易的因素,我至少想知道为什么这样做会破坏行为。

谢谢。

1 个答案:

答案 0 :(得分:2)

通常,当您进行多个更改时,每个更改都将分别撤消。但是在一个函数内部,所有内容都集中在一起作为一个单一的更改。

您打算在一开始(当光标尚未移动时)进行此虚拟更改的目的是,光标会在撤消后返回到该点。

但是,我认为Vim将ChangeEnv()内所做的全部更改视为一个重大修改,它返回到更改行范围的开始(标记{{1 }}),就像撤消内置命令时一样。 “第一个”执行哪个更改命令无关紧要,重要的是更改的行的范围。当您的第二个分支向后搜索'[并在那里进行更改时,这就是撤消后光标所在的位置。我认为这没有办法。撤消操作不受脚本的影响,因为这可能会导致不一致。

您可以做的是在进行更改后设置标记(在功能末尾:\begin),以便您可以快速跳回那里(通过:normal! m'或{{1} }。