💾 Archived View for thrig.me › blog › 2023 › 05 › 13 › vi-backwards-search-bug.gmi captured on 2024-05-26 at 15:22:59. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-11-14)
-=-=-=-=-=-=-
The OpenBSD vi†has a bug that prevents a backwards search for "?"—but only with "extended" regular expressions enabled—as "?" is special to both the command (which uses the delimiter "?" to indicate a backwards search) and to extended regular expressions (which use the "?" to indicate that the previous portion of the expression is optional. The command "??" indicates that the previous regular expression should be used, but the command "?\?" is an error because the search delimiter parser removes the "\" which leaves a search of "?" which is an invalid extended regular expression. After sleeping on this I figured that a search of "[?]" would also work; hiding characters in character classes also sees use to e.g. prevent a grep from seeing itself in the process table—but you probably instead want to use `pgrep foo` and not `ps ... | grep '[f]oo'`. Anyways the command "?[\?]" works; the internal "?" must be escaped to prevent the outer command delimiter search from yielding the invalid expression of "[".
Finding this was pretty fun, as many vi commands simply call into some ex function (with a "but this is vi, not ex!" flag set)‡, and from there eventually one may find common/search.c, and maybe add code to "do the (hopefully) right thing" with the input "?\?" when extended regular expressions are enabled. Or how often do you search backwards for a literal "?" in a file with extended regex? How old is this bug?
Other weird things found along the way:
It also helps if you can see what you are searching for, or to have the text formatted in a predictable way, which automatic code formatters may help with. For C functions I use the following form, formatted by way of the ex command ":,/^`/-1!clang-format"
int main(int argc, char *argv[]) { ; }
so that "/^main" can easily find the function name; this is somewhat more difficult if the function name is hiding somewhere after the return type on the same line. Probably one of these years I should learn ctags, but I have other ways to accomplish "show me what files contain this here extended regular expression in this directory tree (or git repository)" and from there can launch into vi with those files. The startup and shutdown time of vi is negligible, so it's easy to quit out to some other command or shell to find a new set of files. You do lose marks, as vi doesn't have a .viminfo to store those in across instances.
It may also help to have a command that can associate process table entries with the relevant tmux pane as the tty, if you forgot where exactly you were editing triangle.go from a few days ago. Implementing something like the "j" command (or finding the various implementations of it) is left as an exercise to the reader.
$ ps axo pid,tty,command | grep '[v]i' 55438 ttyp4 /usr/bin/perl /home/jmates/bin/blog-about vi-backwards-se 6533 ttyp4 vi -c5 /home/jmates/tmp/blog-about.4CnLWsa225.gmi 6463 ttypa vi triangle.go 54238 ttypb vi vi/v_search.c ex/ex_cmd.c common/search.c $ tmux list-windows '-aF#{pane_tty} #S:#I' /dev/ttyp7 ci:0 ... $ j PID TTY CMD 6463 pa:2 vi triangle.go 54238 re:1 vi vi/v_search.c ex/ex_cmd.c common/search.c 6533 re:0 vi -c5 /home/jmates/tmp/blog-about.4CnLWsa225.gmi $ grep votcana ~/.cwmrc bind-key 4-1 "xdotool search --name votcana-pa windowactivate" bind-key 4-2 "xdotool search --name votcana-re windowactivate" bind-key 4-3 "xdotool search --name votcana-ci windowactivate" bind-key 4-4 "xdotool search --name votcana-vo windowactivate" command votcana /home/jmates/libexec/votcana
tmux screen "pa" (the upper left xterm, clockwise to "re", "ci", and "vo") and window 2 thereof is a bit easier to get to than "where the heck is ttypa?" especially as the number of tmux screens and windows increases.
tags #vi #openbsd #ex
—
†Descended from "Version 1.79 (10/23/96) The CSRG, University of California, Berkeley" though modified since.
‡ Actually more complicated than described; vi sometimes injects a fake command into some system I haven't fully grokked and then...