I am trying to use jq
to find the layout of the currently active container in i3. i3-msg -t get_tree
returns a recursive structure of containers with .layout
and .focused
properties. The trick is that I don't want the .layout
of the container with .focused == true
, but the one of its parent node:
// partial output, this might be several `.nodes[]` down
{
"focused": false,
"layout": "splitv", // Return this
"nodes": [
{
"focused": true, // Find by this
"layout": "splith" // Don't return this
"nodes": []
}
]
}
I started off by recursive search from Recursive search values by key:
$ i3-msg -t get_tree | jq -r '.. | select(.focused?) | .layout'
splith
but that returns the wrong value as shown in example before. If jq
had a hypothetical parent()
function, I would do something like .. | select(.focused?) | parent().parent().layout
to get from the current level to .nodes[]
and then once more to the parent container.
I then tried to follow How do I print a parent value of an object when I am already deep into the object's children?, but I am running into some errors that I believe are caused by ..
operator iterating over non-dict objects:
$ i3-msg -t get_tree | jq -r '.. | select(.nodes[] | select(.focused?)) | .layout'
jq: error (at <stdin>:1): Cannot index number with string "nodes"
$ i3-msg -t get_tree | jq -r '.. | select(.nodes[]? | select(.focused?)) | .layout'
jq: error (at <stdin>:1): Cannot index number with string "nodes"
$ i3-msg -t get_tree | jq -r '.. | select(.nodes?[] | select(.focused?)) | .layout'
jq: error (at <stdin>:1): Cannot iterate over null (null)
$ i3-msg -t get_tree | jq -r '.. | select(.nodes? | select(.focused?)) | .layout'
# no output
Here is a gist with my dump of i3-msg -t get_tree
for anyone who would like to have a go without installing i3.
Instead of selecting an item from whose context .focused
might evaluate to true
, select an item under which .nodes
might be an array, and in any
(i.e. at least one) of which's children's contexts .focused
might evaluate to true
:
.. | select(.nodes | any(.focused))?.layout
To avoid the "might" circumstances along with the error suppression operator ?
, check for arrays
and objects
explicitly. Under the latter, any key is either defined or evaluates to (a "falsey") null
if missing:
.. | objects | select(.nodes | arrays | any(objects.focused)).layout
To get the whole parent, just remove the final .layout
.