Two small Sway scripts I find useful

I’ve used Sway as my window manager for a few years. I’m not a power user by any means, and probably have just as many small frustrations with the tiling window layout as I do with manually resizing windows. For instance, I’ve never managed to get an intuition for how the tree of windows works and is navigated, so will occasionally end up with a very deeply nested window I resort to moving between workspaces to hoist up.

Nonetheless, I’ve written and make heavy use of a couple of short scripts that interface with Sway, which I’ll share and explain here.

Swallow

First is a script called swallow, which reads as follows:

#!/bin/sh

TREE=$(swaymsg -rt get_tree)
PID=$(printf "%s" "$TREE" | jq 'recurse(.nodes[]) | select(.focused) | .id')
WORKSPACE=$(printf "%s" "$TREE" | jq 'recurse(.nodes[]) | select(.type == "workspace" and (recurse(.nodes[]) | .focused)) | .name')

swaymsg "[con_id=$PID] focus; move scratchpad"
trap 'swaymsg "[con_id=$PID] focus; floating disable; move window to workspace $WORKSPACE"' EXIT

"$@"

The name is taken from i3-swallow, and the implementation is adapted from swayhide. This script will hide the current window (expected to be a terminal) by moving it to the scratchpad. Then it will run the remainder of its arguments as a program, and attempt to restore the hidden terminal when the child process finishes.

This is useful for running graphical programs that require arguments. For “niladic” programs like Firefox, there are any number of launchers available. Running a media player or PDF viewer will probably require the file to be passed as the argument, so I always run them from the terminal. This means the terminal window will be left behind while I’m interacting with the application. Rather than use shell background jobs, I prefer to hide the terminal altogether with this script.

At some point, I should investigate writing a shell completion that behaves like those for sudo and other wrapping commands. It might also be possible to remember more about where the window came from in the layout tree to restore it more accurately, but I tend to use very simple layouts so this doesn’t bother me too much.

Emacs Client Focus

Second, and finally, is a script called emacsclientfocus, which reads as follows:

#!/bin/sh

PREVIOUS_FOCUS=$(swaymsg -rt get_tree | jq 'recurse(.nodes[]) | select(.focused) | .id')

swaymsg '[app_id="emacs"] focus'
trap 'swaymsg "[con_id=$PREVIOUS_FOCUS] focus"' EXIT

emacsclient "$*"

It follows a very similar structure. I suspect this is less broadly appealing than swallow due to the integration with Emacs, which is far from the most used editor. This script takes a filename, opens it in a running Emacs server, and switches focus to the Emacs window. When the server is done with the file, such as when the user confirms their edits, focus is returned to the starting window.

I use this for integrating Emacs with other programs. For instance, I configure Mutt to compose emails via emacsclientfocus, so I can jump from that terminal to an open buffer in Emacs, write the email, and return to Mutt to send it. That’s actually about all I use it for, as Git commit messages are automatically edited in Emacs by Magit.

Conclusion

Neither of these scripts are especially groundbreaking, but they sand some rough edges off of my workflows, which is always satisfying. I’m trying to remember to keep my eyes open for any other opportunities to make things a bit nicer for myself with a short script.

I’ll note, as ever, that I’m no expert at shell scripting or Sway. Any improvements or suggestions are welcome.