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

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

输入这个:

if( whatever )
{ <CR>

然后得到这个:

if( whatever )
{
  |  
}

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

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

【问题讨论】:

  • 注意:Vim 是一个非常强大的文本编辑器,它在某些方面可以像 IDE 一样工作……但它不是 IDE。在这种情况下,这是一个文本编辑功能,这是 Vim 擅长的,所以你是金子。

标签: vim autocomplete


【解决方案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>
              

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

              【讨论】:

              • 这是修复 '.'不使用自动匹配的括号。
              【解决方案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>
                      

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 2016-10-03
                        • 2011-11-25
                        • 2011-09-10
                        • 1970-01-01
                        • 2021-10-12
                        • 1970-01-01
                        • 2019-09-04
                        相关资源
                        最近更新 更多