用于 Ultisnips+Deoplete 兼容性的 vimscript

vimscript for Ultisnips+Deoplete compatibility

我想知道如何编写重载 <TAB> 的函数。

首先它会检查是否有需要完成的片段,如果有片段,则展开它。

否则,我希望该函数在按下 Tab 之前检查光标前是否有 space(或者我们在新行上)。如果是这样,那么它应该做常规 <tab>。 否则,我想让它调用

deoplete#manual_complete()

除非已经打开了一个菜单,在这种情况下,我应该可以通过 Tab 键浏览它。

这是我的尝试(完全失败)和一些设置供参考:

let g:ulti_expand_or_jump_res = 0 "default value, just set once

function! Ulti_ExpandOrJump_and_getRes()
  call UltiSnips#ExpandSnippetOrJump()
  return g:ulti_expand_or_jump_res
endfunction

inoremap <silent><expr> <tab>
  \ (Ulti_ExpandOrJump_and_getRes() > 0) ? "\<C-y>"
  \ : pumvisible() ? "\<C-n>" :
  \ <SID>check_back_space() ? "\<TAB>" :
  \ deoplete#manual_complete()

function! s:check_back_space() abort "{{{
  let col = col('.') - 1
  return !col || getline('.')[col - 1] =~ '\s'
endfunction "}}}

奇怪的是,当我按 Tab 键时,vim 的右下角显示我输入了“^I”,这是非常奇怪的行为。

我没有 ultisnips expand trigger as "tab" 的原因是它禁止使用 tab 来 deoplete(无论出于何种原因。)

我认为您 运行 遇到的主要问题是 UltiSnips#ExpandSnippetOrJump() 会尝试移动光标,这是插入模式下 <expr> 映射的问题。使用 <C-R>=...<CR> 应该可以使它工作。 (至少那是 UltiSnips 文档中的示例所使用的。)

我还建议使用单个函数来处理所有 Tab 大小写,而不是相当长的单行代码。这样您就可以使用 ifs 并具体记录每个案例。

我还认为,对于扩展或跳转 UltiSnips 的情况,您希望扩展到空而不是 <C-y>,对吗?

综合起来:

function! HandleTab() abort
  " First, try to expand or jump on UltiSnips.
  call UltiSnips#ExpandSnippetOrJump()
  if g:ulti_expand_or_jump_res > 0
    return ""
  endif
  " Then, check if we're in a completion menu
  if pumvisible()
    return "\<C-n>"
  endif
  " Then check if we're indenting.
  let col = col('.') - 1
  if !col || getline('.')[col - 1] =~ '\s'
    return "\<Tab>"
  endif
  " Finally, trigger deoplete completion.
  return deoplete#manual_complete()
endfunction

inoremap <silent> <Tab> <C-R>=HandleTab()<CR>

您可能想查看支票的顺序。在我看来,应该首先检查 pumvisible() 。此外,检查你是否缩进可能比检查 UltiSnips 扩展更便宜,尽管我猜你可能在有 space 时跳过字段......无论如何,调整它应该很容易使它有效。