-module(i3_client_trees). -moduledoc """ Functions for processing i3 layout trees. All functions assume they receive the whole tree, as returned by `i3_client:get_tree/1,2`. """. -export([table/1, table/2]). -include_lib("stdlib/include/qlc.hrl"). -doc """ Equivalent to [`table(Tree, dfs)`](`table/2`). """. -spec table(Table) -> QueryHandle when Table :: map(), QueryHandle :: qlc:query_handle(). table(Tree) -> table(Tree, dfs). -doc """ Returns a Query List Comprehension (QLC) query handle. The `m:qlc` module provides a query language, very similar to list comprehensions, which allows iterator style traversal of data structures. Calling `table/1,2` is the means to make the i3 tree `Tree` usable to QLC. The `Algo` argument can be either `dfs` or `bfs` which stand for depth-first and breadth-first traversal respectively. Usually, depth-first traversal is preferred so it's the default when calling `table/1`. _Examples:_ An example query for the focused node: ```erlang 0> {ok, Pid} = i3_client:start_link([]), 1> {ok, Tree} = i3_client:get_tree(Pid), 2> QH = qlc:q([Node || #{~"focused" := true} = Node <- i3_client_trees:table(Tree)]). 3> [#{~"focused" := true}] = qlc:eval(QH) ``` > #### Info {: .info } > It is necessary to add the following line to the source code: > ``` > -include_lib("stdlib/include/qlc.hrl"). > ``` """. -spec table(Table, Algo) -> QueryHandle when Table :: map(), Algo :: dfs | bfs, QueryHandle :: qlc:query_handle(). table(Tree, Algo) when (Algo =:= dfs) or (Algo =:= bfs) -> TraverseFun = fun() -> next([[Tree]], Algo) end, qlc:table(TraverseFun, []). next([], _) -> []; next([[] | Rest], Algo) -> next(Rest, Algo); next([[Node | Siblings] | Rest], dfs = Algo) -> #{~"nodes" := Nodes, ~"floating_nodes" := FloatingNodes} = Node, [Node | fun() -> next([Nodes, FloatingNodes, Siblings | Rest], Algo) end]; next([[Node | Siblings] | Rest], bfs = Algo) -> #{~"nodes" := Nodes, ~"floating_nodes" := FloatingNodes} = Node, [Node | fun() -> next([Siblings, Nodes, FloatingNodes | Rest], Algo) end].