dotfiles/notes/vim/vim_batch_editing.md

3.2 KiB

Quick help

for f in *.html; do nvim -Nes "$f" < ex_commands; done
for f in "$(rg -l homu)"; do nvim -Nes "$f" < ex_commands; done

for f in $(fd -tf -e html); do
  nvim -Nes <<'EX'
g/^Stl/exe "norm! cStyle: new\<CR>\<esc>"
$ | a
# ex: ff=unix:
.
wq
EX
done

Batch editing with ex

Ever needed to apply the same edit to several files? Well ex-mode is the only generalized solution for this

Ex-mode is vim's equivalent of ed and ex is symlinked as vim -e on many systems. Use the -N flag for a more familiar experience. Enter this mode while in vim with gQ. Using the ex executable is slightly different from neovim's implementation, notably neovim doesn't echo back with nu and p

ex file
vim -Nes file

Ex-mode uses vim's command-mode syntax, which is similar though different from visual mode

:21             Goes to line 21. ^ and $ are for the first and last line
:10,20d         Deletes lines 10 through 20, inclusive on both ends
:u[ndo]         Undoes the last action
:mark a         Makes a mark at a. From vim
:ka             Also makes a mark at a. From ex
:'a             Go to mark a
:g/re/p         Globally exectute a command on lines with /re/
:v/re/p         Inverse of :g. Executes on all lines without /re/
:3,6co$         Copy lines [3,6] to the end of the document
:3m6            Move line 3 to line 6
:z=3            Pretty print lines in [-2,+2]
:norm! @l       Execute keystrokes, if all else fails

Several commands can be chained with |, similar to ; in bash

:g/bash/exe "normal! cfish\<esc>" | undo | nu

Changes every line with "bash" to "fish", undoes that, then prints the line

:g/string/nu | g/num/nu

Does NOT print all the lines with string or num. This prints all the lines with string then reprints them if they also have num. :g only uses a new line to delimit its commands from the next set!

Batch editing styles:

  1. Here-string: For only one command, here-strings are a quick and easy choice
for f in $(find ~/); do nvim -Nes <<<"%s/re/p | wq"; done
  1. Here-ansi-c-string: Allows including c-style escape sequences
for f in $(find ~/); do vim -Nes <<< $'%s/re/nu\nwq'; done
  1. Here-documents: The best choice for quick batch edits
for file in $(fd -at type subs_); do
  nvim -Nes $file <<'DOC'
g/^Stl/exe "norm! cStyle: new\<CR>\<esc>"
$ | a
# ex: ff=unix:
.
wq
DOC
done
for file in ~/.bash*; do vim -Nes $file <<EOF
a
# ex: set syntax=bash:ff=unix:
.
wq
EOF
done
  1. Sourced documents: Better for recurring batch edits. Similar to nvim -S
fd -a subs_ -x ex < change_font
fd -a subs_ -x nvim -Nes < change_font

for f in *.html; do nvim -Nes "$f" < ex_commands; done
for f in "$(rg -l homu)"; do nvim -Nes "$f" < ex_commands; done

Best practices

Use -t file in fd, otherwise ex may stop when it hits a directory

Unless you're really confident, always use files to store commands, then first try them out on copies of files you'd like to edit. It's often hard to debug an edit in advance and there's no undo

Batch editing manually

This isn't really a batch edit... though it's worth mentioning

fd -t file . -X rg --files-with-matches 'ex:' | xargs -o vim