如何在vim中有效地撤消自动完成

如何在vim中有效地撤消自动完成,vim,autocomplete,vim-plugin,Vim,Autocomplete,Vim Plugin,现在我正在vim中玩自动完成,我已经决定处理我的完成。虽然它运行非常平稳,而且(我认为)完全符合它的设计,但我想知道如何改变一些东西 首先,我在Ubuntu12.04LTS上运行7.3.429 set completeopt=menuone,preview,longest 这样我就有了带有supertab的bash类型的自动完成和默认完成 假设我的文件中有以下内容: aaabbbcccddd aaabbccddeef aaabbcddeeff 如果我键入aa并点击Tab,那么vim意识到aa

现在我正在vim中玩自动完成,我已经决定处理我的完成。虽然它运行非常平稳,而且(我认为)完全符合它的设计,但我想知道如何改变一些东西

首先,我在Ubuntu12.04LTS上运行7.3.429

set completeopt=menuone,preview,longest
这样我就有了带有supertab的bash类型的自动完成和默认完成

假设我的文件中有以下内容:

aaabbbcccddd
aaabbccddeef
aaabbcddeeff
如果我键入
aa
并点击Tab,那么vim意识到
aaabb
是匹配项中最长的公共字符串,因此它插入
aaabb
,并显示包含三个选项的菜单。如果我真的想要这些选择中的一个,那么一切都很好。但也许我真的想要
aaaaaazzzzz
,但没有意识到我还没有打出来

有没有好办法对维姆说:“哦,对不起!我毕竟不是有意的!请假装我没有。”

目前,我显然有以下选择:

  • 按Tab键或Shift+Tab键的次数足够多,以返回到初始设置。但是如果有很多相似的词,特别是长度不同的词,这是很烦人的
  • 无论需要多少次,都可以点击backspace,或者其他一些简单的删除操作。但这些肯定是不必要的关键点
  • 按Esc+u键可撤消,但这会撤消我的整个单词(如果我快速键入,则会撤消更多)。这是完全不能接受的。然后,我需要重新进入插入模式并重新键入。真恶心
  • 按Ctrl+U组合键撤消操作,而不退出插入模式。但这也有一个趋势,即删除的方式太多
  • 按Ctrl+W删除最后一个单词。虽然我可以在不退出插入模式的情况下执行此操作,但仍然需要重新键入。这是迄今为止我找到的最好的
  • 如果我没有启用
    longest
    ,那么我可以使用Ctrl+E,它退出菜单而不插入任何其他内容。但由于“最长”处于启用状态,它会停止自动完成,但会保留输入的最长公共匹配


    当然,必须有更好的方法来做到这一点。

    这很难,但我也遇到了同样的问题,并且已经实现了一些东西。缺点是,我必须重载任何(内置的和自定义的)完成触发器,以首先调用一个自定义函数,该函数将标记设置为完成的开始。然后我在插入模式下映射
    (弹出菜单可见)以删除该标记之前的文本

    function! s:SetUndo()
        call setpos("'\"", getpos('.'))
        return ''
    endfunction
    inoremap <expr> <SID>(CompleteStart) <SID>SetUndo()
    function! s:UndoLongest()
            " After a completion, the line must be the same and the column must be
            " larger than before.
            if line("'\"") == line('.') && col("'\"") < col('.')
                return "\<C-\>\<C-o>dg`\""
            endif
        endif
        return ''
    endfunction
    imap <expr> <Esc>      pumvisible() ? <SID>UndoLongest() : '<Esc>'
    
    inoremap <script> <C-x><C-n> <SID>(CompleteStart)<C-x><C-n>
    inoremap <script> <C-x><C-p> <SID>(CompleteStart)<C-x><C-p>
    ...
    
    函数!s:SetUndo()
    调用setpos(“\”,getpos(“.”)
    返回“”
    端功能
    inoremap(CompleteStart)SetUndo()
    函数!s:UndoLongest()
    “完成后,行必须相同,列必须相同。”
    “比以前大。
    如果行(“\”)==行(“.”)和列(“\”)<列(“.”)
    返回“\\dg`\”
    恩迪夫
    恩迪夫
    返回“”
    端功能
    imap pumvisible()?撤消最长的():“”
    inoremap(CompleteStart)
    inoremap(CompleteStart)
    ...
    
    在vim中有两种本机方法可以实现这一点。如果您知道该项目不在完成菜单中,您可以使用
    接受当前匹配,如果您在任何补全过程中都没有移动该匹配,则将只返回您插入的文本。(第二种方式)但是,如果您确实在完成菜单中移动,您可以移动直到返回到原始文本


    然而,我想简单地接受最长的匹配并编辑单词并不难。您还可以使用
    u
    将撤消块分解为
    映射。虽然这可能会打破历史比你想要的更多。

    知道这已经有一段时间了,但这就是我成功完成它的方式

    自动完成是我使用的。您可能需要根据具体情况将其更改为
    。)

    “当自动完成菜单不可见时,使C-n启动一个新的撤消序列
    “见-https://vi.stackexchange.com/a/2377
    inoremap pumvisible()?“”:“u”
    “当“自动完成”菜单可见时,重载Esc以仅执行撤消操作
    inoremap pumvisible()?“u”:”
    
    谢谢。我没有尝试。但我承认,我有点困惑。阅读文档时,我根本不会将“当前匹配”解释为最初插入的、最长的文本。尤其是当似乎表明它应该是撤销完成的文本时。我读文档时是不是大错特错?我理解你为什么感到困惑d关于
    但是您需要进一步阅读:结束完成,返回到选择匹配之前的内容(键入的内容或最长的公共字符串)。
    " When the auto-complete menu is not visible, make C-n start a new undo sequence
    " See - https://vi.stackexchange.com/a/2377
    inoremap <expr> <C-n> pumvisible() ? "<C-n>" : "<C-g>u<C-n>"
    
    " Overload Esc to just do an undo when auto-complete menu is visible
    inoremap <expr> <Esc> pumvisible() ? "<C-o>u" : "<Esc>"