What is nvim-cmp and How It Configures Code Completion in jdhao/nvim-config

nvim-cmp is a highly extensible completion engine for Neovim that aggregates candidates from LSP clients, buffers, file paths, and snippets, and in the jdhao/nvim-config repository it is configured via lua/config/nvim-cmp.lua with sources declared lazily in lua/plugin_specs.lua.

The nvim-cmp plugin serves as the central completion framework in modern Neovim setups. In the jdhao/nvim-config repository, the author implements a comprehensive code completion workflow using nvim-cmp alongside multiple specialized sources. This configuration delivers context-aware suggestions for programming languages, file paths, and command-line operations.

What is nvim-cmp?

nvim-cmp is a lightweight, extensible completion engine for Neovim. Unlike monolithic completion plugins, it operates as a framework that aggregates completion candidates from modular sources such as LSP servers, open buffers, filesystem paths, and snippet engines. The plugin presents these candidates in a searchable pop-up menu, allowing users to mix and match sources based on filetype and context.

In jdhao/nvim-config, the author integrates nvim-cmp with six specific sources:

  • cmp-nvim-lsp: Pulls completion items from Neovim's built-in LSP client
  • cmp-path: Provides filesystem path completion
  • cmp-buffer: Suggests words from the current buffer
  • cmp-omni: Enables omni-completion for filetypes like LaTeX
  • cmp-cmdline: Powers command-line completion for / and : prompts
  • cmp-nvim-ultisnips: Handles snippet expansion via UltiSnips

These dependencies are declared in lua/plugin_specs.lua (lines 24-38) and lazy-loaded by lazy.nvim:

-- Excerpt from lua/plugin_specs.lua
{ "hrsh7th/cmp-nvim-lsp", lazy = true },
{ "hrsh7th/cmp-path", lazy = true },
{ "hrsh7th/cmp-buffer", lazy = true },
{ "hrsh7th/cmp-omni", lazy = true },
{ "hrsh7th/cmp-cmdline", lazy = true },
{ "quangnguyen30192/cmp-nvim-ultisnips", lazy = true },

{
  "hrsh7th/nvim-cmp",
  name = "nvim-cmp",
  event = "VeryLazy",
  config = function()
    require("config.nvim-cmp")
  end,
},

How nvim-cmp is Configured in jdhao/nvim-config

The complete behavior of the completion engine is defined in lua/config/nvim-cmp.lua. This file orchestrates source loading, key mappings, visual formatting, and context-specific overrides.

Core Setup and Snippet Integration

The configuration begins by requiring all completion source modules and setting up snippet expansion. The author uses UltiSnips for snippet management, configured via the snippet.expand function:

-- Excerpt from lua/config/nvim-cmp.lua
local cmp = require("cmp")
require("cmp_nvim_lsp")
require("cmp_path")
require("cmp_buffer")
require("cmp_omni")
require("cmp_nvim_ultisnips")
require("cmp_cmdline")

cmp.setup {
  snippet = {
    expand = function(args)
      vim.fn["UltiSnips#Anon"](args.body)
    end,
  },
  -- additional configuration follows
}

Completion Sources and Behavior

The source priority determines which completions appear first. In jdhao/nvim-config, the default source order is:

  1. nvim_lsp: Language server suggestions (highest priority)
  2. ultisnips: Code snippets
  3. path: Filesystem paths
  4. buffer: Words from the current buffer (requires 2-character keyword length)

The configuration sets keyword_length = 1 for general completion and completeopt = "menu,noselect" to show the menu without auto-selecting the first item. The view uses custom entries formatting (entries = "custom").

Key Mappings for Navigation

The mapping table defines intuitive controls for the completion menu:

  • <Tab>: Select the next item when visible, otherwise insert a tab character
  • <S-Tab>: Select the previous item
  • <CR>: Confirm the selected completion
  • <C-e>: Abort completion and close the popup
  • <C-d> / <C-f>: Scroll documentation up and down

These mappings are implemented using cmp.mapping.preset.insert() for consistency with standard editor behavior.

Visual Formatting with mini.icons

To enhance the user interface, the configuration integrates mini.icons to prepend semantic icons to completion items. The formatting function retrieves icons based on LSP item kinds:

local MiniIcons = require("mini.icons")

cmp.setup {
  formatting = {
    format = function(_, vim_item)
      local icon, hl = MiniIcons.get("lsp", vim_item.kind)
      vim_item.kind = icon .. " " .. vim_item.kind
      vim_item.kind_hl_group = hl
      return vim_item
    end,
  },
}

This produces a VS Code-style appearance where each completion type (function, variable, class) displays a distinct icon and highlight group.

Filetype-Specific and Command-Line Configuration

The setup includes specialized configurations for specific contexts. For LaTeX files (tex), the omni source receives highest priority:

cmp.setup.filetype("tex", {
  sources = {
    { name = "omni" },
    { name = "ultisnips" },
    { name = "buffer", keyword_length = 2 },
    { name = "path" },
  },
})

For command-line completion, separate setups handle search and ex commands:

-- Search completion (/)
cmp.setup.cmdline("/", {
  mapping = cmp.mapping.preset.cmdline(),
  sources = { { name = "buffer" } },
})

-- Command completion (:)
cmp.setup.cmdline(":", {
  mapping = cmp.mapping.preset.cmdline(),
  sources = cmp.config.sources(
    { { name = "path" } },
    { { name = "cmdline" } }
  ),
})

The highlight groups are customized in lines 92-111 of nvim-cmp.lua to match a dark theme aesthetic.

Practical Usage Examples

To interact with the completion engine effectively:

  • Navigate suggestions: Press <Tab> to move forward through the menu or <S-Tab> to move backward
  • Confirm selection: Press <CR> to insert the highlighted completion into the buffer
  • Cancel completion: Press <C-e> to dismiss the popup without inserting text
  • Scroll documentation: Use <C-d> to scroll down or <C-f> to scroll up within the documentation window
  • Expand snippets: Type a snippet trigger (e.g., for) and press the UltiSnips expand key (configured separately) to expand via vim.fn["UltiSnips#Anon"]
  • Complete paths: Type ./ or / in insert mode to trigger filesystem suggestions from cmp-path
  • Command-line completion: In : mode, type e then <Tab> to see commands like edit or e!

Summary

  • nvim-cmp functions as the central completion framework in jdhao/nvim-config, aggregating LSP, buffer, path, and snippet sources
  • Plugin dependencies are declared in lua/plugin_specs.lua (lines 24-38) with lazy-loading via event = "VeryLazy"
  • Core configuration resides in lua/config/nvim-cmp.lua, defining source priorities, UltiSnips integration, and custom key mappings
  • The setup uses mini.icons for visual enhancement and defines custom highlight groups (lines 92-111) for a dark theme
  • Filetype-specific rules prioritize omni completion for LaTeX, while dedicated cmdline setups handle / and : completion contexts

Frequently Asked Questions

What sources does nvim-cmp use in jdhao/nvim-config?

The configuration utilizes six completion sources: cmp-nvim-lsp for language server suggestions, cmp-nvim-ultisnips for snippet expansion, cmp-path for filesystem completion, cmp-buffer for buffer words, cmp-omni for LaTeX omni-completion, and cmp-cmdline for command-line suggestions. These are declared in lua/plugin_specs.lua and loaded in lua/config/nvim-cmp.lua.

How are the completion menu keybindings configured?

The keybindings use cmp.mapping.preset.insert() with custom overrides. <Tab> and <S-Tab> navigate items, <CR> confirms selection, and <C-e> aborts the menu. The configuration also maps <C-d> and <C-f> for scrolling documentation. These mappings are defined in the mapping table within lua/config/nvim-cmp.lua.

Why does LaTeX completion behave differently in this configuration?

LaTeX files (tex filetype) receive a specialized source order via cmp.setup.filetype(). The omni source is prioritized first to provide citation and reference completion, followed by UltiSnips, buffer words, and paths. This ensures academic writing workflows have access to BibTeX and label completion before general snippets.

How does the configuration integrate with UltiSnips?

Snippet expansion is handled through the snippet.expand function in cmp.setup(), which calls vim.fn["UltiSnips#Anon"](args.body). This bridges nvim-cmp with the UltiSnips engine, allowing snippet triggers to appear in the completion menu and expand when selected.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →