在插入模式下遍历文本

384

在 Vim 的插入模式中,除使用箭头键外,是否有其他方式可以移动一些字符向前或向后遍历文本?

如果我在插入模式下按下 hjkl 键,则屏幕上会打印出相应的字符,而不是在文本中移动。

目前我使用的方法是使用 Ctrl + [Esc),然后再遍历文本;但显然这样不够高效。


1
顺带一提:将 escape 映射到更近的组合键(如imap jk <Esc>)也会很有帮助,这样你就不用打断势头并越过键盘去按下该键了。 - tsujin
8
我喜欢将 <ESC> 键映射为 kj,而不是 jk;我的好友 Dijkstra 应该为此负责! - DrBeco
14
我有jkkj,所以我用两个手指按它就像按一个大按钮一样,而且顺序并不重要,这样我就回到正常状态了。 - Edu Ruiz
13个回答

758

在插入模式下使用 h j k l 键来遍历编辑器,似乎是有道理的,但这并不是 Vim 的预期用法! Vim 提供了许多命令,可以使编辑更快速,更容易。

正确的方法是按下 Esc,转到要进行小修正的位置,进行修正,然后返回并继续编辑。这很有效,因为 Vim 比普通字符向前/向后/向上/向下移动的能力更强。学习更多这些能力之后,你会发现效率更高。

