]> git.lizzy.rs Git - bspwm.git/blob - contrib/zsh_completion
4e9948ded2d86ae7c5c78d0c8685118693f98d87
[bspwm.git] / contrib / zsh_completion
1 #compdef bspc
2
3 _bspc_selector() {
4         [[ ${@[(r)--]} = '--' ]] && shift ${@[(i)--]}
5         local -a completions=() completions_display=()
6         local index=0 name id sel_type="$1"
7         shift 1
8         case $sel_type in
9                 (node) compset -P '*[#.:/@]' ;;
10                 (desktop) compset -P '*[#.:]' ;;
11                 (monitor) compset -P '*[#.]' ;;
12                 (*) return 1 ;;
13         esac
14         case "$sel_type $IPREFIX" in
15                 (desktop*:)
16                         local ipfx=${${IPREFIX##*@}%:}
17                         while do
18                                 if completions=("${(@f)$(bspc query --names -D -m ${ipfx} 2> /dev/null)}") ;then
19                                         until ((++index > $#completions)) do
20                                                 completions[index]="^${index}:${completions[index]}"
21                                         done
22                                         completions+='focused'
23                                         _describe "${sel_type} selector" completions $@ -S '' -J ${sel_type}
24                                         break
25                                 else
26                                         completions=()
27                                         [ -n "$ipfx[(r)#]" ] &&
28                                                 ipfx="${ipfx#*#}" ||
29                                                 break
30                                 fi
31                         done
32                         ;|
33                 (node*[^@/:.])
34                         bspc query -N -n .window 2> /dev/null |
35                                 while read id ;do
36                                         id=${id//:/\\:}
37                                         if which xdotool &> /dev/null ;then
38                                                 name=$(xdotool getwindowname $id 2> /dev/null)
39                                         elif which xprop &> /dev/null ;then
40                                                 name=$(xprop -id $id -notype WM_NAME 2> /dev/null) &&
41                                                         [[ "$name" = 'WM_NAME ='* ]] &&
42                                                         name="${${name#*\"}%\"*}" ||
43                                                         name=""
44                                         else
45                                                 name="install xdotool or xprop to see window titles here"
46                                         fi
47                                         completions+="$id:$name"
48                                 done
49                         ;|
50                 ((desktop|monitor)*[^:.])
51                         local max_name_len=0 max_index_len i
52                         local -a snames names ids
53                         bspc query -${(U)sel_type[1]} 2> /dev/null |
54                                 while read id ;do
55                                         ((index++))
56                                         name=$(bspc query --names -${(U)sel_type[1]} -${sel_type[1]} $id 2> /dev/null)
57                                         [[ "$name" == *[:.!]* ]] &&
58                                                 sel_name="%${name//:/\\:}" ||
59                                                 sel_name="$name"
60                                         ((max_name_len = $#sel_name > max_name_len ? $#sel_name : max_name_len))
61                                         ids+="${id}"
62                                         snames+="${sel_name}"
63                                         names+="${name}"
64                                 done
65                                 max_index_len=$(($#index + 1))
66                                 ((max_name_len >= max_name_len)) && ((max_name_len=max_name_len + 1))
67                                 for ((i = 1 ; i <= $#ids ; i++)) ;do
68                                         (($#ids[i] <= max_name_len)) &&
69                                                 completions_display+="${(r($max_name_len+1))ids[i]}:${names[i]}" ||
70                                                 completions_display+="${ids[i]}:${names[i]}"
71                                         completions+="${ids[i]}:${names[i]}"
72                                 done
73                                 for ((i = 1 ; i <= $#ids ; i++)) ;do
74                                         completions+="${snames[i]}:${names[i]}"
75                                         completions_display+="${(r($max_name_len))snames[i]}:${names[i]}"
76                                 done
77                                 for ((i = 1 ; i <= $#ids ; i++)) ;do
78                                         completions+="^${i}:${names[i]}"
79                                         completions_display+="^${i}:${names[i]}"
80                                 done
81                         ;|
82                 (node*('@'(*':'|*'/'|)))
83                         _describe 'node path' jump -S '/' -r "#. ${quote}" -J nodes
84                         ;|
85                 (node*'/')
86                         ;;
87                 (*'.')
88                         _bspc_prefix '!' "${sel_type} modifiers" ${sel_type}_mod $@ -J ${sel_type}_mod
89                         ;|
90                 ((desktop|monitor)*@)
91                         ;&
92                 (*[^:.@/])
93                         if (( $#completions_display)) ;then
94                         _describe "${sel_type} selector" ${sel_type}_desc $@ -S '.' -r ". \n:#${quote}\-" -J ${sel_type} \
95                                 -- completions_display completions $@ -S '.' -r ". \n:#${quote}\-" -J ${sel_type}
96                         else
97                         _describe "${sel_type} selector" ${sel_type}_desc $@ -S '.' -r ". \n:#${quote}\-" -J ${sel_type} \
98                                 -- completions $@ -S '.' -r ". \n:#${quote}\-" -J ${sel_type}
99                         fi
100                         ;|
101                 (node*@*'#'*)
102                         ;;
103                 (node*@*)
104                         _bspc_selector desktop -S ':' -qr ".#\-\n ${quote}"
105                         ;;
106                 (desktop*)
107                         _bspc_selector monitor -S ':' -r ".#\-\n ${quote}"
108                         ;;
109         esac
110 }
111
112 _bspc_prefix(){
113         [[ ${@[(r)--]} = '--' ]] && shift ${@[(i)--]}
114         [[ "$PREFIX[1]" == "$1" ]] &&
115                 local a="-n" b ||
116                 local b="-n" a
117         _describe $@[2,-1] $a -- $@[3,-1] $b -p "$1"
118 }
119
120 _bspc_query_names() {
121         [[ ${@[(r)--]} = '--' ]] && shift ${@[(i)--]}
122         local -a items=("${(@f)$(bspc query $2 --names 2> /dev/null)}") ||
123                 return
124         local c
125         for c in '\' ':' '[' '(' '*'
126                 items=("${(@)items//$c/\\$c}")
127         _values -w  "$1" "${items[@]}"
128 }
129
130 _bspc() {
131         local -a commands=(node desktop monitor query rule wm subscribe config quit) \
132                 resize_handle=(top bottom top_left top_right bottom_left bottom_right left right) \
133                 node_state=(tiled pseudo_tiled floating fullscreen) \
134                 flag=(hidden sticky private locked marked urgent) \
135                 layer=(below normal above) \
136                 dir=(north west south east) \
137                 cycle_dir=(next prev)
138         local -a jump=($dir first second brother parent 1 2) \
139                 node_desc=($dir $cycle_dir any last newest older newer focused pointed biggest smallest) \
140                 node_mod=($node_state $flag $layer focused automatic local \
141                 active leaf window same_class descendant_of ancestor_of) \
142                 desktop_desc=($cycle_dir any last newest older newer focused) \
143                 desktop_mod=(focused occupied local urgent) \
144                 monitor_desc=($dir $cycle_dir any last newest older newer focused pointed primary) \
145                 monitor_mod=(focused occupied) \
146                 presel_dir=($dir cancel)
147         local quote="${compstate[quote]}" context state state_descr line
148         typeset -A opt_args
149
150         compset -n 2
151         compset -S "${quote}"
152
153         if ((CURRENT==1)) ;then
154                 _describe 'command or domain' commands
155                 return
156         fi
157
158         case $words[1] in
159                 (node)
160                         ((CURRENT==2)) && _bspc_selector node
161                         ((CURRENT>2)) && [[ "$words[2]" != '-'* ]] && compset -n 2
162                         ((CURRENT>2)) && [[ "$words[CURRENT-2]" =~ "^-(m|d|n|s|-to-(monitor|desktop|node)|-swap)$" ]] &&
163                                 _values 'option' '--follow[If passed, the focused node will stay focused]'
164                         _arguments -C \
165                                 '*'{-a,--activate}'[Activate the selected or given node]::node selector:_bspc_selector -- node'\
166                                 '*'{-B,--balance}'[Adjust the split ratios of the tree rooted at the selected node so that all windows occupy the same area]'\
167                                 '*'{-C,--circulate}'[Circulate the windows of the tree rooted at the selected node]:direction:(forward backward)'\
168                                 '*'{-c,--close}'[Close the windows rooted at the selected node]'\
169                                 '*'{-d,--to-desktop}'[Send the selected node to the given desktop]:desktop selector:_bspc_selector -- desktop'\
170                                 '*'{-E,--equalize}'[Reset the split ratios of the tree rooted at the selected node to their default value]'\
171                                 '*'{-F,--flip}'[Flip the the tree rooted at selected node]: :(horizontal vertical)'\
172                                 '*'{-f,--focus}'[Focus the selected or given node]::node selector:_bspc_selector -- node'\
173                                 '*'{-g,--flag}'[Set or toggle the given flag for the selected node]: :-> flag'\
174                                 '*'{-i,--insert-receptacle}'[Insert a receptacle node at the selected node]'\
175                                 '*'{-k,--kill}'[Kill the windows rooted at the selected node]'\
176                                 '*'{-l,--layer}"[Set the stacking layer of the selected window]:stacking layer:($layer)"\
177                                 '*'{-m,--to-monitor}'[Send the selected node to the given monitor]:monitor selector:_bspc_selector -- monitor'\
178                                 '*'{-n,--to-node}'[Transplant the selected node to the given node]:node selector:_bspc_selector -- node'\
179                                 '*'{-o,--presel-ratio}'[Set the splitting ratio of the preselection area]:preselect ratio: ( )'\
180                                 '*'{-p,--presel-dir}'[Preselect the splitting area of the selected node or cancel the preselection]: :_bspc_prefix -- "~" preselect presel_dir'\
181                                 '*'{-r,--ratio}'[Set the splitting ratio of the selected node (0 < ratio < 1)]: :( )'\
182                                 '*'{-R,--rotate}'[Rotate the tree rooted at the selected node]:angle:(90 270 180)'\
183                                 '*'{-s,--swap}'[Swap the selected node with the given node]:node selector:_bspc_selector -- node'\
184                                 '*'{-t,--state}'[Set the state of the selected window]: :_bspc_prefix -- "~" "node state" node_state '\
185                                 '*'{-v,--move}'[Move the selected window by dx pixels horizontally and dy pixels vertically]:dx:( ):dy:( )'\
186                                 '*'{-z,--resize}"[Resize the selected window by moving the given handle by dx pixels horizontally and dy pixels vertically]:handle:($resize_handle):dx:( ):dy:( )"
187                         [ "$state" = flag ] && _values 'flag' "${flag[@]:#urgent}::set flag:(on off)"
188                         ;;
189                 (desktop)
190                         ((CURRENT==2)) && _bspc_selector desktop
191                         ((CURRENT>2)) && [[ "$words[2]" != '-'* ]] && compset -n 2
192                         ((CURRENT>2)) && [[ "$words[CURRENT-2]" =~ "^-m|-s|--monitor|--swap$" ]] &&
193                                 _values 'option' '--follow[If passed, the focused desktop will stay focused]'
194                         _arguments \
195                                 '*'{-a,--activate}'[Activate the selected or given desktop]:: :_bspc_selector -- desktop'\
196                                 '*'{-b,--bubble}"[Bubble the selected desktop in the given direction]:direction:($cycle_dir)"\
197                                 '*'{-f,--focus}'[Focus the selected or given desktop]:: :_bspc_selector -- desktop'\
198                                 '*'{-l,--layout}"[Set or cycle the layout of the selected desktop]:desktop layout:($cycle_dir monocle tiled)"\
199                                 '*'{-m,--to-monitor}'[Send the selected desktop to the given monitor]: :_bspc_selector -- monitor'\
200                                 '*'{-n,--rename}'[Rename the selected desktop]:desktop name:( )'\
201                                 '*'{-r,--remove}'[Remove the selected desktop]'\
202                                 '*'{-s,--swap}'[Swap the selected desktop with the given desktop]: :_bspc_selector -- desktop'
203                         ;;
204                 (monitor)
205                         ((CURRENT==2)) && _bspc_selector monitor
206                         ((CURRENT>2)) && [[ "$words[2]" != '-'* ]] && compset -n 2
207                         _arguments \
208                                 '*'{-a,--add-desktops}'[Create desktops with the given names in the selected monitor]:*:add desktops:( )'\
209                                 '*'{-d,--reset-desktops}'[Rename, add or remove desktops]:*: :->desktops'\
210                                 '*'{-f,--focus}'[Focus the selected or given monitor]:: :_bspc_selector -- monitor'\
211                                 '*'{-g,--rectangle}'[Set the rectangle of the selected monitor]:WxH+X+Y:( )'\
212                                 '*'{-n,--rename}'[Rename the selected monitor]: :( )'\
213                                 '*'{-o,--reorder-desktops}'[Reorder the desktops of the selected monitor]:*:reorder desktops:_bspc_query_names -- desktops -D'\
214                                 '*'{-r,--remove}'[Remove the selected monitor]'\
215                                 '*'{-s,--swap}'[Swap the selected monitor with the given monitor]: :_bspc_selector -- monitor'
216                         ;;
217                 (query)
218                         local -a cmds_no_names=('-T' '--tree' '-N' '--nodes')
219                         local -a cmds=($cmds_no_names '-D' '--desktops' '-M' '--monitors')
220                         _arguments \
221                                 '*'{-d,--desktop}'[Constrain matches to the selected desktop]: :_bspc_selector -- desktop'\
222                                 '*'{-m,--monitor}'[Constrain matches to the selected monitor]: :_bspc_selector -- monitor'\
223                                 '*'{-n,--node}'[Constrain matches to the selected node]: :_bspc_selector -- node'\
224                                 "($cmds_no_names --names)--names[Print names instead of IDs. Can only be used with -M and -D]"\
225                                 "($cmds --names)"{-N,--nodes}'[List the IDs of the matching nodes]'\
226                                 "($cmds --names)"{-T,--tree}'[Print a JSON representation of the matching item]'\
227                                 "($cmds)"{-D,--desktops}'[List the IDs (or names) of the matching desktops]'\
228                                 "($cmds)"{-M,--monitors}'[List the IDs (or names) of the matching monitors]'
229                         ;;
230                 (wm)
231                         _arguments \
232                                 '*'{-d,--dump-state}'[Dump the current world state on standard output]'\
233                                 '*'{-l,--load-state}'[Load a world state from the given file]:load state from file:_files'\
234                                 '*'{-a,--add-monitor}'[Add a monitor for the given name and rectangle]:add monitor:( )'\
235                                 '*'{-O,--reorder-monitors}'[Reorder the list of monitors to match the given order]:*: :_bspc_query_names -- monitors -M'\
236                                 '*'{-o,--adopt-orphans}'[Manage all the unmanaged windows remaining from a previous session]'\
237                                 '*'{-h,--record-history}'[Enable or disable the recording of node focus history]:history:(on off)'\
238                                 '*'{-g,--get-status}'[Print the current status information]'
239                         ;;
240                 (subscribe)
241                         if [[ "$words[CURRENT-1]" != (-c|--count) ]] ;then
242                                 _values -w "options" \
243                                         '(-f --fifo)'{-f,--fifo}'[Print a path to a FIFO from which events can be read and return]'\
244                                         '(-c --count)'{-c,--count}'[Stop the corresponding bspc process after having received specified count of events]'
245                                 _values -w -S "_" events all report pointer_action \
246                                         "monitor:: :(add rename remove swap focus geometry)"\
247                                         "desktop:: :(add rename remove swap transfer focus activate layout)"\
248                                         "node:: :(add remove swap transfer focus activate presel stack geometry state flag layer)"
249                         fi
250                         ;;
251                 (rule)
252                         local -a completions by_index
253                         local index=0 target settings class id instance json
254                         _arguments -C \
255                                 {-a,--add}'[Create a new rule]:*: :->add'\
256                                 {-r,--remove}'[Remove the given rules]:*: :->remove'\
257                                 '(-l --list)'{-l,--list}'[List the rules]'
258                         compset -N "-([ar]|-add|-remove)"
259                         case $state$CURRENT in
260                                 (add1)
261                                         compset -P '*:'
262                                         bspc query -N -n '.window' 2> /dev/null |
263                                                 while read id ; do
264                                                         json=$(bspc query -T -n $id 2>/dev/null) || continue
265                                                         [[ "$json[1]" = '{' ]] || continue
266                                                         class=${${json##*\"className\":\"}%%\",\"*}
267                                                         instance=${${json##*\"instanceName\":\"}%%\",\"*}
268                                                         [[ "$class[1]" != '{' && "$instance[1]" != '{'  ]] || continue
269                                                         if [ -n "$IPREFIX" ] ;then
270                                                                 [[ "$IPREFIX" == ("${class}:"|('\'|)'*:') ]] &&
271                                                                         completions[(r)$instance]=$instance
272                                                         else
273                                                                 class=${class%%:/\\:}
274                                                                 completions[(r)$class]="$class"
275                                                         fi
276                                                 done
277                                         ;;
278                                 (add*)
279                                         _values -w 'add rule' {border,focus,follow,manage,center}': :(on off)'\
280                                                 '(--one-shot)-o'\
281                                                 '(-o)--one-shot'\
282                                                 'monitor: :_bspc_selector -- monitor'\
283                                                 'desktop: :_bspc_selector -- desktop'\
284                                                 'node: :_bspc_selector -- node'\
285                                                 'rectangle: :( )'\
286                                                 'split_ratio:split ratio:( )'\
287                                                 "split_dir:split direction:(${dir})"\
288                                                 "state:state:(${node_state})"\
289                                                 "${flag[@]:#urgent}:set flag:(on off)"\
290                                                 "layer:layer:(${layer})"
291                                         return
292                                         ;;
293                                 (remove*)
294                                         compset -P '*:'
295                                         bspc rule -l 2> /dev/null |
296                                                 while IFS=" " read target settings ;do
297                                                         by_index+="^$((index++)):${target} ${settings}"
298                                                         if [ -n "$IPREFIX" ] ;then
299                                                                 completions+="${target#*:}"
300                                                         else
301                                                                 completions+="${target%:*}"
302                                                         fi
303                                                 done
304                                         [[ -z "$IPREFIX" ]] &&
305                                                 _describe 'remove rule by position' '(head tail)' -J by_index -- by_index -J by_index
306                                         ;;
307                                 (*)
308                                         return
309                                         ;;
310                         esac
311                         completions[(r)\*]=*
312                         [ -n "$IPREFIX" ] &&
313                                 _describe 'match window instance' completions ||
314                                 _describe 'match window class' completions -q -S ':'
315                         ;;
316                 (config)
317                         local -a {look,behaviour,input}{_bool,}
318                         look_bool=(borderless_monocle gapless_monocle)
319                         look=({normal,active,focused}_border_color {top,right,bottom,left}_padding {top,right,bottom,left}_monocle_padding presel_feedback_color border_width window_gap)
320                         behaviour_bool=(single_monocle removal_adjustment ignore_ewmh_focus center_pseudo_tiled honor_size_hints remove_disabled_monitors remove_unplugged_monitors merge_overlapping_monitors)
321                         behaviour=(mapping_events_count ignore_ewmh_fullscreen external_rules_command split_ratio automatic_scheme initial_polarity directional_focus_tightness status_prefix)
322                         input_bool=(swallow_first_click focus_follows_pointer pointer_follows_{focus,monitor})
323                         input=(click_to_focus pointer_motion_interval pointer_modifier pointer_action{1,2,3})
324                         if [[ "$CURRENT" == (2|3) ]];then
325                                 _arguments \
326                                         '-d[Set settings for the selected desktop]: :_bspc_selector -- desktop'\
327                                         '-m[Set settings for the selected monitor]: :_bspc_selector -- monitor'\
328                                         '-n[Set settings for the selected node]: :_bspc_selector -- node'
329                         fi
330                         if [[ "${words[2]}" == -* ]] ;then
331                                 (( CURRENT == 3 )) && return
332                                 if (( CURRENT > 3 )) ;then
333                                         compset -n 3
334                                 fi
335                         fi
336                         if ((CURRENT==2)) ;then
337                                 _describe 'look' look -J look -- look_bool -J look
338                                 _describe 'input' input -J input -- input_bool -J input
339                                 _describe 'behaviour' behaviour -J behaviour -- behaviour_bool -J behaviour
340                         elif ((CURRENT==3)) ;then
341                                 setting=$words[2]
342                                 case $setting in
343                                         (ignore_ewmh_fullscreen)
344                                                 _values -S "," "set $setting" all none "enter:: :(exit)" "exit:: :(enter)"
345                                                 ;;
346                                         (initial_polarity)
347                                                 _values "set $setting" first_child second_child
348                                                 ;;
349                                         (pointer_action(1|2|3))
350                                                 _values "set $setting" move resize_side resize_corner focus none
351                                                 ;;
352                                         (pointer_modifier)
353                                                 _values "set $setting" shift control lock mod1 mod2 mod3 mod4 mod5
354                                                 ;;
355                                         (directional_focus_tightness)
356                                                 _values "set $setting" low high
357                                                 ;;
358                                         (click_to_focus)
359                                                 _values "set $setting" any button1 button2 button3 none
360                                                 ;;
361                                         (*)
362                                                 [[ -n $look_bool[(r)$setting] ]] ||
363                                                         [[ -n $behaviour_bool[(r)$setting] ]] ||
364                                                         [[ -n $input_bool[(r)$setting] ]] &&
365                                                         _values "set $setting" true false
366                                                 ;;
367                                 esac
368                         fi
369                         ;;
370         esac
371 }
372
373 _bspc "$@"