Skip to content

MajorDallas/ajr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 

Repository files navigation

ajr

Another JQ REPL using FZF

Inspired by the tool Up and the jq-zsh-plugin, this is a simple attempt at making a "REPL" for jq using fzf. Strictly speaking, it's not a repl in the sense that the jq compiler is not evaluating code in a loop which it controls itself, as with eg. bash or Python, but technicalities aside, it behaves like a REPL.

One thing I found to be annoying about the other two tools is that, while you're typing in the jq query, the results of the previous query are erased. This could probably be addressed to some degree with some "debouncing" logic like in the official rg example. However, I also felt that there's an entire half-screen of empty space in fzf that's meant to hold lines of input data, ostensibly for matching. Why couldn't that space hold some useful information? Say, every single key in the document? Then, not only would exploring the contents of the document be that much easier, my goldfish brain would no longer hamper me by forgetting which key I was about to add to the query because it would always be right in front of me.

Implementation

The jq query is amazingly simple, considering it took over four hours to figure out:

def getkeys: [to_entries[] | {(.key): (.value | getkeys?) }];
getkeys

This simple, recursive function visits every key in a depth-first order, which is important for this application. The standard recursive descent operator in jq, the .. filter, is breadth-first. To illustrate the difference, given

{
  "top_key1": {
    "mid_key1": {
      "bottom_key1": 0
    },
    "mid_key2": {
      "bottom_key2": 1
    }
  },
  "top_key2": {
    "mid_key3": {
      "bottom_key3": 2
    },
    "mid_key4": {
      "bottom_key4": 3
    }
  }
}

We want this order, as it reflects the path we'll need for a query:

top_key1
mid_key1
bottom_key1
mid_key2
bottom_key2
top_key2
mid_key3
bottom_key3
mid_key4
bottom_key4

To get this order, the tree must be traversed depth-first. With .. and a breadth-first ordering, we instead get

top_key1
top_key2
mid_key1
mid_key2
mid_key3
mid_key4
bottom_key1
bottom_key2
bottom_key3
bottom_key4

which makes it hard to know if the query to get eg. bottom_key3 should be .top_key1.mid_key1.bottom_key3 or some other combination of intermediate keys.

okay, how do I use it?

Install jq and fzf, of course. Also, install yq (which is available from pip and many other package managers).

Then, add to your bashrc:

# Extract all keys recursively (depth-first) with jq from $1, pipe the resulting json
# to yq to get the slightly more compact yaml format, and finally pipe that into fzf,
# with fzf set to run new jq queries against $1.
# This keeps all the keys in view, even while typing a new query and the preview
# disappears.
# Pass '-y' as $1 and a yaml file instead of a json file :D
function jqrepl {
	if [[ $1 = '-y' ]]; then
		q='yq -y'
		mid='cat'
		shift
	else
		q='jq'
		mid='yq -y'
	fi
	$q 'def getkeys: [to_entries[] | {(.key): (.value | getkeys?) }]; getkeys' "$1" \
	| $mid	\
	| fzf	--disabled \
			--print-query \
			--preview "jq --color-output -r {q} $1"
}

As the docstring suggests, this also works with YAML documents thanks to yq--just pass -y as the first argument.

The result will look something like this: image

About

Another JQ REPL using FZF

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors