在 Vim 中自动插入匹配的大括号

Posted

技术标签:

【中文标题】在 Vim 中自动插入匹配的大括号【英文标题】:Automatically insert a matching brace in Vim 【发布时间】:2011-05-30 03:21:20 【问题描述】:

方式花了太多时间摸索,因为 Vim 不像大多数 IDE 那样处理右括号。这就是我想要发生的事情:

输入这个:

if( whatever )
 <CR>

然后得到这个:

if( whatever )

  |  

&lt;CR&gt; 表示点击 ENTER 键,| 是光标的位置。这就是 Eclipse 所做的。这就是 Visual Studio 所做的。这就是我希望 Vim 做的事情。

我看过一些插件,尝试了一些,但似乎没有一个会出现这种行为。当然,我不可能是第一个想要这个的程序员

【问题讨论】:

github.com/garbas/vim-snipmate 注意:Vim 是一个非常强大的文本编辑器,它在某些方面可以像 IDE 一样工作……但它不是 IDE。在这种情况下,这是一个文本编辑功能,这是 Vim 擅长的,所以你是金子。 【参考方案1】:

在 VimL 中,您可以映射 以完全按照您的意愿进行操作:

inoremap  <CR><Esc>ko

根据您的自动缩进设置,您可能需要在&lt;CR&gt; 之后添加&lt;BS&gt;

要获得更完整的解决方案,我建议您查看Luc Hermitte's vim plugins。到目前为止,他们从来没有让我失望过。

【讨论】:

映射&lt;CR&gt; 也可以吗?我的意思是,如果我在 python、js 或 ruby​​ 中只输入一个哈希 "something":"like this" 会怎样? 是的,&lt;CR&gt; 是可能的。这就是我的 .vimrc &lt;CR&gt; &lt;CR&gt;&lt;Esc&gt;ko 嗨@AgmLauncher,如果我输入,它可以工作,但是当我粘贴包含的代码块时会出现问题,它会添加 at结束。 @Evan - 粘贴代码时,很多事情都会出错,尤其是自动缩进等。在粘贴之前尝试 :set paste ,然后在完成后尝试 :set nopaste 。这会切换粘贴模式。【参考方案2】:

将 AutoClose 与以下配合使用可以正常工作。

inoremap <CR> <CR><C-o>O

至少对我的系统来说是这样(Mac OS X 上的 Unix 终端)。

【讨论】:

【参考方案3】:

大括号、方括号和括号的解决方案,中间有制表符。

