Writing my Neovim config from scratch

Infatuation & Contempt: How it started

Arkjain
7 min readJun 2, 2024

Credits to Josean Martinez

For a while now I’ve been using Neovim, a subtle flex to the world that I’m a programmer. I bring with me an elitist air filled with judgment for people using eclipse or vscode however I too was once a pariah to the crustacean, ThePrimeagen community. It started out in 2022 when I was writing a review for a paper in nano when a guy said “why are you using nano!” with a contemptuous tone reserved usually for a butcher.

On multiple occasions I had seen my friend who works at Stripe use this fancy terminal to program faster than he spoke Spanish and without using his keypad that I was drawn to this thing called neovim — a text editor building on vim, new vim. Once you start using it, you’ll fall in love with the key binds to do some of the follows:

  • Navigate up and down blocks of code [k(↑) j(↓) l(→) h(←)], Go down half a page, Go up half a Page [^-D, ^-U]
  • *View all your files using TreeSitter [<Space> — n]
  • *Get all function, structs and headers in a single file [<Space> — ae]
  • Quit [:q], Write [:w], Visual Mode for selecting files[:v], Insert Mode[i],
  • Delete [dd], Copy to clipboard [:+y], Select a function within bounds of curly brackets [:yi{], delete everything in curly brackets [:di{]
  • Delete a word [:daw], change upto the first occurrence of a character [:ca“ch” where “ch” is the character]
  • ,and so much more…

Thus I decided to code up my own neovim config and this my guide to do so!

Initial SETUP

Make sure you have homebrew installed.

cd ~
brew --version # check if you have homebrew
brew install neovim # install neovim
nvim --version # check if you have nvim installed
brew tap homebrew/cask-fonts # Get fonts, I want to use nerd fonts

brew install ripgrep
# https://github.com/BurntSushi/ripgrep - for rege
brew install node # ensures you have node

Now once you have everything install, from your root run the following commands:

mkdir -p ~/.config/nvim      # -p makes a parent directory, we need a nvim folder
cd ~/.config/nvim
touch init.lua
mkdir lua/arkash/core
mkdir lua/arkash/plugins
touch lua/arkash/lazy.lua

The init.lua file allows you to manage your setup, keybinds and extensions. Plugins are all the external packages we will install like treesitter, lsp, copilot etc. To view your files nicely, run:

brew install tree

Now open up nvim and use shift + 5 to make the options.lua file to change the view of the file explorer. Hit enter in vim to navigate to the options.lua file and press i to insert. We can use vim commands in lua as well and by using the netrw package, we can use liststyles for a better vim view of our files in the nvim tree.

vim.cmd("let g:netrw_liststyle = 3")

Press control — C to exit insert mode (I prefer this to esc cause I’m on a MacBook Pro 13', so esc is tiny), hit “:Explore” to exit the file and navigate to “../” to go a level up. Reach the init.lua file and type:

require("arkash.core.options")

Exit nvim by typing “:q” and run “nvim .”

local opt = vim.opt
opt.relativenumbers = true

Once done, run :source %.

Configs

General

vim.cmd("let g:netrw_liststyle = 3")
local opt = vim.opt
opt.relativenumber = true

opt.number = true

-- tabs & indentation
opt.tabstop = 2
opt.shiftwidth = 2 -- 2 spaces for indent width
opt.expandtab = true -- expand tab to spaces
opt.autoindent = true -- copy indent of current line to new line

-- :h autoindent for help

opt.wrap = false

-- search settings
opt.ignorecase = true -- case insensitive search
opt.smartcase = true -- uses mixed case for case sensitive search

-- opt.cursorline = true

-- turn on termguicolors for tokyonight colorscheme to work

-- opt.termguicolors = true
opt.background = "dark" -- colorschemes can be light or dark
opt.signcolumn = "yes" -- show sign column so that text doesnt shift

-- backspace
opt.backspace = "indent,eol,start" -- allow backspace on indent, end of line or insert mode start position

-- clipboard
opt.clipboard:append("unnamedplus") -- use system clipboard as default register

-- split windows
opt.splitright = true -- split vertical window to the right
opt.splitbelow = true -- split horizontal window to the bottom

Set alias for core by making an init.lua in the core folder.

Now we can go to the main init.lua and simply use require(“arkash.core”).

Keymaps

General ones

vim.g.mapleader = " "
local keymap = vim.keymap -- for conciseness

-- press jk in insert mode to escape
-- keymap.set("i", "jk", "<ESC>", {desc = "Exit Insert mode with jk"})

-- press n to remove highlights
keymap.set("n", "<leader>nh", ":nohl<CR>", {desc="Clear search highlights"})

-- increment and decrement numbers
keymap.set("n", "<leader>+", "<C-a>", {desc = "Increment Number"}) -- increment
keymap.set("n", "<leader>-", "<C-x>", {desc = "Decrement Number"}) -- decrement

For managing window

-- window management
keymap.set("n", "<leader>sv", "<C-w>v", {desc="Split window vertically"})
keymap.set("n", "<leader>sh", "<C-w>s", {desc="Split window horizontally"})
keymap.set("n", "<leader>se", "<C-w>=", {desc="Make splits equal size"})
keymap.set("n", "<leader>sx", "<cmd>close<CR>", {desc="Close current split"})
-- tab management
keymap.set("n", "<leader>to", "<cmd>tabnew<CR>", {desc="Open New Tab"})
keymap.set("n", "<leader>tx", "<cmd>tabclose<CR>", {desc="Close current tab"})
keymap.set("n", "<leader>tn", "<cmd>tabn<CR>", {desc="Go to next tab"})
keymap.set("n", "<leader>tp", "<cmd>tabp<CR>", {desc="Go to prev tab"})
keymap.set("n", "<leader>tf", "<cmd>tabnew %<CR>", {desc="Open current buffer in new tab"})

Lazy

To setup lazy, navigate to the lazy.nvim and add this boilerplate from https://github.com/folke/lazy.nvim

local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not (vim.uv or vim.loop).fs_stat(lazypath) then
vim.fn.system({
"git",
"clone",
"--filter=blob:none",
"https://github.com/folke/lazy.nvim.git",
"--branch=stable", -- latest stable release
lazypath,
})
end
vim.opt.rtp:prepend(lazypath)

Once done, add:

require("lazy).setup("arkash.plugins")

Navigate to our init.lua file (global one) and add:

require("arkash.plugins")

Now when you exits nvim and run nvim . and reopen vim, you’ll see an error:

Thats because we dont have any plugins here yet!! So lets add them. I made an init.lua in the plugins folder and added a couple of github repos for the config.

  • Look at the bottom, lazy detects changes to your config.
  • Make a colorscheme.lua file to add a tokyonight scheme
return {
"folke/tokyonight.nvim",
priority = 1000,
config = function()
vim.cmd("colorscheme tokyonight")
end
}
  • Add a nvim-tree.lua
return {
"nvim-tree/nvim-tree.lua",
dependencies = "nvim-tree/nvim-web-devicons",
config = function()
vim.g.loaded_netrw=1
vim.g.loaded_netrwPlugin=1

nvimtree.setup({
view = {
width = 35,
relativenumber = true,
},

-- change folder arrow icons
renderer = {
indent_markers = {
enable = true,
},
icons = {
glyphs = {
folder = {
arrow_closed = "", -- arrow when folder is closed
arrow_open = "", -- arrow when folder is open
},
},
},
},
-- disable window_picker for
-- explorer to work well with
-- window splits
actions = {
open_file = {
window_picker = {
enable = false,
},
},
},
filters = {
custom = { ".DS_Store" },
},
git = {
ignore = false,
},

-- setting keymaps
local keymap = vim.keymap

keymap.set("n", "<leader>ee", "<cmd>NvimTreeToggle<CR>", {desc="Toggle file explorer"})
keymap.set("n", "<leader>ef", "<cmd>NvimTreeFindFileToggle<CR>", {desc="Toggle file explore on current file"})
keymap.set("n", "<leader>ec", "<cmd>NvimTreeCollapse<CR>", {desc="Collapse file explore"})
keymap.set("n", "<leader>er", "<cmd>NvimTreeRefresh<CR>", {desc="Refresh file explorer"})

})
end
}

Take a break!

Even as a vim veteran, I have shown you so many key-maps here that it's hard for me to keep up. Therefore, I will use the https://github.com/folke/which-key.nvim plugin which will wait for an arbitrary amount of time after I press a key to bring out the keymaps for it.

return {
"folke/which-key.nvim",
event = "verylazy",
init = function()
vim.o.timeout = true
vim.o.timeoutlen = 500
end,
opts = {
-- leave opts empty for default
},
}

The next article will talk about more plugins, hope you had fun setting up nvim till now. Note that I took all the material from https://www.youtube.com/watch?v=6pAG3BHurdM&t=803s, which is the best nvim tutorial I’ve ever used.

To be continued…

--

--