🔗PHILOSOPHY AND MODAL EDITING
Vim's defining characteristic is that it is a modal editor. There is no persistent insert state. You are always in one mode, and that mode determines exactly what every keystroke means.
The payoff: once you internalise the grammar, editing becomes a composable language. d3w (delete three words), ci" (change inside quotes), gUip (uppercase inner paragraph) — these are statements in a grammar you can extend indefinitely.
Core ideas:
- Keep your hands on the home row. The mouse is a context switch.
- Spend most of your time in Normal mode — it is the command mode, not a waiting state.
- Every operator + motion combination is a sentence. You do not need to remember two hundred commands; you learn a vocabulary of ~30 and combine them.
- The dot (
.) command repeats the last change. Design your edits so they are repeatable. - Use text objects, not character-by-character selection.
ci(is faster than going to the first char, visually selecting, then deleting.
🔗Vim vs Neovim
| Feature | Vim | Neovim |
|---|---|---|
| Config language | Vimscript | Lua (first class), Vimscript (supported) |
| Async | Limited | Full async via libuv |
| Built-in LSP | No | Yes |
| Built-in Treesitter | No | Yes |
| Built-in terminal | Yes | Yes (better integration) |
| RPC/remote plugins | Via Python/Ruby | Via msgpack-RPC |
| Floating windows | No | Yes |
| Default options | Conservative | More sensible defaults |
| Active development | Maintenance mode | Active |
For a modern installation, Neovim is the optimal choice. It offers native Lua support, integrated language server capabilities, and advanced UI features.
🔗INSTALL AND UPGRADE
🔗Neovim
Arch Linux:
sudo pacman -S neovim
Ubuntu / Debian (Latest Stable):
sudo add-apt-repository ppa:neovim-ppa/stable
sudo apt update && sudo apt install neovim
Build from source:
sudo pacman -S base-devel cmake ninja unzip gettext curl
git clone [https://github.com/neovim/neovim.git](https://github.com/neovim/neovim.git)
cd neovim
git checkout stable
make CMAKE_BUILD_TYPE=Release
sudo make install🔗Clipboard Support
Neovim delegates clipboard tasks to external tools. Your configuration uses unnamedplus for Wayland integration.
# Wayland
sudo pacman -S wl-clipboard # provides wl-copy, wl-paste
# X11
sudo pacman -S xclip # or xsel
# check Neovim sees it
nvim -c ':checkhealth' -c ':only'
🔗CONFIG PATHS AND LAUNCH
Neovim follows the XDG Base Directory Specification. Your main configuration file is ~/.config/nvim/init.lua.
| Path | Purpose |
|---|---|
~/.config/nvim/init.lua | Main config (Lua) |
~/.config/nvim/lua/ | Lua modules directory |
~/.local/share/nvim/ | Data: plugins, undo history, swap files |
~/.local/share/nvim/lazy/ | lazy.nvim plugin store |
~/.local/state/nvim/ | Log files, shada |
~/.cache/nvim/ | Cache |
🔗Reloading Config
To reload your configuration dynamically inside Neovim:
:source $MYVIMRC
🔗THE MODAL MODEL
Vim has several modes. Understanding each and how to enter and exit them is the foundation of everything else.
| Mode | Indicator | Entry | Exit |
|---|---|---|---|
| Normal | (none) | Escape, Ctrl-[, Ctrl-c | — (this is home) |
| Insert | -- INSERT -- | i, a, o, s, c, R... | Escape |
| Visual (char) | -- VISUAL -- | v | Escape or v |
| Visual (line) | -- VISUAL LINE -- | V | Escape or V |
| Visual (block) | -- VISUAL BLOCK -- | Ctrl-v | Escape or Ctrl-v |
| Command-line | : or / or ? | :, /, ?, ! | Enter or Escape |
| Replace | -- REPLACE -- | R | Escape |
| Terminal | -- TERMINAL -- | :terminal, i in term buf | Ctrl-\ then Ctrl-n |
🔗Why Normal Mode is Home
Every other editor puts you in an insert state by default. Vim inverts this: Normal mode is the resting state. Text editing breaks down into navigating to the edit, making the change, and returning to Normal to navigate again. Vim optimises for navigating.
🔗NORMAL MODE — MOTIONS
Motions move the cursor. Every motion can be preceded by a count. Motions combined with operators form the editing grammar.
🔗Character Motions
| Key | Movement |
|---|---|
h | Left one character |
j | Down one line |
k | Up one line |
l | Right one character |
0 | Column zero (start of line, including whitespace) |
^ | First non-blank character of line |
$ | End of line (after last character) |
g_ | Last non-blank character of line |
🔗Word Motions
A word is a sequence of alphanumeric characters and underscores. A WORD is any sequence of non-whitespace characters.
| Key | Movement |
|---|---|
w | Start of next word |
W | Start of next WORD |
b | Start of previous word |
B | Start of previous WORD |
e | End of current/next word |
E | End of current/next WORD |
🔗Find and To (Character Search on Line)
| Key | Movement |
|---|---|
f{c} | Forward to next occurrence of character c on line |
F{c} | Backward to previous occurrence of c on line |
t{c} | Forward to just before next c |
T{c} | Backward to just after previous c |
; | Repeat last f/F/t/T in same direction |
, | Repeat last f/F/t/T in opposite direction |
🔗Line Number and Document Motions
| Key | Movement |
|---|---|
gg | First line of file |
G | Last line of file |
{N}G | Line N |
% | Matching bracket/paren/brace/HTML tag |
{ | Start of previous paragraph |
} | Start of next paragraph |
🔗NORMAL MODE — OPERATORS
Operators act on the text covered by a following motion or text object. The pattern is: [count] {operator} [count] {motion}.
| Key | Action |
|---|---|
d | Delete (cut — goes into register) |
y | Yank (copy) |
c | Change (delete then enter Insert mode) |
> | Indent right |
< | Indent left |
= | Auto-indent (format indentation) |
gq | Format lines (wrap to textwidth) |
gU | Uppercase |
gu | Lowercase |
~ | Toggle case of character under cursor |
🔗Composed Examples
d3w-- delete 3 wordsd$-- delete to end of linedd-- delete current linedG-- delete to end of fileyap-- yank around paragraphci"-- change inside double quotesgUiw-- uppercase inner word
🔗The Dot Command
. repeats the last change — not the last command. A change is any action that modified text: insert, delete, replace, etc. Design your edits for repeatability. For example: ciw<new text><Esc>, then press . on the next word to apply the identical change.
🔗TEXT OBJECTS
Text objects allow selecting structured regions of text without navigating to their boundaries. They only work after an operator or in visual mode. Format: {i|a}{object} — i = inner (without delimiters), a = around (with delimiters).
| Object | Inner (i) | Around (a) |
|---|---|---|
w | Word | Word + surrounding whitespace |
W | WORD | WORD + surrounding whitespace |
s | Sentence | Sentence + whitespace |
p | Paragraph | Paragraph + blank lines |
" | Inside double quotes | Including double quotes |
' | Inside single quotes | Including single quotes |
( or ) | Inside parentheses | Including parentheses |
[ or ] | Inside square brackets | Including brackets |
{ or } | Inside curly braces | Including braces |
t | Inside HTML/XML tag | Including the tags |
🔗Text Object Examples
diw-- delete inner word (leaves whitespace)daw-- delete around word (removes word + space)ci(-- change inside parenthesesyi'-- yank inside single quotes
🔗INSERT MODE
Insert mode is where you type text. The goal is to enter it, type the minimum, and leave.
| Key | Entry Point |
|---|---|
i | Before the cursor |
I | Before first non-blank character of line |
a | After the cursor |
A | After the last character of line (end of line) |
o | Open new line below and enter insert |
O | Open new line above and enter insert |
s | Delete character under cursor and enter insert |
S | Delete entire line content and enter insert |
c{motion} | Delete through motion, enter insert |
🔗Insert Mode Commands
| Key | Action |
|---|---|
Ctrl-[ | Exit Insert mode (same as Escape) |
Ctrl-w | Delete word before cursor |
Ctrl-u | Delete all characters before cursor on current line |
Ctrl-o | Execute one Normal mode command, return to Insert |
Ctrl-r {reg} | Insert contents of register |
🔗VISUAL MODE
Visual mode lets you select a region and then apply an operator to it.
| Key | Mode |
|---|---|
v | Character-wise visual |
V | Line-wise visual |
Ctrl-v | Block visual |
gv | Reselect last visual selection |
o | Toggle cursor to opposite end of selection |
🔗Block Visual Mode
Block visual (Ctrl-v) selects a rectangular region. Operations apply to each line of the block independently. This is extremely powerful for prepending text to multiple lines simultaneously (Ctrl-v, select lines, I, type text, Escape).
🔗COMMAND-LINE MODE
Command-line mode is entered with :, /, ?, or !. It accepts Ex commands, search patterns, and shell commands.
🔗Ranges
Ranges prefix Ex commands to specify which lines they operate on.
%Entire file (same as1,$)'<,'>Last visual selection (auto-populated when pressing:in Visual mode)1,10Lines 1 to 10.,+5Current line to 5 lines below
🔗Global Command (:g)
:g/{pattern}/{command} runs a command on every line matching a pattern.
:g/TODO/d" delete all TODO lines:g/^$/d" delete blank lines:v/pattern/d" delete all non-matching lines
🔗Filter Command (:!)
:%!sort" sort entire file:'<,'>!python3" run visual selection through python
🔗SEARCH AND SUBSTITUTE
🔗Search
/pattern" search forward?pattern" search backwardn" next match (same direction)N" previous match (opposite direction)*" search word under cursor forward (whole word)
Your configuration ensures searches are fast and ergonomic:
ignorecaseis enabled so lowercase inputs match both cases.smartcaseis enabled so queries containing uppercase letters strictly match case.
🔗Substitute
:s/old/new/" replace first match on current line:%s/old/new/g" replace all matches in file:%s/old/new/gc" replace all, confirm each:'<,'>s/old/new/g" replace in visual selection
🔗REGISTERS
Registers store text. They are accessed with " followed by the register name.
| Register | Name | Description |
|---|---|---|
"" | Unnamed | Last deleted, changed, or yanked text |
"0 | Yank | Most recent yank only (not affected by delete) |
"1–"9 | Numbered | Rolling history of deletes and changes |
"a–"z | Named | User-controlled, explicitly named |
"+ | Clipboard | System clipboard |
"_ | Black hole | Discard — no register is affected |
"/ | Search | Last search pattern |
🔗The Unnamed and Yank Registers
The most common confusion: "1 through "9 shift on every delete. But "0 only updates on explicit yanks, never on deletes. Always use "0p to paste a yank after subsequent deletes.
🔗MACROS
Macros record a sequence of Normal, Insert, and Command-line mode actions into a register and replay them.
q{register}" begin recording into register (e.g.qq)q" stop recording@{register}" execute macro once{N}@{register}" execute macro N times@@" repeat last executed macro
🔗WINDOWS, BUFFERS, AND TABS
🔗Windows
A window is a viewport onto a buffer.
Ctrl-w vVertical splitCtrl-w sHorizontal splitCtrl-w h/j/k/lMove between windowsCtrl-w =Equalise all window sizesCtrl-w cClose window
🔗Buffers
A buffer is a file loaded into memory. It exists whether or not it is currently displayed in a window.
:ls" list all listed buffers:b{N}" switch to buffer N:bn/:bp" next / previous buffer:bd" unload and remove current buffer
🔗Tabs
Tabs in Vim are not like editor tabs — they are separate window layouts, each containing their own set of splits. Use tabs for distinct working contexts, not for individual files.
:tabnew" open new tabgt/gT" Next / previous tab
🔗NEOVIM LUA ESSENTIALS
Neovim exposes its API through the vim global Lua object.
vim.opt.number = true -- set an option
vim.g.mapleader = " " -- set a global variable
vim.fn.expand("%") -- call a Vim built-in function
vim.cmd("w") -- execute Ex commands
vim.api.nvim_get_current_buf() -- interact with the Neovim C API🔗Neovim Lua Autocommands
vim.api.nvim_create_autocmd("FileType", {
pattern = { "lua", "sh", "markdown" },
callback = function()
-- action to perform
end,
})
🔗NEOVIM — THIS CONFIG DEEP-DIVE
Your init.lua sets up a highly tailored, keyboard-driven development environment, leaning on modern Lua plugins rather than legacy Vimscript.
🔗Core Settings
Your environment establishes standard editor behaviors and aesthetics natively:
- The
mapleaderandmaplocalleaderare bound to theSpacekey. - Absolute line numbers (
number = true) and relative line numbering (relativenumber = true) are both enabled to facilitate rapid vertical jumping. - Full mouse support is active across all modes (
mouse = "a"). - Case-insensitive searching is enabled (
ignorecase = true), which intelligently becomes case-sensitive if you type an uppercase character (smartcase = true). - The
updatetimeis lowered to250milliseconds, ensuring diagnostics and plugin updates feel responsive. - True 24-bit color is enforced with
termguicolors = true. - System clipboard integration is handled seamlessly using the
unnamedplusregister. - The
spelllangis strictly set to"en_gb".
🔗Package Management: Lazy.nvim
The setup utilizes lazy.nvim as its package manager. It dynamically bootstraps itself via git clone into stdpath("data") .. "/lazy/lazy.nvim" if the directory does not exist. It targets the stable branch and enforces a blobless clone (--filter=blob:none) for speed.
🔗Plugins
🔗Theme: Flexoki
- The
kepano/flexoki-neovimplugin is loaded with top priority (priority = 1000). - It executes the
colorscheme flexoki-darkcommand immediately upon loading. - It explicitly overrides the
NormalandNormalFloathighlight groups, painting their backgrounds with the#100F0Fhex code to mesh perfectly with your broader Sway/system aesthetic.
🔗Syntax and Parsing: Nvim-Treesitter
nvim-treesitter/nvim-treesitteris configured to download and compile parsers natively.- It is explicitly instructed to install parsers for
lua,bash,markdown, andmarkdown_inline. - A
FileTypeautocommand triggersvim.treesitter.start()automatically whenever you openlua,sh, ormarkdownfiles.
🔗Autocompletion: Nvim-Cmp
- The
hrsh7th/nvim-cmpplugin handles code completion, relying strictly on two local dependencies:cmp-pathandcmp-buffer. - The
sourcesconfiguration limits data aggregation to local file paths ({ name = "path" }) and current text buffers ({ name = "buffer" }). - Key mappings are explicitly structured around standard control keys:
<C-b>scrolls docs up,<C-f>scrolls docs down,<C-Space>manually triggers the menu,<C-e>aborts the operation, and<CR>confirms the selection.
🔗Buffer Navigation: Bufferline.nvim
akinsho/bufferline.nvimrequiresnvim-web-deviconsto function correctly in your setup.- The bar is configured in
buffersmode, rendering background buffers at the top of the terminal. - It displays
ordinalnumbers on the tabs and hides all graphical closing icons (show_buffer_close_icons = false,show_close_icon = false) for a cleaner visual profile. - It enforces regular tabs (
enforce_regular_tabs = true), a thin separator (separator_style = "thin"), and ensures the bar is always visible. - Custom keymaps are defined for navigation:
<S-h>calls<cmd>BufferLineCyclePrev<CR>,<S-l>calls<cmd>BufferLineCycleNext<CR>, and<leader>xterminates the active buffer with<cmd>bdelete<CR>.
🔗Markdown Enhancements: Render-Markdown
MeanderingProgrammer/render-markdown.nvimleverages both treesitter and devicons to paint Markdown files beautifully in the terminal.- Heading signs are disabled (
sign = false), and heading icons are replaced with a custom array of specialized font characters (' ',' ',' ',' ',' ',' '). - Code blocks disable the standard sign column, render natively as visual blocks (
width = "block"), and inject a minor right-side padding (right_pad = 1).
🔗Writing Focus: Zen-mode.nvim
folke/zen-mode.nvimstrips away terminal distractions.- The isolated window is restricted to a column width of 80 (
width = 80). - Absolute and relative line numbers are forcefully disabled within the Zen pane (
number = false,relativenumber = false). - It is triggered instantly via the
<leader>zkeybinding, invoking<cmd>ZenMode<CR>.