Tinkering with Neovim
2024-11-2 15:0:0 Author: maskray.me(查看原文) 阅读量:4 收藏

After migrating from Vim to Emacs as my primary C++ editor in 2015, I switched from Vim to Neovim for miscellaneous non-C++ tasks as it is more convenient in a terminal. Customizing the editor with a language you are comfortable with is important. I found myself increasingly drawn to Neovim's terminal-based simplicity for various non-C++ tasks. Recently, I've refined my Neovim setup to the point where I can confidently migrate my entire C++ workflow away from Emacs. This post explores the key improvements I've made to achieve this seamless transition.

Key mapping

I've implemented custom functions that simplify key mappings.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
local function map(mode, lhs, rhs, opts)
local options = {}
if opts then
if type(opts) == 'string' then
opts = {desc = opts}
end
options = vim.tbl_extend('force', options, opts)
end
vim.keymap.set(mode, lhs, rhs, options)
end
local function nmap(lhs, rhs, opts)
map('n', lhs, rhs, opts)
end
local function tmap(lhs, rhs, opts)
map('t', lhs, rhs, opts)
end

Cross references

Like many developers, I spend significantly more time reading code than writing it. Efficiently navigating definitions and references is crucial for productivity.

Many Emacs and Neovim configurations advocate for gd. However, its placement on the QWERTY keyboard can be less than ideal. For years, I relied on M-j to quickly jump to definitions.

To avoid a conflict with my recent zellij change (I adopted M-hjkl for pane navigation), I've reassigned J to trigger definition searches. While losing the original J (join lines) functionality is unfortunate, vJ provides a suitable alternative.

1
2
nmap('J', '<cmd>Telescope lsp_definitions<cr>', 'Definitions')
nmap('<M-,>', '<cmd>Telescope lsp_references<CR>', 'References')

I've adopted x as a prefix key for cross-referencing extensions, further streamlining the process. dl provide a suitable alternative for x's original functionality.

1
2
3
4
5
6
7
8
9
10
11
12
13
nmap('xB', '<cmd>CclsBaseHierarchy<cr>')
nmap('xC', '<cmd>CclsOutgoingCalls<cr>', 'callee')
nmap('xD', '<cmd>CclsDerivedHierarchy<cr>')
nmap('xM', '<cmd>CclsMemberHierarchy<cr>', 'member')
nmap('xb', '<cmd>CclsBase<cr>')
nmap('xc', '<cmd>CclsIncomingCalls<cr>', 'caller')
nmap('xd', '<cmd>CclsDerived<cr>')
nmap('xi', '<cmd>lua vim.lsp.buf.implementation()<cr>', 'Implementation')
nmap('xm', '<cmd>CclsMember<cr>', 'member')
nmap('xn', function() M.lsp.words.jump(vim.v.count1) end, 'Next reference')
nmap('xp', function() M.lsp.words.jump(-vim.v.count1) end, 'Prev reference')
nmap('xt', '<cmd>lua vim.lsp.buf.type_definition()<cr>', 'Type definition')
nmap('xv', '<cmd>CclsVars<cr>', 'vars')

I utilize xn and xp to find the the next or previous reference. The implementation, copied from from LazyVim, only works with references within the current file. I want to enable the xn map to automatically transition to the next file when reaching the last reference in the current file.

Semantic highlighting

I've implemented rainbow semantic highlighting using ccls and LSP Semantic Tokens. Please refer to ccls and LSP Semantic Tokens for my setup.

Window navigation

While I've been content with the traditional C-w + hjkl mapping for years, I've recently opted for the more efficient C-hjkl approach.

1
2
3
4
5
6
7
8
9
nmap('<C-h>', '<C-w>h')
nmap('<C-j>', '<C-w>j')
nmap('<C-k>', '<C-w>k')
nmap('<C-l>', '<C-w>l')

tmap('<C-h>', '<cmd>wincmd h<cr>')
tmap('<C-j>', '<cmd>wincmd j<cr>')
tmap('<C-k>', '<cmd>wincmd k<cr>')
tmap('<C-l>', '<cmd>wincmd l<cr>')

This streamlined approach mirrors my pane navigation preferences in tmux and zellij, where I utilize M-hjkl.

To accommodate this change, I've shifted my tmux prefix key from C-l to C-Space. Consequently, I've also adjusted my input method toggling from C-Space to C-S-Space.

Debugging

For C++ debugging, I primarily rely on cgdb. I find it superior to GDB's single-key mode and significantly more user-friendly than LLDB's gui command.

1
2
3
4
cgdb --args ./a.out args

rr record ./a.out args
rr replay -d cgdb

I typically arrange Neovim and cgdb side-by-side in tmux or zellij. During single-stepping, when encountering interesting code snippets, I often need to manually input filenames into Neovim. While Telescope aids in this process, automatic file and line updates would be ideal.

Given these considerations, nvim-dap appears to be a promising solution. However, I haven't yet determined the optimal configuration for integrating rr with nvim-dap.

Live grep

I've defined mappings to streamline directory and project-wide searches using Telescope's live grep functionality:

1
2
nmap('<leader>sd', '<cmd>lua require("telescope.builtin").live_grep({cwd=vim.fn.expand("%:p:h")})<cr>', 'Search directory')
nmap('<leader>sp', '<cmd>lua require("telescope.builtin").live_grep({cwd=MyProject()})<cr>', 'Search project')

Additionally, I've mapped M-n to insert the word under the cursor, mimicking Emacs Ivy's M-n (ivy-next-history-element) behavior.

Lua

Neovim embraces Lua as a preferred scripting language. While Lua's syntax is lightweight and easy to learn, it doesn't shy away from convenience features like func 'arg' and func {a=42}.

LuaJIT offers exceptional performance.

LuaJIT with the JIT enabled is much faster than all of the other languages benchmarked, including Wren, because Mike Pall is a robot from the future. -- wren.io

This translates into noticeably smoother editing with LSP, especially for hefty C++ files – a significant advantage over Emacs. With Emacs, I've always felt that editing a large C++ file is slow.

The non-default local variables and 1-based indexing (shared with languages like Awk and Julia) are annoyances that I can live with when using a configuration language. So far, I've only needed index-sensitive looping in one specific location.

1
2
3
4
5
6

for type, colors in pairs(all_colors) do
for i = 1,#colors do
vim.api.nvim_set_hl(0, string.format('@lsp.typemod.%s.id%s.cpp', type, i-1), {fg=colors[i]})
end
end

文章来源: https://maskray.me/blog/2024-11-02-tinkering-with-neovim
如有侵权请联系:admin#unsafe.sh