" Automatically closing braces
inoremap <CR> <CR><Esc>ko<tab>
inoremap [<CR> [<CR>]<Esc>ko<tab>
inoremap (<CR> (<CR>)<Esc>ko<tab>

结果:

function() 
  |

【讨论】:

【参考方案4】:

这是我的 vimrc 中的内容:

let s:pairs=
            \'<': '>',
            \'': '',
            \'[': ']',
            \'(': ')',
            \'«': '»',
            \'„': '“',
            \'“': '”',
            \'‘': '’',
        \
call map(copy(s:pairs), 'extend(s:pairs, v:val : v:key, "keep")')
function! InsertPair(left, ...)
    let rlist=reverse(map(split(a:left, '\zs'), 'get(s:pairs, v:val, v:val)'))
    let opts=get(a:000, 0, )
    let start   = get(opts, 'start',   '')
    let lmiddle = get(opts, 'lmiddle', '')
    let rmiddle = get(opts, 'rmiddle', '')
    let end     = get(opts, 'end',     '')
    let prefix  = get(opts, 'prefix',  '')
    let start.=prefix
    let rmiddle.=prefix
    let left=start.a:left.lmiddle
    let right=rmiddle.join(rlist, '').end
    let moves=repeat("\<Left>", len(split(right, '\zs')))
    return left.right.moves
endfunction
 noremap! <expr> ,f   InsertPair('')
 noremap! <expr> ,h   InsertPair('[')
 noremap! <expr> ,s   InsertPair('(')
 noremap! <expr> ,u   InsertPair('<')

而且,对于某些文件类型:

inoremap <CR> <C-o>o<C-o>O

// 我知道 InsertPair 函数是微不足道的,但它可以节省时间,因为有了它我可以用一个命令定义命令和普通模式映射,而无需编写大量 &lt;Left&gt;s。

【讨论】:

【参考方案5】:

最后我发现不需要插件,但这对我来说很完美:

inoremap  <Esc>ha
inoremap ( ()<Esc>ha
inoremap [ []<Esc>ha
inoremap " ""<Esc>ha
inoremap ' ''<Esc>ha
inoremap ` ``<Esc>ha

【讨论】:

【参考方案6】:

将以下内容放入您的 .vimrc 文件中:

inoremap  <ESC>ha

每当您在插入模式下按 时,都会生成 并将您的光标放在右大括号上,这样您就可以立即开始在它们之间输入。通过将花括号按顺序而不是放在不同的行上,您可以手动将制表符放在 前面。这样你就不会在它前面有错误数量的标签。

也许有人可以弄清楚如何计算光标所在的标签数量,然后在新行上的 前面生成相同数量的标签。

【讨论】:

【参考方案7】:

对于像我一样遇到这种情况并且正在寻找比 AutoClose 更新的东西的任何人:delimitMate 我发现它不仅是 AutoClose 的更可取的解决方案,行为明智,而且还在积极开发中。根据vim.org 的说法,AutoClose 自 2009 年以来一直没有更新。

【讨论】:

请注意delmitMateExpand 选项默认是关闭的。您需要将let delimitMate_expand_cr = 1 添加到您的.vimrc【参考方案8】:

我尝试了不同的插件,但我发现auto-pairs 最准确和最容易使用。它非常直观,当您安装它时,您会得到开箱即用的预期效果。

【讨论】:

这个答案发布已经五年了。万一其他人遇到类似问题,这对我有用,至少不会破坏其他插件。【参考方案9】:

我一直更喜欢 sublime text 的作用,它将右大括号作为下一个字符附加,所以我在我的 .vimrc 中添加了以下内容:

inoremap (  ()<ESC>hli

将光标移动到两个大括号之间。

【讨论】:

这会将( 替换为()hli。 Mac 上的 Vim8。【参考方案10】:
inoremap ( ()<ESC>i
inoremap " ""<ESC>i
inoremap ' ''<ESC>i
inoremap  <Cr><Esc>O

【讨论】:

【参考方案11】:

正如您将在wikia tip 中看到的那样:对于这个反复出现的问题有很多解决方案(我什至有mine)。

也就是说,如果您将自己限制在括号对中。在这里,您处于控制语句的上下文中。因此,您更有可能发现在键入“if”语句时不会期望您键入“) ”的 sn-p 系统。 Vim 快捷方式往往比我在你的问题中读到的更短。这里再次有很多选择,你会找到最有可能的狙击手,可能是我的C&C++ suite。

【讨论】:

仅供参考:Google 在尝试获取 lh-cpp-1.0.0.vba vimball 时会给出 404。我用的是svn,以前没注意过。 确实如此。我的错。我想在正式发布 vimball 之前完成文档。【参考方案12】:

delimitMate 对此进行了设置。

【讨论】:

更多信息,请。哪种设置? 嗯,这是不久前的事了。我的意思可能是delimitMate_expand_cr,尽管它似乎并没有完全按照要求做。似乎正确插入换行符,但可能没有添加结束括号。帮助文件在这里:github.com/Raimondi/delimitMate/blob/master/doc/delimitMate.txt 就个人而言,这些天我只使用 endwise (github.com/tpope/vim-endwise) 并匹配我自己的括号,因为没有自动化完全正确。 感谢指向 endwise 的指针。以前看的时候不知道是什么。【参考方案13】:

Vim 补丁 7.4.849 添加了一个绑定以允许光标移动而无需重新启动撤消序列。一旦更新到 >= 7.4.849,这样的东西就很好用。

inoremap ( ()<C-G>U<Left>

请注意,我是直接从补丁中包含的文档中获取的。此功能迄今为止最简单的解决方案。

提交补丁 7.4.849: https://github.com/vim/vim/commit/8b5f65a527c353b9942e362e719687c3a7592309 邮件列表线程:http://vim.1045645.n5.nabble.com/Any-automatic-bracket-insertion-plugins-not-breaking-undo-td5723654.html

【讨论】:

这是修复 '.'不使用自动匹配的括号。【参考方案14】:

按照标题为 Automatically append closing characters 的文章中的建议安装和使用 Vim 脚本 AutoClose。

【讨论】:

自动关闭不符合我的要求。它将右大括号留在同一行,让我按两次 Enter,返回命令模式,向上移动一行,插入模式,制表符,最后键入。【参考方案15】:

只是给@Bob 的便条。

Karl Guertin 的AutoClose 有一个名为“双大括号”的函数,即可以键入两次大括号,如下所示。

int func_name(void)  ==> Type `' twice here.

会导致:

int func_name(void) 
| ==> Cursor here.

然后,您可以键入 单个 Tab,根据您的 `shiftwidth' 设置缩进,然后键入。

【讨论】:

【参考方案16】:

如果您输入 并点击alti,您将在INSERT 模式下处于大括号之间(至少在终端中)。然后你可以点击 ENTER 后跟 altshifto 来插入换行符。你也可以只做&lt;CR&gt;altshifto

这可能不是全自动的,但我认为它是半自动的。它消除了对更多插件的需求,并且是了解其他用例的有用信息。例如,我一直使用 altshifto 来插入空行,而不必显式离开 INSERT 模式,而 alti 用于进入() 等。

【讨论】:

【参考方案17】:

如果您启用了自动缩进,请将其插入您的 ~/.vimrc

inoremap <CR> <CR><Esc>ko
inoremap [<CR> [<CR>]<Esc>ko
inoremap (<CR> (<CR>)<Esc>ko

如果不是

inoremap <CR> <CR><Esc>ko<tab>
inoremap [<CR> [<CR>]<Esc>ko<tab>
inoremap (<CR> (<CR>)<Esc>ko<tab>

然后你可以映射一个键(在我的例子中,键是ä,这可以替换为你想要的任何东西)...

map ä A<space><CR>

...自动为您完成所有这些操作,如果您在按键行中的任何位置。

示例('|' 表示您的光标所在的位置):int main(int a|rgc) 当你现在按下键时(在我的例子中是 ä 在命令模式下),结果将是这样的:

int main(int argc) 
    |

【讨论】:

【参考方案18】:

您不需要特殊的插件来执行此操作 - 但这是一个两步过程。

首先,将以下内容添加到您的.vimrc 以吃掉触发字符:

" eat characters after abbreviation
function! Eatchar(pat)
    let c = nr2char(getchar(0))
    return (c =~ a:pat) ? '' : c
endfunction

然后将此缩写添加到您的.vimrc

inoreabbr <silent>  
      \<cr><space><space>
      \<cr><esc>0i<esc>k$i<c-r>=Eatchar('\m\s\<bar>\r')<cr>

第二行和第三行开头的\ 只是一个续行字符。您可以在一行中完成所有这些,但是我添加了它,以便我可以以一种反映您正在寻找的输出的方式传播缩写 - 只是让事情更直观一些。

【讨论】:

【参考方案19】:

我的解决方案:

inoremap <expr> <CR> InsertMapForEnter()
function! InsertMapForEnter()
    if pumvisible()
        return "\<C-y>"
    elseif strcharpart(getline('.'),getpos('.')[2]-1,1) == ''
        return "\<CR>\<Esc>O"
    elseif strcharpart(getline('.'),getpos('.')[2]-1,2) == '</'
        return "\<CR>\<Esc>O"
    else
        return "\<CR>"
    endif
endfunction

说明:

上面的代码首先检查你是否使用Enter来确认代码完成,如果不是,它会在你输入Enter时缩进|。此外,它还提供html标签自动缩进。

示例:

if( whatever )|

Enter你会得到

if( whatever )

  |  

这也适用于 html 文件。看下面的例子

<html>|<html>

Enter你会得到

<html>
    |
</html>

【讨论】:

以上是关于在 Vim 中自动插入匹配的大括号的主要内容,如果未能解决你的问题,请参考以下文章

Edge Animate 中的大括号不匹配

试编写一个算法从检查一个Java语言中的大括号方括号小括号是不是配对,若能够全?

wps打数学方程组的大括号怎么打?

数学公式中的方程组联立的大括号怎么输入啊?

如何让 Vim 自动放置大括号?

Xcode:调整自动生成的大括号的缩进?