Replacing Autokey on Wayland
Snippets are bits of text you use frequently. Boilerplate email responses, code blocks, and whatever else you regularly need to type. My general rule is, if I type it more than twice, I save it as a snippet.
I have a lot of little snippets of text and code from years of doing this. When I used the i3 desktop (and X11) I used Autokey to invoke shortcuts and paste these snippets where I need them. In Autokey you define a shortcut for your longer chunk of text, and then whenever you type that shortcut Autokey “expands” it to your longer text.
It’s a great app, but I switched to a Wayland-based desktop (Sway) and Autokey doesn’t work in Wayland yet. It’s unclear to me whether it’s even possible to have an Autokey-like app work within Wayland’s security model (Hawck claims to, but I have not tested it).
Instead, after giving it some thought, I came up with a way to do everything I need in a way like even better, using tools that I already have installed.
Rolling Your Own Text Snippet Manager
Autokey is modeled on the idea of typing shortcuts and having them replaced with a larger chuck of text. It works to a point, but has the mental overhead of needing to remember all those keystroke combos.
Dedicating memory to digital stuff feels like we’re doing it wrong. Why not search for a snippet instead of trying to remember some key combo? If the searching is fast and seamless there’s no loss of “flow,” or switching contexts, and no need to remember some obtuse shortcut.
To work though the search must be fast. Fortunately there’s a great little command line app that offers lighting-fast search: fzf
, a command line “fuzzy” finder. fzf
is a find-as-you-type search interface that’s incredibly fast, especially when you pair it with ripgrep
instead of find
.
I already use fzf
as a DIY application launcher, so I thought why not use it to search for snippets? This way I can keep my snippets in a simple text file, parse them into an array, pass that to fzf
, search, and then pass the selected result on to the clipboard.
I combined Alacritty, a Python script, fzf
, sed
, and some Sway shortcuts to make a snippet manager I can call up and search through with a single keystroke.
Python
It may be possible to do this entirely in a bash script, but I’m not that great at bash scripting so I did the text parsing in Python, which I know well enough.
I wanted to keep all my snippets in a single text file, with the option to do multiline snippets for readability (in other words I didn’t want to be writing \n
characters just because that’s easier to parse). I picked ---
as a delimiter because… no reason really.
The other thing I wanted was the ability to use tags to simplify searching. Tags become a way of filtering searches. For example, all the snippets I use writing for Wired can be tagged wired and I can see them all in one view by typing “wired” in fzf
.
So my snippet files looks something like this:
<div class="cluster">
<span class="row-2">
</span>
</div>
tags:html cluster code
---
```python
```
tags: python code
---
Another goal, which you may notice above, is that I didn’t want any format constraints. The snippets can take just about any ascii character. The tags line can have a space, not a have space, have commas, semicolons, doesn’t matter because either way fzf
can search it, and the tags will be stripped out before it hits the clipboard.
Here’s the script I cobbled together to parse this text file into an array I can pass to fzf
:
import re
with open('~/.textsnippets.txt', 'r') as f:
data = f.read()
snips = re.split("---", data)
for snip in snips:
# strip the blank line at the end
s = '\n'.join(snip.split('\n')[1:-1])
#make sure we output the newlines, but no string wrapping single quotes
print(repr(s.strip()).strip('\''))
All this script does is open a file, read the contents into a variable, split those contents on ---
, strip any extra space and then return the results to stdout.
The only tricky part is the last line. We need to preserve the linebreaks and to do that I used repr
, but that means Python literally prints the string, with the single quotes wrapping it. So the last .strip('\'')
gets rid of those.
I saved that file to ~/bin
which is already on my $PATH
.
Shell Scripting
The next thing we need to do is call this script, and pass the results to fzf
so we can search them.
To do that I just wrote a bash script.
#!/usr/bin/env bash
selected="$(python ~/bin/snippet.py | fzf -i -e )"
#strip tags and any trailing space before sending to wl-copy
echo -e "$selected"| sed -e 's/tags\:\.\*\$//;$d' | wl-copy
What happens here is the Python script gets called, parses the snippets file into chunks of text, and then that is passed to fzf
. After experimenting with some fzf
options I settled on case-insensitive, exact match (-i -e
) searching as the most efficient means of finding what I want.
Once I search for and find the snippet I want, that selected bit of text is stored in a variable called, creatively, selected
. The next line prints that variable, passes it to sed
to strip out the tags, along with any space after that, and then sends that snippet of text the clipboard via wl-copy.
I saved this file in a folder on my PATH
(~/bin
) and called it fzsnip
. At this point in can run fzsnip
in a terminal and everything works as I’d expect. As a bonus I have my snippets in a plain text file I can access to copy and paste snippets on my phone, tablet, and any other device where I can run NextCloud.
That’s cool, but on my laptop I don’t want to have to switch to the terminal every time I need to access a snippet. Instead I invoke a small terminal window wherever I am. To do that, I set up a keybinding in my Sway config file like this:
bindsym $mod+s exec alacritty --class 'smsearch' --command bash -c 'fzsnip | xargs -r swaymsg -t command exec'
This is very similar to how I launch apps and search passwords, which I detailed in my post on switching from i3 to Sway. The basic idea is whatever virtual desktop I happen to be on, launch a new instance of Alacritty, with the class smsearch
. Assigning that class gives the new instance some styling I’ll show below. The rest of the line fires off that shell script fzsnip
. This allows me to hit Alt+s
and get a small terminal window with a list of my snippets displayed. I search for the name of the snippet, hit return, the Alacritty window closes and the snippet is on my clipboard, ready to paste wherever I need it.
This line in my Sway config file styles the window class launcher
:
for_window [app_id="^smsearch$"] floating enable, border none, resize set width 80 ppt height 60 ppt, move position 0 px 0 px
That puts the window in the upper left corner of the screen and makes it about 1/3 the width of my screen. You can adjust the width and height to suite your tastes.
If you don’t use Alacritty, adjust the command to use the terminal app you prefer. If you don’t use Sway, you’ll need to use whatever system-wide shortcut tool your window manager or desktop environment offers. Another possibility it is using Guake which might be able to this for GNOME users, but I’ve never used it.
Conclusion
I hope this gives anyone searching for a way to replace Autokey on Wayland some ideas. If you have any questions for run into problems, don’t hesitate to drop a comment below.
Is it as nice as Autokey? I actually like this far better now. I often had trouble remembering my Autokey shortcuts, now I can search instead.
As I said above, if I were a better bash scripter I get rid of the Python file and just use a bash loop. That would make it easy to wrap it in a neat package and distribute it, but as it is it has too many moving parts to make it more than some cut and paste code.
Shoulders Stood Upon
- Using
fzf
instead ofdmenu
— This is the post that got me thinking about ways I could use tools I already use (fzf
, Alacritty) to accomplish more tasks.
2 Comments
Hello,
You said the terminal closes after hitting return. But here on Sway, after hitting return, Alacrity or Kitty really does not close itself. It is still stuck and forces me to Ctrl + C to close, but I could not paste the selected shortcut.
Gustavo-
That sucks. I am not sure why that happens, but I have run into this from time to time. 99 percent of the time everything works fine for me on Sway 1.5.1, but that 1 percent is annoying. I have actually since switched from Alacritty to Foot (https://codeberg.org/dnkl/foot), which I find to be a bit quicker. You might try that. Here’s what the code in my Sway config looks like with foot:
bindsym $mod+s exec foot --app-id=smsearch bash -c 'fzsnip | xargs -r swaymsg -t command exec'
Otherwise, make sure it works in the terminal first. So just run
fzsnip
in your terminal and see if that works. If not then something is wrong with the script. Feel free to post any error messages and I’ll try to help you figure out what’s going on.Thoughts?
Please leave a reply:
All comments are moderated, so you won’t see it right away. And please remember Kurt Vonnegut's rule: “god damn it, you’ve got to be kind.” You can use Markdown or HTML to format your comments. The allowed tags are
<b>, <i>, <em>, <strong>, <a>
. To create a new paragraph hit return twice.