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

> Discover nvim-cmp an extensible Neovim completion engine. Learn how jdhao nvim-config customizes code completion using LSP buffers and snippets.

- Repository: [jdhao/nvim-config](https://github.com/jdhao/nvim-config)
- Tags: deep-dive
- Published: 2026-03-04

---

**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`](https://github.com/jdhao/nvim-config/blob/main/lua/config/nvim-cmp.lua) with sources declared lazily in [`lua/plugin_specs.lua`](https://github.com/jdhao/nvim-config/blob/main/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`](https://github.com/jdhao/nvim-config/blob/main/lua/plugin_specs.lua) (lines 24-38) and lazy-loaded by lazy.nvim:

```lua
-- 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`](https://github.com/jdhao/nvim-config/blob/main/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:

```lua
-- 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:

```lua
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:

```lua
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:

```lua
-- 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`](https://github.com/jdhao/nvim-config/blob/main/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`](https://github.com/jdhao/nvim-config/blob/main/lua/plugin_specs.lua) (lines 24-38) with lazy-loading via `event = "VeryLazy"`
- Core configuration resides in [`lua/config/nvim-cmp.lua`](https://github.com/jdhao/nvim-config/blob/main/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`](https://github.com/jdhao/nvim-config/blob/main/lua/plugin_specs.lua) and loaded in [`lua/config/nvim-cmp.lua`](https://github.com/jdhao/nvim-config/blob/main/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`](https://github.com/jdhao/nvim-config/blob/main/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.