UltiSnips和YouCompleteMe

142
我在我的MacVim上安装了bundles Ultisnips和YouCompleteMe插件。 问题是,由于YCM绑定了Tab键,所以Ultisnips无法工作。 我尝试使用let g:UltiSnipsExpandTrigger = "<s-tab>"来设置Shift-Tab触发代码片段完成,但由于某种未知的原因它并没有生效。我可以使用Caps键作为触发器,但目前我还没有找到这样做的方法。
你们中有人同时使用这两个附加组件吗? 我该如何让Shift-Tab起作用? 你能推荐另一个触发代码片段的键吗?

YCM 也映射 <S-Tab>,UltiSnips 也是如此,如果我没记错的话。你应该询问 YCM 的作者,我猜。 - romainl
我在ycm上更改了以前完成的键,并删除了s-tab,但仍然无法正常工作。我想我会尝试在GitHub上给他发消息。 - pvinis
1
通过使用 :verbose map <S-Tab> 命令,检查你的映射是否正常工作,但在命令行 vim 中可能无法正常工作。在我看来,一个相当不错的替代方案是 <CR> - Daan Bakker
谢谢,我迫不及待地想找到一个解决方案,而YouCompleteMe没有论坛这一事实很让人恼火。谢谢。 - patm
2
最近你尝试过这个吗?一个或两个插件肯定已经更新了,因为UltiSnips的文档中写到:"YouCompleteMe - 自带UltiSnips完成支持。它提供了一个非常漂亮的片段完成对话框"。 - Kyle Strand
14个回答

209

另一个选择是使用SuperTab插件:

" if you use Vundle, load plugins:
Bundle 'ervandew/supertab'
Bundle 'Valloric/YouCompleteMe'
Bundle 'SirVer/ultisnips'

" make YCM compatible with UltiSnips (using supertab)
let g:ycm_key_list_select_completion = ['<C-n>', '<Down>']
let g:ycm_key_list_previous_completion = ['<C-p>', '<Up>']
let g:SuperTabDefaultCompletionType = '<C-n>'

" better key bindings for UltiSnipsExpandTrigger
let g:UltiSnipsExpandTrigger = "<tab>"
let g:UltiSnipsJumpForwardTrigger = "<tab>"
let g:UltiSnipsJumpBackwardTrigger = "<s-tab>"

在这里,YouCompleteMe绑定到另一个组合键Ctrln,但是该组合键被绑定到通过SuperTab进行选项卡切换。 UltiSnips和SuperTab配合良好,因此您可以直接将UltiSnips绑定到tab,并且一切都会顺利进行。


8
乔伊的建议对我不起作用(选项卡无法展开任何内容,只能滚动到下一个自动完成选项)。这个答案非常有效,但是我必须先更新和重新编译YouCompleteMe。 - BenjaminGolder
3
可以在自动完成列表中突出显示片段吗? - syntagma
4
该翻译为:该死!伙计!运作得非常好!有史以来最佳解决方案! - Yves Lange
7
这很好,但在代码片段中按下“tab”键会前往下一个制表位,而不是完成YCM的建议。我不得不添加let g:UltiSnipsJumpForwardTrigger="<Right>"let g:UltiSnipsJumpBackwardTrigger="<Left>"以使其正常工作。 - Gabriel Florit
1
这个解决方案是否应该让ycm自动完成仍然可以使用tab键?现在,ycm自动完成无法使用tab键了。 - ElefEnt
显示剩余7条评论

55

在您的.vimrc文件中,尝试在YouCompleteMe问题跟踪器页面上提供的建议

let g:UltiSnipsExpandTrigger="<c-j>"

虽然这个设置会使得扩展代码片段时使用默认的跳转映射,但它模拟了 UltiSnips 帮助标签中提到的 TextMates 行为。

由于我已经将大写锁定键映射为 Ctrl 键,因此这个映射可以很顺畅地工作。


1
这应该是最好的答案,简单明了。虽然在我的macOS 10.12上,<c-j>无法使用,但我将其更改为<c-k>,然后一切正常。 <tab>向前,<s-tab>向后,<c-k>展开片段。谢谢。 - gpanda
1
我之前对Ultisnips不熟悉,尝试了这个建议。但是我不建议这样做,因为将“向前跳”和“展开”映射到同一个键会使嵌套片段无法使用,而这是你最终可能需要的功能。 - Kevin

40
将以下代码复制到你的vimrc中,然后享受它带来的便利。此功能将处理YCM和UltiSnips之间的所有问题。
function! g:UltiSnips_Complete()
    call UltiSnips#ExpandSnippet()
    if g:ulti_expand_res == 0
        if pumvisible()
            return "\<C-n>"
        else
            call UltiSnips#JumpForwards()
            if g:ulti_jump_forwards_res == 0
               return "\<TAB>"
            endif
        endif
    endif
    return ""
endfunction

au BufEnter * exec "inoremap <silent> " . g:UltiSnipsExpandTrigger . " <C-R>=g:UltiSnips_Complete()<cr>"
let g:UltiSnipsJumpForwardTrigger="<tab>"
let g:UltiSnipsListSnippets="<c-e>"
" this mapping Enter key to <C-y> to chose the current highlight item 
" and close the selection list, same as other IDEs.
" CONFLICT with some plugins like tpope/Endwise
inoremap <expr> <CR> pumvisible() ? "\<C-y>" : "\<C-g>u\<CR>"

28
我认为应当给予一些应得的赞扬:https://github.com/Valloric/YouCompleteMe/issues/36#issuecomment-15451411,还有稍后几个评论中的BufEnter autocmd。 - ches
3
对我来说,在2014年7月10日之后,这似乎在Mac OS X上不起作用。然而,Siegfried的答案有效。 - miguel.martin
到目前为止看起来很不错!但是我如何在代码段断点之间进行“制表符切换”? - chmanie
@chmanie 如果ycm自动完成弹出窗口可见,请先按<Enter>关闭它,然后您可以“通过Tab键”进行操作。 - Joey Liu
1
我发现将 g:UltiSnipsJumpForwardTrigger="<cr>" 绑定是很方便的,这样我仍然可以通过 Tab 键浏览所有可能的完成项/代码片段。 - alaroldai
1
这让我可以通过制表符浏览YCM列表完成(包括Ultisnips建议),但最后的inoremap <expr>行似乎实际上并没有影响我的回车键按下。我可以使用<C-y>手动触发完成,但是Enter键无任何作用。有什么建议吗? - HaaR

18

个人选择手动导航而不使用 <tab> 键与 YouCompleteMe 进行自动补全。

因此,我将以下内容添加到我的 .vimrc 文件中:

let g:ycm_key_list_select_completion=[]
let g:ycm_key_list_previous_completion=[]

这只是简单地禁用了YCM中的tab键。相反,您可以使用移动键(箭头或CTRL-N/CTRL-P)并使用CR选择条目。UltiSnips默认使用tab


18

我在我的vimrc文件中有以下内容:

"" YouCompleteMe
let g:ycm_key_list_previous_completion=['<Up>']

"" Ultisnips
let g:UltiSnipsExpandTrigger="<c-tab>"
let g:UltiSnipsListSnippets="<c-s-tab>"

这就是我第一次尝试做的事情,但我把"UltiSnips"拼错成了"Ultisnips"... 哦,没关系,最终总算解决了!


5

借鉴了Michaelslec、Joey Liu的答案,结合我在这个问题线程这位用户的vimrc文件中找到的解决方案,现在我有了一个可以解决几乎所有问题的方法。

function! g:UltiSnips_Complete()
  call UltiSnips#ExpandSnippet()
  if g:ulti_expand_res == 0
    if pumvisible()
      return "\<C-n>"
    else
      call UltiSnips#JumpForwards()
      if g:ulti_jump_forwards_res == 0
        return "\<TAB>"
      endif
    endif
  endif
  return ""
