-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtabapp
254 lines (224 loc) · 8.14 KB
/
tabapp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
#!/bin/bash
#
# BY twix https://github.com/Twix53791
#
# USAGE:
# Launch the application appname as a tab into the tabbed instance 'tabbed.emanppa':
# tabapp appname - Run a tabbed application
# tabapp appname into <yourname> - Specify a custom tabbed instance name (optionnal)
# tabapp appname -R - Reset : kill any previous tabbed instance of the appname
#
# tabapp firefox -R into kitty : will launch firefox into the tabbed instance named ‘kitty’,
# reseting it if already existing
#
# To avoid any ambiguous grep and insure a unique name, tabbed instance names are
# set to the name given by the user (or the appname) reversed
#
# You can pass arguments:
# 1) to the application launched if no command is given:
# tabapp kitty -e bpytop
# 2) to tabbed, from the $3 positionnal parameter, with a command:
# tabapp add -R firefox kitty -o Red will launch (or reset, if existing)
# a tabbed instance with a red background
#
# Commands [tabapp command arguments]:
#
# add PATTERN <yourname> <args> - Add the window matching the PATTERN into
# the tabbed instance <yourname>, with the <args> to tabbed
# The PATTERN can be a node id, or a class name, or a PID, anything
# from the wmctrl output. You can change the wmctrl command to get even
# more possibilities
#
# gather PATTERN <yourname> <args> - Gather ALL nodes matching the PATTERN in
# the output of wmctrl -lx command and add them
# to the tabbed instance 'tabbed.yourname'
# The PATTERN should be a window class name.
#
# The 'gather' and 'add' command can be called with the -R flag:
# tabapp gather -f kitty : gather all kitty windows except the focused one
# and tab them into a tabbed instance named ‘kitty’
#
# <add/gather> -f PATTERN - By default, the focused node is sent to tabbed, if added or gathered
# Use the -f flag to avoid this behavior and to ignore the focused node
#
## Settings ###
#
# tab_opt : pass 'default' arguments to tabbed. Default:
# -c : close tabbed when the last tab is closed
# -p -1 : open a new tab at the last position (right side)
# newtab_command : will spawn this command into every new tab
# By default, the new tab is open opened automatically when tabbed start
# (see -s flag in the spawn function below), but only manually when you
# press Ctrl+Shift+Return
#
#=======================================================================
#=======%% SETTINGS %%================================================
# Set options to pass to tabbed by default:
tab_opt=("-c")
# Set a command to run into every 'new tab' you can spawn with Ctrl+Shift+Return
# If the value is not set, the spawning of a new tab will not be activated in tabbed#
# Examples: newtab_cmd=('ranger')
# newtab_cmd=('bash' '-c' 'ls;sleep 3')
# newtab_cmd=('bash' '-c' '-i' 'a command sourced via .bashrc/.zshrc')
#
[[ -f /usr/local/bin/tabbed-fzf ]] && newtab_cmd=('tabbed-fzf') ||
newtab_cmd=('bash' '-c' 'echo "Customize your own new tab command in tabapp";read')
# To run a simple st terminal into the new tab uncomment:
#newtab_cmd=0
#=======%% FUNCTIONS %%===============================================
# Get the nodes matching the PATTERN given in wmctrl -lx
getnodes(){
wmctrl -lxp | tr -s ' ' | cut -d' ' -f-4 | grep $1 | cut -d' ' -f1
}
# Spawn a new tabbed instance specific to an app name
spawn(){
[[ -z $1 ]] && exit
name=$(echo $1 | rev); shift
instance=$(wmctrl -lx | cut -d' ' -f-4 | grep "tabbed.$name")
if [[ ! -z $instance ]]; then
echo ${instance%%' '*}
return
else
if [[ ! -z $newtab_cmd ]] && [[ $newtab_cmd != 0 ]]; then
tabbed -n "tabbed.$name" "${tab_opt[@]}" "$@" -r 2 -s st -w '' -e "${newtab_cmd[@]}" &>/dev/null &
elif [[ ! -z $newtab_cmd ]] && [[ ! -z $(command -v st) ]; then
tabbed -n "tabbed.$name" "${tab_opt[@]}" "$@" -r 2 -s st -w '' &>/dev/null &
else
tabbed -n "tabbed.$name" "${tab_opt[@]}" "$@" &>/dev/null &
fi
instance=$(bspc subscribe -c 1 node_add)
echo ${instance##*' '}
fi
}
# Gather all nodes matching a pattern and add them into a tabbed instance
gather(){
# Reset if -R flag
if [[ "$1" == "-R" ]]; then
shift
nme=${2:-$1}
name=$(echo $nme | rev)
isrunning=$(wmctrl -lx | cut -d' ' -f-4 | grep "tabbed.$name")
[[ ! -z $isrunning ]] &&
bspc node ${isrunning%%' '*} -c &&
sleep .1
elif [[ "$1" == "-f" ]]; then
F=1 && shift
fi
# Get win and tab node ids
pattern=$1;instance=$2;tabargs=${@:3}
[[ -z $pattern ]] && exit
mapfile -t nodes < <(getnodes ${pattern,,})
[[ $F == 1 ]] &&
focused=$(bspc query -N -n focused) &&
nodes=( "${nodes[@]/${focused,,}}" )
[[ -z ${nodes[@]} ]] && exit
iname=${instance:-$pattern}
tabapp=$(spawn $iname ${tabargs[@]})
# If not the following, send nodes to tabbed from another desktop crashes bspwm
d=$(bspc query -D -n $tabapp)
for node in "${nodes[@]}"; do
nd=$(bspc query -D -n $node)
[[ $nd != $d ]] && bspc node $node -d $d
done
bspc node -f $tabapp
# Reparent nodes - node can be 'empty', because of "${nodes[@]/${focused,,}}"
for node in "${nodes[@]}"; do
[[ ! -z $node ]] &&
arehidden+=($(bspc query -N -n $node -n .hidden))
xdotool windowreparent $node $tabapp
done
# Unhide the hidden nodes
for hidden in "${arehidden[@]}";do
bspc node $hidden -g hidden=off
done
}
# Add a node to a tabbed instance
add(){
# Reset if -R flag
if [[ "$1" == "-R" ]]; then
shift
nme=${2:-$1}
name=$(echo $nme | rev)
isrunning=$(wmctrl -lx | cut -d' ' -f-4 | grep "tabbed.$name")
[[ ! -z $isrunning ]] &&
bspc node ${isrunning%%' '*} -c &&
sleep .1
elif [[ "$1" == "-f" ]]; then
F=1 && shift
fi
# Get win and tab node ids, as the args to pass to tabbed
pattern=$1;instance=$2;tabargs=${@:3}
[[ -z $pattern ]] && exit
wid=$(getnodes ${pattern,,} | tail -1)
[[ $F == 1 ]] &&
focused=$(bspc query -N -n focused) &&
wid=${wid##${focused,,}}
[[ -z $wid ]] && exit
# Check if the window node is hidden
ishidden=$(bspc query -N -n $wid -n .hidden)
iname=${instance:-$pattern}
tabapp=$(spawn $iname ${tabargs[@]})
# If not the following, send nodes to tabbed from another desktop crashes bspwm
d=$(bspc query -D -n $tabapp)
nd=$(bspc query -D -n $wid)
[[ $nd != $d ]] && bspc node $wid -d $d
bspc node -f $tabapp
# Add node
xdotool windowreparent $wid $tabapp
# Unhide is hidden
[[ ! -z $ishidden ]] && bspc node $wid -g hidden=off
}
# Run an application, then tab it into a tabbed instance of the app name
run(){
cmd=$1
nme=$cmd
shift
# Reset if -R flag
if [[ "$1" == "-R" ]]; then
shift
[[ "$1" == "into" ]] && nme=$2 && shift 2
name=$(echo $nme | rev)
isrunning=$(wmctrl -lx | cut -d' ' -f-4 | grep "tabbed.$name")
[[ ! -z $isrunning ]] &&
bspc node ${isrunning%%' '*} -c &&
sleep .1
elif [[ "$1" == "-f" ]];then
shift # do nothing, but don't break the command
[[ "$1" == "into" ]] && nme=$2 && shift 2
elif [[ "$1" == "into" ]]; then
nme=$2
shift 3
elif [[ -z $1 ]]; then
noargs=1
fi
# Run the tabbed app
validcmd=$(command -v $cmd)
[[ -z $validcmd ]] && exit
# wid=$(bspc subscribe -c 1 node_add)
if [[ -z $noargs ]]; then
$cmd "$@" 2>/dev/null &
else
$cmd 2>/dev/null &
fi
# Grabs from bspc subscribe the id of the node created
# Creates the tabbed instance named $name
wid=$(bspc subscribe -c 1 node_add)
tabapp=$(spawn $nme)
# If not the following, send nodes to tabbed from another desktop crashes bspwm
d=$(bspc query -D -n $tabapp)
nd=$(bspc query -D -n ${wid##*' '})
[[ $nd != $d ]] && bspc node ${wid##*' '} -d $d
bspc node -f $tabapp
# Reparent the new app window to tabbed
xdotool windowreparent ${wid##*' '} $tabapp
}
#=======%% SCRIPT %%=================================================
app=$1; shift
case $app in
gather) gather "$@";;
add) add "$@";;
*) run $app "$@";;
esac
# Temporary. In bspwm, tabbing a floating window leaves a 'ghost' window or some artefacts
# This "refresh" the screen to get rid of them. I would like to find a cleaner way...
bspc desktop -l next;bspc desktop -l next