Tutor :Tutor launch tutor Verb, count, motion count + verb + count + motion navigation is the default verb, can be omitted Motions w jump forward to the start of a word e jump forward to the end of a word b jump back to the start of a word ge jump back to the end of of a word $ jump forward to the end of a line 0 jump backwards to the start of a line ^ same as 0 , but does not take white spaces into account W E B gE works the same, but splits words by white space, while lowercased versions split works also with dot, paren, quote Count + motion = Repeat motion 3w jump forward to the end of a word 3 times Insert mode (text) a put caret after cursor A put caret at the end of the line i put caret before cursor I put caret at the start of the line o add line below and put caret O add line above and put caret ge go to the last insertion point Esc normal mode (navigate and manipulate text) Select v granule text selection in Visual mode V line text selection in Visual mode C-v block vertical text selection (handy for csv data), $ - expands the selection to the longest line Or just click and drag mouse Esc / v exit Visual mode gv go back to prev selection o in Visual mode - jump to the start/end of selection S select with Seeking Surrounding Objects Expand selection there is no native vim way, but can use treesitter plugin Create or edit ~/.config/nvim/lua/plugins/treesitter.lua
return {
"nvim-treesitter/nvim-treesitter",
opts = function(_, opts)
opts.incremental_selection = vim.tbl_deep_extend("force", opts.incremental_selection or {}, {
enable = true,
keymaps = {
init_selection = "gnn", -- start at node under cursor
node_incremental = "grn", -- expand outward
node_decremental = "grm", -- shrink inward
scope_incremental = "grc", -- expand to scope (func/class)
},
})
end,
}
Run :Lazy sync, then restart NeoVim Put cursor inside some code. Type: gnn → selection starts. Then: grn → expand outward. Again: grn → expand more. grm → shrink back. Registers Registers are different named clipboards where you copy text " open register list "ayy copy line into named a register "ap paste from the a register you may also delete and replace into the register adding again to the same named register replaces the content "Ay copy into upper-cased named A register appends text into existing a register System clipboard is synched with + and * registers Space s " show all registers and add content to + register with Enter Ctrl+r show same menu in Insert mode last copied test is always available at 0 register and you may paste it with "0p Last typed text goes into . register Last deleted small text goes into - register The name of the file that you are currently editing goes into % register :let @c=@. copy . register to named c register Copy (yank) y copy highlighted text (yank) yy copy whole line Y copy to the end of the line yw copy to the word's end yiq / yaq copy inside nearest quotes / including quotes yib / yab copy inside nearest brackets / including brackets yiw / yaw copy nearest word / word and whitespaces around yig copy whole file Paste p paste deleted text after cursor 5p paste 5 times P paste deleted text before cursor In Insert mode to paste Ctrl+r followed by + Yanky.nvim Plugin Install it from :LazyExtras and pushing x in front of it, then reload NeoVim Space p opens the clipboard history list p[y[y[y… / p]y]y]y… pastes previous/next clipboard entries in cycle [p / ]p pastes indented above/below current line >p/<p/>P/<P put after/before and indent right/left Undo, Redo u undo the last command U undo all for the line C-r redo C-u undo in Insert mode Command mode : command mode :q! exit without save Open project in NeoVim Navigate to you project in terminal with cd Type nvim Save :w write :w TEST.txt write under TEST name :write TEST.txt same v motion :w FILENAME saves the Visually selected lines in file FILENAME. Exit :q quite :wq write & quit :x write & quit :q! quit without save Navigate in list Tab move down in list Ctrl+y accept Arrow Down accept Cursor movement j up k down h left l right Cursor history Ctrl+o jump back in history location Ctrl+i jump forward in history location Ctrl+g show cursor position + file name Jump by line (go to) 15G jumps to line #15 :15 jumps to line #15 gg jumps to first line G jumps to last line Jump by sentence ( / ) jump to start/end of the sentence Jump by paragraph { / } jump to start/end of the paragraph Jump by bracket [ / ] open go to prev/next menu ]) go to block's ) ]} go to block's } ]> go to block's > ]% go to block's brace (universal, works for <>()[]{} ) Jump to matching bracket Place cursor on bracket % jumps to closing bracket Jump by variable instance [[ / ]] jumps to prev/next variable instances Jump by function [f / ]f jumps to prev/next function start [F / ]F jumps to prev/next function end Jump by parameter [a / ]a jumps to prev/next parameter start [A / ]A jumps to prev/next parameter end Jump by method [m / ]m jumps to prev/next method start [M / ]M jumps to prev/next method end Jump by class [c / ]c jumps to prev/next class start [C / ]C jumps to prev/next class end Jump by scope [i / ]i jumps to start/end of scope Jump by error, warning, spell, diagnostic [e / ]e jumps to prev/next error [w / ]w jumps to prev/next warning [s / ]s jumps to prev/next spell issue ( Space+us to enable spell check) [d / ]d jumps to prev/next diagnostic message [t / ]t jumps to prev/next TODO or FIXME comment Space cd show full error message under cursor Jump by hunk (changes) Hunk - modifications that haven't been staged or committed yet [h / ]h jumps to prev/next changes Find f puts you in Find mode type a char and cursor jumps to the next typed char f jumps to the next x 3fx jumps to the 3rd x from you F / , same, but backwards To t same as Find mode, but puts cursor before the found char t searches for next char Seek s seek mode you may jump to any visible text simply by typing part of it and press green label character Seek in object May seek inside text object where your cursor is vS / dS / cS / yS select/delete/change/copy & enter into SEEK mode Green labels will surround the text part, a,b,c,d,e... from the inner to outer Seek remote May for ex copy (yank) something from remote place r yr (enters into Seek mode) + phrase + ib (inside brackets) Cursor comes back to the initial place Seek remote object Copy something from remote object with R (capital) yR (enters into Seek mode) + phrase + a (tag) Cursor does not come back Personally did not understand why it is helpful, better to jump to place, select & yank Surrounding Pair To change quotation marks or brackets, or content inside enable mini.surround extra plugin Select some text gsa add surrounding to selection " / ' / ` add quotation mark around ( / { / [ add braces with empty spaces ) / } / ] add braces without empty spaces Instead of selecting the text first may do directly gsaiB" to add quotation marks inside braces at your cursor gsa$" will surround text between the cursor and the end of the line with double quotation marks gsaSb' will surround text that you select with the label b after an S operation with single quotation marks gsdb delete surrounding braces gsdq delete surrounding quotes gsd[ delete surrounding square brackets 2gsd{ delete the second set of curly braces from cursor position gsr"' replace double quotes with single gsfb / gsFb jump to next/prev bracket gsfb highlight paired braces gsat add tags around selection Scroll Ctrl+d/u scroll down/up 50% Ctrl+f/b scroll down/up 100% 5 Ctrl+f scroll down 5 screens Ctrl+e/y scroll down/up 1 line z t/b scroll up/down to move active line almost to the top/bottom zz scroll to move active line to the middle Delete (verb) d [number] motion - delete operator dh / dl delete the character to the left/right of the cursor. dw delete to the beginning of next word d2w delete 2 words de delete to the end of the word db delete to the start of the word d0 delete to the start of the line d$ delete to the end of the line dd delete whole line (shortcut) 2dd delete 2 lines d2fe delete to the second e , including e d2ta delete to the second a dsfoos the label s that pops up when you use Seek mode to seek to foo . Note that Seek mode jumps to the beginning of the word D delete to the end of the line (shortcut) diq / daq delete inside nearest quotes / including quotes dib / dab delete inside nearest brackets / including brackets diw / daw delete nearest word / word and whitespaces around Delete char (verb) x delete char under cursor 5x delete 5 chars X delete char before cursor Change (verb) c - deletes and inters into Insert mode same as d + motion + i cw deletes to the end of the word & enters into Insert mode cc changes whole line (shortcut) C changes to the end of the line (shortcut) ciq / caq changes inside nearest quotes / including quotes cib / cab changes inside nearest brackets / including brackets ciw / caw changes nearest word / word and whitespaces around cag changes whole file Replace char (verb) r go into replace mode of single char, then a to replace with a R go into global replace mode Join lines J join lines merging white spaces gJ join lines keeping white spaces UpperCase & LowerCase ~ inverts case under the cursor gU / gu upper/lower case mode gUU / guu same, for whole line Dot repeat . repeats the verb 2. repeats the verb two times (if you removed 3 lines with 3dd , 2. will not remove 6 lines, but 2) Record command qq start recording and store commands into q named register q stop recording qQ continue recording (append commands to q register) Q play most recent recording @a play back recording stored at a register saved previously by qa @@ replay whichever register you most recently played To edit the recording just past it from the register by "qp if it was written to the named q register, then modify the text and copy it back to the q register by "qyiw Search / phrase search prompt, then Enter ? phrase search prompt in backwards direction n find next N find next in reverse direction Ctrl+o go back to older position Ctrl+i go back to newer position Find and replace :s/old/new/ replaces "old" with "new" occurrence in line :s/old/new/g replaces "old" with "new" all occurrences in line :1,5s/old/new/g replaces "old" with "new" all occurrences in 1...5 lines :%s/old/new/g replaces "old" with "new" in file :%s/old/new/gc replaces "old" with "new" in file with prompt External command :!ls show files :!rm FILENAME remove FILENAME file Read content and paste :r TEST reads content from the file TEST and pastes below the cursor :r !ls reads content from external command and pastes below the cursor Search file Search files in Current Working Directory Current Working Directory (CWD) is the directory where your terminal was in when you typed nvim Space fF files fuzzy search in (CWD) To check where you are, type :pwd (Print Working Directory) To change CWD :cd path/to/directory To change CWD just in one tab :lcd path/to/directory Search files in Root Directory Root Directory is where package.json or tsconfig.json Space Space files fuzzy search in current project Space ff same Root Directory may be confusing, coz they may change silently. Imagine you are in a monorepo with multiple tsconfig.json files and you will have different Current Working Directory depending on which file you are working on. In this case you may want to search relative to CWD Search gotchas Search is case insensitive, until you type a capital letter phrase1 phrase2 - type phrase1 first, get search results, hit Space , type second phrase2 , already visible results will be narrowed by fuzzy search with second phrase, super convenient Alt+s seek mode (may need to enable Alt first iTerm2 → Preferences → Profiles → [your profile] → Keyboard and set Left Option Key to: Esc+ ) Ctrl+j Ctrl+k move down/up in the list Ctrl+h backspace Tab select multiple results Enter confirm selection Esc Esc exit from search mode Explorer Space+e open file explorer at Root Directory Space+E open file explorer at CWD j / k down/up 3j jump down 3 lines Enter expand/collapse folder Backspace go to parent folder Enter expand/collapse folder Tab multiple select Ctrl f/b scroll down/up i jump to search field in Insert mode to search for a specific file Alt+s seek mode during Insert mode s seek mode also covers the explorer window d delete file a add file/folder r rename y / p copy/paste m move file ? being focused on explorer - help window with other useful shortcuts mini.files Like explorer, but more Vim-ish mini.files Installation Go to LazyVim extras by x from the dashboard Move your cursor to the line that contains mini.files Press x to install, then restart NeoVim mini.files Usage Space fm open dir of current file at explorer Space fM open the directory where your terminal was in when you typed nvim (CWD) j / k move up/down h / l move out/in o add file/folder dd delete i go to Insert mode to rename yy copy p paste q close the explorer view = save changes Useful vim plugin for vscode learn vim plugin for vscode vimtutor terminal app to learn vim on most Unix operating systems cheatsheet NeoVim https://neovim.io/ is Vim-based text editor LazyVim is opinionated popular Neovim setup Font https://www.nerdfonts.com/font-downloads Download FiraCode Nerd Font, unzip, install all fonts Open iTerm2, then Preferences, then Profiles, then Text, pick FiraCode Nerd Font Restart the terminal Dashboard :lua Snacks.dashboard() open dashboard from editor Plugins The Lazy Extras mode can be accessed by pressing x from the dashboard or :LazyExtras from the editor Navigate and press x to pick Relaunch NeoVim Space cm open Mason, some other plugin list, alternative to LazyExtras Buffers H / L switch buffers visible in the currently active window [b / ]b same, switch buffers Space , open current buffer list Ctrl+x close buffer from the list Space ` switch to previous buffer Space bb same, switch to previous buffer Space bd close (delete) buffer Space bD close (delete) buffer & window split Space bp pin a buffer Space bl / br / bo / bP close to left/right/others/pinned buffers split Space . open scratch buffer where you may write notes. Scratch buffers are tied to the current working directory. Space S open scratch buffer list Windows Window in Vim is a pane or split Space w v/s split vertically/horizontally Same works in mini.files plugin Ctrl+v/s open in vertically/horizontally split from explorer Ctrl+h/j/k/l move between windows Space w h/j/k/l same, move between windows Space w q close window Space w d same, close window Space w o close other windows Resize split with mouse by dragging middle bar Space w </>/+/- same, resize split window Space w = reset split windows to equal size Space w Space go into Hydra mode, it will keep the menu open, now you may keep pressing >>>>> to continuously resize Space u z go into Zen mode, center the window and dim all around Tabs Skipped, did not understand why it is needed... Fold z c/a fold / unfold za toggle folding zR unfold all zO unfold all folds under cursor Session Session keeps information about windows, splits and tabs Space qq to exit LazyVim cd to the project and open NeoVim by nvim s to restore the last session Space qs same, restore session Space qS open session list, can be useful to see last opened projects Space qd close without saving the session, useful when you temporarily opened NeoVim and close it Language server :LspRestart restart the language server :checkhealth / :LazyHealth health of various installed plugins (do not expect all to be green) (there are overlaps, LazyHealth is easier to read) Space xx/xX show diagnostic window with list of errors Code action Space ca open code actions Notice NeoVim has a notice window in the top right corner where some important messages pops up once in a while Space cna show list of messages ESLint Lint plugin for NeoVim nvim-lint Add file ~/.config/nvim/lua/plugins/nvim-lint.lua
return {
"mfussenegger/nvim-lint",
event = { "BufReadPre", "BufNewFile" },
config = function()
local lint = require("lint")
lint.linters_by_ft = {
javascript = { "eslint" },
typescript = { "eslint" },
javascriptreact = { "eslint" },
typescriptreact = { "eslint" },
}
-- Always use the project's local eslint
lint.linters.eslint = lint.linters.eslint or {}
lint.linters.eslint.prefer_local = "node_modules/.bin"
-- Prefer the nearest folder that actually has the eslint binary;
-- otherwise fall back to a folder with an ESLint config; else git root.
lint.linters.eslint.cwd = function(bufnr)
local bufpath = vim.api.nvim_buf_get_name(bufnr)
local start = vim.fs.dirname(bufpath)
-- 1) nearest node_modules/.bin/eslint
local bin = vim.fs.find("node_modules/.bin/eslint", { path = start, upward = true })[1]
if bin then
-- strip trailing /node_modules/.bin/eslint -> project root
return (bin:gsub("/node_modules/.bin/eslint$", ""))
end
-- 2) nearest ESLint config
local cfg = vim.fs.find({
"eslint.config.js",
"eslint.config.cjs",
".eslintrc",
".eslintrc.json",
".eslintrc.js",
".eslintrc.cjs",
}, { path = start, upward = true })[1]
if cfg then
return vim.fs.dirname(cfg)
end
-- 3) git root, then current cwd
local git = vim.fs.find(".git", { path = start, upward = true })[1]
return git and vim.fs.dirname(git) or vim.loop.cwd()
end
vim.api.nvim_create_autocmd({ "BufWritePost", "BufEnter", "InsertLeave" }, {
callback = function()
lint.try_lint()
end,
})
end,
}
Formatter Lint plugin for NeoVim conform Add file ~/.config/nvim/lua/plugins/conform.lua
return {
"stevearc/conform.nvim",
opts = {
formatters_by_ft = {
javascript = { "prettier" },
javascriptreact = { "prettier" },
typescript = { "prettier" },
typescriptreact = { "prettier" },
json = { "prettier" },
css = { "prettier" },
html = { "prettier" },
yaml = { "prettier" },
markdown = { "prettier" },
-- add more filetypes if needed
},
},
}