以下是一些用例:

  • 你不小心输入了 "accifentally"。没问题,序列 EscFfrdA 可以纠正错误,并将你带回到你正在编辑的位置。 Ff 移动将把光标向后移动到第一个遇到的 "f" 字符。相比之下,在普通编辑器中,Ctrl+DeldEnd 基本上可以完成相同的任务,但需要更多的按键操作,并且需要将手移出键盘区域。
  • 你不小心输入了 "you accidentally typed",但是想要将其更正为 "you intentionally typed"。然后,Esc2bcw 可以删除你想要修正的单词,并进入插入模式,这样你就可以立即重新输入它。要返回编辑模式,只需按下 A,而不是 End,这样你就不必将手移动到 End 键了。
  • 你不小心输入了“mouse”而不是“mice”,没问题——按下经典的Ctrl+w将在不离开插入模式的情况下删除上一个单词。删除一个小单词比修复其中的错误要快得多,我已经习惯了这种方式,在打这条信息时我甚至已经使用了它把浏览器页面关闭了!
  • 重复计数往往被大量闲置。在进行移动之前,您可以输入一个数字;移动将重复这个数字次数。例如,15h将使您的光标向后移动15个字符,4j将使您的光标向下移动4行。开始使用它们,很快你就会习惯它们。如果您的光标距离10个字符处出现了错误,您会发现按下键10次比迭代移动光标的方法慢得多。因此,您可以快速键入12h(作为移动光标所需向后移动多少个字符的粗略猜测),然后立即使用ll向前移动两次以快速更正错误。
  • 但是,如果您仍然想在不离开插入模式的情况下进行小文本遍历,请遵循rson建议并使用Ctrl+O。以我上面提到的第一个示例为例,Ctrl+OFf将使您移动到先前的“f”字符并保持插入模式。


    47
    +1 赞同你的答案,感谢你提供的所有例子! - Andreas Grech
    94
    值得一提的是,在普通模式下,您可以使用 Ctrl+o 发出一个单独的命令。在与 t/T 和 f/F 移动命令结合使用时,这有时可以帮助您到达目标位置。 - Randy Morris
    9
    “你似乎误用了vim,但这很可能是因为你不太熟悉它。”这句话有点儿轻蔑,不是吗? - David Rivers
    19
    这是一个很好的关于如何正确使用Vim的见解。然而,我发现按下“Esc”键很麻烦,因此我认为值得指出的是,你可以将一个更易于访问的键映射到该功能上,例如“imap jj <esc>”。 - Symmetric
    38
    修正笔误时 不应该 退出插入模式。Vim 的强大之处在于您可以创建原子、可重复的操作。插入一个笔误,然后修正它会创建两个分离的操作。修正笔误的正确方式是在不离开插入模式的情况下完成。如果这意味着使用箭头键进行导航,那也没关系。Vim 确实有一些用于在插入模式下导航的按键绑定,请查看 :h ins-special-keysctrl-h:退格,ctrl-w:删除单词,ctrl-u:删除到行首,alt-b:返回上一个单词。 - everett1992
    显示剩余15条评论

    226

    插入模式下,使用CtrlO可以暂时回到正常模式执行一个命令:

    CTRL-O h  move cursor left 
    CTRL-O l  move cursor right
    CTRL-O j  move cursor down
    CTRL-O k  move cursor up
    

    这可能是实现您想要的最简单的方法,而且容易记住。

    在插入模式下,其他非常有用的控制键:

    CTRL-W    delete word to the left of cursor
    CTRL-O D  delete everything to the right of cursor
    CTRL-U    delete everything to the left of cursor
    CTRL-H    backspace/delete
    CTRL-J    insert newline (easier than reaching for the return key)
    CTRL-T    indent current line
    CTRL-D    un-indent current line
    

    这些将消除许多不必要的切换回普通模式。


    18
    谢谢。这应该被视为正确答案。它实际上是有帮助的。 - Atcold
    2
    在我的 Mac 上,是小写字母 o 而不是大写字母 O。这与“标准 vim”有什么不同吗?我看到很多地方似乎都是说大写字母(除非那只是粗心的写法)。你能确认一下吗? - Floris
    好的,非常有用。但是我很难找到一个有趣的组合,这就是删除行。如果不小心插入了一行,这是非常被低估的操作。 - patrik
    10
    Floris Vim不区分Ctrl组合键中的大小写字母,因此无法映射Ctrl + Shift + something。 - Mahmoud Al-Qudsi
    1
    “CTRL-H”就是现金。简直不敢相信我浪费了多少时间去按退格键进行键盘遍历。 - J.M. Janzen

    101

    插入模式

    移动

    hjkl

    尽管 Pavel Shved - 可能更明智的是习惯于退出插入模式 - 这里是一个示例映射集,用于在插入模式下快速导航:

    " provide hjkl movements in Insert mode via the <Alt> modifier key
    inoremap <A-h> <C-o>h
    inoremap <A-j> <C-o>j
    inoremap <A-k> <C-o>k
    inoremap <A-l> <C-o>l
    

    这将使得在插入模式下按下Alt+h向左移动一个字符,Alt+j向下移动,以此类推,与正常模式下的hjkl相似。

    您必须将该代码复制到您的vimrc文件中,以便每次启动vim时加载它(您可以在正常模式下键入:new $myvimrc打开它)。

    任何正常模式操作

    由于默认情况下未映射Alt修饰键(映射到某些重要操作),您可以以相同的方式将其他(或所有)正常模式功能转移到插入模式。例如:
    使用Alt+b移动到当前单词的开头:

    inoremap <A-b> <C-o>b
    inoremap <A-w> <C-o>w
    

    (在插入模式下使用 Alt 的其他用途)

    值得一提的是,Alt 键可能有比复制普通模式行为更好的用途:例如,以下是从相邻行复制当前列到该行末尾部分的映射:

    " Insert the rest of the line below the cursor.
    " Mnemonic: Elevate characters from below line
    inoremap <A-e> 
        \<Esc>
        \jl
            \y$
        \hk
            \p
            \a
    " Insert the rest of the line above the cursor.
    " Mnemonic: Y depicts a funnel, through which the above line's characters pour onto the current line.
    inoremap <A-y> 
        \<Esc>
        \kl
            \y$
        \hj
            \p
            \a
    

    我使用\换行符和缩进来增加清晰度。命令被解释为单行代码。

    编辑的内置快捷键

    CTRL-H   delete the character  in front of the cursor (same as <Backspace>)
    CTRL-W   delete the word       in front of the cursor
    CTRL-U   delete all characters in front of the cursor (influenced by the 'backspace' option)
    

    (在插入模式中没有显著的内置热键用于移动。)

    参考: :help insert-index


    命令行模式

    这组映射使得在命令行中可以使用上方的Alt+hjkl进行移动

    " provide hjkl movements in Command-line mode via the <Alt> modifier key
    cnoremap <A-h> <Left>
    cnoremap <A-j> <Down>
    cnoremap <A-k> <Up>
    cnoremap <A-l> <Right>
    

    或者,这些映射可以一次性将插入模式和命令行模式中的移动都添加进去:

    " provide hjkl movements in Insert mode and Command-line mode via the <Alt> modifier key
    noremap! <A-h> <Left>
    noremap! <A-j> <Down>
    noremap! <A-k> <Up>
    noremap! <A-l> <Right>
    

    将普通模式命令转换为命令行模式的映射命令与插入模式映射命令略有不同(因为命令行模式缺少插入模式的Ctrl+O):

    " Normal mode command(s) go… --v <-- here
    cnoremap <expr> <A-h> &cedit. 'h' .'<C-c>'
    cnoremap <expr> <A-j> &cedit. 'j' .'<C-c>'
    cnoremap <expr> <A-k> &cedit. 'k' .'<C-c>'
    cnoremap <expr> <A-l> &cedit. 'l' .'<C-c>'
    
    cnoremap <expr> <A-b> &cedit. 'b' .'<C-c>'
    cnoremap <expr> <A-w> &cedit. 'w' .'<C-c>'
    

    内置热键用于移动和编辑

    CTRL-B       cursor to beginning of command-line
    CTRL-E       cursor to end       of command-line
    
    CTRL-F       opens the command-line window (unless a different key is specified in 'cedit')
    
    CTRL-H       delete the character  in front of the cursor (same as <Backspace>)
    CTRL-W       delete the word       in front of the cursor
    CTRL-U       delete all characters in front of the cursor
    
    CTRL-P       recall previous command-line from history (that matches pattern in front of the cursor)
    CTRL-N       recall next     command-line from history (that matches pattern in front of the cursor)
    <Up>         recall previous command-line from history (that matches pattern in front of the cursor)
    <Down>       recall next     command-line from history (that matches pattern in front of the cursor)
    <S-Up>       recall previous command-line from history
    <S-Down>     recall next     command-line from history
    <PageUp>     recall previous command-line from history
    <PageDown>   recall next     command-line from history
    
    <S-Left>     cursor one word left
    <C-Left>     cursor one word left
    <S-Right>    cursor one word right
    <C-Right>    cursor one word right
    
    <LeftMouse>  cursor at mouse click
    

    参考资料: :help ex-edit-index


    @YugalJindle:谢谢!:) 我现在已经添加了有关调整命令行模式的信息。(这种方法与插入模式有点不同。) - Aaron Thoma
    左/右移动整个单词!!我怎么不知道这个。谢谢。 - Floris
    1
    实际上,在终端模式下,Alt 在输入命令之前会自动发送 Esc。 - Fuseteam

    35

    如果你是一个 vim 纯粹主义者,请跳过阅读此答案。但如果你是新手,想要一些在众多的 vim 教程和博客中找不到的有用提示,那就请继续往下看... :-)

    几种非正统的(vim)方法

    现在是2014年,作为一个最近重新使用 vim 的人,我可以提供一些潜在的反对意见和技巧。

    使用 shift+左箭头或 shift+右箭头来遍历单词

    虽然在 vim 中重复是一个强大的概念,但我(个人而言)发现使用它会迫使我计算(行数、字符数、单词数等)或猜测。我的大脑通常会想“我想把光标放在这里”,而不是“我想把光标移动_5个单词_”。能够快速移动光标,并通过视觉观察插入点的位置,使我能够将注意力集中在正在编辑的内容上,而不必计算我需要移动多少次才能到达需要编辑的位置。

    打开鼠标模式,并使用鼠标滚轮和点击

    …来浏览大量文本。

    大多数(甚至全部)现代计算机都有一个与键盘紧密结合的触摸板(例如 MacBook)。工业设计师花费了很多时间来优化这些设计,以便不必将手移开键盘。好吧,如果你习惯使用鼠标并且不喜欢切换,那么可能还是会有这个问题,但对于任何新手(比如通过搜索找到本帖子的人),这应该不是什么大问题。

    额外奖励,点击+拖动可以进入可视模式

    启用鼠标后,单击和拖动会切换到可视模式并标记一个区域进行复制。

    使用滚轮

    使用鼠标(滚轮)滚动页面,点击定位光标是很容易的。详细信息请参见http://usevim.com/2012/05/16/mouse/

    所以...

    这些是我称之为更现代化的(使用鼠标、滚轮等)在vim中导航的方法,根据您喜好的输入方式同样有效。

    希望对您有所帮助。


    8
    @MilesRout 是的,我有免责声明。但说真的,我认为有很大一部分 Vim 用户和我一样思考。也就是说……我的大脑通常的工作方式是“我想要光标在那里”,而不是“我想要光标在左边的第五个单词”。传统的 Vim 方式并不适合这些人。我喜欢 Vim,因为它无处不在且功能强大。然而,我并不觉得有必要遵循所有默认机制。 - Shyam Habarakada
    4
    @MilesRout,在vim中有很多与这种事情相关的宗教信仰,所以我不会与您就此进行辩论。重复计数方法对我没有帮助,而且被接受的答案也称其为一种被大量低估的东西。我只能猜测原因是什么。使用w、b等导航到附近位置是很好的,但对于更远的地方,鼠标滚轮对我来说效果更好。干杯。 - Shyam Habarakada
    4
    我不理解就会点踩。有免责声明,喜欢就接受,不喜欢就跳过。 - fangmobile
    这是一个非常有帮助的答案。 - Slava
    2
    作为最近转向VIM的人,我发现这个答案的前提是绝对正确的。能够立即告诉光标在给定位置所需的重复次数可能是经验带来的,也可能不是。就像@ShyamHabarakada一样,我的大脑现在就是不工作。无论这有多么不正统,我个人将fn+hjkl重新映射到箭头键上,用于非常小的移动。对于大的移动,我通常会估算重复次数,然后进行微调。对我来说,这是我能做到的最快速度。 - Jacoscaz
    显示剩余3条评论

    15

    许多Vim社区的人认为你不应该在插入模式下导航,因为这不是Vim的方式。我认为这是一种错误的情绪,当从标准编辑器转换到Vim时学习而来。

    当您使用其工具创建原子、可重复的动作或查找时,Vim最强大。

    如果您正在修复同一插入会话中的错误,则可以在插入模式下导航。但是,您不应该导航到修改的文本范围之外。

    如果在输入文本时出现错误并退出插入模式进行更正,则无法重复预期的操作,.将重复更正。

    Vim支持许多插入模式导航键。显然有箭头键、Home和End,但还有许多其他快捷键。请参阅:h ins-special-keys


    6
    为了在插入模式下更好地导航,为什么不映射一些快捷键呢?
    imap <C-b> <Left>
    imap <C-f> <Right>
    imap <C-e> <End>
    imap <C-a> <Home>
    " <C-a> is used to repeat last entered text. Override it, if its not needed
    

    如果你能解决在终端中Meta键的问题,你就可以更好地模拟emacs模式。正常模式下的导航要好得多,但对于较短的移动操作,保持插入模式会更有帮助。

    对于较长跳转,我喜欢以下默认的翻译:

    <Meta-b>    maps to     <Esc><C-left>
    

    这将切换到普通模式并返回一个单词


    4
    在GVim中,你可以使用鼠标。但说实话,使用箭头键有什么问题吗?它们之所以在键盘上是有原因的。

    9
    但这个原因并没有考虑到Vim用户。Vim的一个中心优势在于,你可以在不将手从键盘主位移开的情况下完成各种操作,尤其是hjkl移动。 - Aaron Thoma
    1
    我同意@ammoQ的观点。使用箭头键没有任何问题。如果使用箭头键可以提高你的生产力,那就用它吧。 - Eun Woo Song
    赞誉:我在使用vi时更喜欢使用hjkl而不是箭头键,但在模式之间切换已经成为我的下意识动作。 - Erich Kitzmueller

    2

    我相信在插入模式下,HomeEnd(和PageUp/PageDn)也可以正常使用,但除此之外,我不认为还有其他标准键用于文本遍历。


    但是可能没有什么方法只使用字母键来遍历文本吗? - Andreas Grech
    5
    如果你不想能够打出某些字母,那当然是可以的... ;) - hobbs
    @hobbs,Ctrl+hjkl怎么样?那应该有意义。 - user4052054

    1
    您可以创建在插入模式下工作的映射。方法是通过inoremap实现的。请注意命令开头的'i'(noremap可用于避免键映射冲突)。相应的是'正常'模式的'n'。您可以推断出vim认为什么是'正常'的;)
    然而,您真正想要使用“正常”模式来浏览文本。Vim非常擅长这种操作,所有这些功能都可以从正常模式中获得。 Vim已经提供了易于从正常模式转换到插入模式的方法(例如,i,I,a,A,o,O)。诀窍是使进入正常模式变得容易。方法是将escape键重新映射为更方便的键。但是您需要一个不会与常规打字发生冲突的键。我使用:
    inoremap jj <Esc>
    

    既然“jj”(连续快速按下两个j)似乎不在我的词汇表中,其他人会将其映射到他们习惯的位置。

    我做的另一个重要更改是通过使用主机计算机的键盘配置将大写锁定和控制键互换位置(这对Emacs用户很常见)。因为我几乎从不使用大写锁定键,并且它正好在我想要的位置上有一个大而美丽的按钮。(缺点是当你发现自己在一个未修复的键盘上时!啊啊啊!)

    一旦重新映射了大写锁定键,您就可以舒适地使用以下插入模式的重新映射:

    请记住,某些键已经在插入模式中映射(默认情况下,回删一个单词是C-w(Control-w)),您可能已经拥有所需的绑定。尽管如此,我仍然喜欢C-h,在我的.vimrc文件中添加了以下内容:

    inoremap <C-h> <C-w>
    

    但是,您可能希望在正常模式下拥有相同的肌肉记忆痉挛,因此我还将C-h映射为:

    nnoremap <C-h> db
    

    (d)向后删除与同一键位组合的(b)相同。这种快速编辑在处理打字错误时非常有用。但是,移动文本和除了删除前一个单词之外的任何操作都要使用正常模式。一旦你养成了切换模式的习惯(当然使用重新映射),它将比重新映射插入模式更加高效。


    不错的逃逸字符重新映射 - 我认为它适用于除了转写阿拉伯语之外的任何东西! - jjt

    1

    抱歉,但vim不是那样工作的。

    您应该切换到“正常”模式,导航,然后再次返回插入模式。


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接