<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Vimtricks.wiki</title>
    <description>The latest articles on DEV Community by Vimtricks.wiki (@vimtrickswiki).</description>
    <link>https://dev.to/vimtrickswiki</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3788558%2F1f6f3636-6d8d-43ce-baa0-1b73150f20a8.jpg</url>
      <title>DEV Community: Vimtricks.wiki</title>
      <link>https://dev.to/vimtrickswiki</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vimtrickswiki"/>
    <language>en</language>
    <item>
      <title>A safer Vim workflow before bulk text changes</title>
      <dc:creator>Vimtricks.wiki</dc:creator>
      <pubDate>Mon, 30 Mar 2026 12:06:42 +0000</pubDate>
      <link>https://dev.to/vimtrickswiki/a-safer-vim-workflow-before-bulk-text-changes-421l</link>
      <guid>https://dev.to/vimtrickswiki/a-safer-vim-workflow-before-bulk-text-changes-421l</guid>
      <description>&lt;p&gt;Big edits are where I make my most expensive mistakes: replacing too much, landing in the wrong spot, or clobbering the text I meant to paste later. Over time I ended up with a small pre-flight workflow in Vim that reduces that risk a lot. It is not flashy, but it saves me from cleanup commits and awkward "why did this file change?" moments.&lt;/p&gt;

&lt;p&gt;These are the five commands I reach for most when I am about to touch a lot of text.&lt;/p&gt;

&lt;h2&gt;
  
  
  1) Dry-run a substitution count first
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Before I run any large &lt;code&gt;:s&lt;/code&gt; command, I want impact size first. Counting matches gives me a fast confidence check: "am I about to change 3 places or 300?"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;%s&lt;span class="sr"&gt;/TODO/&lt;/span&gt;DONE/gn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;I am renaming a marker in a long file and my regex is slightly fancy. Instead of trusting myself at 11 PM, I run the &lt;code&gt;gn&lt;/code&gt; version first. If Vim reports a suspicious number, I fix the pattern before touching content.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;n&lt;/code&gt; flag reports counts only, so no text is changed. Still, make sure your pattern is exact; a broad regex can look "correct" while counting things you did not intend.&lt;/p&gt;

&lt;h2&gt;
  
  
  2) Keep your last yank safe with the black hole register
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Deleting text right before a paste is a classic way to destroy the value you yanked two seconds ago. The black hole register lets you delete or change text without overwriting the unnamed register.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="c"&gt;"_d{motion}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;I yank a function name, jump elsewhere, then need to delete one word before pasting. Using &lt;code&gt;"_dw&lt;/code&gt; deletes that word but keeps my yanked function name intact, so &lt;code&gt;p&lt;/code&gt; still pastes what I expected.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;This is great when you intentionally do &lt;strong&gt;not&lt;/strong&gt; want deleted text later. If you might need what you removed, use a named register (like &lt;code&gt;"adw&lt;/code&gt;) instead of discarding it.&lt;/p&gt;

&lt;h2&gt;
  
  
  3) Land at the end of a match when searching
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Sometimes you want the match, but you want the cursor at the tail of it for the next edit. Search offsets avoid the extra motion after every jump.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="sr"&gt;/TODO/&lt;/span&gt;&lt;span class="k"&gt;e&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;I am scanning TODO markers and immediately appending context after each one. Landing on the final character of &lt;code&gt;TODO&lt;/code&gt; means I can hit &lt;code&gt;a&lt;/code&gt; right away instead of moving to the end manually each time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;The pattern is still just &lt;code&gt;TODO&lt;/code&gt;; &lt;code&gt;/e&lt;/code&gt; only changes landing position. If you forget that, repeated &lt;code&gt;n&lt;/code&gt;/&lt;code&gt;N&lt;/code&gt; behavior can feel surprising at first.&lt;/p&gt;

&lt;h2&gt;
  
  
  4) Replace only the current line with shell output
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;For quick one-line transformations, this is faster than copying into another tool and pasting back. You can treat Vim as a focused terminal filter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:.!&lt;/span&gt;&lt;span class="k"&gt;tr&lt;/span&gt; &lt;span class="s1"&gt;'[:lower:]'&lt;/span&gt; &lt;span class="s1"&gt;'[:upper:]'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;I have a mixed-case identifier list and need one line normalized to uppercase for a config key. Running &lt;code&gt;:.!tr ...&lt;/code&gt; on that line does it in place and keeps me in flow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;This runs an external shell command, so behavior depends on tools available on your machine. Keep it for trusted commands, and avoid it on untrusted text pipelines.&lt;/p&gt;

&lt;h2&gt;
  
  
  5) Save only changed files across the arglist
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;After multi-file edits, &lt;code&gt;:argdo write&lt;/code&gt; can touch files that were never modified, which creates unnecessary timestamp churn. &lt;code&gt;update&lt;/code&gt; writes only buffers that are actually changed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;argdo&lt;/span&gt; &lt;span class="k"&gt;update&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;I run a refactor across 40 files, but only 11 really changed. &lt;code&gt;:argdo update&lt;/code&gt; saves exactly those 11, so file watchers and git history stay cleaner.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;This works on the current argument list, so scope matters. Check &lt;code&gt;:args&lt;/code&gt; first, or build the list carefully with &lt;code&gt;:argadd&lt;/code&gt; before running batch commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;My default safety loop is simple: estimate first, edit deliberately, then write only what changed. These commands remove friction without adding ceremony, which is exactly what I want during real work.&lt;/p&gt;

&lt;p&gt;If you want more practical Vim tricks, I publish them at &lt;a href="https://vimtricks.wiki" rel="noopener noreferrer"&gt;https://vimtricks.wiki&lt;/a&gt;.&lt;br&gt;
What is your go-to command for making bulk edits safer?&lt;/p&gt;

</description>
      <category>vim</category>
      <category>neovim</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>How I do safer multi-file edits in Vim</title>
      <dc:creator>Vimtricks.wiki</dc:creator>
      <pubDate>Mon, 23 Mar 2026 12:06:55 +0000</pubDate>
      <link>https://dev.to/vimtrickswiki/how-i-do-safer-multi-file-edits-in-vim-229d</link>
      <guid>https://dev.to/vimtrickswiki/how-i-do-safer-multi-file-edits-in-vim-229d</guid>
      <description>&lt;p&gt;Bulk edits are where even experienced Vim users can accidentally create a mess: too-wide matches, noisy jump history, or a replacement that looked right three files ago but is wrong in this one. Over time, I ended up with a short workflow that keeps speed high without giving up control.&lt;/p&gt;

&lt;p&gt;This is the sequence I use when I need to change code across a project but still keep context and sanity.&lt;/p&gt;

&lt;h2&gt;
  
  
  1) Build a literal quickfix list from the current word
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Before changing anything, I want a tight target list. If the first search is sloppy, every step after that becomes cleanup work. &lt;code&gt;:vimgrep&lt;/code&gt; with &lt;code&gt;\V&lt;/code&gt; gives me a literal search and sends matches straight into quickfix so I can inspect what I am about to touch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;vimgrep&lt;/span&gt; &lt;span class="sr"&gt;/\V&amp;lt;C-r&amp;gt;&amp;lt;C-w&amp;gt;/&lt;/span&gt;gj **/*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You are renaming a function like &lt;code&gt;process_order&lt;/code&gt; across a service and want an editable hit list first. Run the command on the symbol, open quickfix with &lt;code&gt;:copen&lt;/code&gt;, and skim entries before applying any change. That 15-second pass catches the obvious false positives early.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;C-r&amp;gt;&amp;lt;C-w&amp;gt;&lt;/code&gt; inserts the current &lt;em&gt;word&lt;/em&gt; under cursor, not arbitrary punctuation-heavy text. If you need broader text insertion, switch approach (for example &lt;code&gt;&amp;lt;C-r&amp;gt;&amp;lt;C-a&amp;gt;&lt;/code&gt; for WORD-style text) and still keep the literal &lt;code&gt;\V&lt;/code&gt; behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  2) Apply quickfix-wide substitution without polluting state
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Once quickfix is curated, I want batch changes that do not wreck my navigation tools. This command applies the replace, writes only changed files, and avoids clobbering jump and search state while it runs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;cdo&lt;/span&gt; &lt;span class="k"&gt;keepjumps&lt;/span&gt; &lt;span class="k"&gt;keeppatterns&lt;/span&gt; %s&lt;span class="sr"&gt;/\&amp;lt;OldSymbol\&amp;gt;/&lt;/span&gt;NewSymbol/ge &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;update&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You searched for a deprecated API name and got 60 entries in 18 files. After confirming the list, run this once to replace exact word matches and persist edits. Then use quickfix navigation again to spot-check updated call sites.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;cdo&lt;/code&gt; executes per quickfix entry, so this can repeat work inside the same file. If your operation should run once per file instead of once per match, use &lt;code&gt;:cfdo&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  3) Use selective replacement when global replace is too risky
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Not every rename is safe to automate globally. Some matches need changing, others must stay. The &lt;code&gt;*&lt;/code&gt; + &lt;code&gt;cgn&lt;/code&gt; flow gives me speed with per-match judgment, and &lt;code&gt;.&lt;/code&gt; keeps it fast after the first replacement.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;*
cgnnew_name&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;Esc&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You are changing &lt;code&gt;count&lt;/code&gt; to &lt;code&gt;item_count&lt;/code&gt;, but &lt;code&gt;count_total&lt;/code&gt; and &lt;code&gt;discount&lt;/code&gt; should stay untouched. Start on the first exact &lt;code&gt;count&lt;/code&gt;, run the sequence, and press &lt;code&gt;n&lt;/code&gt; to skip contexts you do not want before using &lt;code&gt;.&lt;/code&gt; again.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;This flow depends on the active search pattern. If your last search is stale, hit &lt;code&gt;*&lt;/code&gt; again on the exact token you intend to change before continuing.&lt;/p&gt;

&lt;h2&gt;
  
  
  4) Walk older edits with context restored
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;After a multi-file pass, review speed matters. Jumping by changelist alone is useful, but hidden folds and poor viewport placement slow verification. Chaining these motions gives me a dependable “show me the last real edit here” move.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;g&lt;/span&gt;;zvzz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You made several edits in a long file and want a final sweep before commit. Repeating this sequence walks backward through changes, opens folds when needed, and centers each location so you can validate intent quickly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;g;&lt;/code&gt; walks changelist entries, which are not a semantic diff. For project-wide review, I still pair this with quickfix, &lt;code&gt;:changes&lt;/code&gt;, or git diff depending on scope.&lt;/p&gt;

&lt;h2&gt;
  
  
  5) Add a temporary line prefix across a matched set
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;During debugging, I often need to disable or mark lines quickly without visual-block gymnastics. &lt;code&gt;:global&lt;/code&gt; with &lt;code&gt;:normal&lt;/code&gt; scales that action from one line to many using a clear match rule.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;g&lt;/span&gt;&lt;span class="sr"&gt;/^/&lt;/span&gt;normal I&lt;span class="sr"&gt;//&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You want to comment a copied block during an experiment, run tests, then revert cleanly afterward. One command prepends &lt;code&gt;//&lt;/code&gt; at the first non-blank position across matching lines, keeping indentation readable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;As written, this targets every line matched by &lt;code&gt;^&lt;/code&gt;, including empty lines. Narrow the pattern when needed (for example &lt;code&gt;:g/^\s*\k/normal I//&lt;/code&gt;) to avoid touching blank separators.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;This workflow is simple on purpose: build a precise list, batch safely, switch to selective edits where needed, review quickly, and use repeatable linewise transforms for temporary changes. The commands are small, but together they reduce the two expensive problems in refactors: accidental changes and slow verification.&lt;/p&gt;

&lt;p&gt;If you want more practical Vim tricks, I publish them at &lt;a href="https://vimtricks.wiki" rel="noopener noreferrer"&gt;https://vimtricks.wiki&lt;/a&gt;.&lt;br&gt;
What part of multi-file editing in Vim still feels fragile in your workflow?&lt;/p&gt;

</description>
      <category>vim</category>
      <category>neovim</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>How I clean many files in Vim without losing context</title>
      <dc:creator>Vimtricks.wiki</dc:creator>
      <pubDate>Mon, 16 Mar 2026 12:07:49 +0000</pubDate>
      <link>https://dev.to/vimtrickswiki/how-i-clean-many-files-in-vim-without-losing-context-4dl7</link>
      <guid>https://dev.to/vimtrickswiki/how-i-clean-many-files-in-vim-without-losing-context-4dl7</guid>
      <description>&lt;p&gt;Batch edits usually fail in the boring parts: navigation state, whitespace noise, and output I forget to capture before moving on. When I have to sweep through multiple files, I want a workflow that is fast but still reversible when I spot a mistake.&lt;/p&gt;

&lt;p&gt;These are five built-in commands I use together for that exact job.&lt;/p&gt;

&lt;h2&gt;
  
  
  1) Remove blank lines before doing anything else
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Blank and whitespace-only lines add visual noise, make diffs harder to review, and often hide real structure problems. I usually clean them first so every later change is easier to inspect.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;g&lt;/span&gt;&lt;span class="sr"&gt;/^\s*$/&lt;/span&gt;&lt;span class="k"&gt;d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;I paste a generated config snippet into a repo and it comes with random empty lines between sections. Running this once gives me a compact file before I start renaming keys or moving blocks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;This is destructive for intentional spacing (like markdown readability blocks). If spacing is meaningful, run it on a visual range or specific section instead of the whole buffer.&lt;/p&gt;

&lt;h2&gt;
  
  
  2) Save-and-advance inside a macro-driven file pass
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;When processing files one by one, context switching is what burns time. &lt;code&gt;:wn&lt;/code&gt; lets a macro finish each file, write changes, and jump to the next entry in the argument list in one step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;wn&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;I load target files with &lt;code&gt;:args **/*.md&lt;/code&gt;, record a macro that does a focused cleanup, and end it with &lt;code&gt;:wn&lt;/code&gt;. Then &lt;code&gt;99@q&lt;/code&gt; walks forward until there are no files left.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;:wn&lt;/code&gt; expects an argument list. If you forgot to set &lt;code&gt;:args&lt;/code&gt; (or reached the last file), Vim will stop with an error. I usually test the macro on two files first.&lt;/p&gt;

