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.

Aerospace goodness

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!

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,

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']
...

---

Home