---
title: Neovim language services, completion and formatting
url: https://doc.liz6.com/en/tools/nvim/04-language-tools
locale: en
area: tools
tags:
- Neovim
- Developer tools
date: 2026-09-15
modified: 2026-09-15
description: Distinguish language-tool layers and diagnose file type, project root, executable and client-attachment problems.
---

# Neovim language services, completion and formatting

Highlighting, completion, definition lookup and test execution come from different components. Identify the responsible component before reinstalling tools.

## What opening a file triggers

| Component | Responsibility | Limit |
| --- | --- | --- |
| File type detection | Identify Rust, Lua and other types | Does not install tools |
| Treesitter parser | Syntax structure for highlights and selections | Not project type checking |
| LSP client/server | Definitions, references, diagnostics, rename | Does not run all tests |
| Completion interface | Present LSP, snippet and other candidates | Does not supply all semantics |
| Formatter | Rearrange text by rules | Does not prove behaviour |
| DAP client/adapter | Breakpoints, variables and execution control | Still needs SDKs, targets and symbols |

Language extras connect some of these layers. Optional plugin settings apply only when the plugin is installed; runtimes and project dependencies remain separate. [LazyVim extras](https://www.lazyvim.org/extras)

## Start with one language

For Rust, make `cargo check` work outside the editor before enabling Rust through `:LazyExtras`. Resolve toolchain, dependency and compiler failures there first.

Open a Rust file in the Cargo project:

```vim
:set filetype?
:pwd
:lua print(vim.inspect(vim.lsp.get_clients({ bufnr = 0 })))
```

Expect `rust` and an attached language client. `:pwd` is the editor working directory, not necessarily the LSP root; inspect the client's configuration as well. [Neovim LSP](https://neovim.io/doc/user/lsp/)

A workspace server may use an outer root. A file copied outside its project can lack module and dependency context.

## Verify individual language features

Try definitions, references, hover and rename on a known local function. Direct calls help separate API behaviour from key mappings:

```vim
:lua vim.lsp.buf.definition()
:lua vim.lsp.buf.references()
:lua vim.lsp.buf.hover()
```

No result can mean an unsupported target, unresolved dependency or incomplete indexing rather than no server. Establish a known working local target first.

After rename, inspect affected buffers, save intended changes and review Git diff. A successful request is not the final correctness check.

## Choose who formats

LazyVim commonly uses Conform. `:ConformInfo` reports configured formatters, availability and logs. To make changes explicit while learning, put this in `lua/config/options.lua`:

```lua
vim.g.autoformat = false
```

Trigger formatting manually and review differences. Respect project files such as `.editorconfig`, `.clang-format` and `rustfmt.toml`.

This override in `lua/plugins/formatting.lua` selects StyLua for Lua:

```lua
return {
  {
    "stevearc/conform.nvim",
    opts = function(_, opts)
      opts.formatters_by_ft = opts.formatters_by_ft or {}
      opts.formatters_by_ft.lua = { "stylua" }
    end,
  },
}
```

It selects a program but does not install it. Avoid adding another save autocmd that also invokes LSP formatting, which can duplicate work or apply conflicting rules.

## Diagnostics, tests and debugging

Static diagnostics can find syntax and type problems while missing incorrect business boundaries. The [project exercise](05-project-workflow.md) demonstrates code that compiles but fails a requirement.

Debugging additionally needs a launchable target, working directory, arguments and adapter. Make the same target run from the command line first. Rust, Go, C# and Java use different backends; nvim-dap alone does not provide all of them.

## A diagnostic sequence

1. Check `:set filetype?`.
2. Verify project context, configuration and dependencies.
3. Inspect executable resolution, for example `:lua print(vim.fn.exepath("rust-analyzer"))`; plugins may also specify their own path.
4. Check client attachment and startup logs.
5. Verify the specific server capability and whether failure is file-specific.
6. Inspect formatter and debugger tools independently rather than repeatedly reinstalling LSP.

Change one condition at a time. Reproduce the result with logs and a small project before applying the fix to the normal configuration.
