#!/usr/bin/env python3 """qs-launch โ€” wofi-based launcher modes: emoji pick, calculator, DuckDuckGo search. Subcommands: emoji feed a curated emoji list into wofi --dmenu, copy the picked emoji calc type an expression in wofi, evaluate with qalc, copy + toast result search type a query in wofi, open DuckDuckGo in the default browser All binary paths are injected via $QS_* env vars by the .local/bin/qs-launch wrapper so execution works regardless of PATH (same pattern as qs-bt's $BLUECTL). When no DISPLAY/WAYLAND_DISPLAY is present, wofi can't open, so each mode exits silently with code 1. """ import os import subprocess import sys import urllib.parse # Curated emoji list: " ". Searchable by name, output splits # on the first whitespace so only the emoji character gets copied. EMOJI = """๐Ÿ˜€ grin ๐Ÿ˜ƒ smiley ๐Ÿ˜ beam ๐Ÿ˜‚ joy ๐Ÿคฃ rofl ๐Ÿ˜Š blush ๐Ÿ™‚ slight smile ๐Ÿ˜‰ wink ๐Ÿ˜ heart eyes ๐Ÿ˜˜ kiss ๐Ÿคฉ star struck ๐Ÿฅณ party ๐Ÿ˜Ž cool ๐Ÿค“ nerd ๐Ÿ˜‡ halo ๐Ÿ˜ smirk ๐Ÿ˜œ winky tongue ๐Ÿฅบ plead ๐Ÿ˜ฌ grimace ๐Ÿค” think ๐Ÿคฏ mind blown ๐Ÿ˜ด sleepy ๐Ÿ˜ญ cry ๐Ÿ˜ข sad ๐Ÿ˜ž disappointed ๐Ÿ˜  angry ๐Ÿ˜ค triumph ๐Ÿคฌ swear ๐Ÿ™„ roll eyes ๐Ÿ˜ neutral ๐Ÿ˜‘ expressionless ๐Ÿ™‚๐Ÿ™ƒ upside down ๐Ÿ˜ฑ scream ๐Ÿค’ sick ๐Ÿค• hurt ๐Ÿ’€ skull ๐Ÿ‘ป ghost ๐Ÿ‘ฝ alien ๐Ÿค– robot ๐ŸŽƒ pumpkin ๐Ÿ’ฉ poo ๐Ÿ™Œ yes ๐Ÿ‘ clap ๐Ÿ™ pray ๐Ÿค handshake ๐Ÿ‘ thumbs up ๐Ÿ‘Ž thumbs down ๐Ÿ‘Š fist โœŠ raised fist ๐Ÿคž crossed fingers โœŒ๏ธ peace ๐Ÿ‘‹ hello wave ๐Ÿ–๏ธ hand โœ๏ธ writing ๐Ÿ’ช muscle ๐Ÿซถ heart hands ๐Ÿฆพ bionic arm ๐Ÿง  brain ๐Ÿ‘€ eyes ๐Ÿ‘๏ธ eye ๐Ÿ‘„ lips ๐Ÿ‘… taste tongue ๐Ÿง› vampire ๐ŸงŸ zombie โค๏ธ heart ๐Ÿงก orange heart ๐Ÿ’› yellow heart ๐Ÿ’š green heart ๐Ÿ’™ blue heart ๐Ÿ’œ purple heart ๐Ÿ–ค black heart ๐Ÿค white heart ๐ŸคŽ brown heart ๐Ÿ’” broken heart โค๏ธโ€๐Ÿ”ฅ heart fire ๐Ÿ’ฏ hundred ๐Ÿ’ฅ boom ๐Ÿ’ซ dizzy โœจ sparkles ๐Ÿ”ฅ fire ๐ŸŒŸ star โญ star white โ˜€๏ธ sun ๐ŸŒ™ moon ๐ŸŒ‘ new moon ๐ŸŒˆ rainbow โ˜๏ธ cloud โ›ˆ๏ธ storm โ„๏ธ snow ๐ŸŒŠ ocean wave ๐ŸŒ earth ๐ŸŒบ hibiscus ๐ŸŒธ cherry blossom ๐ŸŒน rose ๐ŸŒท tulip ๐ŸŒต cactus ๐ŸŒด palm ๐Ÿ€ clover ๐Ÿ„ mushroom ๐Ÿถ dog ๐Ÿฑ cat ๐ŸฆŠ fox ๐Ÿป bear ๐Ÿผ panda ๐Ÿจ koala ๐Ÿฆ lion ๐Ÿฏ tiger ๐Ÿธ frog ๐Ÿต monkey ๐Ÿง penguin ๐Ÿฆ„ unicorn ๐Ÿ bee ๐Ÿฆ‹ butterfly ๐Ÿข turtle ๐Ÿ™ octopus ๐Ÿฆˆ shark ๐Ÿฌ dolphin ๐Ÿ pineapple ๐Ÿฅญ mango ๐Ÿ’ cherries ๐Ÿ“ strawberry ๐Ÿ‘ peach ๐Ÿฅ‘ avocado ๐Ÿ• pizza ๐Ÿ” burger ๐ŸŸ fries ๐ŸŒญ hotdog ๐Ÿฟ popcorn ๐ŸŒฎ taco ๐Ÿฐ cake ๐Ÿฉ donut ๐Ÿฅ croissant โ˜• coffee ๐Ÿต tea ๐Ÿบ beer ๐Ÿป cheers โšฝ football ๐Ÿ€ basketball ๐ŸŽพ tennis โšพ baseball ๐Ÿˆ american football ๐ŸŽฎ game ๐ŸŽฒ dice ๐ŸŽฏ target ๐ŸŽต music ๐ŸŽถ notes ๐ŸŽค mic ๐ŸŽง headphones ๐Ÿ“ป radio ๐ŸŽฌ movie ๐Ÿ“บ tv ๐Ÿ’ป laptop ๐Ÿ“ฑ phone ๐Ÿ–ฅ๏ธ computer ๐Ÿ–ฑ๏ธ mouse ๐Ÿ’พ floppy ๐Ÿ’ฟ disc ๐Ÿ”‹ battery ๐Ÿ”Œ plug ๐Ÿ’ก bulb ๐Ÿ”ฆ flashlight ๐Ÿ—‘๏ธ trash ๐Ÿ”’ lock ๐Ÿ”“ unlocked ๐Ÿ”‘ key โœ‚๏ธ scissors ๐Ÿ“Ž paperclip ๐Ÿ“Œ pin ๐Ÿ“ location ๐Ÿงฒ magnet ๐Ÿ› ๏ธ tools โš™๏ธ gear ๐Ÿ”ง wrench โœ๏ธ pencil ๐Ÿ–Š๏ธ pen ๐Ÿ“– book ๐Ÿ“š books ๐Ÿ“„ doc ๐Ÿ“ folder ๐Ÿ“ฆ package โœ‰๏ธ mail ๐Ÿ“ memo ๐Ÿ“Š chart ๐Ÿ’ฐ money ๐Ÿ’ณ card ๐Ÿงพ receipt ๐Ÿ† trophy ๐Ÿฅ‡ gold ๐Ÿฅˆ silver ๐ŸŽ gift ๐ŸŽˆ balloon ๐ŸŽ‰ party popper ๐Ÿฅ‚ toast ๐ŸŽŠ confetti ๐Ÿงน clean ๐Ÿงฝ sponge โฐ alarm โฑ๏ธ stopwatch ๐Ÿ•ฐ๏ธ clock ๐Ÿ“… calendar ๐Ÿ“† date ๐Ÿ”” bell ๐Ÿ”• bell off โŒ cross โœ… check โš ๏ธ warning ๐Ÿšซ no entry โž• plus โž– minus โž— divide โœ–๏ธ multiply ๐Ÿ”„ refresh โฌ†๏ธ up โฌ‡๏ธ down โฌ…๏ธ left โžก๏ธ right โ†ฉ๏ธ return ๐Ÿ”™ back ๐Ÿ”œ soon ๐ŸŒ globe ๐Ÿš€ rocket ๐Ÿ›ธ saucer โœˆ๏ธ plane ๐Ÿš— car ๐Ÿš• taxi ๐ŸšŒ bus ๐Ÿš‚ train ๐Ÿšฒ bike ๐Ÿ๏ธ motorcycle ๐Ÿ‘ป spooky โ˜ ๏ธ skull crossbones ๐Ÿ’ฃ bomb ๐Ÿš chopper ๐Ÿšข ship ๐Ÿš„ bullet train ๐Ÿšฆ traffic light โ›ฝ fuel ๐Ÿ…ฟ๏ธ parking ๐Ÿšง roadwork ๐ŸŒ‰ bridge ๐Ÿฐ castle โ›บ camp ๐ŸŒ‹ volcano ๐Ÿ—ผ tower ๐Ÿฏ pagoda ๐ŸŒ† city dusk ๐ŸŒƒ city night ๐Ÿ™๏ธ skyline ๐Ÿ–ผ๏ธ frame ๐ŸŽจ palette ๐Ÿ–Œ๏ธ brush ๐Ÿงถ yarn ๐Ÿงต thread ๐Ÿ’ ring ๐Ÿ‘Ÿ sneaker ๐Ÿ‘  heel ๐Ÿงข cap ๐ŸŽ“ graduate ๐Ÿ‘’ hat ๐Ÿงฃ scarf ๐Ÿงค gloves ๐Ÿงฅ coat ๐Ÿ‘” tie ๐Ÿ‘• shirt ๐Ÿ‘– jeans ๐Ÿ’ญ thought ๐Ÿ’ฌ speech ๐Ÿ—ฏ๏ธ anger โŒจ๏ธ keyboard ๐Ÿ–จ๏ธ printer ๐Ÿงฎ abacus ๐Ÿ•น๏ธ joystick ๐ŸŽณ bowling ๐Ÿ“ ping pong ๐Ÿธ badminton ๐ŸฅŠ boxing ๐Ÿฅ‹ martial arts ๐ŸŽฝ running shirt ๐Ÿšด cyclist ๐Ÿง— climber ๐ŸŠ swimmer ๐ŸŽช circus ๐ŸŽ  carousel ๐Ÿ—ฟ moai ๐Ÿ›๏ธ classical ๐ŸŸ๏ธ stadium ๐Ÿซ school ๐Ÿฅ hospital ๐Ÿฆ bank ๐Ÿช store ๐Ÿญ factory ๐Ÿ๏ธ island ๐Ÿ–๏ธ beach โ›ฑ๏ธ umbrella ๐Ÿงญ compass""" def run(command, **kwargs): return subprocess.run(command, capture_output=True, text=True, **kwargs) def wofi(entries, prompt, exec_search=False): cmd = [os.environ.get("QS_WOFI", "wofi"), "--dmenu", "--prompt", prompt] if exec_search: cmd.append("--exec-search") result = run(cmd, input=entries) if result.returncode != 0: return None return result.stdout.rstrip("\n") def cmd_mode(): if "WAYLAND_DISPLAY" not in os.environ and "DISPLAY" not in os.environ: return 1 sub = sys.argv[1] if len(sys.argv) > 1 else "" if sub == "emoji": return emoji_mode() if sub == "calc": return calc_mode() if sub == "search": return search_mode() print(__doc__, file=sys.stderr) return 2 def emoji_mode(): picked = wofi(EMOJI, "\U0001f600 Emoji") if not picked: return 0 char = picked.split(" ", 1)[0] if not char: return 0 wl_copy = os.environ.get("QS_WLCOPY", "wl-copy") run([wl_copy, char]) return 0 def calc_mode(): expr = wofi("", "=? \u2014 1+2 then Enter", exec_search=True) if not expr: return 0 qalc = os.environ.get("QS_QALC", "qalc") result = run([qalc, "-t", expr]) if result.returncode != 0: return 0 answer = result.stdout.strip() wl_copy = os.environ.get("QS_WLCOPY", "wl-copy") run([wl_copy, answer]) notify(os.environ.get("QS_NOTIFY", "notify-send"), "\U0001f4d0 " + expr, "= " + answer + " (copied)") return 0 def search_mode(): query = wofi("", "Search the web", exec_search=True) if not query: return 0 url = "https://duckduckgo.com/?q=" + urllib.parse.quote_plus(query) xdg_open = os.environ.get("QS_XDGO", "xdg-open") subprocess.Popen([xdg_open, url]) return 0 def notify(sender, title, body): try: run([sender, "-a", "qs-launch", title, body]) except OSError: pass if __name__ == "__main__": raise SystemExit(cmd_mode())