Over the summer, after finally getting around to learning Vim motions (see blog post #9), I quickly fell down the Neovim rabbithole and have been procrastinating work by tinkering away at my configurations ever since! This post will be sharing setup that I have currently landed at to turn my Neovim editor into a supercharged workhorse.
Table of Contents
TL;DR
I think my setup is pretty sweet. If you want to try out my setup without having to do the configuration yourself, you can run these commands to add my setup as a "profile" that you can switch to in Neovim:
- Clone the repository and install plugins:
git clone git@github.com:micahkepe/dotfiles ~/.config/micahkepe/dotfiles
- Open Neovim with this configuration:
NVIM_APPNAME=micahkepe/dotfiles/nvim nvim
If you're interested in the nerdy details of my setup, keep reading!
What is Neovim Anyway?
Vim (short for Vi Improved) was created by Bram Moolenaar in 1991 as an enhanced version of the Vi editor, which was originally developed in 1976 by Bill Joy for Unix systems. Vim quickly became popular due to its efficiency and ability to perform complex text manipulations with minimal keystrokes.
The original Vi program running with 'visuals'
However, Vim had its limitations, especially with handling modern development features such as better plugin systems, scripting flexibility, and ease of configuration. Neovim, a fork of Vim, was initiated in 2014 to address these challenges and provide a more modern, extensible framework.
Neovim differentiates itself by embracing the Lua programming language for faster, more customizable configurations. This shift has given rise to a flourishing ecosystem of plugins that are tailored to extend Neovim’s capabilities—from file navigation and autocompletion to even embedding images inside your text editor.
Getting Started with Neovim
If you want to follow along with setup, you can install Neovim by following the instructions below. If you already have Neovim installed, you can skip ahead to the setup.
To install Neovim, check the INSTALL.md file on the Neovim repository for the instructions for your machine.
The Setup
First off, a confession. I am not using off the shelf Neovim but starting from a very strong base configuration provided by the awesome folks at NVChad. NVChad is not a Neovim distro, but an opinionated starting Neovim configuration that provides a great starting place.
I particularly like NVChad for the following reasons:
-
Pre-configured LSP: NVChad provides a hassle-free Language Server Protocol (LSP) setup.
-
Lazy-loading Plugins: With the lazy.nvim plugin manager, NVChad optimizes startup time by only loading plugins when necessary.
-
Rich Theming: NVChad comes with lots of themes and color schemes to choose from (I am currently using
palenight
). -
Community Support: NVChad’s community is active, and the configuration gets frequent updates and improvements.
If you are following along, let's first install NVChad before we continue:
For Mac and Linux Users:
git clone https://github.com/NvChad/starter ~/.config/nvim && nvim
Windows Users:
A little more complicated (as usual), check out the install documentation here
Changes to NVChad's Default Settings
Diagnostics Menu
One of the things I changed from NVChad was the diagnostics display. By default, NVChad has the diagnostics displayed inline in red text. One consequence of this is that long diagnostic messages do not wrap at the end of the buffer, making it difficult to read the entire message:
NvChad default diagnostics
To make the diagnostics more readable and "Visual-Studio-Code-like", I changed the diagnostics to underline the offending line and display to a floating window at the offending line on a cursor hold:
To do this, I created a separate file for the diagnostics configuration in
nvim/lua/configs/diagnostics.lua
:
-- nvim/lua/configs/diagnostics.lua
local M = {}
M.setup = function()
vim.lsp.handlers["textDocument/publishDiagnostics"] = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
virtual_text = false, -- no inline diagnostics
underline = true, -- underline problematic code
})
-- Set the update time for diagnostics
vim.o.updatetime = 250
-- Automatically show diagnostics on cursor hold
vim.cmd [[
autocmd CursorHold,CursorHoldI * lua vim.diagnostic.open_float(nil, { focus = false })
]]
end
return M
Then to load this configuration, I added the following lines to the top of my
nvim/lua/configs/lspconfig.lua
:
-- nvim/lua/configs/lspconfig.lua
local diagnostics = require "configs.diagnostics"
-- Diagnostics popup
diagnostics.setup()
Enable Hidden Files in nvim-tree
Display
Another change I made was to show hidden files in the nvim-tree
file explorer.
By default, hidden files are not displayed in the file explorer, which can be a
little annoying when you need to access a .gitignore
, configuration files, or
a .env
file, for example.
To do this, I altered the section in the nvim/lua/init.lua
file that loads
NvChad's defined plugins:
-- nvim/lua/init.lua
-- load plugins
require("lazy").setup({
{
"NvChad/NvChad",
lazy = false,
branch = "v2.5",
import = "nvchad.plugins",
config = function()
require "options"
-- Override nvim-tree settings
local nvim_tree_options = require "nvchad.configs.nvimtree"
nvim_tree_options.filters.dotfiles = false
nvim_tree_options.git = { enable = true }
nvim_tree_options.filters.git_ignored = false
nvim_tree_options.filters.custom = { "^\\.git$", "DS_Store" }
end,
},
{ import = "plugins" },
}, lazy_config)
In the nvim_tree_options.filters.custom
table above, I added "^\\.git$"
and
"DS_Store"
regular expressions to not display files from the .git/
folder,
and to ignore the .DS_Store
files that macOS creates, respectively.
Plugins
I won't be detailing every plugin that I use, but instead the ones that have
become staples in my editing experience. All plugins snippets that follow will
be using lazy.nvim
install configurations. I will break this section into the
plugins that come by default from NVChad and the plugins that I have added on.
Note: If you are curious about all of my plugins, you can see them here.
NVChad Plugins
NVChad comes with a carefully curated set of plugins that provide a solid foundation for your Neovim setup. Here are some of the key plugins included:
-
nvim-tree/nvim-tree.lua: A file explorer tree for Neovim written in Lua. It provides a sleek and customizable way to navigate your project files.
-
nvim-treesitter/nvim-treesitter: Treesitter configurations and abstraction layer for Neovim. It provides better syntax highlighting and code understanding.
-
lewis6991/gitsigns.nvim: Git integration for buffers. It shows which lines have been added, removed, or modified in the gutter.
-
hrsh7th/nvim-cmp: A completion plugin for Neovim coded in Lua. It provides autocompletion functionality similar to what you'd find in modern IDEs.
-
williamboman/mason.nvim: Portable package manager for Neovim that runs everywhere Neovim runs. Easily install and manage LSP servers, DAP debugger servers, linters, and formatters.
-
neovim/nvim-lspconfig: A collection of common configurations for Neovim's built-in LSP client.
-
folke/which-key.nvim: Displays a popup with possible key bindings of the command you started typing. Incredibly useful for discovering and remembering mappings.
-
nvim-telescope/telescope.nvim: A highly extendable fuzzy finder over lists. It helps you search, filter, find, and pick things in your Neovim setup.
These plugins work together to provide a fully-featured IDE-like experience right out of the box. NVChad's setup ensures that these plugins are configured to work well together, providing a smooth and cohesive editing experience.
Added Plugins "Musts"
In no particular order, here are the plugins that I have added to augment NVChad's base.
gelguy/wilder.nvim
Makes navigating the Neovim command line much faster with fuzzy search capabilities, providing instant suggestions as you type commands.
When executing a command or searching, wilder.nvim
offers a real-time list of
suggestions based on your command history, file paths, and available commands.
This dramatically speeds up workflows that involve repeated or complex command
usage.
lazy.nvim:
-- nvim/lua/plugins/wilder.nvim
return {
{
"gelguy/wilder.nvim",
event = "CmdlineEnter",
build = ":UpdateRemotePlugins",
dependencies = {
"nvim-tree/nvim-web-devicons",
},
config = function()
local wilder = require "wilder"
wilder.setup { modes = { ":", "/", "?" } }
wilder.set_option("pipeline", {
wilder.branch(
wilder.python_file_finder_pipeline {
file_command = function(_, arg)
if string.find(arg, ".") ~= nil then
return { "fd", "-tf", "-H" }
else
return { "fd", "-tf" }
end
end,
dir_command = { "fd", "-td" },
filters = { "fuzzy_filter", "difflib_sorter" },
},
wilder.cmdline_pipeline(),
wilder.python_search_pipeline()
),
})
wilder.set_option(
"renderer",
wilder.popupmenu_renderer {
highlighter = wilder.basic_highlighter(),
left = { " ", wilder.popupmenu_devicons() },
right = { " ", wilder.popupmenu_scrollbar { thumb_char = " " } },
highlights = {
default = "WilderMenu",
accent = wilder.make_hl("WilderAccent", "Pmenu", {
{ a = 1 },
{ a = 1 },
{ foreground = "#f4468f" },
}),
},
}
)
end,
},
}
3rd/image.nvim
Enables image rendering in Neovim, essential for tasks like markdown previews and documentation editing. When editing markdown files or any other file format that supports images, image.nvim renders inline images. This eliminates the need to switch to a browser or other external tool, making Neovim more than just a text editor—it's a media-enabled workspace.
Honestly this one was a pain in the ass to setup but worth it.
I did have to make the switch to the Kitty
terminal emulator from iTerm2 as they implement
different terminal image protocols (kitty
vs. imgcat
) and Kitty's protocol
has more support as of writing. Additionally, getting the right Luarocks
version (5.1) is a little tricky as it is an older version of Luarocks.
Honestly, I needed images in Neovim in order to even consider making the switch from Visual Studio Code, so getting this plugin working was a non-negotiable for me.
Note: This particular configuration of the plugin must be run in Kitty to work. See the
backend
option if you want to use a different emulator.
lazy.nvim:
-- nvim/lua/plugins/image-nvim.lua
-- For dependencies see
-- `~/github/dotfiles-latest/neovim/nvim-lazyvim/README.md`
--
-- -- Uncomment the following 2 lines if you use the local luarocks installation
-- -- Leave them commented to instead use `luarocks.nvim`
-- -- instead of luarocks.nvim
-- Notice that in the following 2 commands I'm using luaver
-- package.path = package.path
-- .. ";"
-- .. vim.fn.expand("$HOME")
-- .. "/.luaver/luarocks/3.11.0_5.1/share/lua/5.1/magick/?/init.lua"
-- package.path = package.path
-- .. ";"
-- .. vim.fn.expand("$HOME")
-- .. "/.luaver/luarocks/3.11.0_5.1/share/lua/5.1/magick/?.lua"
--
-- -- Here I'm not using luaver, but instead installed lua and luarocks directly through
-- -- homebrew
package.path = package.path .. ";" .. vim.fn.expand "$HOME" .. "/.luarocks/share/lua/5.1/?/init.lua"
package.path = package.path .. ";" .. vim.fn.expand "$HOME" .. "/.luarocks/share/lua/5.1/?.lua"
return {
{
-- luarocks.nvim is a Neovim plugin designed to streamline the installation
-- of luarocks packages directly within Neovim. It simplifies the process
-- of managing Lua dependencies, ensuring a hassle-free experience for
-- Neovim users.
-- https://github.com/vhyrro/luarocks.nvim
"vhyrro/luarocks.nvim",
-- this plugin needs to run before anything else
priority = 1001,
opts = {
rocks = { "magick" },
},
},
{
"3rd/image.nvim",
lazy = false, -- load on start up
dependencies = { "luarocks.nvim" },
config = function()
require("image").setup {
backend = "kitty",
kitty_method = "normal",
integrations = {
-- Notice these are the settings for markdown files
markdown = {
enabled = true,
clear_in_insert_mode = false,
-- Set this to false if you don't want to render images coming from
-- a URL
download_remote_images = true,
-- Change this if you would only like to render the image where the
-- cursor is at
-- I set this to true, because if the file has way too many images
-- it will be laggy and will take time for the initial load
only_render_image_at_cursor = true,
-- markdown extensions (ie. quarto) can go here
filetypes = { "markdown", "vimwiki" },
},
neorg = {
enabled = true,
clear_in_insert_mode = false,
download_remote_images = true,
only_render_image_at_cursor = false,
filetypes = { "norg" },
},
-- This is disabled by default
-- Detect and render images referenced in HTML files
-- Make sure you have an html treesitter parser installed
-- ~/github/dotfiles-latest/neovim/nvim-lazyvim/lua/plugins/treesitter.lua
html = {
enabled = false,
},
-- This is disabled by default
-- Detect and render images referenced in CSS files
-- Make sure you have a css treesitter parser installed
-- ~/github/dotfiles-latest/neovim/nvim-lazyvim/lua/plugins/treesitter.lua
css = {
enabled = true,
},
},
max_width = nil,
max_height = nil,
max_width_window_percentage = nil,
-- This is what I changed to make my images look smaller, like a
-- thumbnail, the default value is 50
-- max_height_window_percentage = 20,
max_height_window_percentage = 40,
-- toggles images when windows are overlapped
window_overlap_clear_enabled = false,
window_overlap_clear_ft_ignore = { "cmp_menu", "cmp_docs", "" },
-- auto show/hide images when the editor gains/looses focus
editor_only_render_when_focused = true,
-- auto show/hide images in the correct tmux window
-- In the tmux.conf add `set -g visual-activity off`
tmux_show_only_in_active_window = true,
-- render image files as images when opened
hijack_file_patterns = { "*.png", "*.jpg", "*.jpeg", "*.gif", "*.webp", "*.avif" },
}
end,
},
}
rmagatti/autosession
Automatically saves and restores Neovim sessions, allowing you to pick up your
work right where you left off. If you close Neovim and reopen it later,
autosession
will restore your previous session (open files, split windows,
etc.). This is incredibly useful when you are juggling multiple projects and
want to resume exactly where you left off.
lazy.nvim:
-- automatically creates a Vim session when Neovim opens for saving work
return {
"rmagatti/auto-session",
lazy = false,
config = function()
local auto_session = require "auto-session"
auto_session.setup {
auto_restore = false,
suppressed_dirs = { "~/", "~/Dev/", "~/Downloads", "~/Documents", "~/Desktop/" },
}
end,
}
Then I define these mappings to save and restore sessions:
-- nvim/lua/mappings.lua
-- Autosession mappings
map("n", "<leader>ws", "<cmd>SessionSave<CR>", { desc = "Save session for auto session root dir" })
map("n", "<leader>wr", "<cmd>SessionRestore<CR>", { desc = "Restore session for cwd" })
christoomey/vim-tmux-navigator
Enables smooth navigation between Neovim windows and
tmux panes, making it feel like a unified
experience. If you’re using tmux and Neovim together,vim-tmux-navigator
allows
you to navigate between tmux panes and Neovim splits using the same keybindings
(like <C-h>
,<C-j>
, <C-k>
, and <C-l>
). This makes my workflow more fluid
as I don't have to think about whether I'm moving inside Neovim or across Tmux.
Not to mention I find this bindings much less awkward than the default <C-w>
Vim windown motions.
The true value of this plugins comes when you are working in various tmux panes running a combination of Neovim, a shell, and other tools. Without thinking I can navigate between these panes with ease.
lazy.nvim:
{
"christoomey/vim-tmux-navigator",
lazy = false, -- load on start up to immediately enable
cmd = {
"TmuxNavigateLeft",
"TmuxNavigateDown",
"TmuxNavigateUp",
"TmuxNavigateRight",
"TmuxNavigatePrevious",
},
keys = {
{ "<C-h>", "<cmd><C-U>TmuxNavigateLeft<cr>", desc = "Navigate left" },
{ "<C-j>", "<cmd><C-U>TmuxNavigateDown<cr>", desc = "Navigate down" },
{ "<C-k>", "<cmd><C-U>TmuxNavigateUp<cr>", desc = "Navigate up" },
{ "<C-l>", "<cmd><C-U>TmuxNavigateRight<cr>", desc = "Navigate right" },
{ "<C-\\>", "<cmd><C-U>TmuxNavigatePrevious<cr>", desc = "Navigate previous" },
},
},
Note: If using NVChad, you will need to override its mapping of these keys to use the Tmux navigation commands instead:
-- nvim/lua/options.lua require "nvchad.mappings" local map = vim.keymap.set -- override nvchad mappings for window navigation so I can use them for -- vim-tmux-navigator map("n", "<C-h>", "<cmd>TmuxNavigateLeft<cr>", { desc = "Navigate left" }) map("n", "<C-j>", "<cmd>TmuxNavigateDown<cr>", { desc = "Navigate down" }) map("n", "<C-k>", "<cmd>TmuxNavigateUp<cr>", { desc = "Navigate up" }) map("n", "<C-l>", "<cmd>TmuxNavigateRight<cr>", { desc = "Navigate right" }) map("n", "<C-\\>", "<cmd>TmuxNavigatePrevious<cr>", { desc = "Navigate previous" })
If using tmux, add the following to your ~/.tmux.conf
:
# ~/.tmux.conf
# Smart pane switching with awareness of Vim splits.
# See: https://github.com/christoomey/vim-tmux-navigator
is_vim="ps -o state= -o comm= -t '#{pane_tty}' \
| grep -iqE '^[^TXZ ]+ +(\\S+\\/)?g?(view|l?n?vim?x?|fzf)(diff)?$'"
bind -n 'C-h' if-shell "$is_vim" "send-keys C-h" "select-pane -L"
bind -n 'C-j' if-shell "$is_vim" "send-keys C-j" "select-pane -D"
bind -n 'C-k' if-shell "$is_vim" "send-keys C-k" "select-pane -U"
bind -n 'C-l' if-shell "$is_vim" "send-keys C-l" "select-pane -R"
bind -n 'C-\' if-shell "$is_vim" "send-keys C-\\" "select-pane -l"
tmux_version='$(tmux -V | sed -En "s/^tmux ([0-9]+(.[0-9]+)?).*/\1/p")'
if-shell -b '[ "$(echo "$tmux_version < 3.0" | bc)" = 1 ]' \
"bind-key -n 'C-\\' if-shell \"$is_vim\" 'send-keys C-\\' 'select-pane -l'"
if-shell -b '[ "$(echo "$tmux_version >= 3.0" | bc)" = 1 ]' \
"bind-key -n 'C-\\' if-shell \"$is_vim\" 'send-keys C-\\\\' 'select-pane -l'"
bind-key -T copy-mode-vi 'C-h' select-pane -L
bind-key -T copy-mode-vi 'C-j' select-pane -D
bind-key -T copy-mode-vi 'C-k' select-pane -U
bind-key -T copy-mode-vi 'C-l' select-pane -R
bind-key -T copy-mode-vi 'C-\' select-pane -l
# Enable passthrough for panes
set -g allow-passthrough on
pocco81/auto-save.nvim
Automatically saves your files when you leave insert mode. This plugin is a lifesaver for those who forget to save their work frequently. It ensures that your changes are always saved, even if you forget to do so manually. It is also highly customizable, allowing you to configure the save interval and other settings to suit your workflow.
lazy.nvim:
-- nvim/lua/plugins/init.lua
{
"pocco81/auto-save.nvim",
lazy = false,
config = function()
require("auto-save").setup {}
end,
},
stevearc/dressing.nvim
This plugins provides way better styling to the default vim.ui
interfaces. The
biggest improvement in my opinion is over the vim.input
interface that is used
for renaming files in nvim-tree
and renaming variable definitions using
NvChad's renamer. This is another highly customizable plugin that allows you to
style the UI to your liking.
lazy.nvim:
-- nvim/lua/plugins/init.lua
{ "stevearc/dressing.nvim", event = "VeryLazy" },
Key Mappings
Similarly, I have a ton of mappings that I have defined so I will just be going
over the ones that I can't live without. Additionally, I will not be detailing
the mappings that come with the NVChad base configuration (NVChad users can view
these by doing <leader>ch
to pull up the mappings cheat sheet).
Quality of Life Remaps
-- nvim/lua/mappings.lua
require "nvchad.mappings" -- NVChad-defined mappings
local map = vim.keymap.set
-- Quickly exit Normal mode with `jk`
-- This makes the transition from typing to command mode faster and more comfortable for the fingers.
-- UPDATE: I disabled this and instead just use Karabiner to map capslock to ESC
-- map("i", "jk", "<ESC>")
-- Map <C-s> to save
-- This is a common shortcut in many editors, bringing familiarity from other tools like VSCode.
map({ "n", "i", "v" }, "<C-s>", "<cmd> w <cr>")
"Reveal in Finder" Dupe
One of the things that I was missing coming from Visual Studio Code was the option in the file explorer to "Reveal in Finder" so I created a simple Vim user command that allows me to open a file under in my cursor in a Finder window either from the open file buffer or from the file explorer sidebar.
-- Open file in default viewer
vim.api.nvim_create_user_command("OpenFileInViewer", function()
local current_file = vim.fn.expand "%:p"
vim.fn.system('open "' .. current_file .. '"')
end, {})
-- Map <leader>sv to open file in standard viewer
-- NOTE: if cursor is on the file name Nvim Tree, you can simply press `sv` to open the file in the default viewer
-- since the leader key is already used by Nvim Tree.
map("n", "<leader>sv", ":OpenFileInViewer<CR>", { noremap = true, silent = true, desc = "Open file in default viewer" })
Window Management
These mappings manage window splits and layout efficiently in Neovim. The desc
key provides a description of the mapping for use in command help or plugins
like which-key.nvim
.
map("n", "<leader>v", "<C-w>v", { desc = "Split window vertically" }) -- split window vertically
map("n", "<leader>sd", "<cmd>close<CR>", { desc = "Close current split" }) -- close current split window
map("n", "<leader>se", "<C-w>=", { desc = "Equalize splits" }) -- equalize split layouts
-- can't use <leader>sh since that is used by LSPs to signature help
map("n", "<leader>s", "<cmd>split<CR>", { desc = "Split window horizontally" }) -- split window horizobtally
Visually Appealing Scrolling and Searching
These mappings keep the cursor and search result centered in the window while scrolling or jumping to search results.
-- maintain visual context on page navigation and searching
map("n", "<C-d>", "<C-d>zz") -- Keeps cursor centered when going down the page
map("n", "<C-u>", "<C-u>zz") -- Keeps cursor centered when going up the page
map("n", "n", "nzzzv") -- Keeps the search result in the center after jumping to next result
map("n", "N", "Nzzzv") -- Keeps the search result in the center after jumping to previous result
GitSigns Mappings
These are the mappings I use for GitSigns, which I believe are fairly standard.
gitsigns
works in "hunks" of code, hence all of these mappings begin with an
h
after the leader.
map("n", "<leader>hn", "<cmd>lua require'gitsigns'.next_hunk()<CR>", { desc = "Next hunk" })
map("n", "<leader>hp", "<cmd>lua require'gitsigns'.prev_hunk()<CR>", { desc = "Previous hunk" })
map("n", "<leader>hs", "<cmd>lua require'gitsigns'.stage_hunk()<CR>", { desc = "Stage hunk" })
map("n", "<leader>hu", "<cmd>lua require'gitsigns'.undo_stage_hunk()<CR>", { desc = "Undo stage hunk" })
map("n", "<leader>hr", "<cmd>lua require'gitsigns'.reset_hunk()<CR>", { desc = "Reset hunk" })
map("n", "<leader>hR", "<cmd>lua require'gitsigns'.reset_buffer()<CR>", { desc = "Reset buffer" })
map("n", "<leader>hp", "<cmd>lua require'gitsigns'.preview_hunk()<CR>", { desc = "Preview hunk" })
map("n", "<leader>hb", "<cmd>lua require'gitsigns'.blame_line()<CR>", { desc = "Blame line" })
map("n", "<leader>hS", "<cmd>lua require'gitsigns'.stage_buffer()<CR>", { desc = "Stage buffer" })
map("n", "<leader>hU", "<cmd>lua require'gitsigns'.reset_buffer_index()<CR>", { desc = "Reset buffer index" })
Options
These options provide a basic, yet highly functional configuration for Neovim that enhances usability by enabling features like clipboard integration and better search behavior.
-- nvim/lua/options.lua
require "nvchad.options"
local o = vim.o
local opt = vim.opt
-- Cursorline
o.cursorlineopt = "both" -- to enable cursorline!
-- Make line numbers defaults
o.number = true
-- Search and replace
opt.ignorecase = true -- ignore case letters when searching
opt.smartcase = true -- match case if capital letter is present
opt.incsearch = true -- show search matches as you type
opt.inccommand = "split" -- show live preview of substitute commands
-- disable swapfile
opt.swapfile = false
-- clipboard
opt.clipboard:append "unnamedplus"
-- text wrapping
o.wrap = false
Conclusion
While transitioning from VSCode to Neovim wasn’t without its challenges— especially getting used to Vim motions and configuring the plugins to my liking—it has ultimately made my workflow faster and more enjoyable. I particularly appreciated how customizable Neovim is; I can tailor it exactly to my needs, unlike most GUI-based editors.
It took me about a month to feel completely comfortable using Neovim, but once the muscle memory kicks in, you start to realize the immense productivity boost. If you’re on the fence, I highly recommend giving Neovim a chance for at least a few weeks.
If you have any questions about my setup, want to share your own tips and tricks, or just want to chat about Neovim, feel free to write in the comments below!
References
- Understanding the Origins and the Evolution of Vi & Vim
- How I Setup Neovim On My Mac To Make it AMAZING in 2024
- NVChad Documentation
- An Experienced (Neo)Vimmer's Workflow. \