💾 Archived View for thrig.me › tech › ex.gmi captured on 2023-07-22 at 17:37:27. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-05-24)
-=-=-=-=-=-=-
Various ex commands may have escaped the notice of the reader. For instance, the
:e filename
command to edit a file has variations, including
:e!
to revert to the saved version of the file, also known as %, or
:e#
to edit the alternate filename. This can be useful when flipping between two files,
$ touch a b $ vi a :e b :e#
control+^ was for some reason bound to the switch-to-alternate-file
command in vi, probably due to frequent file flips.
The current filename % may once have been useful to create a backup file
:w %.orig
though these days this may be better handled with version control
:w! :!git stash :e!
and then to restore from the "backup"
:!git stash apply :e!
The current file % is useful in various "bang" or ! commands
:!TROFFMACS=tmac. nroff -Tlocale -e -h -mt % | less
this line and the following blank line (the extra newline is of use) can be saved to the buffer "t" with
"t2yy
and then the contents of the buffer "t" can be executed with
@t
which sends the contents of the current file to nroff and from there to less. The extra blank link in the buffer will clear the ex prompt "Press any key to continue" after less is exited. Use @@ to repeat the previous named buffer execution.
In my own flavor of vi, I added an ex command, buffer, that puts the given text into the named buffer; this avoids the step of having to write the commands out then yank them. On the other hand, a scratch file with various snippets might be good to have.
It may be useful to enable the autowrite option; this will help make changes available to external commands. On the other hand, this could remove the ability to revert changes with :e!. Another way would be to capture the three line construct
:w! :!TROFFMACS=tmac. nroff -Tlocale -e -h -mt % | less
with "t3yy. In my version of vi, autowrite happens in many more cases, as I usually want the bits on disk, and do not want needless prompts about whether I am sure I want to save something. Prompts and such interruptions are generally the sign of a bad user interface (see: Windows, or the modern web).
The above is not the only way to preview a file; unix is the IDE, so in another terminal one might run
$ echo file.roff | entr sh -c 'make file.pdf && mopen file.pdf'
This can also be done in vi,
:!make file.pdf && mopen file.pdf
though here we lose the ability to use % unless we invent some command that given file.roff does the right thing with it,
#!/usr/bin/env tclsh8.6 set pdf [file rootname [lindex $argv 0]].pdf if {[catch {exec make $pdf} e]} {puts stderr $e; exit 1} exec mopen $pdf
or something like that, perhaps with more error checking and support for more input types. Some have argued that entr(1) should be provided by the operating system, and that it might be nice to have that interface portable across various OS, but I pretty much only use OpenBSD these days, so...
Yet another way would be to pipe the contents as a filter; this requires a tee(1) or equivalent if the contents must not change. This is less efficient than using a file directly. copycat(1) is what I use to tee the contents of a buffer into a clipboard and also back into vi. Unlike the vim X11 clipboard integration, this works in vi, on the command line, or even in emacs, god forbid.
The grep(1) command is named after an ed(1) command pattern--global, regular expression, print. Other names are possible, for instance grid that "gets rid of" lines
$ printf 'a\nx\ne\ny\n' > xxx $ ex xxx xxx: unmodified: line 4 :g/[aeiou]/d :%p x y :put e :%p x y e :wq xxx: 3 lines, 6 characters
The global command only preserves the last line deleted in the default put buffer; at times one may want to both delete and collect all matching lines. Upper case letters append to a buffer, so
$ printf 'a\nx\ne\ny\n' > xxx $ ex xxx xxx: unmodified: line 4 :g/[aeiou]/d Y :put y a :%p x y a e :q!
we have deleted all lines containing vowels into the buffer "y" then put them at the end of the file. This pattern could perhaps be called greedY. In vi one could also use "yp to put the lines. The :display buffer command--with less typing just :di bu--shows what is in what buffer, helpful to review before @x causes something inappropriate to be treated as a series of vi commands.
A warning regarding ex commands:
The syntax of the ex commands is unbelievable irregular, and a special case from beginning to end. Each command has an associated "syntax script" which describes the "arguments" that are possible. The script syntax is as follows ... -- /usr/src/usr.bin/vi/ex/ex_cmd.c on OpenBSD
Chains of commands use context; "UNIX Text Processing" (O'Reilly, 1987) shows how to delete trailing blanks, here modified to apply to all whitespace.
:set extended :g/[[:space:]]+$/s///
That is, match infinity to 1 whitespace characters at line's end; the empty first argument to s uses those matches and replaces them with the nothing of the second argument to s. re_format(7) details the extended syntax. This context shows up in other languages, though may be surprising if used at distance from the associated match or if the first argument to s/// turns out to be empty:
$ perl -E '$_ = q/cat/; /c/; s//b/; say' bat
A different way to remove trailing whitespace is
:%s/[[:space:]]+$//
In this context % is shorthand for the range 1,$ or what the global command operates on.
You can sometimes omit a portion of the range, in which case it will be assumed to be the current line. So
:.,$cat
and
:,$cat
are equivalent (from the current line to the end of the file ...). Ranges can be combined with offsets, so while perhaps not readable the following searches backwards for the first line that begins with ```, then from the next line below that in the file to the current line indents those lines by one level. Maybe you can think of a use for this?
:?^```?+1,>
tags #vi #ex