Denote query links: rejecting regexps with doubled backslashes
- YT :: https://www.youtube.com/watch?v=VgL7usTlpsc
- Original title :: Emacs: refinements for Denote and testing
A spontaneous live stream in which Prot handles a Denote edge case from issue 733. A user copied a regexp from re-builder, which uses Lisp string syntax with doubled backslashes, into a query link prompt, and it matched nothing. Every Emacs minibuffer reader escapes backslashes again, so \\( typed at a prompt becomes four backslashes internally. Prot explores a silent "do what I mean" fix that strips the extra backslashes, rejects it as too clever and a source of inconsistency, and instead adds a predicate that signals an error. He wires it into all query-link commands, writes ERT tests, tests interactively and commits. He then checks a suspected bug in an autoloaded Denote global minor mode, which turns out to be fine. Chat covers rx, SQL tooling, Guix/Nix, Kakoune and meow, Emacs versus the Unix philosophy, PipeWire audio, OpenBSD and his Doric themes.
Query links recap
- Query links point to a search, not a file.
denote-query-filenames-linkopens a real Dired buffer of files whose names match the regexp.denote-query-contents-linkopens a standard Xref buffer of grep matches. Both differ from a directdenote-linkto one file. - The link stores the
denote:type, a query specifier, the query and a description. - The prompt comes from a macro that uses
completing-readover history orread-string. - With Vertico,
M-RETsubmits the literal input instead of the selected candidate. Forgetting this caused a few false alarms during the stream.
The backslash problem
re-builderexpects Lisp syntax, so one regexp escape is written as two backslashes. Interactive prompts expect a single backslash and escape it internally.- Pasting re-builder output into a prompt therefore produces a broken regexp with doubled escapes.
- Prot tries
read-string,read-regexp,read-from-minibuffer,read-minibufferandcompleting-read. All behave the same, so no built-in "read it literally" option exists. A chat suggestion thatformatwas to blame does not matter, since he will not advise something this fundamental.
Rejected approach: silently fix the input
replace-regexp-in-stringcan strip the extra backslashes, but the regexp needed to match backslashes is "borderline silly" and raises invalid-replacement errors.- A neat wrapper (
denote-prompt-with-args:applythe reader, thenthread-lastthe result through a cleanup) works for bothread-stringandcompleting-read. - He drops it because packages built on Denote that call the plain readers would behave differently, and that inconsistency is asking for trouble.
consult-denoteturns out not to use them, but third parties might. He prefers to teach the user with an error rather than be "too smart".
Detecting extra backslashes
- Failed attempts:
string-match-p,string-searchandsplit-stringon a single backslash all fight the escaping rules. Character classes do not help either. seq-countwith(eq c ?\\)(char 92) counts literal backslashes correctly, but only for trivial strings.- Working approach:
split-stringat the regexp constructs (parens, pipe) with omit-nulls, thenseq-someover the pieces to find one with two backslashes before a construct. - New functions:
denote-extra-backslashes-p: its docstring explains that the regexp is valid in Lisp calls but escaped again byread-stringand friends.denote-extra-backslashes-with-error: returns the string or signals"String has extra backslashes".- Called in the
interactivespec ofdenote-query-contents-link,denote-query-filenames-link,denote-link-to-file-with-contentsanddenote-link-to-all-files-with-contents(plus its alias). - Chat asked whether valid escapes like
a\nbare affected. They pass through untouched. A doubled backslash beforenalso passes, because it legitimately means a literal backslash-n. - On Windows-style
\\serverpaths, Emacs uses forward slashes internally anyway. He jokes that the real fix is a link to a Linux distro.
Tests and commit
ert-deftestcases cover the predicate with several should and should-not permutations. A keyboard macro builds theshould-errorcases for the erroring variant.- A linter warning insisted the error message start with a capital letter. He complied, puzzled.
- Interactive checks of all four commands show the error on doubled input and correct links on single-backslash input.
- Commit: "Error on query link input with extra backslashes", referencing issue 733 and the stream. He may extend it to all prompts later.
- Aside: he avoids
pareditbecause he often leaves parens open while editing elsewhere.
Autoloaded minor mode check
- An autoloaded Denote global minor mode can run before
denoteis required. It usessetqto store the original value of a variable when enabled. - He suspected the stored value was wrong. After restarting Emacs and trying a plain call and
with-eval-after-load, the value is correct. - Capturing it at enable time rather than in the
defvaris deliberate, so the user's customised value is kept rather than the package default.
Chat topics
- He never learned
rx: regexp flavours are messy enough without another one. - SQL users leaving PyCharm/DataGrip: no need to switch if it works. Adopt Emacs piecemeal for Org, other languages and mail, and keep the old tool for that one job. He knows no specific replacement.
- Denote bugs: GitHub issues are fine and visible to others; private email works too.
- Audio static: a few-line PipeWire config in his stow-managed dotfiles (committed on the 28th, Debian 13 specific) appears to have fixed it.
- Guix/Nix: impressive and robust.
guix shellgives disposable dev environments, and reproducibility pays off across many machines. As a single-machine Elisp coder he has no use case, but would pick Guix (Lisp, GNU, GPL). FHS non-compliance means doing things "the Guix way". - Kakoune and meow: good editors in the Unix spirit. Emacs is not better at text editing as such. Its strength is one uniform Elisp environment, so a function works across mail, RSS, agenda and code. Making Vim, tmux, Neomutt and Newsboat share a theme script taught him how hard cross-tool consistency is.
- OpenBSD tempts him, but he keeps postponing it.
- Theme on screen: Doric Lilac from
doric-themes, his minimalist few-colour set. He also usesspacious-paddingbut disables it on stream for clearer window borders. - Light banter: Greek coffee versus Vim users and Brazilian coffee, Balkan hot-headedness, and a Lithuanian ex-roommate.