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
|
---
post_date: 2024-11-20
---
# Leveling up the toolkit
A story of exploration, optimization, and how awesome open-source tooling can be.
I'm somewhat stuck using a mac because of multiple critical tools that I use on it. I've always been a DIYer with my tools though, which is something FOSS OS's like Linux or *BSD enable much more. But I've found two tools that I enjoy a great deal: Aerospace (a tiling window manager in the vein of i3) and sketchybar (a status bar like i3bar or polybar). Both of these tools offer fantastic configurability and do an admirable job piercing the walled-garden that is the Mac OS.
Because a desktop status bar generally displays the list of workspaces and indicates which one is active, there's a good deal of integration needed between the two. I got started with the [suggestion in the Aerospace wiki](https://nikitabobko.github.io/AeroSpace/goodness#show-aerospace-workspaces-in-sketchybar).
## The starting point: documented suggestions
First, the instructions have us configure aerospace to (a) start up sketchybar after it starts up itself, and (b) trigger a custom sketchybar event whenever the active workspace changes.
```
# ~/.aerospace.toml
after-startup-command = ['exec-and-forget sketchybar']
exec-on-workspace-change = ['/bin/bash', '-c',
'sketchybar --trigger aerospace_workspace_change FOCUSED_WORKSPACE=$AEROSPACE_FOCUSED_WORKSPACE'
]
```
Next, in sketchybar's configuration file (which is just a shell script - beautiful) we'll both create the custom event for aerospace to trigger, and loop over aerospace's workspaces to display them in the status bar. These status bar items will also listen for the custom event, and trigger a script in the sketchybar config's plugin directory.
```
# ~/.config/sketchybar/sketchybarrc
sketchybar --add event aerospace_workspace_change
for sid in $(aerospace list-workspaces --all); do
sketchybar --add item space.$sid left \
--subscribe space.$sid aerospace_workspace_change \
--set space.$sid \
background.color=0x44ffffff \
background.corner_radius=5 \
background.height=20 \
background.drawing=off \
label="$sid" \
click_script="aerospace workspace $sid" \
script="$CONFIG_DIR/plugins/aerospace.sh $sid"
done
```
The "click_script" in there is a nice touch, it's having aerospace change the active workspace when we click one in the status bar.
Finally, we'll create that script in the plugin directory. It's ultimately what's going to be run whenever there's a change to the currently-active workspace.
```
# ~/.config/sketchybar/plugins/aerospace.sh
#!/usr/bin/env bash
if [ "$1" = "$FOCUSED_WORKSPACE" ]; then
sketchybar --set $NAME background.drawing=on
else
sketchybar --set $NAME background.drawing=off
fi
```
The condition here ensures that an extra background will be drawn around only the currently active workspace, which is great.
The visual update in the bar felt a little sluggish though.
## An idea for improvement
I realized that I was never aware of where my windows were. I could still always cmd-tab my way around applications in standard mac fashion, but I felt I was under-utilizing my great tiling WM. I decided I wanted a different background to appear around any workspace which has an application window on it.
A simple enough edit to sketchybar's aerospace plugin script.
```
# ~/.config/sketchybar/plugins/aerospace.sh
#!/usr/bin/env bash
POPULATED="$(aerospace list-windows --all --format '%{workspace}' | sort | uniq | tr '\n' ' ')"
if [ "$1" = "$FOCUSED_WORKSPACE" ]; then
sketchybar --set $NAME background.drawing=on background.color=0xaaeab676
else
if [[ $POPULATED =~ $1 ]]; then
sketchybar --set $NAME background.drawing=on background.color=0x8800ffff
else
sketchybar --set $NAME background.drawing=off
fi
fi
```
I can first shell out to ask aerospace for the workspace that each window is on (and then unique that list), then with an extra conditional on non-active workspaces I can style them differently if they were in the list. Spruce it up with a bit of color and we look to be there!
=> /~tjp/i/sketchybar-colors.jpg sketchybar with colors!
But the "little sluggish" from before has become horrendous performance. It's a few seconds for this to update now.
## The need for speed
I had just added a shell-out to an external program into sketchybar/plugins/aerospace.sh. Looking back at how this script gets executed,
- the workspace items in the sketchybar each listen to the aerospace_workspace_change event
- they each invoke plugins/aerospace.sh with their own id as a positional argument
This means that the script runs *separately for each workspace* whenever the active workspace changes. In my case this was 22 times. But that "POPULATED" list would be the same for each - I definitely don't have to collect it 22 times.
So: this will be a sizable refactor, but I instead want to have a plugin script that updates the display of all 22 workspaces in the sketchybar, and then perhaps I can wire it up to only run once for every change of active workspace.
First, let's update the plugin script to reset styles on *all* the workspaces.
```
# ~/.config/sketchybar/plugins/aerospace.sh
#!/usr/bin/env bash
POPULATED="$(aerospace list-windows --all --format '%{workspace}' | sort | uniq | tr '\n' ' ')"
FOCUSED="$(aerospace list-workspaces --focused | tr '\n' ' ')"
for ws in $(aerospace list-workspaces --all); do
if [[ $FOCUSED =~ $ws ]]; then
sketchybar --set space.$ws background.drawing=on background.color=0xaaeab676
else
if [[ $POPULATED =~ $ws ]]; then
sketchybar --set space.$ws background.drawing=on background.color=0x8800ffff
else
sketchybar --set space.$ws background.drawing=off
fi
fi
done
```
Now let's update the sketchybar startup script as well and get rid of the "--subscribe" and "script=" on each and every workspace displayed.
```
# ~/.config/sketchybar/sketchybarrc
sketchybar --add event aerospace_workspace_change
for sid in $(aerospace list-workspaces --all); do
sketchybar --add item space.$sid left \
--set space.$sid \
background.color=0x44ffffff \
background.corner_radius=5 \
background.height=20 \
background.drawing=off \
label="$sid" \
click_script="aerospace workspace $sid"
done
```
But, now *nothing* is subscribed to that "aerospace_workspace_change" event. This was perhaps pretty lazy, but since I just need *anything* to bridge the event to the script, and the next thing in the sketchybar is a little arrow icon...
```
sketchybar --add item chevron left \
--set chevron icon= label.drawing=off \
--subscribe chevron aerospace_workspace_change \
--set chevron script="$CONFIG_DIR/plugins/aerospace.sh" \
...
```
Eh, it'll do. We should be ready! And it does, indeed, work. And it is, indeed, faster. Testing the script itself by just running it directly under "time", It's taking around 550ms. Passable for something that's at least only running once per interaction.
## The needier for speedier
I realized, though, that I hadn't gotten rid of the N+1 subprocesses problem. Namely, my script is running "sketchybar" independently for every workspace, even though you can stack up multiple --set parameters in a single call. Let's try that instead, building up the command in the loop and then just running it once.
```
# ~/.config/sketchybar/plugins/aerospace.sh
#!/usr/bin/env bash
POPULATED="$(aerospace list-windows --all --format '%{workspace}' | sort | uniq | tr '\n' ' ')"
FOCUSED="$(aerospace list-workspaces --focused | tr '\n' ' ')"
CMD="sketchybar"
for ws in $(aerospace list-workspaces --all); do
if [[ $FOCUSED =~ $ws ]]; then
CMD+=" --set space.$ws background.drawing=on background.color=0xaaeab676"
else
if [[ $POPULATED =~ $ws ]]; then
CMD+=" --set space.$ws background.drawing=on background.color=0x8800ffff"
else
CMD+=" --set space.$ws background.drawing=off"
fi
fi
done
$CMD
```
It works, and runs in about 170ms - over 3X faster.
## One bug to fix
I found that if I kick a window to a different workspace with `CMD+Option+Shift+<letter>` (my keybinding for this action), of course the display in the status bar is now potentially all wrong.
The nice thing about having a 170ms script that updates everything though, is you can just call it whenever you need to and not worry too much about it.
In my aerospace config file I previously had:
```
cmd-alt-shift-a = 'move-node-to-workspace A'
cmd-alt-shift-b = 'move-node-to-workspace B'
cmd-alt-shift-c = 'move-node-to-workspace C'
...
```
And now those directives are:
```
cmd-alt-shift-a = ['move-node-to-workspace A', 'exec-and-forget /usr/local/bin/sketchybar --trigger aerospace_workspace_change']
cmd-alt-shift-b = ['move-node-to-workspace B', 'exec-and-forget /usr/local/bin/sketchybar --trigger aerospace_workspace_change']
cmd-alt-shift-c = ['move-node-to-workspace C', 'exec-and-forget /usr/local/bin/sketchybar --trigger aerospace_workspace_change']
...
```
> Note: This was ported from my old gemini capsule, still served on gemini at `gemini.ctrl-c.club/~tjp`
|