neoclide / coc.nvim

Nodejs extension host for vim & neovim, load extensions like VSCode and host language servers.
Other
24.15k stars 953 forks source link

How to Combine coc-snippets and coc.nvim Configurations to Achieve Desired Tab Key Behavior #5043

Closed Elite-zx closed 2 weeks ago

Elite-zx commented 2 weeks ago

I expect the following functionality when pressing the Tab key:

Trigger completion, navigate to the next completion item, and select it by pressing Enter. After selecting a completion, pressing Tab should navigate to the next placeholder. I have the following references:

The content of coc-snippets' README

inoremap <silent><expr> <TAB>
      \ coc#pum#visible() ? coc#_select_confirm() :
      \ coc#expandableOrJumpable() ? "\<C-r>=coc#rpc#request('doKeymap', ['snippets-expand-jump',''])\<CR>" :
      \ CheckBackspace() ? "\<TAB>" :
      \ coc#refresh()

function! CheckBackspace() abort
  let col = col('.') - 1
  return !col || getline('.')[col - 1]  =~# '\s'
endfunction

let g:coc_snippet_next = '<tab>'

The content of coc.nvim's README

" Use tab for trigger completion with characters ahead and navigate
" NOTE: There's always complete item selected by default, you may want to enable
" no select by `"suggest.noselect": true` in your configuration file
" NOTE: Use command ':verbose imap <tab>' to make sure tab is not mapped by
" other plugin before putting this into your config
inoremap <silent><expr> <TAB>
      \ coc#pum#visible() ? coc#pum#next(1) :
      \ CheckBackspace() ? "\<Tab>" :
      \ coc#refresh()
inoremap <expr><S-TAB> coc#pum#visible() ? coc#pum#prev(1) : "\<C-h>"

" Make <CR> to accept selected completion item or notify coc.nvim to format
" <C-g>u breaks current undo, please make your own choice
inoremap <silent><expr> <CR> coc#pum#visible() ? coc#pum#confirm()
                              \: "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"

function! CheckBackspace() abort
  let col = col('.') - 1
  return !col || getline('.')[col - 1]  =~# '\s'
endfunction

However, I am not sure how to combine these two configurations to achieve my goal. Thank you.

Vim verison: VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Mar 1 2021 16:57:56)

The following is my current configuration for cocnvim:

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" coc-nvim config
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" use <tab> to trigger completion and navigate to the next complete item
function! CheckBackspace() abort
  let col = col('.') - 1
  return !col || getline('.')[col - 1]  =~# '\s'
endfunction

inoremap <silent><expr> <Tab>
      \ coc#pum#visible() ? coc#pum#next(1) :
      \ coc#expandableOrJumpable() ? "\<C-r>=coc#rpc#request('doKeymap', ['snippets-expand-jump',''])\<CR>" :
      \ CheckBackspace() ? "\<Tab>" :
      \ coc#refresh()
inoremap <expr><S-TAB> coc#pum#visible() ? coc#pum#prev(1) : "\<C-h>"
let g:coc_snippet_next = '<Tab>'

" Make <CR> to accept selected completion item or notify coc.nvim to format
" <C-g>u breaks current undo, please make your own choice
inoremap <silent><expr> <CR> coc#pum#visible() ? coc#pum#confirm()
      \: "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"
" Show all diagnostics
nnoremap <silent><nowait> <space>a  :<C-u>CocList diagnostics<cr>
" Find symbol of current document
nnoremap <silent><nowait> <space>o  :<C-u>CocList outline<cr>
" Do default action for next item
nnoremap <silent><nowait> <space>j  :<C-u>CocNext<CR>
" Do default action for previous item
nnoremap <silent><nowait> <space>k  :<C-u>CocPrev<CR>
" Having longer updatetime (default is 4000 ms = 4s) leads to noticeable
" delays and poor user experience
set updatetime=300
kaiuri commented 2 weeks ago

In my setup, snippet and completion have separate keymaps.

That said, maybe this could help you get started.

local opts = { noremap = true, expr = true, silent = true }
-- because or opts.expr we gotta return something
vim.keymap.set("i", "<Tab>", function()
  if vim.fn["coc#pum#visible"]() == 1 then
    return vim.fn["coc#pum#next"](1)
  elseif vim.fn["coc#expandableOrJumpable"]() then
    return "<Plug>(coc-snippets-expand-jump)"
  else
    return "<C-i>"
  end
end, opts)

vim.keymap.set("i", "<S-Tab>", function()
  if vim.fn["coc#pum#visible"]() == 1 then
    return vim.fn["coc#pum#prev"](1)
  elseif vim.fn["coc#jumpable"]() then
    return vim.fn["coc#snippet#prev"]() --> this turns into <Ignore> when the keymap runs
  elseif vim.fn.indent(vim.fn.line(".")) == vim.fn.col(".") - 1 then
    return "<C-d>"
  else
    return "<C-w>"
  end
end, opts)

vim.keymap.set("i", "<CR>", function()
  if vim.fn["coc#pum#visible"]() == 1 then
    vim.fn["coc#pum#close"]("confirm")
  else
    vim.api.nvim_feedkeys(vim.keycode("<C-m>"), "n", false)
    vim.fn["coc#on_enter"]()
  end
end, { noremap = true, silent = true })

-- This might be useful since some snippets sometimes add text before the
-- cursor and that might influence completion
vim.keymap.set("i", "<C-Space>", function()
  if vim.fn["coc#pum#visible"]() == 1 then
    vim.fn["coc#pum#close"]()
  else
    vim.fn["coc#start"]()
  end
end, { noremap = true, silent = true })