coc.nvim is a powerful autocompletion engine that brings IDE-like features to Vim and Neovim.

Let’s set up coc.nvim to get intelligent code completion. We’ll use it with TypeScript as an example, but the principles apply to many languages.

First, ensure you have a plugin manager installed. If you’re using vim-plug, add these lines to your ~/.vimrc or ~/.config/nvim/init.vim:

Plug 'neoclide/coc.nvim', {'branch': 'release'}

Then, run :PlugInstall in Vim.

Next, we need to configure coc.nvim. Add this to your ~/.vimrc or ~/.config/nvim/init.vim:

" Use :CocConfig to configure.
" Enable completion on keypress.
inoremap <silent><expr> <CR> pumvisible() ? coc#_select_confirm() : "\<CR>"
inoremap <expr><Tab> pumvisible() ? coc#_navigate_next() : GetCocExpandTrigger()

" Use <C-j> and <C-k> for navigation.
inoremap <silent><expr> <C-j> pumvisible() ? coc#_navigate_next() : "\<C-j>"
inoremap <silent><expr> <C-k> pumvisible() ? coc#_navigate_prev() : "\<C-k>"

" Use <C-p> and <C-n> for completion.
inoremap <silent><expr> <C-p> pumvisible() ? coc#_navigate_prev() : coc#pum#next(1)
inoremap <silent><expr> <C-n> pumvisible() ? coc#_navigate_next() : coc#pum#next(0)

" Use <C-Space> for trigger completion.
inoremap <silent><expr> <C-Space> coc#refresh()

" Show doc on hover.
augroup coc_hover_doc
  autocmd!
  autocmd CursorHold * silent call CocActionAsync('showHover')
augroup END

Now, open a TypeScript file and type some code. You should see completion suggestions appear automatically. If not, press Ctrl+Space to trigger them manually.

The real power comes from language servers. coc.nvim acts as a client, and language servers provide the intelligence. For TypeScript, we need the tsserver. Install it globally using npm:

npm install -g typescript typescript-language-server

After installing the language server, restart Vim. coc.nvim should automatically detect and load tsserver.

You can configure coc.nvim more deeply using :CocConfig. This opens a JSON file. Here’s a basic configuration to enable formatting on save and show diagnostics:

{
  "coc.preferences.formatOnSaveFiletypes": ["typescript", "javascript", "json"],
  "coc.preferences.diagnostic.virtualText": true,
  "coc.preferences.diagnostic.locationlist": true
}

Apply these changes by saving the coc-settings.json file.

Let’s see coc.nvim in action. Open a TypeScript file with a syntax error:

function greet(name: string) {
  console.log("Hello, " + name)
  retun "Done"; // Typo here
}

As you type, coc.nvim will highlight the error (retun is not a valid keyword). If you hover your mouse over the error (or use a keybinding if configured), you’ll see a tooltip explaining the issue.

Now, let’s trigger a refactoring. Place your cursor on the greet function name. Press gd (go to definition) to jump to its declaration. Press gr to find all references to the function.

To rename the function, place the cursor on greet, type :CocRename, and enter the new name, e.g., sayHello. Press Enter. All instances of greet will be updated.

function sayHello(name: string) {
  console.log("Hello, " + name)
  retun "Done";
}

The language server for TypeScript (tsserver) provides a wealth of information. It understands your project structure, dependencies, and type definitions. coc.nvim relays this to you through various UI elements and commands.

One subtle but powerful feature is how coc.nvim handles asynchronous operations. When you trigger an action like showHover or CocRename, coc.nvim doesn’t block Vim. It sends a request to the language server and then continues to process Vim events. When the language server responds, coc.nvim updates the UI or performs the requested action. This is managed by the AsyncAction system within coc.nvim, allowing for a responsive editing experience even with complex language server operations.

To explore available commands, type :CocCommand and press Tab. You’ll see a list of commands provided by coc.nvim and its installed extensions.

The next step in mastering coc.nvim is to explore its vast ecosystem of extensions for different languages and tools.

Want structured learning?

Take the full Vim course →