escape code

Revisiting array-to-quote

joepd, 15 April 2014

Computing professionals are in some way similar to athletes and musicians: Continued practicing sessions makes them better at what they do. Interestingly, it seems that there is not so much a culture of inconsequential coding sessions to sharpen your skills. Dave Thomas practices what he preaches with Code kata's.

The nice part about repetitive tasks, is that there is a reason to automate 'em. And when the automated solution starts to feel like a drag, it's time to improve the solution. Repetitive tasks lend themselves very well to katas. You probably know the corner cases, and have some ideas of what would suit your work flow. Continued study of the mechanics of simple manipulations really can get you forward. As an addition to the metaphor of kata's, I'd like to propose to think about the wood worker sharpening his tools.

That was more than enough meta for an introduction to pretty down-to-earth stuff. As I regularly have to shape one output in a quoted, comma separated list, I came to revisit the solution posted in my first post. This time, I set myself to make a keyboard shortcut that operates on the closest word to the cursor in a terminal running zsh.

Just drop this part in your ~/.zshrc, and you should have that short moment of gratification when it seems that the computer is obeying your will at the gentlest of gestures:

array-to-quote() {
    autoload -U modify-current-argument
    modify-current-argument '$(
        if [[ ${(Pt)ARG} = "array" ]]; then
            print ${(j., .)${(qq)${(P)ARG}}}
        elif [[ -r $ARG ]]; then
            print ${(j., .)${(qq)${(f)"$(<$ARG)"}}}
        else
            print ${(qq)ARG}
        fi
    )'
}
zle -N array-to-quote
# Terminal: Stop stealing CTRL-q and CTRL-s!
stty start '^-' stop '^-'
bindkey "^q" array-to-quote

If you copy-paste this into your zsh, and press CTRL-q, the word under your cursor will become quoted. If that word happens to be a file, the lines of that file will appear as a quoted list. If the word i an array, the elements are added nicely quoted and comma separated. Nice huh?

So, what is actually happening in these few lines?

First, a function is defined, that uses a function usually distributed with zsh: modify-current-argument. This function takes a function as an argument, and as a bonus, this function can use the variable $ARG: the word under or left of the cursor. Have a look at man zshcontrib for a complete description.

The function that modify-current-argument calls, make use of parameter expansion flags, and you should be able to follow along after reading my earlier post on the topic.

Now we have a function that takes the word under the cursor as an argument. This we need to have as a keyboard shortcut. zle -N function-name does the first part: It makes the function function-name availabe as a command line editing widget. This widget is in turn bound to CTRL q with the bindkey statement. There happened to be something special about CTRL-Q: I needed to tell the terminal driver to not listen to a functionality that I have never knowingly used with the stty-command. Please tell me if I miss out on cool stuff...

But wait a sec. There is this other thing that I regularly do: To make a regular expression from some kind of list. This is what does that trick, and binds it under CTRL \:

array-to-pipe() {
    autoload -U modify-current-argument
    modify-current-argument '$(
        if [[ ${(Pt)ARG} = "array" ]]; then
            print ${(j.|.)${(P)ARG}}
        elif [[ -r $ARG ]]; then
            print ${(j.|.)${(f)"$(<$ARG)"}}
        else
            print ${ARG}
        fi
    )'
}
zle -N array-to-pipe
bindkey '^\' array-to-pipe

Keep sharpening your knives :)