Idiomdrottning’s homepage

Shell scripting with completing-read

Here’s a li’l completing-read that asks you to select one line from all the lines piped into it, and pipes that one line out. So you can use it in the middle of pipes, it doesn’t have to be at the end.

The smart thing is that if you’re in Emacs, like in shell-mode for example, it uses Emacs’ completing-read (which you hopefully have souped up with vertico or the like), and if you’re outside of Emacs in another terminal, it just passes it on to gum choose.

It has a ton of dependencies as per usual with these small anti-NIH hacks where I don’t wanna reinvent a ton of wheels:

Note that you can call it from any shell, not just zsh. That’s how zshbrev works: it can run zsh commands, aliases, and sourced shell functions in brev, which is why it needs zsh installed, but then the commands defined in zshbrev work in any shell. Even bash.

Here is the zshbrev function:

(zsh-import (stdout gum) (sexp emacsclient))

(define (completing-read)
  (cond ((get-environment-variable "INSIDE_EMACS")
         (emacsclient
          '-e
          (with-output-to-string
            (fn (pp `(completing-read "Please select: " ',(read-lines)))))))
        ((string=? "dumb" (get-environment-variable "TERM"))
         ;; not sure how to handle dumb terms here,
         ;; maybe I should just shuf -n 1? or head -1? or print all the lines?
         ;; for now just error out
         (niy))
        (else (gum 'choose) (void))))

Put that in .zshbrev/functions.scm, then run zshbrev, and there you have it.