Fuzzy search snippets for the desktop.
The problem
During everyday computer use, there are several non-trivial things that must be
typed fairly often. Things like your email address or ¯\_(ツ)_/¯. Usually
this means typing it out in full, or navigating to somewhere like
https://textfac.es/ and copying emojis from there. In the spirit of
automating everything and efficiency, let’s see if we can improve on this!
The idea
So, what if I could press a key sequence, fuzzy search for a “snippet” by name, and instantly have it typed or copied to the clipboard?
The solution
After some fiddling around with bash and python scripts, I managed to work out a solution that seems to work pretty well! Simply put, it does the following:
- Load in a yaml file containing
name: snippetentries. - Launch rofi with the snippet names for fuzzy search.
- Copy the corresponding snippet to the clipboard or use xdotool to type it out.
view of fuzzy searching snippets with rofi
The script can be called with python scriptname.py copy|type
path/to/database.yml. This can be set up with a keybinding for launching, for
example in i3:
bindsym Mod4+z exec clip-snippet.py type ~/Documents/snippets.yml
bindsym Mod4+Shift+z exec clip-snippet.py copy ~/Documents/snippets.yml
Now the workflow becomes: press Mod4+z, type a couple of characters from the
snippet name, press Enter, and it gets instantly typed into the active
window! Alternatively, Mod4+Shift+z to copy the snippet to the clipboard.
The code
For reference, the code (current version) and an example snippets file is below. Note: the code is also available on GitHub.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright © 2017 Samuel Walladge
# fuzzy search for text snippets to copy to clipboard
# depends on PyYaml, rofi, xsel, xdotool, and a yaml file containing key:snippet pairs
import yaml
import sys
import subprocess
COPY = 'copy'
TYPE = 'type'
if len(sys.argv) < 3:
print('Usage: clip-snippet.py copy|type YAML_DB_FILENAME')
sys.exit()
mode = sys.argv[1]
db_filename = sys.argv[2]
if mode not in (COPY, TYPE):
print('Invalid mode! Must be either copy or type.')
sys.exit(-1)
try:
# { 'name': 'snippet' }
db = yaml.load(open(db_filename))
except Exception as e:
print('Failed to load database file ({!r})!'.format(db_filename))
print('Ensure that it exists and is a valid yaml file.\n')
print(e)
sys.exit(-1)
keys = '\n'.join(db.keys())
result = subprocess.run(['rofi', '-dmenu', '-no-custom', '-p', 'snippet:', '-matching', 'fuzzy'],
input=keys, stdout=subprocess.PIPE, encoding='utf-8')
if result.returncode != 0:
sys.exit(-1)
key = result.stdout.strip()
snippet = db.get(key, None)
if snippet is None:
sys.exit(-1)
# copy to primary and clipboard selection
if mode == COPY:
subprocess.run(['xsel', '-ip'], encoding='utf-8', input=str(snippet))
subprocess.run(['xsel', '-ib'], encoding='utf-8', input=str(snippet))
elif mode == TYPE:
subprocess.run(['xdotool', 'type', '--', snippet], encoding='utf-8')
Example snippets file. I chose yaml because it’s simple and way more flexible that json for hand editing.
# snippets file for clip-snippet.py
# keys are snippet names (able to be fuzzy searched on)
# values are the snippets themselves - values can be multiline if required too
shrug: ¯\_(ツ)_/¯
email: test@example.com
koala emoji: ʕ•ᴥ•ʔ
disapproval emoji: ಠ_ಠ
table flip: (╯°□°)╯︵ ┻━┻
It’s all pretty hacky and simple, but it works nicely. Hope this will be useful to someone! Comments, feedback, or suggestions for improvement welcome!