Write yourself an emoji picker for fun and profit

I recently transitioned from elementary OS to Manjaro with KDE as the desktop manager. The experience has been great so for, but I was very much dissatisfied with the KDE emoji picker. Watching Luke Smith’s videos, I became familiar with his personal emoji picker, so I knew right off the bat that was what I wanted to use.

This may look like neat-picking, but the advantage of things like Luke Smith’s emoji picker is that it is extremely configurable: it’s just a shell-script that calls dmenu (a suckless tool for creating dynamic menus) on a text file with emojis in it. Hence Luke’s emoji picker can be repurposed for other uses too.

For example, as someone who studies mathematics for a living I often find myself inserting mathematical characters in text. To avoid copying-and-pasting characters from sites like unicode-table.com/ I wrote an alternative version of Luke’s emoji picker that picks mathematical characters instead:

#!/bin/sh
# Select mathematical characters with dmenu

chosen=$(cut -d ';' -f1 ~/.local/share/math-symbols | dmenu -i -l 20 | sed "s/ .*//")

[ -z "$chosen" ] && exit

printf "$chosen" | xclip -selection clipboard
notify-send "'$chosen' copied to clipboard" &

If you’re interested in knowing what is stored in ~.local/share/math-symbols, here’s the Python script I used to generate it:

import re, unicodedata
from pylatexenc import latexencode

def uni_name(c: str) -> str:
    try:
        return unicodedata.name(c).lower()
    except ValueError:
        return None

def tex(c: str) -> str:
    try:
        l = latexencode.utf8tolatex(c, brackets=False, fail_bad_chars=True)
    except ValueError:
        return None

    l = l.replace('boldsymbol', 'mathbf')
    m = re.match(r'\\ensuremath{(\\.+)}', l)

    if m:
        return m.group(1)
    elif l.startswith('\\text') and l.endswith('arrow'):
        return l.replace('text', '')
    else:
        return l

math_chars = set()

# Operators
math_chars |= {chr(c) for c in range(0x2200, 0x22FF + 1)}

# Alpha numeric symbols
math_chars |= {chr(c) for c in range(0x1d400, 0x1d7ff + 1)}

# Suplemental operators
math_chars |= {chr(c) for c in range(0x2a00, 0x2aff + 1)}

# Miscellaneous symbols (A)
math_chars |= {chr(c) for c in range(0x27c0, 0x27ef + 1)}

# Miscellaneous symbols (B)
math_chars |= {chr(c) for c in range(0x2980, 0x29FF + 1)}

# Greek and Coptic
math_chars |= {chr(c) for c in range(0x0370, 0x3ff + 1)}

# APL symbols
math_chars |= {chr(c) for c in range(0x2336, 0x237a + 1)} | {chr(0x2395)}

# Letterlike symbols
math_chars |= {chr(c) for c in range(0x2100, 0x214f + 1)}

# Superscripts
math_chars |= {chr(c) for c in range(0x2070, 0x207f + 1)}

# Subscripts
math_chars |= {chr(c) for c in range(0x2080, 0x2093 + 1)}

# Arrows
math_chars |= {chr(c) for c in range(0x2190, 0x21ff + 1)}

math_chars = {(c, uni_name(c)) for c in math_chars}
math_chars = {(c, name, f'{ord(c):X}') for c, name in math_chars
                                       if name}

for char, name, code in sorted(math_chars, key=lambda x: (x[1], x[0])):
    print(f'{char} {name}; {code};')
    tex_equivalent = tex(char)

    if tex_equivalent:
        print(f'{char} {tex_equivalent}; {code};')

To finish-off, notice you can set keyboard shortcuts for both this scripts, so that you can launch them with a single key-chord. Hope this helps someone 😌