(import json)
(defn item-with-id [id items]
(find |(= ($ "id") id) items))
(defn contains? [id node]
(if (= node :null)
false
(or (= (node "id") id)
(contains? id (node "firstChild"))
(contains? id (node "secondChild")))))
(defn partition-on-focused [focused-id {"firstChild" node-a "secondChild" node-b}]
(if (contains? focused-id node-a)
[node-a node-b]
[node-b node-a]))
(defn count-hidden [node]
(match node
:null 0
{"hidden" true} 1
{"firstChild" node-a "secondChild" node-b} (+ (count-hidden node-a)
(count-hidden node-b))))
(defn collect-hidden [node]
(def hidden @[])
(defn put-hidden [node]
(match node
:null nil
{"hidden" true} (array/push hidden node)
{"firstChild" node-a "secondChild" node-b} (do
(put-hidden node-a)
(put-hidden node-b))))
(put-hidden node)
hidden)
(defn fully-unhidden
"Gets the first node with all children unhidden"
[node]
(match node
:null nil
{"firstChild" {"hidden" false} "secondChild" {"hidden" false}} node
{"firstChild" {"hidden" true} "secondChild" second} (fully-unhidden second)
{"firstChild" first "secondChild" {"hidden" true}} (fully-unhidden first)))
(defn innermost-hidden [focused-id node]
(match node
:null nil
{"hidden" true} node
_ (let [[focused not-focused] (partition-on-focused focused-id node)]
(or (innermost-hidden focused-id focused)
(innermost-hidden focused-id not-focused)))))
(defn rotate-clockwise []
(os/execute ["bspc" "node" "@/" "--rotate" "90"] :p))
(defn rotate-counterclockwise []
(os/execute ["bspc" "node" "@/" "--rotate" "-90"] :p))
(defn toggle-hidden [node]
(os/execute ["bspc" "node" (string (node "id")) "--flag" "hidden"] :p))
(defn get-state []
(with [pipe (os/spawn ["bspc" "wm" "-d"] :p {:out :pipe})]
(:read (pipe :out) :all)))
(defn current-desktop []
(let [data (get-state)
state (json/decode data)
monitor (item-with-id (state "focusedMonitorId") (state "monitors"))]
(item-with-id (monitor "focusedDesktopId") (monitor "desktops"))))
(defn zoom-in []
(let [desktop (current-desktop)
unhidden (fully-unhidden (desktop "root"))
focused-id (desktop "focusedNodeId")]
(match unhidden
nil (print "Não há mais nós para esconder")
{"firstChild" :null "secondChild" :null} (toggle-hidden unhidden)
_ (let [[_ not-focused] (partition-on-focused focused-id unhidden)]
(toggle-hidden not-focused)
(rotate-counterclockwise)))))
(defn zoom-out []
(let [desktop (current-desktop)
node (innermost-hidden (desktop "focusedNodeId") (desktop "root"))]
(when node
(rotate-clockwise)
(toggle-hidden node))))
(defn zoom-level []
(let [desktop (current-desktop)]
(print (count-hidden (desktop "root")))))
(defn level-zero []
(let [desktop (current-desktop)]
(each node (collect-hidden (desktop "root"))
(rotate-clockwise)
(toggle-hidden node))))
(defn main [& args]
(if (= 1 (length args))
(print "Que comando você quer executar? `in` ou `out`?")
(match (args 1)
"in" (zoom-in)
"out" (zoom-out)
"zoom-level" (zoom-level)
"level-zero" (level-zero)
command (print "Comando não reconhecido: " command))))