&lt;h2&gt;
  
  
  3) Reindent the entire buffer without polluting jumps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Whole-file reindent is common after edits, but it can trash your jump history and make review navigation annoying. &lt;code&gt;:keepjumps&lt;/code&gt; preserves your jump/changelist context while still applying the indent pass.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;keepjumps&lt;/span&gt; normal&lt;span class="p"&gt;!&lt;/span&gt; gg&lt;span class="p"&gt;=&lt;/span&gt;G
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;After replacing tabs/spaces in a script, I want one consistent indent pass. This command reindents from top to bottom, and &lt;code&gt;Ctrl-o&lt;/code&gt; still takes me through my real investigation path instead of formatting jumps.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;normal!&lt;/code&gt; intentionally ignores mappings. That is usually what you want for deterministic automation, but call it out in team docs if teammates rely on custom mapped behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  4) Capture command output into a register for reuse
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Debug output often flashes by and disappears from working memory five seconds later. Redirecting &lt;code&gt;:messages&lt;/code&gt; into a register turns transient output into editable text you can paste, diff, or search.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;redir&lt;/span&gt; @&lt;span class="k"&gt;a&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;messages&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;redir&lt;/span&gt; END
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;I run a batch command, get a few warnings, then need those exact lines in a scratch buffer while fixing issues. After redirecting, I paste with &lt;code&gt;"ap&lt;/code&gt; and work from concrete evidence instead of memory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;Only one redirection can be active at a time. Always end with &lt;code&gt;redir END&lt;/code&gt;; otherwise later command output may keep going to the wrong place.&lt;/p&gt;

&lt;h2&gt;
  
  
  5) Yank to a searched target without entering Visual mode
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Visual selection is fine, but for repetitive structural edits I prefer operator + motion. &lt;code&gt;y/{pattern}&amp;lt;CR&amp;gt;&lt;/code&gt; is quick, precise, and easy to replay.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;y&lt;/span&gt;/&lt;span class="p"&gt;{&lt;/span&gt;pattern&lt;span class="p"&gt;}&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;I need to copy from my current cursor position to the next &lt;code&gt;END_BLOCK&lt;/code&gt; marker repeatedly in a large template file. Using search as a motion keeps my hands in normal flow and works nicely with counts and repeats.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;Search motions are exclusive by default, so the matched text is not included in the yank. If you need the match too, adjust the pattern or yank one extra motion after confirming the boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;This set works well as a practical sequence: remove junk lines, run a repeatable per-file macro pass, reindent safely, capture diagnostics, and copy targeted ranges without modal detours.&lt;/p&gt;

&lt;p&gt;If you want more practical Vim tricks, I publish them at &lt;a href="https://vimtricks.wiki" rel="noopener noreferrer"&gt;https://vimtricks.wiki&lt;/a&gt;.&lt;br&gt;
What part of your current multi-file editing workflow still feels fragile?&lt;/p&gt;

</description>
      <category>vim</category>
      <category>neovim</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>A Vim workflow for safer bulk text edits</title>
      <dc:creator>Vimtricks.wiki</dc:creator>
      <pubDate>Sun, 15 Mar 2026 19:23:38 +0000</pubDate>
      <link>https://dev.to/vimtrickswiki/a-vim-workflow-for-safer-bulk-text-edits-4i4</link>
      <guid>https://dev.to/vimtrickswiki/a-vim-workflow-for-safer-bulk-text-edits-4i4</guid>
      <description>&lt;p&gt;Most refactor mistakes I make are not syntax errors—they’re scope errors. I change too much, target the wrong region, or apply the right command in the wrong mode. Over time I ended up with a small set of Vim commands that make bulk edits faster &lt;em&gt;and&lt;/em&gt; less risky.&lt;/p&gt;

&lt;p&gt;Here are five that I keep reaching for when I need to change many lines without turning my buffer into archaeology.&lt;/p&gt;

&lt;h2&gt;
  
  
  1) Run a controlled multi-file replace with the argument list
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;When you need a rename across many files, a one-liner can save minutes, but only if it is scoped correctly. Using the argument list keeps the target set explicit, and &lt;code&gt;:update&lt;/code&gt; writes only changed files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;args&lt;/span&gt; **&lt;span class="sr"&gt;/*.py | argdo %s/&lt;/span&gt;\&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;old_name\&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="sr"&gt;/new_name/&lt;/span&gt;ge &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;update&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;I’m renaming a helper used across a Python package. I first narrow the scope to &lt;code&gt;**/*.py&lt;/code&gt;, run the substitution with word boundaries, and let &lt;code&gt;:update&lt;/code&gt; save only files that actually changed. That avoids touching timestamps in unrelated files.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;Double-check the file glob before executing. &lt;code&gt;:args&lt;/code&gt; defines the blast radius. Also, use the &lt;code&gt;e&lt;/code&gt; flag in &lt;code&gt;%s///ge&lt;/code&gt; so files without matches do not interrupt the run.&lt;/p&gt;

&lt;h2&gt;
  
  
  2) Force a linewise motion to behave characterwise
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Operators like &lt;code&gt;d&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt;, and &lt;code&gt;y&lt;/code&gt; inherit the motion type. Sometimes that is too broad. The operator-pending &lt;code&gt;v&lt;/code&gt; modifier gives you precise control when a normal linewise motion would delete more than you intended.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;dvj
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You’re on a long line and want to delete down one screen line without wiping full lines. &lt;code&gt;dj&lt;/code&gt; is linewise and aggressive. &lt;code&gt;dvj&lt;/code&gt; forces characterwise behavior, so the delete ends at the corresponding position on the next line.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;With forced characterwise behavior, linewise motions become exclusive. Test once on a disposable line if exact endpoint behavior matters for a macro.&lt;/p&gt;

&lt;h2&gt;
  
  
  3) Use expression replacement for arithmetic substitutions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Simple text replacement breaks down when each match needs computed output. Vim’s &lt;code&gt;\=&lt;/code&gt; replacement lets you evaluate an expression per match, which is perfect for version bumps and numeric rewrites.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;%s&lt;span class="sr"&gt;/\(\d\+\)/&lt;/span&gt;\&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;submatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;/&lt;span class="k"&gt;g&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You have a config file with repeated numeric thresholds and need to bump all of them by one. Instead of editing line by line or exporting to a script, one substitution updates every matched number in place.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;This matches any digit sequence, so scope it first if needed (range, pattern, or visual selection). Otherwise you may increment numbers you did not intend to touch.&lt;/p&gt;

&lt;h2&gt;
  
  
  4) Change substitute delimiters when paths make slash-heavy patterns unreadable
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Escaping every &lt;code&gt;/&lt;/code&gt; in a path replacement is error-prone and hard to review. Switching delimiters makes the command easier to read and reduces typo risk.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;s#&lt;span class="sr"&gt;/old/&lt;/span&gt;&lt;span class="nb"&gt;path&lt;/span&gt;#&lt;span class="sr"&gt;/new/&lt;/span&gt;&lt;span class="nb"&gt;path&lt;/span&gt;#&lt;span class="k"&gt;g&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;I’m updating include paths in a config line from &lt;code&gt;/usr/local/...&lt;/code&gt; to &lt;code&gt;/opt/...&lt;/code&gt;. With &lt;code&gt;#&lt;/code&gt; as delimiter, I can see the pattern clearly and avoid backslash noise.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;Pick a delimiter that does not appear in your pattern or replacement. Vim supports many non-alphanumeric delimiters, but consistency in one command is required.&lt;/p&gt;

&lt;h2&gt;
  
  
  5) Skip directly to the Nth next search match
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Repeating &lt;code&gt;n&lt;/code&gt; ten times is slow and easy to lose track of. Count prefixes turn search navigation into a precise jump.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="k"&gt;n&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;After searching for a recurring token in a large log, I often want the third or fourth next occurrence, not the immediate one. Prefixing &lt;code&gt;n&lt;/code&gt; with a count gets me there in one keystroke.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;n&lt;/code&gt; repeats the &lt;em&gt;last&lt;/em&gt; &lt;code&gt;/&lt;/code&gt; or &lt;code&gt;?&lt;/code&gt; search pattern and direction. Make sure your current search is the one you intend before using larger counts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;These are not flashy tricks, but they are reliable pressure reducers when edits get broad. I use them to keep scope visible, lower typo risk, and avoid mode surprises while moving fast.&lt;/p&gt;

&lt;p&gt;If you want more practical Vim tricks, I publish them at &lt;a href="https://vimtricks.wiki" rel="noopener noreferrer"&gt;https://vimtricks.wiki&lt;/a&gt;.&lt;br&gt;
What’s your current “high-risk” edit that you still do manually?&lt;/p&gt;

</description>
      <category>vim</category>
      <category>neovim</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>Vim commands I reach for when simple edits get complex</title>
      <dc:creator>Vimtricks.wiki</dc:creator>
      <pubDate>Fri, 13 Mar 2026 12:22:25 +0000</pubDate>
      <link>https://dev.to/vimtrickswiki/vim-commands-i-reach-for-when-simple-edits-get-complex-16ic</link>
      <guid>https://dev.to/vimtrickswiki/vim-commands-i-reach-for-when-simple-edits-get-complex-16ic</guid>
      <description>&lt;p&gt;There's a point in most editing sessions where a simple substitution or a quick &lt;code&gt;dd&lt;/code&gt; stops being enough. You're mid-refactor, your search history is getting polluted, your macro keeps running past where it should, or you just want to get back to the line you were editing five minutes ago. These are the commands I keep reaching for in those moments.&lt;/p&gt;

&lt;h2&gt;
  
  
  1) Matching only part of a pattern with &lt;code&gt;\zs&lt;/code&gt; and &lt;code&gt;\ze&lt;/code&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;\zs&lt;/code&gt; and &lt;code&gt;\ze&lt;/code&gt; atoms let you pinpoint &lt;em&gt;which part&lt;/em&gt; of a match gets highlighted or replaced — without writing lookaheads or making the regex more complex. The surrounding context still needs to match, but only the portion between &lt;code&gt;\zs&lt;/code&gt; and &lt;code&gt;\ze&lt;/code&gt; counts as the actual match.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="c"&gt;" Match the function name only, not the 'function ' keyword before it&lt;/span&gt;
/\&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;\s\&lt;span class="p"&gt;+&lt;/span&gt;\&lt;span class="p"&gt;)&lt;/span&gt;\zs\&lt;span class="k"&gt;w&lt;/span&gt;\&lt;span class="p"&gt;+&lt;/span&gt;

&lt;span class="c"&gt;" Substitute: rename only the value after 'color: '&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;%s&lt;span class="sr"&gt;/color: \zsred/&lt;/span&gt;blue/&lt;span class="k"&gt;g&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You're grepping through a codebase for function definitions and want to rename all functions that follow the pattern &lt;code&gt;process_*&lt;/code&gt; — but only the name part, not the keyword. Without &lt;code&gt;\zs&lt;/code&gt;, you'd need a capture group and a &lt;code&gt;\1&lt;/code&gt; backreference. With it, you write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;%s&lt;span class="sr"&gt;/\(function\s\+\)\zs\w\+/&lt;/span&gt;handle_data/&lt;span class="k"&gt;g&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only the function name gets replaced. &lt;code&gt;function&lt;/code&gt; stays intact.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;\zs&lt;/code&gt; and &lt;code&gt;\ze&lt;/code&gt; are Vim-specific — they don't exist in POSIX regex or most other languages' regex engines. If you export a pattern for use in a script or shell command, you'll need to convert it to a capture group approach.&lt;/p&gt;




&lt;h2&gt;
  
  
  2) Substituting without losing your current search with &lt;code&gt;:keeppattern&lt;/code&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Every time you run &lt;code&gt;:%s/foo/bar/g&lt;/code&gt;, Vim quietly replaces your active search pattern with &lt;code&gt;foo&lt;/code&gt;. That kills your highlighted matches and sends &lt;code&gt;n&lt;/code&gt;/&lt;code&gt;N&lt;/code&gt; chasing the substitution target instead of what you were originally searching for. &lt;code&gt;:keeppattern&lt;/code&gt; is a modifier that prevents this side effect entirely.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;keeppattern %s&lt;span class="sr"&gt;/old/&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;/&lt;span class="k"&gt;g&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You're stepping through a file looking at all &lt;code&gt;TODO&lt;/code&gt; comments with &lt;code&gt;/TODO&lt;/code&gt; and &lt;code&gt;n&lt;/code&gt;. Mid-review, you realize a variable name needs a quick rename. Running a bare &lt;code&gt;:%s/myVar/myVariable/g&lt;/code&gt; nukes your search context. Prepend &lt;code&gt;:keeppattern&lt;/code&gt; and &lt;code&gt;n&lt;/code&gt; still jumps to the next &lt;code&gt;TODO&lt;/code&gt; after the substitute finishes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;keeppattern %s&lt;span class="sr"&gt;/myVar/&lt;/span&gt;myVariable/&lt;span class="k"&gt;g&lt;/span&gt;
&lt;span class="c"&gt;" n still navigates to the next TODO — untouched&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;:keeppattern&lt;/code&gt; works on any Ex command that normally updates &lt;code&gt;@/&lt;/code&gt;, not just &lt;code&gt;:s&lt;/code&gt;. But it only preserves the &lt;em&gt;search register&lt;/em&gt; — if your substitution also changes the cursor position, that still happens. Worth knowing if you have mappings that depend on cursor state after a substitute.&lt;/p&gt;




&lt;h2&gt;
  
  
  3) Making a macro stop itself automatically with a recursive call
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;If you've ever guessed &lt;code&gt;99@q&lt;/code&gt; hoping a macro stops at the right line, this is the alternative. A recursive macro calls itself at the end of its recording. When any motion inside it fails — usually &lt;code&gt;j&lt;/code&gt; hitting the last line — Vim aborts the macro chain. No guessing required.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="c"&gt;" Step 1: clear register q so @q does nothing during recording&lt;/span&gt;
qqq

&lt;span class="c"&gt;" Step 2: record the macro with a self-call at the end&lt;/span&gt;
qqA;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;Esc&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;j&lt;/span&gt;@qq

&lt;span class="c"&gt;" Step 3: run it&lt;/span&gt;
@&lt;span class="k"&gt;q&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You have a 300-line file of JavaScript variable declarations and need a semicolon appended to every line. You don't want to count the lines and you don't want to use &lt;code&gt;:%normal A;&lt;/code&gt; (maybe the formatting logic is more complex than that, and you want the macro). Record once, run once with &lt;code&gt;@q&lt;/code&gt;, and it processes every line and stops cleanly at the end of file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;qqq&lt;/code&gt; clear step is non-negotiable. If register &lt;code&gt;q&lt;/code&gt; already contains something, &lt;code&gt;@q&lt;/code&gt; during recording will execute that old macro mid-recording, and the result is unpredictable. Also make sure &lt;code&gt;wrapscan&lt;/code&gt; is off (&lt;code&gt;:set nowrapscan&lt;/code&gt;) if your macro includes a search — otherwise the macro wraps back to the top and runs forever.&lt;/p&gt;




&lt;h2&gt;
  
  
  4) Inserting computed values inline with the expression register
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;C-r&amp;gt;=&lt;/code&gt; opens an expression prompt while in Insert mode. Type any Vimscript expression, press &lt;code&gt;&amp;lt;CR&amp;gt;&lt;/code&gt;, and the result gets inserted at the cursor. It's a small feature with a surprising surface area: inline math, timestamps, current line numbers, shell output — all available without leaving Insert mode.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="c"&gt;" Insert today's date&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;r&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="nb"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'%Y-%m-%d'&lt;/span&gt;&lt;span class="p"&gt;)&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;" Insert the current line number&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;r&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="nb"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;)&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;" Quick math&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;r&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="m"&gt;1024&lt;/span&gt; * &lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You're writing a config file and need to insert a timestamp for a &lt;code&gt;created_at&lt;/code&gt; field. You could &lt;code&gt;:r !date&lt;/code&gt;, but that inserts on a new line. With &lt;code&gt;&amp;lt;C-r&amp;gt;=&lt;/code&gt;, you stay in Insert mode and drop the result exactly where the cursor is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;created_at&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;r&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="nb"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'%Y-%m-%dT%H:%M:%S'&lt;/span&gt;&lt;span class="p"&gt;)&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One keystroke sequence, no mode switching, no cleanup.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;system()&lt;/code&gt; works inside expressions, but it inserts a trailing newline. Use &lt;code&gt;system('date')[:-2]&lt;/code&gt; or &lt;code&gt;trim(system('date'))&lt;/code&gt; to strip it. Also, &lt;code&gt;&amp;lt;C-r&amp;gt;=&lt;/code&gt; evaluates one expression — you can't run multi-statement Vimscript here. For that you'd use &lt;code&gt;:call&lt;/code&gt; or a function.&lt;/p&gt;




&lt;h2&gt;
  
  
  5) Jumping back through your own edit history with &lt;code&gt;g;&lt;/code&gt; and &lt;code&gt;g,&lt;/code&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Vim maintains a &lt;em&gt;changelist&lt;/em&gt; for every buffer — a record of every position where text was modified. &lt;code&gt;g;&lt;/code&gt; jumps backward to the previous change location; &lt;code&gt;g,&lt;/code&gt; jumps forward. This is distinct from the jump list (&lt;code&gt;&amp;lt;C-o&amp;gt;&lt;/code&gt;/&lt;code&gt;&amp;lt;C-i&amp;gt;&lt;/code&gt;), which tracks cursor movement. The changelist tracks only actual edits.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;g&lt;/span&gt;;    " &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; older &lt;span class="k"&gt;change&lt;/span&gt;
&lt;span class="k"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    " &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; newer &lt;span class="k"&gt;change&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;changes&lt;/span&gt;    " see the full &lt;span class="k"&gt;list&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You edited a function at line 50, scrolled to line 300 to look at something, then jumped around reading context. Now you want to get back to where you were working. &lt;code&gt;&amp;lt;C-o&amp;gt;&lt;/code&gt; takes you through every jump including all the reading you just did. &lt;code&gt;g;&lt;/code&gt; takes you directly to line 50 — your last edit — in one or two keystrokes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;g&lt;/span&gt;;     " → &lt;span class="nb"&gt;line&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;where you &lt;span class="k"&gt;last&lt;/span&gt; edited&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;g&lt;/span&gt;;     " → the &lt;span class="k"&gt;edit&lt;/span&gt; before that&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; any
&lt;span class="k"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     " → back &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="nb"&gt;line&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;The changelist is per-buffer and lives only as long as the buffer is open — unless you have &lt;code&gt;:set undofile&lt;/code&gt; configured, in which case it's rebuilt from persistent undo history on next open. If you close a buffer and reopen without &lt;code&gt;undofile&lt;/code&gt;, the changelist resets.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;These five commands don't get much screen time in tutorials, but they show up constantly in real editing sessions. &lt;code&gt;\zs&lt;/code&gt;/&lt;code&gt;\ze&lt;/code&gt; handle targeted substitutions without complex capture groups. &lt;code&gt;:keeppattern&lt;/code&gt; keeps your search context intact while you do unrelated replacements. Recursive macros let you automate repetitive edits across a whole file without counting lines. The expression register turns Insert mode into a small calculator and templating engine. And &lt;code&gt;g;&lt;/code&gt;/&lt;code&gt;g,&lt;/code&gt; give you a direct path back to where you were actually working.&lt;/p&gt;

&lt;p&gt;If you want more practical Vim tricks like these, I publish them at &lt;a href="https://vimtricks.wiki" rel="noopener noreferrer"&gt;https://vimtricks.wiki&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What Vim action still feels slower than it should in your workflow?&lt;/p&gt;

</description>
      <category>vim</category>
      <category>neovim</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>Vim tricks I use when I need operations to land exactly right</title>
      <dc:creator>Vimtricks.wiki</dc:creator>
      <pubDate>Fri, 13 Mar 2026 12:21:48 +0000</pubDate>
      <link>https://dev.to/vimtrickswiki/vim-tricks-i-use-when-i-need-operations-to-land-exactly-right-7ee</link>
      <guid>https://dev.to/vimtrickswiki/vim-tricks-i-use-when-i-need-operations-to-land-exactly-right-7ee</guid>
      <description>&lt;p&gt;There's a category of Vim friction that isn't about speed — it's about landing in the right place. You recorded a macro that's almost right but has one wrong keystroke. You want to delete from here to a line you marked ten minutes ago. You're trying to insert newlines in a substitution and getting garbage characters instead. These aren't beginner problems, but they trip up experienced users too because the solutions aren't obvious.&lt;/p&gt;

