After migrating fromVim to Emacs as my primary C++ editor in 2015, I switched from Vimto Neovim for miscellaneous non-C++ tasks as it is more convenient in aterminal. Customizing the editor with a language you are comfortablewith is important. I found myself increasingly drawn to Neovim'sterminal-based simplicity for various non-C++ tasks. Recently, I'verefined my Neovim setup to the point where I can confidently migrate myentire C++ workflow away from Emacs. This post explores the keyimprovements I've made to achieve this seamless transition.
I've implemented custom functions that simplify key mappings.
1 | local function map(mode, lhs, rhs, opts) |
Like many developers, I spend significantly more time reading codethan writing it. Efficiently navigating definitions and references iscrucial 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 todefinitions.
To avoid a conflict with my recent zellij change (I adoptedM-hjkl
for pane navigation), I've reassigned J to triggerdefinition searches. While losing the original J
(joinlines) functionality is unfortunate, vJ
provides a suitablealternative.
1 | nmap('J', '<cmd>Telescope lsp_definitions<cr>', 'Definitions') |
I've adopted x
as a prefix key for cross-referencingextensions, further streamlining the process. dl
provide asuitable alternative for x
's original functionality.
1 | nmap('xB', '<cmd>CclsBaseHierarchy<cr>') |
I utilize xn
and xp
to find the the next orprevious reference. The implementation, copied from from LazyVim, onlyworks with references within the current file. I want to enable thexn
map to automatically transition to the next file whenreaching the last reference in the current file.
I've implemented rainbow semantic highlighting using ccls and LSPSemantic Tokens. Please refer to ccls and LSPSemantic Tokens for my setup.
While I've been content with the traditional C-w + hjkl
mapping for years, I've recently opted for the more efficientC-hjkl
approach.
1 | nmap('<C-h>', '<C-w>h') |
This streamlined approach mirrors my pane navigation preferences intmux and zellij, where I utilize M-hjkl
.
To accommodate this change, I've shifted my tmux prefix key fromC-l
to C-Space
. Consequently, I've alsoadjusted my input method toggling from C-Space
toC-S-Space
.
For C++ debugging, I primarily rely on cgdb. I find it superior toGDB's single-key mode and significantly more user-friendly than LLDB'sgui
command.
1 | cgdb --args ./a.out args |
I typically arrange Neovim and cgdb side-by-side in tmux or zellij.During single-stepping, when encountering interesting code snippets, Ioften need to manually input filenames into Neovim. While Telescope aidsin this process, automatic file and line updates would be ideal.
Given these considerations, nvim-dap appears to be a promisingsolution. However, I haven't yet determined the optimal configurationfor integrating rr with nvim-dap.
I've defined mappings to streamline directory and project-widesearches using Telescope's live grep functionality:
1 | nmap('<leader>sd', '<cmd>lua require("telescope.builtin").live_grep({cwd=vim.fn.expand("%:p:h")})<cr>', 'Search directory') |
Additionally, I've mapped M-n to insert the word under the cursor,mimicking Emacs Ivy's M-n (ivy-next-history-element)
behavior.
Neovim's NVIM_APPNAME
feature is fantastic for exploring pre-configured distribution to getinspiration.
Neovim embraces Lua as a preferred scripting language. While Lua'ssyntax is lightweight and easy to learn, it doesn't shy away fromconvenience features like func 'arg'
andfunc {a=42}
.
LuaJIT offers exceptional performance.
LuaJIT with the JIT enabled is much faster than all of the otherlanguages benchmarked, including Wren, because Mike Pall is a robot fromthe future. -- wren.io
This translates into noticeably smoother editing with LSP, especiallyfor 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 canlive with when using a configuration language. So far, I've only neededindex-sensitive looping in one specific location.
1 | -- For LSP semantic tokens |