在vim中自动创建匹配的花括号


17

如何在vim中自动创建匹配的花括号?

它的工作方式如下:如果我输入了一个右括号,则右括号应会自动出现,并且光标应位于两者之间。要跳出括号对,Ctrl-j可以使用组合。

有很多插件可以自动插入括号。但是他们

  • 使用不同于Ctrl-j跳出括号对的组合键,或者
  • 干扰UltiSnips按键绑定。

预期效果如下

:inoremap ( ()<Esc>:let leavechar=")"<CR>i
:imap <C-j> <Esc>:exec "normal f" . leavechar<CR>a

但是使用这些设置,UltiSnips片段不再起作用。所以我用UltiSnips插入了右括号:

inoremap ( (<C-R>=UltiSnips_Anon('($1)$0', '(')<CR>

这几乎可行。匹配的括号被插入,我可以用跳过结尾的括号Ctrl-j。但是,仅当开放式支架前面有空间时,此方法才起作用。

main () // works, the closing parentheses is added
main(   // fails without a space

我的解决方案要么需要使用其他键绑定来跳过闭合括号,要么需要在打开的括号前面留一个空间。如何解决这个问题?

注意:我以括号为例。它应使用括号,大括号,方括号和小于号,并且不会干扰UltiSnips插件。


1
您是否尝试过自动关闭?您可以使用跳出配对),重新映射c-j可能会起作用。
凯文(Kevin)

Answers:


4

如何在vim中自动创建匹配的花括号?

正如您将看到的,这个问题并不简单。简单的答案是:使用插件,例如autoclosesmartinput。只是天真地重新映射([..键会在几行中为您提供边缘情况,这就是制作这些插件的原因,以及它们通常非常复杂的原因(如果有的话)。

所以我用UltiSnips插入了右括号

您可以改用此方法(与我最初的建议不同):

inoremap ( ()<CR>=UltiSnips_Anon('$1)$0', ')')<CR>

UltiSnips将在哪里分割线,(而不包括main在比赛中。为此使用代码段插件的问题是(通常)它们不支持嵌套,因此当插入下一个(嵌套的)代码段时,它们会忘记任何跳转位置。

要跳出括号对,Ctrl-j可以使用组合。

您可以重新映射Ctrl-jUltiSnips或冲突的插件。如果映射未在文档中列出,则可以:map/imap/nmap <key>用来显示映射。如果您想Ctrl-j选择并完成两个插件的工作,则要求:

  1. 比我怀疑您可能认为的要先进得多的东西
  2. 我怀疑你不是真的想要的东西

考虑以下bash循环:

while (( ${arr1[i]} < ${arr2[i<CURSOR>]} )); do
  [next_snippet_position_marker]
done

在这种情况下,您需要按Ctrl-j5次才能进入循环主体。使用右大括号跳出相应的对,可以更好地控制光标实际移动的位置。您可以实现一个堆栈来跟踪插入的对并用于Ctrl-j弹出和移动,但是如果您开始手动删除花括号而不将其从堆栈中删除,则会遇到问题。因此,您将开始解决括号插件正在尝试解决的问题。这是重塑的硬轮。

对此进行扩展,您可以得到您最初Ctrl-j想要的内容,并用于跳出括号和代码片段。如果您使用一些虚拟值来表示摘录位置,并且除了右大括号外还将其推入堆栈,则动态重映射Ctrl-j为对应于摘录或大括号的处理。但是随后您将需要实施一些相当高级的启发式方法,以弄清楚应该发生什么魔术,因为您基本上同时处理了两个问题,这些问题目前由代码段插入插件和括号匹配插件的创建者分别解决,并且再次重新解决这些问题,就顶他们的解决方案,实现方便的,那么,魔术。

它归结为控制与便利。我认为在这种情况下,控件将为您提供更好的服务,这意味着您应将这些问题及其相关的插件和键盘映射分开。如果您仍然想要方便,那是可行的,但是很难。


1

我认为delimitMate可以满足您的需求。

它会自动关闭括号或引号,并将光标置于两者之间。要跳出括号对(处于插入模式时),您可以执行Ctrl-g+,g但可以Ctrl-j通过将其添加到您的映射中来重新映射为vimrc

% Jump out of a block of parentheses (uses delimitMate)
imap <C-j> <C-g>g

最好在此处提供更多详细信息,并使用该链接作为进一步阅读的参考。这样,当链接变为无效时,您的答案不会失去所有值。
Anthon 2014年

1

我发现自动关闭会增加一些延迟,并且还会干扰我的设置(Ultisnips和Supertab),但是我喜欢它的模拟Eclipse CDT的方法。

我将delimitMate与以下地图结合使用,以帮助导航和缩进,试图获得相同的结果:

imap <C-F> <C-G>g           " To jump out brackets in same line.
inoremap <C-K> <ESC>ki<TAB> " To move and insert an indent on the line before the current cursor (assuming empty line)

我用这种方式:插入开孔{ <CR><CR><C-K>并开始在缩进的内线中书写。


我发现delimitMate也增加了一些滞后
icc97 '18

1

我个人使用smartinput自动插入括号和引号。例如,{在任何地方键入都将使{}光标位于中间。要离开{括号组,只需}在插入的旁边键入when }

但是,这确实支持您对制表符和跳转到括号之外的要求。它也不会在方括号之间创建新的,但是无论如何您只需要一个额外的键- <CR>

您可以映射<C-J>到下一行:

:inoremap <C-J> <C-O>j

或者如果您想移至下一行的开头:

:inoremap <C-J> <C-O>+

0

这样的事情可能适合您。

inoremap {      {}<Left>
inoremap {<CR>  {<CR>}<Esc>O
inoremap {{     {
inoremap {}     {}

您所建议的是一个简单的映射,不允许跳过右括号。
Marco

0

实际上,Ultisnips可以做到几乎完美(这可能是新的)。稍微修改上面给出的答案,我在

inoremap () ()<C-R>=UltiSnips#Anon('($1)$0', '()', 'double parentheses', 'i')<CR>

必须输入()哪种类型更好,但是也可以更改(。然后,附加的可选参数UltiSnips#Anon是描述和i允许字内扩展的修饰符。

通过<c-j>作品跳出括号,也嵌套在其他片段中。但是,调用嵌套()括号似乎破坏了此功能,这没什么大不了的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.