Skip to content

(neo)vim

Allex edited this page Oct 27, 2025 · 16 revisions

pretty-print a table

:vim.pretty_print(<>)

Diff two files

open both files side-by-side (C-w v) :windo diffthis

3-way merge

  • :Git to open the git status.
  • on the conflicted file, dv to open 3-way vertical diff.
  • ]c to jump through the changes
  • on a conflict d2o to pick the left, d3o to pick th right.
  • Ctrl-w o to close all other windows

wrap/unwrap lines

:set nowrap

refine search in telescope live_grep

When live_greping, <C-space> to fuzzy refine the results list. This allows filtering down to specific files without figuring out how to pass --glob to ripgrep.

plugin changed setting

To find what is changing a setting, run :verbose set <setting>. This will show what last set the value, for example:

:verbose set conceallevel
conceallevel=2
      Last set from /usr/share/nvim/runtime/ftplugin/help.vim line 18

Pass buffer to jq and replace with output

:%! jq .

Pass selection to jq and show output

If the selection has surrounding content on the same line this seems to not work, in that case copy the content to a new line. :'<,'>w !jq '.'

Edit command (with keymaps) before executing

When running a command (: or /), you normally can't use regular keymaps. To switch to a edit mode where you can, press C-f.

Find and replace one-by-one

  • Search as normal (/, n)
  • when on the instance you want to replace, 'cgn' to change the search result in visual mode.
  • 'n' to go to the next hit
  • '.' to repeat the edit

replace all

:%s/pattern/replace/g

Make regex regex again

When searching, start the search with \v to use "very magic" mode. https://neovim.io/doc/user/pattern.html#%2Fmagic

Match * non-greedy

use {-} instead of * when using \v

[Macro] Surround visual selected text

  • Select text to surround
  • q1 start recording macro 1
  • c<prefix><C-R>"<suffix><Esc>
  • q stop recording

For example, to wrap selection in $``$ when working on LaTex in github markdown: q1c$`<C-R>"`$<Esc>q

Same thing, as a keymap

This tends to work a little more stable than the macro version.

vim.keymap.set('v', '4', 'c$`<C-r>"`$<Esc>', { desc = 'Wrap selection with $``$' })

[Macro] Do math on a number

qa"xywciw<C-R>=@x*0.8<CR><ESC>q

  • qa (optional) start recording macro a
  • "xyw yank word into buffer x
  • ciw change inner word
  • <C-R>= Insert contents of register =, but the expression register is special in that you'll get prompted for an expression to insert.
  • @x*0.8<CR> multiply buffer x by 0.8
  • <ESC> exit insert mode
  • q (optional) end macro

Execute macro on multiple lines

https://stackoverflow.com/questions/390174/in-vim-how-do-i-apply-a-macro-to-a-set-of-lines

:'<,'>norm! @a Visual select lines, then :norm! @a to run macro in register a on all selected lines

LSP

Show current LSP capabilities

:lua =vim.lsp.get_active_clients()[1].server_capabilities

C++

To make the clangd LSP work I need to have the compile_commands.json. In CMake this can be done as cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1.

If the build dir is not $SRC or $SRC/build, symlink the output file to $SRC.

Per-project settings

Neovim allows executing files in the cwd named .nvim.lua on startup. This will run after normal init.

vim.o.exrc = true

Disable all-targets for rust-analyzer, for example when working on embedded projects.

local lspconfig = require('lspconfig')

local capabilities = lspconfig.rust_analyzer.manager.config.capabilities
-- Could be used to change existing settings instead of redefining them all like we do here
-- local existing_settings = lspconfig.rust_analyzer.manager.config.settings
local on_attach = lspconfig.rust_analyzer.manager.config.on_attach

-- Overrides any existing setup of rust-analyzer
lspconfig.rust_analyzer.setup {
  capabilities = capabilities,
  on_attach = on_attach,
  settings = {
    ["rust-analyzer"] = {
      cargo = {
        allTargets = false,
      }
    },
  }
}

Configure neotest-jest to match on a specific pattern

-- Configure neotest-jest to match on test.ts(x)
require("neotest").setup({
  adapters = {
    require('neotest-jest')({
      isTestFile = function(file_path)
        if not file_path then
          return false
        end
        -- The default only matches on files with extension, not "test.ts"
        if file_path:match("test.[jt]sx?$") then
          return true
        end
        if require("neotest-jest.jest-util").defaultIsTestFile(file_path) then
          return true
        end
        return false
      end
    }),
  },
})

Show whitespace characters

  • :set list enable list mode
  • :set listchars to change what to show, see :h listchars

DAP

Per-project debug configurations

nvim-dap loads configurations from ./.vscode/launch.json when invoked with dap.continue(). Format of this file and more info: :help dap-configuration

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "python",
      "name": "foo",
      "request": "launch",
      "args": [
        "--help"
      ],
      "justMyCode": false,
      "cwd": "${workspaceFolder}",
      "console": "integratedTerminal",
      "program": "foo.py"
    }
  ]
}

Clone this wiki locally