Update: I created jq-zsh-plugin that does this.
One of my favourite tools of my trade is jq. It essentially enables you to process json streams with the same power that sed, awk and grep provide you with for editing line-based formats (csv, tsv, etc.).
Another one of my favourite tools is fzf. Essentially it is just a command line fuzzy finder, that has some awesome interactive uses.
Now in this REPL case it's fuzzyness isn't particularly necessary, but lucky for me it also has an awesome preview functionality as well.
I took this idea from another blog post about turning simple commands into a live REPL
The full code is the following:
#!/usr/bin/env bash
if [[ -z $1 ]] || [[ $1 == "-" ]]; then
input=$(mktemp)
trap "rm -f $input" EXIT
cat /dev/stdin > $input
else
input=$1
fi
echo '' \
| fzf --phony \
--preview-window='up:90%' \
--print-query \
--preview "jq --color-output -r {q} $input"
Let's walk through what the script does.
if [[ -z $1 ]] || [[ $1 == "-" ]]; then
input=$(mktemp)
trap "rm -f $input" EXIT
cat /dev/stdin > $input
else
input=$1
fi
The first part is just input handling. If there is an argument, it assumes it's a json file to be fed to fzf.
If there is no argument, or the first argument is -
, then it assumes it needs
to cache the input coming from stdout. It caches the input into a temporary
file which it will delete on exit with a
trap statement.
fzf has a --preview
mode that runs a pre-defined command when you change your
query input. The --print-query
option will print out the query you wrote as
the first line once fzf quits.
echo '' | fzf --print-query --preview 'echo {q}'
Feeding fzf with an empty input will mean no fuzzy search can be done, but whatever input you feed it can be used in the preview window and it updates the preview whenever the query changes. This is where we will hoist our REPL onto.
echo '' | fzf --print-query --preview 'jq {q} input.json'
That's it, our REPL is done! I find this small form fascinating. Now what is still missing, that landed in the final script:
- parameterize the jq input with any file
- capture standard input, buffer it and use that as the jq input
- formating the preview window
All of the above is implemented in the first example code.
After I've writen this post I've also found this nice asciicast that shows a generalized fzf REPL idea in action.
Demo: https://asciinema.org/a/ZesX97hokd5VLuEXaeyjJV2Yy