{"id":487,"date":"2019-08-11T05:41:13","date_gmt":"2019-08-11T05:41:13","guid":{"rendered":"https:\/\/gnikesh.com\/?p=487"},"modified":"2025-06-11T05:42:24","modified_gmt":"2025-06-11T05:42:24","slug":"from-i-cant-quit-vim-to-i-cant-live-without-it","status":"publish","type":"post","link":"https:\/\/gnikesh.com\/index.php\/2019\/08\/11\/from-i-cant-quit-vim-to-i-cant-live-without-it\/","title":{"rendered":"From \u201cI Can\u2019t Quit Vim\u201d to \u201cI Can\u2019t Live Without It\u201d"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">1. How it all started<\/h2>\n\n\n\n<p>Vim was the <strong>first text editor I ever heard of<\/strong> when I began dabbling in Linux, shell scripting, and the mysterious world of the command line. Like many newcomers, I quickly discovered that the <em>idea<\/em> of Vim felt empowering\u2014yet the <strong>reality was intimidating<\/strong>. My editor of choice back then was Sublime Text; it was friendly, had fancy tabs, and\u2014crucially\u2014didn\u2019t lock me in when I fat-fingered <code>:q!<\/code>.<\/p>\n\n\n\n<p>Everything changed the day I had to SSH into a production server that <em>only<\/em> had the basics: <code>bash<\/code>, <code>nano<\/code>, and <strong>Vim<\/strong>. Nano was adequate for quick config tweaks, but the more Python I wrote the more I craved<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>multiple cursors<\/li>\n\n\n\n<li>regex-powered substitutions<\/li>\n\n\n\n<li>lightning-fast opens over flaky VPNs<\/li>\n<\/ul>\n\n\n\n<p>There really is no safer bet than Vim on a UNIX-like box\u2014<strong>I have yet to meet a distribution without it pre-installed<\/strong>\u2014so I decided to lean in, ditch the training wheels, and make Vim my daily driver for <strong>one full year<\/strong>. Here\u2019s what happened, what I learned, and how you can avoid a few face-plants along the way.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><strong>Spoiler:<\/strong> Once you \u201cget\u201d Vim, the muscle memory becomes second nature; it feels less like using a tool and more like <em>thinking directly into text<\/em>.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">2. Understanding Vim\u2019s split personality: the modes<\/h2>\n\n\n\n<p>If Vim were a game, each <em>mode<\/em> would be a different character class. Mastering when to switch classes is <strong>80 % of the battle<\/strong>.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Mode (Key Role)<\/th><th>Primary Purpose<\/th><th>Enter With<\/th><th>Exit With<\/th><\/tr><\/thead><tbody><tr><td><strong>Normal<\/strong> (navigation)<\/td><td>Move, delete, copy, paste, issue commands<\/td><td><code>Esc<\/code><\/td><td>\u2014<\/td><\/tr><tr><td><strong>Insert<\/strong><\/td><td>Type text<\/td><td><code>i<\/code>, <code>a<\/code>, <code>o<\/code>, etc.<\/td><td><code>Esc<\/code><\/td><\/tr><tr><td><strong>Visual<\/strong><\/td><td>Select text blocks<\/td><td><code>v<\/code> \/ <code>V<\/code> \/ <code>Ctrl-v<\/code><\/td><td><code>Esc<\/code><\/td><\/tr><tr><td><strong>Command-line (Ex)<\/strong><\/td><td>Run Ex commands (<code>:w<\/code>, <code>:%s\/...\/<\/code>, <code>:!\u2026<\/code>)<\/td><td><code>:<\/code> \/ <code>\/<\/code> \/ <code>?<\/code><\/td><td><code>Esc<\/code><\/td><\/tr><tr><td><strong>Replace \/ Select \/ Term<\/strong><\/td><td>Niche helpers: <code>R<\/code>, <code>gh<\/code>, <code>:term<\/code><\/td><td>Varies<\/td><td><code>Esc<\/code>, <code>Ctrl-w<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Why so many modes?<\/h3>\n\n\n\n<p>Because <em>context-switching with the keyboard is faster<\/em> than reaching for modifier keys or menus. Bram Moolenaar built on Bill Joy\u2019s original <strong>vi<\/strong> philosophy: <strong>make the common case a single keystroke<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">3. Normal Mode: the Jedi temple<\/h2>\n\n\n\n<p>Think of Normal Mode as \u201cread-only plus superpowers.\u201d You aren\u2019t typing text; you\u2019re <em>commanding<\/em> it.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Navigation basics<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>h j k l<\/code> \u2014 move left, down, up, right (muscle-memory gold)<\/li>\n\n\n\n<li><code>w<\/code> \/ <code>b<\/code> \u2014 jump one word forward\/back<\/li>\n\n\n\n<li><code>gg<\/code> \/ <code>G<\/code> \u2014 go to top\/bottom of file<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Editing verbs<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Verb<\/th><th>Action (default)<\/th><th>Example &amp; Explanation<\/th><\/tr><\/thead><tbody><tr><td><code>d<\/code><\/td><td>delete \/ cut<\/td><td><code>dw<\/code> = <em>delete word<\/em><\/td><\/tr><tr><td><code>y<\/code><\/td><td>yank \/ copy<\/td><td><code>yap<\/code> = <em>yank around paragraph<\/em><\/td><\/tr><tr><td><code>c<\/code><\/td><td>change (delete \u2192 insert)<\/td><td><code>ci\"<\/code> = <em>change inside quotes<\/em><\/td><\/tr><tr><td><code>&gt;<\/code> \/ <code>&lt;<\/code><\/td><td>indent \/ outdent<\/td><td><code>&gt;&gt;<\/code> = indent current line<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Once this clicks, Vim starts to feel like text Tetris\u2014pieces snap into place with minimal effort.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">4. Insert Mode tips nobody told me<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Undo granularity<\/strong> \u2014 Vim groups edits between exits from Insert Mode into a single undo step. Pop in and out often (<code>Esc<\/code>, <code>i<\/code>) for <em>micro-undo<\/em> superpowers.<\/li>\n\n\n\n<li><strong>Completion<\/strong> \u2014 Press <code>Ctrl-n<\/code> \/ <code>Ctrl-p<\/code> for context-aware suggestions\u2014even without plugins.<\/li>\n\n\n\n<li><strong>Repeating inserts<\/strong> \u2014 <code>Ctrl-a<\/code> or <code>Ctrl-x<\/code> on a number increments or decrements it\u2014handy for numbered lists.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">5. Visual Mode: the Swiss-army pointer<\/h2>\n\n\n\n<p>Visual Mode turns Vim into a precise selection tool\u2014minus the mouse lag.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Line juggling<\/strong> \u2014 Select lines with <code>V<\/code>, then <code>:m '+1<\/code> or <code>:m '-2<\/code> to move the block (quotes reference selection bounds).<\/li>\n\n\n\n<li><strong>Column editing<\/strong> \u2014 Use <code>Ctrl-v<\/code> for block selections; great for CSVs or aligning code. Follow with <code>J<\/code> (join), <code>I<\/code> (insert on every line), or <code>r<\/code> (replace).<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">6. Command-line Mode: Ex power unleashed<\/h2>\n\n\n\n<p>The humble <code>:<\/code> prompt is where Vim graduates from editor to <strong>text surgeon<\/strong>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>:%s\/old\/new\/gc      \" global substitution with confirmation\n:g\/^#\/d             \" delete every line that starts with #\n:e!                 \" reload file, discarding changes\n:w !sudo tee %      \" save a file needing root AFTER opening normally<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">7. Making Vim feel like \u201chome\u201d: customization &amp; plugins<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">7.1 Minimal <strong><code>~\/.vimrc<\/code><\/strong> starter<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>\" --- Core settings -------------------------------------------------\nset nocompatible            \" Use Vim defaults, not ancient vi\nset number                  \" Show absolute line numbers\nset relativenumber          \" \u2026plus relative numbers for jumps\nset hidden                  \" Allow unsaved buffers in background\nset tabstop=4 shiftwidth=4  \" Four-space tabs\nset expandtab               \" Convert tabs to spaces\nsyntax on                   \" Syntax highlighting\nfiletype plugin indent on   \" Per-filetype goodies<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">7.2 Plugin managers<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Manager<\/th><th>Why I like it<\/th><\/tr><\/thead><tbody><tr><td><strong>vim-plug<\/strong><\/td><td>Dead-simple <code>Plug 'author\/repo'<\/code>; asynchronous installs<\/td><\/tr><tr><td><strong>packer.nvim<\/strong><\/td><td>Lua-first; perfect for Neovim users<\/td><\/tr><tr><td><strong>Pathogen<\/strong><\/td><td>Old reliable\u2014drop plugins into <code>~\/.vim\/bundle<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Example <strong>vim-plug<\/strong> block:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>call plug#begin('~\/.vim\/plugged')\nPlug 'junegunn\/fzf',          { 'do': { -&gt; fzf#install() } }\nPlug 'tpope\/vim-fugitive'      \" Best Git wrapper\nPlug 'preservim\/nerdtree'      \" File explorer\nPlug 'neoclide\/coc.nvim', { 'branch': 'release' }  \" LSP &amp; IntelliSense\nPlug 'junegunn\/goyo.vim'       \" Distraction-free writing\ncall plug#end()<\/code><\/pre>\n\n\n\n<p>Run <code>:PlugInstall<\/code>, grab coffee, and voil\u00e0\u2014your 1991 editor now sports a 2025 tux.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">8. Neovim or classic Vim?<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Neovim<\/strong> (v0.10 + as of 2025) adds built-in LSP, Lua scripting, and async jobs\u2014handy for modern language tooling.<\/li>\n\n\n\n<li><strong>Classic Vim<\/strong> (9.x) is rock-solid and everywhere, even in minimal Docker images.<\/li>\n<\/ul>\n\n\n\n<p>I keep <strong>Neovim locally<\/strong> for rich features and <strong>stock Vim remotely<\/strong> on servers. Config reuse is painless: Neovim reads <code>~\/.vimrc<\/code> and <code>~\/.vim<\/code> by default.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">9. Learning resources that actually stuck<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Resource<\/th><th>Why it works<\/th><\/tr><\/thead><tbody><tr><td><code>vimtutor<\/code> (built-in)<\/td><td>30-minute hands-on tour\u2014repeat weekly for a month<\/td><\/tr><tr><td><strong>Vim Adventures<\/strong> (web game)<\/td><td>Gamified <em>hjkl<\/em> practice<\/td><\/tr><tr><td><code>:help<\/code><\/td><td><em>The<\/em> definitive reference (<code>:help topic<\/code>)<\/td><\/tr><tr><td>Drew Neil\u2019s <em>Practical Vim<\/em><\/td><td>Bite-sized tips that level you up linearly<\/td><\/tr><tr><td>YouTube: <em>ThePrimeagen<\/em>, <em>TJ DeVries<\/em><\/td><td>Real-world configs, humorous rants<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">10. Beyond basics: five skills that turned me pro<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Text objects<\/strong> \u2014 <code>ci\"<\/code> (<em>change inside quotes<\/em>), <code>dap<\/code> (<em>delete around paragraph<\/em>).<\/li>\n\n\n\n<li><strong>Macros<\/strong> \u2014 Record <code>q&lt;letter><\/code>, stop <code>q<\/code>, replay <code>@&lt;letter><\/code>.<\/li>\n\n\n\n<li><strong>Registers<\/strong> \u2014 Yank into <code>\"ay<\/code>, paste with <code>\"ap<\/code>; 26 named + clipboard.<\/li>\n\n\n\n<li><strong>Sessions &amp; workspaces<\/strong> \u2014 <code>:mks!<\/code> saves, <code>:so<\/code> restores every buffer.<\/li>\n\n\n\n<li><strong>Terminal integration<\/strong> \u2014 In Neovim, <code>:term<\/code> inside splits feels IDE-grade.<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">11. Common \u201cgotchas\u201d (and quick fixes)<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Issue<\/th><th>Fix<\/th><\/tr><\/thead><tbody><tr><td>\u201cI can\u2019t quit!\u201d<\/td><td><code>:q<\/code> (quit) \u2022 <code>:q!<\/code> (force) \u2022 <code>:wq<\/code> (write + quit)<\/td><\/tr><tr><td>Esc key awkward on MacBooks<\/td><td><code>:imap jk &lt;Esc&gt;<\/code> for a comfy two-letter escape<\/td><\/tr><tr><td>Arrow keys misbehave over SSH<\/td><td>Add <code>set ttimeoutlen=10<\/code> in <code>.vimrc<\/code><\/td><\/tr><tr><td>Slow start-up<\/td><td>Profile: <code>vim --startuptime vim.log<\/code>, lazy-load plugins<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">12. Final thoughts: why stick with Vim in 2025?<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Omnipresent<\/strong> \u2014 From Alpine containers to Raspberry Pi, Vim <em>is already there<\/em>.<\/li>\n\n\n\n<li><strong>Keyboard-centric<\/strong> \u2014 Your wrists (and trackpad) will thank you.<\/li>\n\n\n\n<li><strong>Hackable<\/strong> \u2014 One-liners, Lua scripts, or full-blown plugins\u2014choose your poison.<\/li>\n\n\n\n<li><strong>Community-powered<\/strong> \u2014 30+ years of wisdom means every obscure query is a search away.<\/li>\n\n\n\n<li><strong>Timeless<\/strong> \u2014 Editors come and go, but modal editing still feels futuristic.<\/li>\n<\/ul>\n\n\n\n<p>So that\u2019s the longer, messier, and infinitely more rewarding path I took\u2014from fearing <code>Esc<\/code> to embracing its power. <strong>Give yourself two weeks of <em>real<\/em> usage<\/strong>, resist the pull of your old editor, and those cryptic commands will morph into muscle memory. When that happens, you\u2019ll understand why we Vim-folk won\u2019t shut up about a program that still runs in a terminal window.<\/p>\n\n\n\n<p><em>Happy hacking\u2014may your <code>:q!<\/code> always be intentional!<\/em><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><strong>Vim stands for \u201cVi IMproved\u201d\u2014and if you stick with it, it\u2019ll improve <em>you<\/em> as well.<\/strong> \\:D<\/p>\n<\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>1. How it all started Vim was the first text editor I ever heard of when I began dabbling in Linux, shell scripting, and the mysterious world of the command line. Like many newcomers, I quickly discovered that the idea of Vim felt empowering\u2014yet the reality was intimidating. My editor of choice back then was [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[7],"tags":[19,20],"class_list":["post-487","post","type-post","status-publish","format-standard","hentry","category-computer-science","tag-computer","tag-programming"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/gnikesh.com\/index.php\/wp-json\/wp\/v2\/posts\/487","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/gnikesh.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/gnikesh.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/gnikesh.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/gnikesh.com\/index.php\/wp-json\/wp\/v2\/comments?post=487"}],"version-history":[{"count":6,"href":"https:\/\/gnikesh.com\/index.php\/wp-json\/wp\/v2\/posts\/487\/revisions"}],"predecessor-version":[{"id":918,"href":"https:\/\/gnikesh.com\/index.php\/wp-json\/wp\/v2\/posts\/487\/revisions\/918"}],"wp:attachment":[{"href":"https:\/\/gnikesh.com\/index.php\/wp-json\/wp\/v2\/media?parent=487"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/gnikesh.com\/index.php\/wp-json\/wp\/v2\/categories?post=487"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/gnikesh.com\/index.php\/wp-json\/wp\/v2\/tags?post=487"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}