Neovim
NeoVim is an extended version of Vim, the well-known text editor, designed to provide a more powerful and user-friendly experience for coding and text editing. It retains the classic modal editing features of Vim while introducing enhancements such as a built-in terminal, asynchronous job control, and better scriptability. This makes NeoVim highly efficient for programming, with support for numerous programming languages and a vast ecosystem of plugins. It's particularly favored by developers who require a highly customizable and efficient editor for coding, server administration, and automation tasks. The integration of modern GUI features, along with its traditional command-line interface, broadens its appeal to both new and experienced users who seek a versatile, lightweight, and powerful text-editing tool.
Build from Source
To install the latest version of neovim, you'll need to build the application from source. The instructions provided require neovim 0.9.x. Fortunately the process is fairly straightforward, provided the prerequisite steps are followed. The following instructions are slightly modified steps sourced from the official Neovim GitHub repository.
Build Prerequisites
Ubuntu
sudo apt-get install ninja-build gettext cmake unzip curl
MacOS
- Install Xcode Command Line Tools:
xcode-select --install
- Install Homebrew
- Install Neovim build dependencies:
brew install ninja cmake gettext curl
Quickstart
git clone https://github.com/neovim/neovim
cd neovim && make CMAKE_BUILD_TYPE=RelWithDebInfo
- If you want the stable release, also run
git checkout stable
.
- If you want the stable release, also run
sudo make install
- Default install location is
/usr/local
- On Debian/Ubuntu, instead of installing files directly with
sudo make install
, you can runcd build && cpack -G DEB && sudo dpkg -i nvim-linux64.deb
to build DEB-package and install it. This should help ensuring the clean removal of installed files.
- Default install location is
Notes:
- From the repository's root directory, running
make
will download and build all the needed dependencies and put thenvim
executable inbuild/bin
. - After building, you can run the
nvim
executable without installing it by runningVIMRUNTIME=runtime ./build/bin/nvim
.
Check Neovim Version
nvim --version
NVIM v0.9.5
Build type: RelWithDebInfo
LuaJIT 2.1.1692716794
Neovim RC Configuration
These instructions are based on the 0 to LSP : Neovim RC From Scratch YouTube video from ThePrimeagen. Remember to like, comment, and subscribe ;)
Directory Structure and init.lua
- Create the
~/.config/nvim/
directory for configuration settings
mkdir ~/.config/nvim && cd ~/.config/nvim
- Launch nvim and create the
init.lua
file.
nvim .
- The default netrw directory listing is launched.
" ============================================================================
" Netrw Directory Listing (netrw v171)
" /home/reece/.config/nvim
" Sorted by name
" Sort sequence: [\/]$,\<core\%(\.\d\+\)\=\>,\.h$,\.c$,\.cpp$,\~\=\*$,*,\.o$,\.obj$,\.i
" Quick Help: <F1>:help -:go up dir D:delete R:rename s:sort-by x:special
" ==============================================================================
../
./
- Type the
%
moniker to create a new file and makeinit.lua
- Within
init.lua
, add a basic print statement:
print("hello")
- From netrw, create a new directory named
lua
to store custom configuration.
- Type the
d
moniker to create the directory - Create another directory with the name to specify your configuration. In my case this will be
~/.config/nvim/lua/reece/
- From within your custom directory, create another
init.lua
file.
print("Hello from reece")
- Require your custom directory in the
~/.config/nvim/init.lua
file. Theinit.lua
file is automatically included.
require("reece")
print("hello")
- Quit nvim and reload your shell. e.g.
zsh
- Observe when relaunching
nvim .
that your print statements are now shown.
nvim .
hello from reece
hello
Press ENTER or type command to continue
The First Remap
- Create a file named
remap.lua
within the custom configuration directory.
- Set configure
vim.g.mapleader
and create the firstvim.keymap.set
vim.g.mapleader = " "
vim.keymap.set("n", "<leader>pv", vim.cmd.Ex)
- The
"n"
means, "in Normal mode" - Test the file by executing
:so
to source the file. - Execute
<leader>pv
and you should be returned toNetrw
using vim's Ex Mode
- Require the
remap.lua
file in theinit.lua
file in the custom configuration directory.
require("reece.remap")
print("hello from reece")
- Note: You do not need to include the
.lua
file extension when requiring the file.
Plugin Manager (Packer)
- Clone the wbthomason/packer.nvim repo.
git clone --depth 1 https://github.com/wbthomason/packer.nvim\
~/.local/share/nvim/site/pack/packer/start/packer.nvim
- Create the
packer.lua
file within the custom configuration directory.
-- This file can be loaded by calling `lua require('plugins')` from your init.vim
-- Only required if you have packer configured as `opt`
vim.cmd [[packadd packer.nvim]]
return require('packer').startup(function(use)
-- Packer can manage itself
use 'wbthomason/packer.nvim'
end
- Source the file using
:so
and then execute:PackerSync
to install the dependencies.
- Install the
telescope.nvim
plugin for fuzzy finding.
- Reference the
packer.vim
configuration from the nvim-telescope/telescope.nvim repository
use {
'nvim-telescope/telescope.nvim', tag = '0.1.5',
-- or , branch = '0.1.x',
requires = { {'nvim-lua/plenary.nvim'} }
}
- Update the
packer.lua
file with the telescope plugin
-- This file can be loaded by calling `lua require('plugins')` from your init.vim
-- Only required if you have packer configured as `opt`
vim.cmd [[packadd packer.nvim]]
return require('packer').startup(function(use)
-- Packer can manage itself
use 'wbthomason/packer.nvim'
use {
'nvim-telescope/telescope.nvim', tag = '0.1.5',
-- or , branch = '0.1.x',
requires = { {'nvim-lua/plenary.nvim'} }
}
end
- Add key remaps for telescope
- Create the
telescope.lua
file in thenvim/after/plugin/
directory.
local builtin = require('telescope.builtin')
vim.keymap.set('n', '<leader>pf', builtin.find_files, {})
vim.keymap.set('n', '<C-p>', builtin.git_files, {})
vim.keymap.set('n', '<leader>ps', function()
builtin.grep_string({ search = vim.fn.input("grep > ") })
end)
vim.keymap.set('n', '<leader>vh', builtin.help_tags, {})
<leader>pf
= "Project Files" - uses telescope to search for files in the project<C-p>
= "Ctrl+P" - uses telescope to search for files tracked only by git.<leader>ps
= "Project Search" - usesripgrep
to grep for files in the current working directory tree.<leader>vh
= "Vim Help" - opens the vim help window for references.
The BurntSushi/ripgrep tool is required to utilze the grep function. Install it by following the directions in the README.md.
Colorscheme
This step is entirely optional, but is provided as part of the YouTube tutorial follow along.
- Update the
packer.lua
file in the custom config directory with therose-pine
colorscheme.
-- This file can be loaded by calling `lua require('plugins')` from your init.vim
-- Only required if you have packer configured as `opt`
vim.cmd [[packadd packer.nvim]]
return require('packer').startup(function(use)
-- Packer can manage itself
use 'wbthomason/packer.nvim'
use {
'nvim-telescope/telescope.nvim', tag = '0.1.5',
-- or , branch = '0.1.x',
requires = { {'nvim-lua/plenary.nvim'} }
}
use({
'rose-pine/neovim',
as = 'rose-pine',
config = function()
vim.cmd('colorscheme rose-pine')
end
})
end
- Modify the color scheme according to personal preferences with a
colors.lua
after plugin file.
require('rose-pine').setup({
disable_background = true
})
function ColorMyPencils(color)
color = color or "rose-pine"
vim.cmd.colorscheme(color)
vim.api.nvim_set_hl(0, "Normal", { bg = "none" })
vim.api.nvim_set_hl(0, "NormalFloat", { bg = "none" })
end
ColorMyPencils()
More Plugins
Treesitter
Tree-sitter is a parser generator tool and an incremental parsing library. It can build a concrete syntax tree for a source file and efficiently update the syntax tree as the source file is edited. Tree-sitter aims to be:
- General enough to parse any programming language
- Fast enough to parse on every keystroke in a text editor
- Robust enough to provide useful results even in the presence of syntax errors
- Dependency-free so that the runtime library (which is written in pure C) can be embedded in any application
via: tree-sitter
- Add the treesitter plugin to the
packer.lua
file in the custom configuration directory
use('nvim-treesitter/nvim-treesitter', { run = ':TSUpdate' })
- Remember to run
:PackerSync
to install the plugin after making changes.
- Create the
treesitter.lua
file in the after plugin file.
require'nvim-treesitter.configs'.setup {
-- A list of parser names, or "all"
ensure_installed = { "vimdoc", "javascript", "typescript", "c", "lua", "rust" },
-- Install parsers synchronously (only applied to `ensure_installed`)
sync_install = false,
-- Automatically install missing parsers when entering buffer
-- Recommendation: set to false if you don't have `tree-sitter` CLI installed locally
auto_install = true,
highlight = {
-- `false` will disable the whole extension
enable = true,
-- Setting this to true will run `:h syntax` and tree-sitter at the same time.
-- Set this to `true` if you depend on 'syntax' being enabled (like for indentation).
-- Using this option may slow down your editor, and you may see some duplicate highlights.
-- Instead of true it can also be a list of languages
additional_vim_regex_highlighting = false,
},
}
Harpoon
- Add the harpoon plugin to the
packer.lua
file in the custom configuration directory
use('theprimeagen/harpoon')
- Create the
harpoon.lua
file in the after plugin file.
local mark = require("harpoon.mark")
local ui = require("harpoon.ui")
vim.keymap.set("n", "<leader>a", mark.add_file)
vim.keymap.set("n", "<C-e>", ui.toggle_quick_menu)
vim.keymap.set("n", "<C-h>", function() ui.nav_file(1) end)
vim.keymap.set("n", "<C-t>", function() ui.nav_file(2) end)
vim.keymap.set("n", "<C-n>", function() ui.nav_file(3) end)
vim.keymap.set("n", "<C-s>", function() ui.nav_file(4) end)
Undotree
- Add the undotree plugin to the
packer.lua
file in the custom configuration directory
use('mbbill/undotree')
- Create the
undotree.lua
file in the after plugin file.
vim.keymap.set("n", "<leader>u", vim.cmd.UndotreeToggle)
Vim Fugitive
- Add the vim-fugitive plugin to the
packer.lua
file in the custom configuration directory.
use('mbbill/undotree')
- Create the
fugitive.lua
file in the after plugin file.
vim.keymap.set("n", "<leader>gs", vim.cmd.Git)
LSP (Language Server Protocol)
The Language Server Protocol (LSP) is a standardized protocol used to provide programming language-specific features to code editors and Integrated Development Environments (IDEs). Its purpose is to separate the language-specific processing (like code completion, diagnostics, definitions) from the editor's interface. By doing this, LSP allows a single language server to be reused in multiple development tools, eliminating the need to implement and update specific language capabilities for each editor. This results in consistent and high-quality developer tools and experiences across different platforms and editors.
- Add the lsp-zero plugin to the
packer.lua
file in the custom configuration directory.
use {
'VonHeikemen/lsp-zero.nvim',
branch = 'v3.x',
requires = {
--- Manage the language servers from neovim
{'williamboman/mason.nvim'},
{'williamboman/mason-lspconfig.nvim'},
-- LSP Support
{'neovim/nvim-lspconfig'},
-- Autocompletion
{'hrsh7th/nvim-cmp'},
{'hrsh7th/cmp-nvim-lsp'},
{'L3MON4D3/LuaSnip'},
}
}
- Create the
lsp.lua
file in the after plugin file.
local lsp_zero = require('lsp-zero')
lsp_zero.on_attach(function(client, bufnr)
-- see :help lsp-zero-keybindings
-- to learn the available actions
lsp_zero.default_keymaps({buffer = bufnr})
end)
require('mason').setup({})
require('mason-lspconfig').setup({
ensure_installed = {
'tsserver',
'eslint',
'lua_ls',
'rust_analyzer',
},
handlers = {
lsp_zero.default_setup,
lua_ls = function()
local lua_opts = lsp_zero.nvim_lua_ls()
require('lspconfig').lua_ls.setup(lua_opts)
end,
},
})
Editor Settings
- Create a
set.lua
file within the custom configuration directory.
vim.opt.guicursor = ""
vim.opt.nu = true
vim.opt.relativenumber = true
vim.opt.tabstop = 4
vim.opt.softtabstop = 4
vim.opt.shiftwidth = 4
vim.opt.expandtab = true
vim.opt.smartindent = true
vim.opt.wrap = false
vim.opt.swapfile = false
vim.opt.backup = false
vim.opt.undodir = os.getenv("HOME") .. "/.vim/undodir"
vim.opt.undofile = true
vim.opt.hlsearch = false
vim.opt.incsearch = true
vim.opt.termguicolors = true
vim.opt.scrolloff = 8
vim.opt.signcolumn = "yes"
vim.opt.isfname:append("@-@")
vim.opt.updatetime = 50
vim.opt.colorcolumn = "80"
- Require the set file from within the
init.lua
file in the custom configuration directory.
require("reece.remap")
require("reece.set")
More Remaps
- Update the
remap.lua
file with the following keymaps.
vim.g.mapleader = " "
vim.keymap.set("n", "<leader>pv", vim.cmd.Ex)
vim.keymap.set("v", "J", ":m '>+1<CR>gv=gv")
vim.keymap.set("v", "K", ":m '<-2<CR>gv=gv")
vim.keymap.set("n", "J", "mzJ`z")
vim.keymap.set("n", "<C-d>", "<C-d>zz")
vim.keymap.set("n", "<C-u>", "<C-u>zz")
vim.keymap.set("n", "n", "nzzzv")
vim.keymap.set("n", "N", "Nzzzv")
-- greatest remap ever
vim.keymap.set("x", "<leader>p", [["_dP]])
-- next greatest remap ever : asbjornHaland
vim.keymap.set({ "n", "v" }, "<leader>y", [["+y]])
vim.keymap.set("n", "<leader>Y", [["+Y]])
vim.keymap.set({ "n", "v" }, "<leader>d", [["_d]])
vim.keymap.set("n", "Q", "<nop>")
vim.keymap.set("n", "<leader>f", vim.lsp.buf.format)
vim.keymap.set("n", "<C-k>", "<cmd>cnext<CR>zz")
vim.keymap.set("n", "<C-j>", "<cmd>cprev<CR>zz")
vim.keymap.set("n", "<leader>k", "<cmd>lnext<CR>zz")
vim.keymap.set("n", "<leader>j", "<cmd>lprev<CR>zz")
vim.keymap.set("n", "<leader>s", [[:%s/\<<C-r><C-w>\>/<C-r><C-w>/gI<Left><Left><Left>]])
vim.keymap.set("n", "<leader>x", "<cmd>!chmod +x %<CR>", { silent = true })