&lt;p&gt;Here are five tricks that consistently reduce that friction.&lt;/p&gt;

&lt;h2&gt;
  
  
  1) Edit a macro as plain text instead of re-recording it
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Re-recording a long macro because of one wrong keystroke is painful. There's a faster way: paste the macro's keystrokes as editable text, fix the mistake, and yank it back.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="c"&gt;"qp         " paste register q as text onto a new line&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;edits&lt;span class="p"&gt;}&lt;/span&gt;     " &lt;span class="k"&gt;fix&lt;/span&gt; what's wrong using normal editing commands
&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="s2"&gt;"qy$       "&lt;/span&gt; &lt;span class="k"&gt;yank&lt;/span&gt; the corrected &lt;span class="nb"&gt;line&lt;/span&gt; back into register &lt;span class="k"&gt;q&lt;/span&gt;
dd          " &lt;span class="k"&gt;delete&lt;/span&gt; the helper &lt;span class="nb"&gt;line&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You recorded a macro in &lt;code&gt;q&lt;/code&gt; that processes log lines, but it uses &lt;code&gt;w&lt;/code&gt; where it should use &lt;code&gt;W&lt;/code&gt;. Type &lt;code&gt;"qp&lt;/code&gt; to paste the raw keystrokes on a new line. The sequence appears as readable (and editable) text, including control characters rendered as &lt;code&gt;^[&lt;/code&gt; for Escape and &lt;code&gt;^M&lt;/code&gt; for Enter. Fix the &lt;code&gt;w&lt;/code&gt;, then &lt;code&gt;0"qy$&lt;/code&gt; to yank the whole corrected line back into register &lt;code&gt;q&lt;/code&gt;, then &lt;code&gt;dd&lt;/code&gt; to clean up. Your macro is now corrected without re-recording a single keystroke.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;Non-printable keys appear as control characters. To insert them while editing, use &lt;code&gt;&amp;lt;C-v&amp;gt;&lt;/code&gt; followed by the key — &lt;code&gt;&amp;lt;C-v&amp;gt;&amp;lt;Esc&amp;gt;&lt;/code&gt; inserts a literal escape byte. Typing a raw caret and bracket (&lt;code&gt;^[&lt;/code&gt;) won't produce the right byte sequence and will break your macro in subtle ways.&lt;/p&gt;




&lt;h2&gt;
  
  
  2) Use a named mark as a motion target for operators
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Named marks aren't just jump destinations — any operator (&lt;code&gt;d&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;gq&lt;/code&gt;) accepts a mark as its motion target, giving you precise linewise ranges without entering visual mode.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;ma&lt;/span&gt;          " &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="k"&gt;mark&lt;/span&gt; &lt;span class="s1"&gt;'a'&lt;/span&gt; &lt;span class="k"&gt;on&lt;/span&gt; the current &lt;span class="nb"&gt;line&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;navigate&lt;span class="p"&gt;}&lt;/span&gt;  " &lt;span class="k"&gt;move&lt;/span&gt; somewhere &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; the &lt;span class="k"&gt;file&lt;/span&gt;
&lt;span class="k"&gt;d&lt;/span&gt;'&lt;span class="k"&gt;a&lt;/span&gt;         " &lt;span class="k"&gt;delete&lt;/span&gt; from current &lt;span class="nb"&gt;line&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; the &lt;span class="nb"&gt;line&lt;/span&gt; containing &lt;span class="k"&gt;mark&lt;/span&gt; &lt;span class="k"&gt;a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You're cleaning up a config file. You set mark &lt;code&gt;a&lt;/code&gt; at the start of a section you want to remove, scroll down to where it ends, and type &lt;code&gt;d'a&lt;/code&gt;. The entire range — inclusive of both lines — is gone in one motion. The same trick works for yanking (&lt;code&gt;y'a&lt;/code&gt;), re-indenting (&lt;code&gt;&amp;gt;'a&lt;/code&gt;), or reformatting (&lt;code&gt;gq'a&lt;/code&gt;). No visual mode, no line counting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;The apostrophe form &lt;code&gt;'a&lt;/code&gt; is &lt;strong&gt;linewise&lt;/strong&gt; — it operates on complete lines from the current line to mark &lt;code&gt;a&lt;/code&gt;'s line. If you need &lt;strong&gt;characterwise&lt;/strong&gt; precision, use backtick: &lt;code&gt;d`a&lt;/code&gt; deletes from the exact cursor position to the exact character where the mark was set. The two behave differently and it's easy to grab the wrong one, especially when the mark falls mid-line.&lt;/p&gt;




&lt;h2&gt;
  
  
  3) Anchor the second address of a range to the first match, not the cursor
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;In Vim range notation, a comma between two addresses makes the second address relative to the &lt;strong&gt;cursor&lt;/strong&gt;. Replace it with a semicolon and the second address becomes relative to whatever line the first address matched — which is almost always what you actually want in scripts and macros.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="sr"&gt;/error/&lt;/span&gt;;&lt;span class="p"&gt;+&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="k"&gt;yank&lt;/span&gt; &lt;span class="k"&gt;a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You want to yank the next &lt;code&gt;error&lt;/code&gt; log line plus the two lines after it, regardless of where your cursor is sitting. With &lt;code&gt;/error/,+2 yank a&lt;/code&gt;, the &lt;code&gt;+2&lt;/code&gt; is relative to the cursor — if you're on line 1 and the error is on line 50, you capture lines 1–52 instead of 50–52. With &lt;code&gt;/error/;+2 yank a&lt;/code&gt;, the &lt;code&gt;+2&lt;/code&gt; is anchored to the match at line 50, so you always get the right three-line block.&lt;/p&gt;

&lt;p&gt;The semicolon form chains cleanly too: &lt;code&gt;:/start/;/middle/;/end/ delete&lt;/code&gt; — each search anchors to the previous result rather than drifting back to the cursor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;This distinction is easy to overlook in interactive use, but it matters a lot inside macros where cursor position is unpredictable. If range-based operations occasionally capture the wrong lines, a misused &lt;code&gt;,&lt;/code&gt; vs &lt;code&gt;;&lt;/code&gt; is often the quiet culprit.&lt;/p&gt;




&lt;h2&gt;
  
  
  4) Use &lt;code&gt;\r&lt;/code&gt;, not &lt;code&gt;\n&lt;/code&gt;, to insert a newline in a substitution replacement
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;In a search pattern, &lt;code&gt;\n&lt;/code&gt; correctly matches a newline. But in the &lt;strong&gt;replacement&lt;/strong&gt; string, &lt;code&gt;\n&lt;/code&gt; inserts a NUL byte (displayed as &lt;code&gt;^@&lt;/code&gt;) — not a line break. To insert an actual newline in the replacement, use &lt;code&gt;\r&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;%s&lt;span class="sr"&gt;/,/&lt;/span&gt;\&lt;span class="k"&gt;r&lt;/span&gt;/&lt;span class="k"&gt;g&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You have a comma-separated list on one line and want each item on its own line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apple,banana,cherry
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running &lt;code&gt;:%s/,/\n/g&lt;/code&gt; produces garbage characters. Running &lt;code&gt;:%s/,/\r/g&lt;/code&gt; correctly splits it into three lines. Same deal when adding a blank line before every function declaration: &lt;code&gt;:%s/^function/\r&amp;amp;/&lt;/code&gt; works; &lt;code&gt;:%s/^function/\n&amp;amp;/&lt;/code&gt; silently inserts NULs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;The asymmetry is consistent: &lt;code&gt;\n&lt;/code&gt; in the search side matches a newline; &lt;code&gt;\r&lt;/code&gt; in the replacement side inserts one. This is intentional in Vim's design, but it trips up nearly everyone at least once. In some Neovim builds &lt;code&gt;\n&lt;/code&gt; in the replacement may happen to work, but &lt;code&gt;\r&lt;/code&gt; is the portable and reliable choice across all Vim and Neovim versions.&lt;/p&gt;




&lt;h2&gt;
  
  
  5) Reuse the last substitution's replacement text with &lt;code&gt;~&lt;/code&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;After a substitution, putting &lt;code&gt;~&lt;/code&gt; in a new replacement string expands to whatever the last replacement was. This lets you apply the same transformation to a different pattern without retyping.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;%s&lt;span class="sr"&gt;/password/&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;REDACTED&lt;span class="p"&gt;]&lt;/span&gt;/&lt;span class="k"&gt;g&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;s&lt;span class="sr"&gt;/api_secret/&lt;/span&gt;&lt;span class="p"&gt;~&lt;/span&gt;/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You're sanitizing a config dump for a bug report. First you replace all occurrences of &lt;code&gt;password&lt;/code&gt; with &lt;code&gt;[REDACTED]&lt;/code&gt;. Then you spot &lt;code&gt;api_secret&lt;/code&gt; a few lines down — same replacement needed. Instead of retyping the bracket-wrapped word, &lt;code&gt;:s/api_secret/~/&lt;/code&gt; expands &lt;code&gt;~&lt;/code&gt; to &lt;code&gt;[REDACTED]&lt;/code&gt; from the previous substitution. If you're normalizing a handful of different identifier patterns to the same replacement, you do the first one verbosely and all subsequent ones with &lt;code&gt;~/&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;~&lt;/code&gt; expands to the &lt;strong&gt;most recent&lt;/strong&gt; replacement text globally — if you run any other substitution in between, even on a different buffer, &lt;code&gt;~&lt;/code&gt; picks up that replacement instead. Keep the sequence tight or verify the current &lt;code&gt;~&lt;/code&gt; value before relying on it in a longer editing session.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;Five tricks that reduce the "close but not quite" friction in Vim work: editing a macro without re-recording it, using marks as operator motion targets, anchoring range endpoints with &lt;code&gt;;&lt;/code&gt;, inserting real newlines with &lt;code&gt;\r&lt;/code&gt; in substitutions, and recycling replacement text with &lt;code&gt;~&lt;/code&gt;. None of these are obscure — they're just behaviors that pay off every few days once you know they exist.&lt;/p&gt;

&lt;p&gt;If you want more practical Vim tricks, I publish them at &lt;a href="https://vimtricks.wiki" rel="noopener noreferrer"&gt;https://vimtricks.wiki&lt;/a&gt;.&lt;br&gt;
What Vim operation still feels more awkward than it should be?&lt;/p&gt;

</description>
      <category>vim</category>
      <category>neovim</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>Vim commands I use when precision editing matters</title>
      <dc:creator>Vimtricks.wiki</dc:creator>
      <pubDate>Fri, 13 Mar 2026 12:16:53 +0000</pubDate>
      <link>https://dev.to/vimtrickswiki/vim-commands-i-use-when-precision-editing-matters-396k</link>
      <guid>https://dev.to/vimtrickswiki/vim-commands-i-use-when-precision-editing-matters-396k</guid>
      <description>&lt;p&gt;Every Vim user builds a personal toolkit over time. The commands below are ones I kept bumping into — not in tutorials, but in the middle of actual work when the usual approach felt like one step too many. Each one solves a real friction point rather than just being clever for its own sake.&lt;/p&gt;

&lt;h2&gt;
  
  
  1) Recursive macros that stop themselves
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;When you record a macro to process N items, you usually need to know N in advance. Most people use a large count like &lt;code&gt;99@q&lt;/code&gt; and hope that's enough. A recursive macro is cleaner: it calls itself at the end of its body and stops automatically the moment any command in the sequence fails — no counting required.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;qqq
qq&lt;span class="p"&gt;{&lt;/span&gt;your commands&lt;span class="p"&gt;}&lt;/span&gt;@qq
@&lt;span class="k"&gt;q&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first line (&lt;code&gt;qqq&lt;/code&gt;) clears register &lt;code&gt;q&lt;/code&gt; so the embedded &lt;code&gt;@q&lt;/code&gt; at the end of the recording is a harmless no-op rather than invoking a stale old macro. Then you record your macro and include &lt;code&gt;@q&lt;/code&gt; as the final keystroke. Once recorded, &lt;code&gt;@q&lt;/code&gt; starts the loop.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You have a list of lines where each one needs the first word removed. You don't know how many lines there are. Record &lt;code&gt;qqdw0j@qq&lt;/code&gt;, then hit &lt;code&gt;@q&lt;/code&gt;. The macro deletes the first word, moves to column 0, steps down one line, and recurses — until &lt;code&gt;j&lt;/code&gt; fails on the last line and the whole chain stops.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;If the macro gets stuck in an infinite loop, &lt;code&gt;&amp;lt;C-c&amp;gt;&lt;/code&gt; interrupts it. Also: if a command fails midway on a line rather than at the end of the file, the macro will stop early. Make sure your "stop condition" is the one thing that naturally fails when the work is done.&lt;/p&gt;




&lt;h2&gt;
  
  
  2) Pattern-relative offsets in Ex ranges
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Ex command ranges usually use line numbers or marks, but Vim also lets you write ranges in terms of search patterns with numeric offsets. This means you can operate on "the three lines after the TODO comment" or "everything between two section markers" without knowing any line numbers at all.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="sr"&gt;/pattern/&lt;/span&gt;&lt;span class="p"&gt;+&lt;/span&gt;N&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sr"&gt;/other-pattern/&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;N &lt;span class="k"&gt;delete&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;/pattern/+1&lt;/code&gt; form says "the line one below the next match of this pattern." The &lt;code&gt;-1&lt;/code&gt; form says "the line one above." You can use these addresses with any Ex command that takes a range: &lt;code&gt;:delete&lt;/code&gt;, &lt;code&gt;:yank&lt;/code&gt;, &lt;code&gt;:move&lt;/code&gt;, &lt;code&gt;:copy&lt;/code&gt;, &lt;code&gt;:substitute&lt;/code&gt;, &lt;code&gt;:normal&lt;/code&gt;, and so on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;A config file has sections delimited by &lt;code&gt;# BEGIN&lt;/code&gt; and &lt;code&gt;# END&lt;/code&gt; comments, and you need to delete everything between them (not including the markers themselves):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="sr"&gt;/# BEGIN/&lt;/span&gt;&lt;span class="p"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sr"&gt;/# END/&lt;/span&gt;&lt;span class="m"&gt;-1&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a complete command. No line number lookup, no visual selection. Works regardless of where in the file the block lives.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;If the search pattern doesn't exist in the buffer, Vim will error out. When scripting this kind of range, wrap the command in &lt;code&gt;:silent!&lt;/code&gt; or guard with a pattern check first. Also remember that &lt;code&gt;/pattern/&lt;/code&gt; searches forward from the cursor — position matters when a pattern appears multiple times.&lt;/p&gt;




&lt;h2&gt;
  
  
  3) Opening the command-line window mid-command
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Vim's command-line window (&lt;code&gt;q:&lt;/code&gt; from Normal mode) is great for editing and re-running previous commands. Less known is that you can open it &lt;em&gt;while you're already typing&lt;/em&gt; a command — press &lt;code&gt;&amp;lt;C-f&amp;gt;&lt;/code&gt; in the middle of your &lt;code&gt;:s&lt;/code&gt; substitution and Vim drops you into the command-line window with your half-typed command loaded and ready for full Vim editing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;f&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;   &lt;span class="p"&gt;(&lt;/span&gt;press &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; / ? &lt;span class="k"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works from any command-line mode: &lt;code&gt;:&lt;/code&gt;, &lt;code&gt;/&lt;/code&gt;, &lt;code&gt;?&lt;/code&gt;, or &lt;code&gt;!&lt;/code&gt;. The in-progress command appears at the bottom of the window, and you can use any Normal-mode motions to fix it before pressing &lt;code&gt;&amp;lt;CR&amp;gt;&lt;/code&gt; to execute.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You're typing a complicated substitution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;%s&lt;span class="sr"&gt;/\v(class|module)\s+\zs\w+/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You realize you got the regex wrong two groups back. Instead of &lt;code&gt;&amp;lt;C-b&amp;gt;&lt;/code&gt; and arrow keys, press &lt;code&gt;&amp;lt;C-f&amp;gt;&lt;/code&gt;. The command opens in an editable buffer. Use &lt;code&gt;F(&lt;/code&gt; to jump to the paren, &lt;code&gt;ci(&lt;/code&gt; to fix it, then &lt;code&gt;&amp;lt;CR&amp;gt;&lt;/code&gt; on the line to run it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;q:&lt;/code&gt; from Normal mode also opens the command-line window, but it only shows history — it cannot capture what you were currently typing. &lt;code&gt;&amp;lt;C-f&amp;gt;&lt;/code&gt; is specifically for the mid-input case. Close the window without running with &lt;code&gt;:q&lt;/code&gt; or &lt;code&gt;&amp;lt;C-c&amp;gt;&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  4) The &lt;code&gt;'^&lt;/code&gt; mark: return to the last insert position
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Vim automatically updates the &lt;code&gt;^&lt;/code&gt; mark every time you leave Insert mode. Pressing &lt;code&gt;'^&lt;/code&gt; in Normal mode jumps back to the exact position where your cursor was when you hit &lt;code&gt;&amp;lt;Esc&amp;gt;&lt;/code&gt;. Unlike &lt;code&gt;gi&lt;/code&gt; — which jumps there and immediately re-enters Insert mode — &lt;code&gt;'^&lt;/code&gt; is a plain mark jump: you arrive, look around, and decide when to start editing again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;'^
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You're editing a function, escape out to check a related block above, then use &lt;code&gt;/search&lt;/code&gt; or &lt;code&gt;%&lt;/code&gt; to explore a bit. When you're ready to return, &lt;code&gt;'^&lt;/code&gt; brings you straight back to column and line — no searching, no &lt;code&gt;&amp;lt;C-o&amp;gt;&lt;/code&gt; chain. Then press &lt;code&gt;a&lt;/code&gt; or &lt;code&gt;i&lt;/code&gt; when you're actually ready to type.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;If &lt;code&gt;gi&lt;/code&gt; already fits your workflow — jump back and start typing — there's no reason to switch. &lt;code&gt;'^&lt;/code&gt; is the right choice when you want to inspect the position first, or when you want to use an operator there rather than enter Insert mode. The mark is also buffer-global: if you switched files, &lt;code&gt;'^&lt;/code&gt; will switch back to the other buffer.&lt;/p&gt;




&lt;h2&gt;
  
  
  5) &lt;code&gt;gP&lt;/code&gt; — paste before the cursor, land after it
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;The standard &lt;code&gt;P&lt;/code&gt; pastes text before the cursor and leaves the cursor sitting on the first character of what was just inserted. &lt;code&gt;gP&lt;/code&gt; pastes in the same position but moves the cursor to &lt;em&gt;after&lt;/em&gt; the inserted text. That might sound minor, but when you're assembling content from multiple pastes or continuing to type immediately after, it eliminates the manual &lt;code&gt;$&lt;/code&gt; or &lt;code&gt;e&lt;/code&gt; move you'd otherwise need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;gP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The lowercase &lt;code&gt;gp&lt;/code&gt; is the after-cursor equivalent of &lt;code&gt;p&lt;/code&gt; — same behavior, cursor ends up after the paste.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You're building a line by pasting three named registers in sequence. With &lt;code&gt;"agP"bgP"cgP&lt;/code&gt;, each paste leaves your cursor positioned for the next, and you end up after all three pieces without touching a motion key in between.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;gP&lt;/code&gt; with a count (&lt;code&gt;3gP&lt;/code&gt;) pastes three copies in a row and leaves the cursor after all three, not after just the first. This is intentional and usually what you want, but it's worth knowing before you use it inside a macro.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;These five commands live in different areas of Vim — macros, Ex ranges, command-line editing, marks, and paste operations — but they share a common thread: each one removes a step that you'd otherwise do manually. Recursive macros eliminate counting. Pattern offsets eliminate line number lookups. &lt;code&gt;&amp;lt;C-f&amp;gt;&lt;/code&gt; eliminates awkward command-line navigation. &lt;code&gt;'^&lt;/code&gt; eliminates refinding your position. &lt;code&gt;gP&lt;/code&gt; eliminates cursor repositioning after paste.&lt;/p&gt;

&lt;p&gt;If you want more practical Vim tricks explained at this level, I publish them at &lt;a href="https://vimtricks.wiki" rel="noopener noreferrer"&gt;https://vimtricks.wiki&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What Vim workflow still has a step you wish you could skip?&lt;/p&gt;

</description>
      <category>vim</category>
      <category>neovim</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>Vim commands that handle the detail work without friction</title>
      <dc:creator>Vimtricks.wiki</dc:creator>
      <pubDate>Mon, 02 Mar 2026 12:45:35 +0000</pubDate>
      <link>https://dev.to/vimtrickswiki/vim-commands-that-handle-the-detail-work-without-friction-4b75</link>
      <guid>https://dev.to/vimtrickswiki/vim-commands-that-handle-the-detail-work-without-friction-4b75</guid>
      <description>&lt;p&gt;Most of the time Vim does what you expect. But there is a category of editing tasks where the obvious approach quietly fails you: numeric data that sorts wrong, a diff window you can only scroll through, a macro that breaks because of your own mappings, or a regex that swallows half the file instead of a small piece of it. None of these are exotic edge cases — they come up in ordinary work.&lt;/p&gt;

&lt;p&gt;These five commands are the ones I reach for when that category of problem shows up.&lt;/p&gt;




&lt;h2&gt;
  
  
  1) Jumping between diff hunks without scrolling
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;When you open two files side by side with &lt;code&gt;vimdiff&lt;/code&gt; or &lt;code&gt;:diffsplit&lt;/code&gt;, the changed sections are highlighted — but you still have to find them. Scrolling through a large file looking for the next colored block is slow and easy to miss. &lt;code&gt;]c&lt;/code&gt; and &lt;code&gt;[c&lt;/code&gt; are motions that jump directly to diff hunks, skipping unchanged content entirely.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;   " jump forward &lt;span class="k"&gt;to&lt;/span&gt; the &lt;span class="k"&gt;next&lt;/span&gt; changed hunk
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;   " jump backward &lt;span class="k"&gt;to&lt;/span&gt; the &lt;span class="k"&gt;previous&lt;/span&gt; changed hunk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You are reviewing a pull request locally with &lt;code&gt;vimdiff old.go new.go&lt;/code&gt;. The files are 300 lines each and there are seven changes scattered through them. Pressing &lt;code&gt;]c&lt;/code&gt; from the top takes you directly to each hunk in sequence. Pressing &lt;code&gt;[c&lt;/code&gt; steps back if you want to re-examine one. No scrolling.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;These motions require an active diff session — they do nothing in a regular buffer. If you land on a hunk and want to act on it, &lt;code&gt;do&lt;/code&gt; (diff obtain) pulls the change from the other window, and &lt;code&gt;dp&lt;/code&gt; (diff put) pushes it the other direction. Run &lt;code&gt;:diffupdate&lt;/code&gt; if the highlighting goes stale after you make edits.&lt;/p&gt;




&lt;h2&gt;
  
  
  2) Sorting lines numerically instead of lexicographically
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Plain &lt;code&gt;:sort&lt;/code&gt; in Vim is alphabetical. That means &lt;code&gt;10&lt;/code&gt; sorts before &lt;code&gt;2&lt;/code&gt;, &lt;code&gt;100&lt;/code&gt; sorts before &lt;code&gt;9&lt;/code&gt;, and a list of version numbers or file sizes ends up in nonsensical order. Adding the &lt;code&gt;n&lt;/code&gt; flag tells Vim to compare lines by numeric value instead of character code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s1"&gt;'&amp;lt;,'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;sort&lt;/span&gt; &lt;span class="k"&gt;n&lt;/span&gt;    " &lt;span class="k"&gt;sort&lt;/span&gt; selected &lt;span class="nb"&gt;lines&lt;/span&gt; numerically&lt;span class="p"&gt;,&lt;/span&gt; ascending
&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s1"&gt;'&amp;lt;,'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;sort&lt;/span&gt; &lt;span class="k"&gt;n&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;   " &lt;span class="k"&gt;sort&lt;/span&gt; numerically&lt;span class="p"&gt;,&lt;/span&gt; descending
&lt;span class="p"&gt;:&lt;/span&gt;%&lt;span class="k"&gt;sort&lt;/span&gt; &lt;span class="k"&gt;n&lt;/span&gt;        " &lt;span class="k"&gt;sort&lt;/span&gt; the whole &lt;span class="k"&gt;buffer&lt;/span&gt; numerically
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You have a list of benchmark results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;150ms  parse_config
23ms   load_cache
1200ms run_query
87ms   render_view
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Selecting all four lines and running &lt;code&gt;:'&amp;lt;,'&amp;gt;sort n&lt;/code&gt; orders them by the leading number: &lt;code&gt;23ms&lt;/code&gt;, &lt;code&gt;87ms&lt;/code&gt;, &lt;code&gt;150ms&lt;/code&gt;, &lt;code&gt;1200ms&lt;/code&gt;. With plain &lt;code&gt;sort&lt;/code&gt;, you get &lt;code&gt;1200ms&lt;/code&gt; second because &lt;code&gt;"1" &amp;lt; "8"&lt;/code&gt; lexicographically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;n&lt;/code&gt; flag extracts the &lt;strong&gt;first integer found&lt;/strong&gt; on each line as the sort key. If a line has no leading number, Vim treats it as zero. Non-numeric lines that happen to mix in will group at the top. For floating-point values or sorting by a middle column, pipe through an external sort instead: &lt;code&gt;:'&amp;lt;,'&amp;gt;!sort -k1 -n&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  3) Running normal mode commands without your mappings interfering
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;:normal {cmd}&lt;/code&gt; is a powerful way to replay Normal mode keystrokes over a range of lines — common in macros, autocommands, and shared vimrc snippets. The problem is that it applies your custom mappings. If you have &lt;code&gt;nnoremap w b&lt;/code&gt; in your config, then &lt;code&gt;:%normal w&lt;/code&gt; moves backward instead of forward. Adding a bang fixes it: &lt;code&gt;:normal! {cmd}&lt;/code&gt; always executes the built-in command, regardless of what you have mapped.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;%norm&lt;span class="p"&gt;!&lt;/span&gt; A;       " &lt;span class="nb"&gt;append&lt;/span&gt; semicolon &lt;span class="k"&gt;to&lt;/span&gt; every &lt;span class="nb"&gt;line&lt;/span&gt; using the real A&lt;span class="p"&gt;,&lt;/span&gt; not any remapped A
&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s1"&gt;'&amp;lt;,'&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;norm&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt;   " &lt;span class="nb"&gt;indent&lt;/span&gt; selected &lt;span class="nb"&gt;lines&lt;/span&gt; using the real &lt;span class="p"&gt;&amp;gt;&amp;gt;,&lt;/span&gt; not any remapping
&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;norm&lt;span class="p"&gt;!&lt;/span&gt; dw    " &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="k"&gt;first&lt;/span&gt; word &lt;span class="k"&gt;on&lt;/span&gt; &lt;span class="nb"&gt;lines&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;–&lt;span class="m"&gt;10&lt;/span&gt; using the real dw
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You are writing a function in a shared vimrc that bulk-indents a range of lines. Without the bang, the function breaks on any machine where &lt;code&gt;&amp;gt;&lt;/code&gt; has been remapped. With &lt;code&gt;:norm!&lt;/code&gt;, the function works identically everywhere, regardless of the user's mapping configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;:norm!&lt;/code&gt; does not accept special key notation directly in command-line usage. If your command needs &lt;code&gt;&amp;lt;CR&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;Esc&amp;gt;&lt;/code&gt;, or &lt;code&gt;&amp;lt;C-a&amp;gt;&lt;/code&gt;, you have to wrap it in &lt;code&gt;:execute "norm! \&amp;lt;CR&amp;gt;"&lt;/code&gt; (using &lt;code&gt;execute&lt;/code&gt; to interpolate the special key). This applies to any key that requires angle-bracket notation.&lt;/p&gt;




&lt;h2&gt;
  
  
  4) Reverting to the last saved state in one step
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Vim's undo history is deep and time-stamped. The &lt;code&gt;:earlier&lt;/code&gt; command navigates it using time units instead of individual undo steps — and &lt;code&gt;f&lt;/code&gt; is the unit for &lt;strong&gt;file writes&lt;/strong&gt;. So &lt;code&gt;:earlier 1f&lt;/code&gt; jumps the buffer back to exactly the state it was in when you last ran &lt;code&gt;:w&lt;/code&gt;. It does not matter if you made 50 changes since then; one command reverts all of them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;earlier&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="k"&gt;f&lt;/span&gt;     " revert &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="nb"&gt;state&lt;/span&gt; at &lt;span class="k"&gt;last&lt;/span&gt; &lt;span class="k"&gt;file&lt;/span&gt; &lt;span class="k"&gt;write&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;earlier&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="k"&gt;f&lt;/span&gt;     " revert &lt;span class="k"&gt;to&lt;/span&gt; two saves ago
&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;later&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="k"&gt;f&lt;/span&gt;       " &lt;span class="nb"&gt;re&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;apply forward &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="k"&gt;next&lt;/span&gt; &lt;span class="k"&gt;write&lt;/span&gt; checkpoint
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You refactored a function, saved, continued editing, and an hour later realized the refactor introduced a subtle bug. You want to see the version just before that last batch of changes without destroying the ability to redo. &lt;code&gt;:earlier 1f&lt;/code&gt; takes you back to the previous save in one command. If you change your mind, &lt;code&gt;:later 1f&lt;/code&gt; restores the current state.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;This uses Vim's &lt;strong&gt;in-memory&lt;/strong&gt; undo tree — it does not reload the file from disk. If you want a true disk reload, use &lt;code&gt;:e!&lt;/code&gt; instead. Also, undo history is lost when you close Vim unless you have &lt;code&gt;:set undofile&lt;/code&gt; enabled. With &lt;code&gt;undofile&lt;/code&gt;, the undo tree persists across sessions, which makes &lt;code&gt;:earlier 1f&lt;/code&gt; useful even after restarting Vim.&lt;/p&gt;




&lt;h2&gt;
  
  
  5) Matching the shortest possible string in a regex
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;By default, &lt;code&gt;.*&lt;/code&gt; in a Vim pattern is greedy — it matches as many characters as possible. When your text has repeated delimiters, that means one &lt;code&gt;.*&lt;/code&gt; can consume far more than you intended, from the first delimiter all the way to the last one in the file. Vim's non-greedy quantifier is &lt;code&gt;\{-}&lt;/code&gt;, and it works as the lazy counterpart to &lt;code&gt;*&lt;/code&gt;, matching as &lt;strong&gt;few&lt;/strong&gt; characters as possible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;/start&lt;span class="p"&gt;.&lt;/span&gt;\&lt;span class="p"&gt;{-}&lt;/span&gt;end        " matches shortest span from &lt;span class="s1"&gt;'start'&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="s1"&gt;'end'&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;%s&lt;span class="sr"&gt;/&amp;lt;b&amp;gt;.\{-}&amp;lt;\/b&amp;gt;//g  " removes each &amp;lt;b&amp;gt;...&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;b&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;tag&lt;/span&gt; pair individually
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You have a log file with repeated bracketed fields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[INFO] Request received [user=alice] [status=200]
[WARN] Timeout reached [user=bob] [status=408]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running &lt;code&gt;:%s/\[.\{-}\]//g&lt;/code&gt; removes every bracket pair individually. Using greedy &lt;code&gt;.*&lt;/code&gt; instead would eat from the first &lt;code&gt;[&lt;/code&gt; all the way to the last &lt;code&gt;]&lt;/code&gt; on the line, deleting content you wanted to keep.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;\{-}&lt;/code&gt; is Vim's regex syntax, not PCRE. If you are accustomed to &lt;code&gt;.*?&lt;/code&gt; from Python or JavaScript, this is the direct equivalent but the syntax is different. In Vim's very-magic mode (&lt;code&gt;\v&lt;/code&gt;), you can write &lt;code&gt;{-}&lt;/code&gt; without the backslash. For zero-or-more non-greedy, use &lt;code&gt;.\{-}&lt;/code&gt;. For one-or-more, use &lt;code&gt;.\{-1,}&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;None of these are obscure. Diff navigation with &lt;code&gt;]c&lt;/code&gt;/&lt;code&gt;[c&lt;/code&gt; replaces scrolling. Numeric sort with &lt;code&gt;sort n&lt;/code&gt; prevents the kind of ordering bug that looks like a data problem until you realize it is not. &lt;code&gt;:norm!&lt;/code&gt; is essential the moment you start writing any vimrc automation. &lt;code&gt;:earlier 1f&lt;/code&gt; is a safety net for the editing session. And non-greedy &lt;code&gt;\{-}&lt;/code&gt; is one of those regex tools you reach for constantly once you know it exists.&lt;/p&gt;

&lt;p&gt;If you want more practical Vim tricks like these, I publish them regularly at &lt;a href="https://vimtricks.wiki" rel="noopener noreferrer"&gt;https://vimtricks.wiki&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Which of these do you already use, and which ones sneak up on you?&lt;/p&gt;

</description>
      <category>vim</category>
      <category>neovim</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>Switching between files in Vim without fuzzy-finding everything</title>
      <dc:creator>Vimtricks.wiki</dc:creator>
      <pubDate>Wed, 25 Feb 2026 07:37:24 +0000</pubDate>
      <link>https://dev.to/vimtrickswiki/switching-between-files-in-vim-without-fuzzy-finding-everything-2hme</link>
      <guid>https://dev.to/vimtrickswiki/switching-between-files-in-vim-without-fuzzy-finding-everything-2hme</guid>
      <description>&lt;p&gt;Most of the time, fuzzy-finding isn't what you need. You already know which file you want — you were just there. The real problem is getting back to it fast.&lt;/p&gt;

&lt;p&gt;Here's a progression from the fastest built-ins to a full fuzzy picker, ordered by how much setup each requires.&lt;/p&gt;




&lt;h2&gt;
  
  
  1) &lt;code&gt;&amp;lt;C-^&amp;gt;&lt;/code&gt; — toggle the file you were just in
&lt;/h2&gt;

&lt;p&gt;If you're jumping between exactly two files — say, &lt;code&gt;auth.go&lt;/code&gt; and &lt;code&gt;auth_test.go&lt;/code&gt; — this is the only command you need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;^&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;C-^&amp;gt;&lt;/code&gt; switches to the &lt;em&gt;alternate file&lt;/em&gt;, which is simply the last buffer you had open. No filename to type, no fuzzy search, no menu. Just one keystroke back where you were.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You jump to a test file with &lt;code&gt;gd&lt;/code&gt; to look up an interface definition. You've read what you need. &lt;code&gt;&amp;lt;C-^&amp;gt;&lt;/code&gt; lands you back at your implementation file, cursor exactly where you left it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;This only remembers &lt;em&gt;one&lt;/em&gt; previous file. The moment you open a third buffer, the earlier one is no longer the alternate. For two-file back-and-forth it's unbeatable; for broader navigation you need something else.&lt;/p&gt;




&lt;h2&gt;
  
  
  2) Global marks (&lt;code&gt;mA&lt;/code&gt;, &lt;code&gt;'A&lt;/code&gt;) — pin files you return to constantly
&lt;/h2&gt;

&lt;p&gt;When you have 2-3 files you keep coming back to during a session — config, main handler, test file — global marks let you warp there instantly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="c"&gt;" Set a global mark (uppercase letter = global, persists across files)&lt;/span&gt;
mA

&lt;span class="c"&gt;" Jump to it from anywhere&lt;/span&gt;
'A
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Lowercase marks (&lt;code&gt;ma&lt;/code&gt;, &lt;code&gt;'a&lt;/code&gt;) are local to the buffer. Uppercase marks (&lt;code&gt;mA&lt;/code&gt;, &lt;code&gt;'A&lt;/code&gt;) are global — they remember both the file and line number. Press &lt;code&gt;'A&lt;/code&gt; from anywhere in Vim and you jump directly to that exact line in that file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You're working on a feature and constantly need to reference &lt;code&gt;routes.go&lt;/code&gt;. Press &lt;code&gt;mR&lt;/code&gt; once on the relevant line. For the rest of the session, &lt;code&gt;'R&lt;/code&gt; gets you there in one keystroke from any file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;Global marks are persistent across Vim sessions (written to &lt;code&gt;~/.viminfo&lt;/code&gt; or &lt;code&gt;~/.local/share/nvim/shada/main.shada&lt;/code&gt;). That's useful but also means stale marks from last week can send you to the wrong place. Clean them up occasionally with &lt;code&gt;:delmarks A-Z&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  3) &lt;code&gt;&amp;lt;C-o&amp;gt;&lt;/code&gt; / &lt;code&gt;&amp;lt;C-i&amp;gt;&lt;/code&gt; — retrace your navigation history
&lt;/h2&gt;

&lt;p&gt;When you've been jumping around a codebase following references — &lt;code&gt;gd&lt;/code&gt; to definition, then another &lt;code&gt;gd&lt;/code&gt;, then a search — &lt;code&gt;&amp;lt;C-o&amp;gt;&lt;/code&gt; walks you back through the full path.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;o&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;   " jump back &lt;span class="p"&gt;(&lt;/span&gt;older position &lt;span class="k"&gt;in&lt;/span&gt; jump &lt;span class="k"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;i&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;   " jump forward &lt;span class="p"&gt;(&lt;/span&gt;newer position&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Vim keeps a &lt;em&gt;jump list&lt;/em&gt; — a history of every position you've jumped to (via &lt;code&gt;gd&lt;/code&gt;, &lt;code&gt;gg&lt;/code&gt;, &lt;code&gt;/pattern&amp;lt;CR&amp;gt;&lt;/code&gt;, &lt;code&gt;'mark&lt;/code&gt;, etc.). &lt;code&gt;&amp;lt;C-o&amp;gt;&lt;/code&gt; steps backward through that history, including across files. It's like a browser back button for your editing session.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You press &lt;code&gt;gd&lt;/code&gt; to follow a function call into a helper, then follow another reference deeper. After reading the implementation, &lt;code&gt;&amp;lt;C-o&amp;gt;&amp;lt;C-o&amp;gt;&lt;/code&gt; brings you back through the call chain to where you started — no need to remember file names or line numbers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;The jump list tracks &lt;em&gt;positions&lt;/em&gt;, not intent. If you've been jumping around a lot, &lt;code&gt;&amp;lt;C-o&amp;gt;&lt;/code&gt; might take you through more stops than expected before landing where you wanted. Use &lt;code&gt;:jumps&lt;/code&gt; to see the full list and get your bearings.&lt;/p&gt;




&lt;h2&gt;
  
  
  4) Native buffer commands — &lt;code&gt;:b partial&amp;lt;Tab&amp;gt;&lt;/code&gt;, &lt;code&gt;]b&lt;/code&gt;/&lt;code&gt;[b&lt;/code&gt;, &lt;code&gt;:ls&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Before reaching for plugins, the built-in buffer commands cover most cases.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;ls&lt;/span&gt;          " &lt;span class="k"&gt;list&lt;/span&gt; &lt;span class="k"&gt;all&lt;/span&gt; &lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="k"&gt;buffers&lt;/span&gt; with numbers &lt;span class="nb"&gt;and&lt;/span&gt; names
&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;b&lt;/span&gt; partial   " switch &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="k"&gt;buffer&lt;/span&gt; by partial filename &lt;span class="k"&gt;match&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;b&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;         " switch &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="k"&gt;buffer&lt;/span&gt; &lt;span class="k"&gt;number&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;b&lt;/span&gt;           " &lt;span class="k"&gt;next&lt;/span&gt; &lt;span class="k"&gt;buffer&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;unimpaired &lt;span class="nb"&gt;or&lt;/span&gt; manual mapping&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;b&lt;/span&gt;           " &lt;span class="k"&gt;previous&lt;/span&gt; &lt;span class="k"&gt;buffer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;:b partial&amp;lt;Tab&amp;gt;&lt;/code&gt; tab-completes buffer names, so typing &lt;code&gt;:b auth&amp;lt;Tab&amp;gt;&lt;/code&gt; switches to &lt;code&gt;auth.go&lt;/code&gt; without typing the full name. &lt;code&gt;:ls&lt;/code&gt; gives you a quick overview when you're not sure what's open. &lt;code&gt;]b&lt;/code&gt;/&lt;code&gt;[b&lt;/code&gt; are useful when you want to cycle through a small number of buffers sequentially.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You remember you had some migration file open but can't remember the full name. &lt;code&gt;:b migr&amp;lt;Tab&amp;gt;&lt;/code&gt; completes to &lt;code&gt;2024_add_users_migration.sql&lt;/code&gt; — done.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;:b partial&lt;/code&gt; matches against the full path, not just the filename. If you have two files with similar paths, the completion might behave unexpectedly. Use &lt;code&gt;:ls&lt;/code&gt; first to check what's open and note the buffer numbers.&lt;/p&gt;




&lt;h2&gt;
  
  
  5) &lt;code&gt;wildmode=lastused&lt;/code&gt; + &lt;code&gt;wildcharm&lt;/code&gt; — a Tab-completion buffer picker
&lt;/h2&gt;

&lt;p&gt;With two config lines, you can turn &lt;code&gt;:b &amp;lt;Tab&amp;gt;&lt;/code&gt; into a fast MRU-ordered buffer picker, and then bind it to a single keypress.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nb"&gt;wildmenu&lt;/span&gt;
&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nb"&gt;wildmode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;lastused
&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nb"&gt;wildcharm&lt;/span&gt;&lt;span class="p"&gt;=&amp;lt;&lt;/span&gt;Tab&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
nnoremap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;leader&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;b&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;b&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;Tab&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;wildmode=lastused&lt;/code&gt; reorders buffer completions so the most recently used buffers appear first. &lt;code&gt;wildcharm=&amp;lt;Tab&amp;gt;&lt;/code&gt; is the less-known piece: it tells Vim which key triggers wildmenu expansion &lt;em&gt;inside mappings&lt;/em&gt; (Tab doesn't work in mappings by default). Together, &lt;code&gt;&amp;lt;leader&amp;gt;b&lt;/code&gt; drops you into a visual buffer list ordered by recency.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You've been alternating between four files all morning. Press &lt;code&gt;&amp;lt;leader&amp;gt;b&lt;/code&gt; and the wildmenu immediately shows the last file you had open — one more &lt;code&gt;&amp;lt;Tab&amp;gt;&lt;/code&gt; for the one before that. No plugin needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;wildmode=lastused&lt;/code&gt; is available in Vim 9.1+ and modern Neovim. Older Vim installations won't have it — check &lt;code&gt;:help 'wildmode'&lt;/code&gt; and look for the &lt;code&gt;lastused&lt;/code&gt; entry.&lt;/p&gt;




&lt;h2&gt;
  
  
  6) Harpoon — a persistent pinned-file list
&lt;/h2&gt;

&lt;p&gt;If you work on the same 4-5 files across multiple sessions, Harpoon gives you numbered slots that survive restarts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="c"&gt;" Add current file to Harpoon list&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;lua&lt;/span&gt; require&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'harpoon.mark'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;add_file&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c"&gt;" Open the Harpoon menu&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;lua&lt;/span&gt; require&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'harpoon.ui'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;toggle_quick_menu&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c"&gt;" Jump directly to slot 1-4&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;leader&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;leader&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;leader&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;leader&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Global marks are session-persistent but limited to 26 slots and tied to specific line numbers. Harpoon gives you a small, curated list of files you're actively working on — the 4-6 files that matter for this task — and lets you jump between them with numbered shortcuts that stay the same all day.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You're implementing a feature that touches &lt;code&gt;handler.go&lt;/code&gt;, &lt;code&gt;service.go&lt;/code&gt;, &lt;code&gt;service_test.go&lt;/code&gt;, and &lt;code&gt;schema.sql&lt;/code&gt;. Mark all four in Harpoon at the start of the day. Now &lt;code&gt;&amp;lt;leader&amp;gt;1&lt;/code&gt; through &lt;code&gt;&amp;lt;leader&amp;gt;4&lt;/code&gt; get you to each one instantly, no matter how many other buffers you open in between.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;Harpoon is Neovim-only and requires Lua configuration. The list is project-aware (scoped to the git root), which is useful but means you maintain separate lists per project. It's intentionally minimal — if you want fuzzy search over the pinned files, you'll need Telescope integration.&lt;/p&gt;




&lt;h2&gt;
  
  
  7) &lt;code&gt;:Telescope buffers&lt;/code&gt; — fuzzy search over all open buffers
&lt;/h2&gt;

&lt;p&gt;When you have many buffers open and don't remember enough of the filename to use &lt;code&gt;:b partial&lt;/code&gt;, the Telescope buffer picker lets you fuzzy-search everything.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;Telescope &lt;span class="k"&gt;buffers&lt;/span&gt;

&lt;span class="c"&gt;" Recommended binding:&lt;/span&gt;
nnoremap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;leader&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;fb &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;cmd&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Telescope &lt;span class="k"&gt;buffers&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;The Telescope buffer picker shows all open buffers with their numbers and modification state (&lt;code&gt;[+]&lt;/code&gt; for unsaved changes). Type any substring to filter in real time. &lt;code&gt;&amp;lt;C-d&amp;gt;&lt;/code&gt; deletes a buffer from the list without leaving the picker — useful for trimming stale buffers during a long session.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You've been working for three hours and have 15 buffers open. You need to get back to a migration file but can't remember the exact name. Type &lt;code&gt;migr&lt;/code&gt; in the picker and it narrows immediately to the one you want.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;Neovim only. If you're on vanilla Vim, &lt;code&gt;fzf.vim&lt;/code&gt;'s &lt;code&gt;:Buffers&lt;/code&gt; command gives you essentially the same picker. Neither requires you to know buffer numbers — just type enough of the name and pick.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;These techniques stack. In practice: &lt;code&gt;&amp;lt;C-^&amp;gt;&lt;/code&gt; for the last file, &lt;code&gt;'A&lt;/code&gt;/&lt;code&gt;'B&lt;/code&gt; for pinned files you visit constantly, &lt;code&gt;&amp;lt;C-o&amp;gt;&lt;/code&gt; to retrace after diving into definitions, &lt;code&gt;&amp;lt;leader&amp;gt;b&lt;/code&gt; for a quick MRU-ordered list when you have a few buffers open, and &lt;code&gt;:Telescope buffers&lt;/code&gt; when you need to search across many.&lt;/p&gt;

&lt;p&gt;The sweet spot for most people is &lt;code&gt;&amp;lt;C-^&amp;gt;&lt;/code&gt; + global marks + &lt;code&gt;wildmode=lastused&lt;/code&gt; — zero plugins, huge improvement over default behavior.&lt;/p&gt;

&lt;p&gt;If you want more of this, the full explanations are on &lt;a href="https://vimtricks.wiki" rel="noopener noreferrer"&gt;vimtricks.wiki&lt;/a&gt;. What file-switching workflow are you currently using that still feels clunky?&lt;/p&gt;

</description>
      <category>vim</category>
      <category>neovim</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>My first post on dev.to</title>
      <dc:creator>Vimtricks.wiki</dc:creator>
      <pubDate>Tue, 24 Feb 2026 08:51:17 +0000</pubDate>
      <link>https://dev.to/vimtrickswiki/my-first-post-on-devto-43ep</link>
      <guid>https://dev.to/vimtrickswiki/my-first-post-on-devto-43ep</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/vimtrickswiki" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3788558%2F1f6f3636-6d8d-43ce-baa0-1b73150f20a8.jpg" alt="vimtrickswiki"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/vimtrickswiki/how-i-handle-bulk-text-changes-in-vim-1c6j" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;How I handle bulk text changes in Vim&lt;/h2&gt;
      &lt;h3&gt;Vimtricks.wiki ・ Feb 24&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#vim&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#neovim&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#productivity&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#programming&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>vim</category>
      <category>neovim</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>How I handle bulk text changes in Vim</title>
      <dc:creator>Vimtricks.wiki</dc:creator>
      <pubDate>Tue, 24 Feb 2026 08:35:02 +0000</pubDate>
      <link>https://dev.to/vimtrickswiki/how-i-handle-bulk-text-changes-in-vim-1c6j</link>
      <guid>https://dev.to/vimtrickswiki/how-i-handle-bulk-text-changes-in-vim-1c6j</guid>
      <description>&lt;p&gt;Most of the time when editing gets tedious, it's not one hard change — it's fifty copies of the same small change, or a block of generated content that shouldn't be there, or inconsistent casing across identifiers. Vim has dedicated commands for each of these situations, but they're easy to miss if you learned the basics and stopped there.&lt;/p&gt;

&lt;p&gt;Here are five commands I reach for when text cleanup turns mechanical.&lt;/p&gt;

&lt;h2&gt;
  
  
  1) Pass the whole buffer through an external tool
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Vim's &lt;code&gt;!&lt;/code&gt; operator sends text through a shell command and replaces it with the output. &lt;code&gt;:%!&lt;/code&gt; does this for the entire buffer. You don't need a plugin or a formatter wired into your editor — if the tool runs from a shell, it works here.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;%&lt;span class="p"&gt;!&lt;/span&gt;jq &lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You're looking at a one-line JSON response pasted from a terminal. Instead of copying it to an online formatter, run &lt;code&gt;:%!jq .&lt;/code&gt; and the buffer is instantly readable. Same idea for &lt;code&gt;:%!sort -u&lt;/code&gt; to deduplicate a list, or &lt;code&gt;:%!column -t&lt;/code&gt; to align a table of values.&lt;/p&gt;

&lt;p&gt;For a subset of lines, use a range: &lt;code&gt;:5,20!indent&lt;/code&gt; formats only those lines. Visual selection followed by &lt;code&gt;!&lt;/code&gt; auto-fills &lt;code&gt;:'&amp;lt;,'&amp;gt;&lt;/code&gt; for you.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;If the command exits nonzero or writes nothing to stdout, Vim restores the original buffer — so it's safe to experiment. But if the tool crashes midway and writes partial output, you'll need &lt;code&gt;u&lt;/code&gt; to undo. Check the result before saving.&lt;/p&gt;




&lt;h2&gt;
  
  
  2) Transform case directly inside a substitute
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;Vim's replacement string supports case-transform atoms: &lt;code&gt;\U&lt;/code&gt; uppercases everything that follows, &lt;code&gt;\L&lt;/code&gt; lowercases it, &lt;code&gt;\u&lt;/code&gt; and &lt;code&gt;\l&lt;/code&gt; affect only the next character. Combined with capture groups, this handles identifier normalization that would otherwise need a separate script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;%s&lt;span class="sr"&gt;/\v&amp;lt;(\w+)&amp;gt;/&lt;/span&gt;\&lt;span class="k"&gt;u&lt;/span&gt;\L\&lt;span class="m"&gt;1&lt;/span&gt;/&lt;span class="k"&gt;g&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You have a config file where environment variable names are inconsistently cased — some &lt;code&gt;SCREAMING_SNAKE&lt;/code&gt;, some &lt;code&gt;screaming_snake&lt;/code&gt;, some mixed. A single &lt;code&gt;:%s/\v(\w+)/\U\1/g&lt;/code&gt; uppercases all of them in one pass. Or you're converting a list of &lt;code&gt;snake_case&lt;/code&gt; keys to &lt;code&gt;Title Case&lt;/code&gt; for a document: &lt;code&gt;:%s/_\(\w\)/\u\1/g&lt;/code&gt; capitalizes after every underscore.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;\U&lt;/code&gt; and &lt;code&gt;\L&lt;/code&gt; affect the rest of the replacement string, not just the next character. If you write &lt;code&gt;\U\1-\2&lt;/code&gt;, both capture groups get uppercased. Use &lt;code&gt;\E&lt;/code&gt; to end the transform explicitly: &lt;code&gt;\U\1\E-\2&lt;/code&gt; uppercases only &lt;code&gt;\1&lt;/code&gt; and leaves &lt;code&gt;\2&lt;/code&gt; unchanged.&lt;/p&gt;




&lt;h2&gt;
  
  
  3) Navigate through matches while still typing the search
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;With &lt;code&gt;incsearch&lt;/code&gt; active (the default in Vim 8+ and Neovim), &lt;code&gt;&amp;lt;C-g&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;C-t&amp;gt;&lt;/code&gt; jump forward and backward through matches while you're still in the search prompt. You can see exactly which occurrence you'll land on before pressing Enter — no committing to a search and then recounting with &lt;code&gt;n&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;/config&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;g&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;g&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;A file has thirty references to &lt;code&gt;user&lt;/code&gt; and you want the third occurrence in a specific function. Type &lt;code&gt;/user&lt;/code&gt;, press &lt;code&gt;&amp;lt;C-g&amp;gt;&lt;/code&gt; twice to skip past the first two matches, then confirm with &lt;code&gt;&amp;lt;CR&amp;gt;&lt;/code&gt;. It beats a blind search followed by &lt;code&gt;n&lt;/code&gt; presses, especially when matches are spread across hundreds of lines.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;This only works with &lt;code&gt;:set incsearch&lt;/code&gt;, which is on by default in modern Vim/Neovim but may be absent in minimal or legacy configs. Also note that &lt;code&gt;&amp;lt;C-g&amp;gt;&lt;/code&gt; in normal mode shows file info — this shortcut is search-prompt-only, so don't confuse the two.&lt;/p&gt;




&lt;h2&gt;
  
  
  4) Delete structured blocks between two pattern markers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;:g&lt;/code&gt; (global) accepts a range, not just individual line targets. &lt;code&gt;:g/start/,/end/d&lt;/code&gt; matches every line containing &lt;code&gt;start&lt;/code&gt;, extends the range to the next line containing &lt;code&gt;end&lt;/code&gt;, and deletes the whole block — both markers and everything between them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;g&lt;/span&gt;&lt;span class="sr"&gt;/&amp;lt;!-- BEGIN GENERATED --&amp;gt;/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sr"&gt;/&amp;lt;!-- END GENERATED --&amp;gt;/&lt;/span&gt;&lt;span class="k"&gt;d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;A template generates HTML with clearly marked scaffolding sections. Before committing, you want those blocks stripped from the output. One command removes every matching block in the file, no matter how many there are. The same pattern cleans up log files: &lt;code&gt;:g/DEBUG START/,/DEBUG END/d&lt;/code&gt; removes every debug dump in a crash log you're trying to read.&lt;/p&gt;

&lt;p&gt;Before previewing what would be removed, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;g&lt;/span&gt;&lt;span class="sr"&gt;/&amp;lt;!-- BEGIN GENERATED --&amp;gt;/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sr"&gt;/&amp;lt;!-- END GENERATED --&amp;gt;/&lt;/span&gt;&lt;span class="k"&gt;p&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;:g&lt;/code&gt; processes matches top to bottom and adjusts line numbers as it goes, so back-to-back blocks are handled correctly. However, if an end marker appears before its corresponding start marker (malformed blocks), the range will expand into unintended territory. Preview with &lt;code&gt;:p&lt;/code&gt; before running &lt;code&gt;d&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  5) Run a command at every quickfix entry
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why it matters
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;:cdo {cmd}&lt;/code&gt; executes a command at each entry in the quickfix list. Unlike &lt;code&gt;:cfdo&lt;/code&gt; (once per file), &lt;code&gt;:cdo&lt;/code&gt; visits each individual match location — useful when you want per-occurrence precision rather than a blanket file-wide substitution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;vimgrep&lt;/span&gt; &lt;span class="sr"&gt;/deprecatedCall/&lt;/span&gt; **/*&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;
&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;cdo&lt;/span&gt; s&lt;span class="sr"&gt;/deprecatedCall/&lt;/span&gt;replacementCall/ &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;update&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Real scenario
&lt;/h3&gt;

&lt;p&gt;You're retiring a function. Grep populates the quickfix list with every call site across the project. &lt;code&gt;:cdo&lt;/code&gt; substitutes at each location and saves the file. Two commands, no manual file-opening. You can also use &lt;code&gt;:cdo norm @q&lt;/code&gt; to replay a recorded macro at each entry — handy when the change is structural and context-dependent enough that a regex won't cut it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;:cdo&lt;/code&gt; runs at every quickfix entry, including duplicate lines if the same line appears in multiple results. Use &lt;code&gt;:cfdo&lt;/code&gt; instead if you'd rather operate once per file. Also, &lt;code&gt;:cdo&lt;/code&gt; doesn't save files by default — always append &lt;code&gt;| update&lt;/code&gt; unless you want to review diffs before writing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;These five commands cover a lot of ground: piping through external formatters, case transforms inside substitutions, navigating matches interactively, deleting structured blocks, and project-wide refactoring from the quickfix list. None require plugins and all work identically in Neovim.&lt;/p&gt;

&lt;p&gt;If you want more practical Vim tricks like these, I publish them at &lt;a href="https://vimtricks.wiki" rel="noopener noreferrer"&gt;https://vimtricks.wiki&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What bulk editing task in Vim still feels slower than it should?&lt;/p&gt;

</description>
      <category>vim</category>
      <category>neovim</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