endfunction

function! g:UltiSnips_Reverse()
  call UltiSnips#JumpBackwards()
  if g:ulti_jump_backwards_res == 0
    return "\<C-P>"
  endif

  return ""
endfunction


if !exists("g:UltiSnipsJumpForwardTrigger")
  let g:UltiSnipsJumpForwardTrigger = "<tab>"
endif

if !exists("g:UltiSnipsJumpBackwardTrigger")
  let g:UltiSnipsJumpBackwardTrigger="<s-tab>"
endif

au InsertEnter * exec "inoremap <silent> " . g:UltiSnipsExpandTrigger     . " <C-R>=g:UltiSnips_Complete()<cr>"
au InsertEnter * exec "inoremap <silent> " .     g:UltiSnipsJumpBackwardTrigger . " <C-R>=g:UltiSnips_Reverse()<cr>"

这对于修复使用COC和Ultisnips时遇到的相同问题非常有帮助。想要使用<TAB>和<S-TAB>在PUM中上下移动以及在Ultisnips占位符内前后移动。谢谢。 - 110100100

4

虽然我知道这篇帖子有点旧,但我有自己的函数,比上面给出的函数更加优化:

function! g:UltiSnips_Complete()
  call UltiSnips#ExpandSnippetOrJump()
  if g:ulti_expand_or_jump_res == 0
    if pumvisible()
      return "\<C-N>"
    else
      return "\<TAB>"
    endif
  endif

  return ""
endfunction

当然,如果您只保留Joey Liu提供的设置并使用此功能,则一切都将完美运行!
编辑:此外,我使用另一个函数来增加YouCompleteMe和UltiSnips之间的回退功能。我会向您展示我的意思:
function! g:UltiSnips_Reverse()                                                                                               
  call UltiSnips#JumpBackwards()                                                                                              
  if g:ulti_jump_backwards_res == 0        
    return "\<C-P>"                                                                                                           
  endif                                                                                                                       

  return ""                                                                                                                   
endfunction

然后只需将以下内容放入您的 .vimrc 文件中:
au BufEnter * exec "inoremap <silent> " . g:UltiSnipsJumpBackwardTrigger . " <C-R>=g:UltiSnips_Reverse()<cr>"

还有let g:UltiSnipsJumpBackwardTrigger="<s-tab>"和你的设置!


4

根据Siegfried的回答,我正在使用以下更自然的方式:

let g:ycm_key_list_select_completion = ['<C-j>']
let g:ycm_key_list_previous_completion = ['<C-k>']

let g:UltiSnipsExpandTrigger = "<C-l>"
let g:UltiSnipsJumpForwardTrigger = "<C-j>"
let g:UltiSnipsJumpBackwardTrigger = "<C-k>"

我还在其他地方使用c-hjkl绑定(在不同窗格之间切换),但这只会在正常模式下进行,所以没有问题。


这很有效,而且感觉很自然。谢谢你的分享! - Rudolf Adamkovič

3
我同时使用它们两个。默认情况下,YouCompleteMe将<Tab><Down>绑定到选择下一个完成项,将<S-Tab><Up>绑定到选择上一个完成项。您可以通过g:ycm_key_list_select_completiong:ycm_key_list_previous_completion选项更改YouCompleteMe的绑定。请注意,当选项从单个字符串更改为字符串列表时,这些选项的名称最近已更改。

3

虽然这篇文章中有很多正确的答案,但我想说问题是由YCM和UltiSnip之间的按键绑定冲突引起的。虽然YCM默认支持UltiSnip代码片段,但它将默认的UltiSnip扩展触发器<tab>作为其完成选择键,因此UltiSnip代码片段将不会通过<tab>进行扩展。给它们不同的按键绑定就可以解决问题,我个人使用<c-n><c-p>来控制YCM,而使用默认的<tab>来控制UltiSnip。您可以在Vim中使用help youcompleteme文档获取更多详细信息。


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