Launcher for Everything*

23 June, 2024

Edit on 16 Oct, 2025 - I have updated launcher from a shell script to a compiled program (rust). reasons were performance. it did not make sense to keep reading so many files again and again, and this approach does not scale well. there would be a updated article sometime in future, but lets just say, if this approach scaled well till about 10,000 entries, newer one scales to 500,000+.

where * refers to applications(or programs), executing commands/scripts, clipboard entries, copying and typing out long/specific/repetitive things, opening files, playing media, bookmarks, searching online, with default and specified search engine with “bangs”, calculations and conversions, and much more

Disclaimer :- This is my first article, and I don’t really know how to write, please forgive me for poor structuring or style or content.

Figure 1: A screenshot of the launcher

What are we doing again ?

It is essentially a “dmenu” like approach to launch/perform various things. My idea is to “package” it neatly such that it is easy to extend, and easy to use, be flexible in what programs you choose to perform various things, and not require much knowledge of programming to extend

Why are we doing this, hasn’t this been done million times ? Why is yours better ?

Yes it has been done many times, even my aim was to mimic , basically all “twm users” do it, because these menus are easy and fast, and keyboard driven, my idea is not to replace anything, heck, I would not even call this a program, it is a “script”, it is just easy to use, and just a template where others can mold it there way.

And how exactly ?

I have written the launcher script in Posix Shellscript. Honestly speaking I have not checked the Posix spec, I have made it such that it works with dash (my /bin/sh). I only know Python, shellscripting, Rust, and Java, and between python and shellscripts, I chose shellscript because it was faster (I have not included benchmarks, but for certain sections, the difference was nearly 20-50 times)

You can find the scripts here.

The idea is setup/operating system agnostic, but my scripts are not, so you likely have to make changes.

I am including the launcher script here because i am going to reference it a lot

#!/usr/bin/env sh
modelsdir="$HOME/data/local-installations/models"
savedir="$HOME/data/save"
tmpoutput=$(mktemp --dry-run)
payload="$(cliphist list | head -n15 | sed 's/^/clipboard\t/' ; \
cat -n "$savedir"/notes | sed 's/^/note\t/' ; \
printf "note\tadd as a note\nunnote\tremove nth note\nexecb\texecute in background\nsave web\tnormal bookmark\nsave webp\tpublic bookmark\nsave contact\tsome number or email with a description\nsave exec\tutable command\nsave command\tsome shell command\nsave random\tstuff to be typed but general\nimport\tbookmarks from html file\nrssadd\nytsub\tsubscribe youtube channel\ncompress\ta file\nyts\tsearch youtube and play video\nplay\tsearch youtube and play audio\nmpv\tplay video\nmpva\tplay audio only\nytdl\tdownload video from youtube\nytdla\tdownload audio from youtube\nexpand\ta shortened url\nupload\ta file and get a linkqr\tgenerate qr with input text\ndownload\tsome link with aria2c\nmdhtml\tconvert md file to html with pandoc\ncalc\tdo calculations\n\nsxpkg\tsearch file in arch packages\nddg\tusing duck duck go to search packages\nwiki\tsearch wik(ipedia or tionary)\n" ; \
sed '/^$/d' "$savedir"/web "$savedir"/web-public | sed 's/^/web\t/' ; \
sed '/^$/d' "$savedir"/contact-details | sed 's/^/type\t/' | sed "s|$|\tcontact-details|" ; \
for i in "$savedir"/snippets-autocomplete/* ; do sed '/^$/d' "$i" | sed 's/^/type\t/' | sed "s|$|\t$(basename ${i})|" ; done ; \
sed '/^$/d' "$savedir"/exec | sed 's/^/exec\t/' ; \
find "$HOME"/games/linux/ -maxdepth 2 -type f -executable | sed 's/^/exec\t/' ; \
sed '/^$/d' "$savedir"/execcopy | sed 's/^/execcopy\t/' ; \
sed '/^$/d' "$savedir"/execsu | sed 's/^/execsu\t/' ; \
sed '/^$/d' "$savedir"/execterm | sed 's/^/execterm\t/' ; \
sed '/^$/d' "$savedir"/exectype | sed 's/^/exectype\t/' ; \
sed '/^$/d' "$savedir"/vpns | sed 's/^/vpn\t/' ; \
sed '/^$/d' "$savedir"/play | sed 's/^/play\t/' ; \
# sed '/^$/d' "$savedir"/bluetooth-devices | sed 's/^/bluetooth\t/' ; \
sed '/^$/d' "$savedir"/recording | sed 's/^/record\t/' ; \
find "$HOME"/data/password-store/ -name "*.gpg" -type f -printf "%P\n" | sed 's/^/pass\t/' ; \
# find "$modelsdir" -maxdepth 1 -name "*.gguf" -type f -printf "%f\n" | sed 's/^/gguf\t/' ; \
find "$HOME"/games/windows/ -maxdepth 3 -type f -name '*.exe' | grep -v 'unins\|UnityCrashHandler\|dxwebsetup\|vcredist' | sed 's/^/wine\t/' ; \
find "$HOME"/games/gameboys/ -type f -name '*.gba' | sed 's/^/gba\t/' ; \
(find "$savedir" "$HOME"/music "$HOME"/.local/bin/scripts "$HOME"/study/books "$HOME"/study/projects "$HOME"/study/sem-8 "$HOME"/downloads -type f -name "*" && find "$HOME"/.config/ -type f -name "*" && sed '/^$/d' "$savedir"/files) | sed 's/^/file\t/' ; \
ls /usr/share/applications | sed 's/^/application\t/')"
payload="$(cat /tmp/launchrs_payload)"
# in most of the script, i am using printf "%s" instead of echo or echo -E, because in some of my bookmarks, i have escape codes, or such thing, which break and printf "%s" seems to preserve it the best
selection=$(printf "%s" "$payload" | tv)


if [ -z "${selection}" ]; then exit ; fi

# uncomment the printf statements for debugging
identifier=$(printf "%s" "$selection" | cut -f 1 | sed "s/^'//") # && printf "%s" "$identifier" && printf "\n"
selected_option=$(printf "%s" "$selection" | cut -f 2 | sed "s/^'//") # && printf "%s" "$selected_option" && printf "\n"

# Perform actions based on the identifier
case "$identifier" in
"application") gtk-launch "$(echo "$selection" | awk 'NF>1{print $NF}')" ;; # instead of using gtk-launch, you can also use exec, and include the exec line in application cache
"type") wtype "$selected_option" ;; # stuff to be auto-typed anywhere you want (currently using to write long commands)
"wine") cd "$(dirname "$selected_option")" && SDL_VIDEODRIVER=windows wine "$selected_option" ;;
"switch") suyu "$selected_option" ;;
"gba") $HOME/games/gameboys/mgba "$selected_option" ;;
"wiiu") Cemu "$selected_option" ;;
"drag-file") dragon-drop "$selected_option" ;;
"exec") output="$(eval "$selected_option" 2>&1)"
notify.sh " " "$output" ;;
"execsu") output="$(pass.sh local/logs | head -n 1 | sudo -SE sh -c "$selected_option" 2>&1)"
notify.sh " " "$output" ;;
"execcopy") eval "$selected_option" | wl-copy --trim-newline ;;
"exectype") eval "$selected_option" | wtype - ;;
"execterm") alacritty msg create-window -e sh -c "$selected_option" ;;
"clipboard") printf "%s" "$selection" | cut -f 2- | cliphist decode | wl-copy --trim-newline ;;
"web") qb-open-url-in-instance.sh "$selected_option" ;; # replace qb-open-url-in-instance.sh, with default browser, or your preferred browser
"man") alacritty msg create-window -e sh -c "zcat $selected_option | groff -t -e -mandoc -Tascii | sed -e 's/\x1b\[[0-9;]*m//g' | hx" ;;
"html") alacritty msg create-window -e sh -c "w3m $selected_option" ;;
"mail") editor-terminal "$XDG_DATA_HOME/mail/$selected_option" ;;
"edit") editor-terminal "$selected_option" ;;
"file") xdg-open "$selected_option" ;;
"play") mpv "$selected_option" ;;
"pass") action=$(printf "view\nsave\ncopy otp\ncopy login id\ncopy password\nedit" | term-dmenu)
file="${selected_option%.gpg}"
case "$action" in
"view") tmpoutput=$(mktemp --dry-run) && pass.sh show "$file" >| "$tmpoutput" && xdg-open "$tmpoutput" && \rm -rf "$tmpoutput";;
# "save") pass.sh show "$file" >| "$HOME/downloads/$(basename $file)" ;;
"copy otp") pass.sh otp "$file" | tr -d '\n' | wl-copy ;;
"copy login id") pass.sh "$file" | head -2 | tail -1 | tr -d '\n' | cut -d' ' -f 2- | wl-copy ;;
"copy password") pass.sh "$file" | head -1 | tr -d '\n' | wl-copy ;;
"edit") alacritty msg create-window -e pass.sh edit "$file" ;;
esac ;;
"record")
case "$selected_option" in
"stop-screen-recording") pkill wl-screenrec ;;
"stop-audio-recording") pkill parec ;;
"screen-only") notify.sh "Recording Stats" "$(wl-screenrec --low-power=off --codec hevc -f ~/downloads/screen-only-recording-$(date "+%Y%m%d-%H%M%S").mkv)" ;;
"screen-section-only") notify.sh "Recording Stats" "$(wl-screenrec --low-power=off --codec hevc --geometry "$(slurp)" -f ~/downloads/screen-section-only-recording-$(date "+%Y%m%d-%H%M%S").mkv)" ;;
"screen-with-audio") notify.sh "Recording Stats" "$(wl-screenrec --low-power=off --codec hevc --audio --audio-codec opus -f ~/downloads/screen-recording-$(date "+%Y%m%d-%H%M%S").mkv)" ;;
"screen-section-with-audio") notify.sh "Recording Stats" "$(wl-screenrec --low-power=off --codec hevc --audio --audio-codec opus --geometry "$(slurp)" -f ~/downloads/screen-section-recording-$(date "+%Y%m%d-%H%M%S").mkv)" ;;
"audio-only") notify.sh "Recording Stats" "$(parec --file-format=oga ~/downloads/voice-recording-$(date "+%Y%m%d-%H%M%S").oga)" ;;
esac ;;
"gguf") # prefix="Your are a smart and efficient assistant, give answers in a structured format, and try to keep your replies as short as possible"
# prompt="remember to be precise and correct always, and no emojis"
alacritty msg create-window -e sh -c "cd /tmp && llama-cli -m $modelsdir/$selected_option --multiline-input --temp 0.6 --ctx-size 4096 --conversation" ;;
"vpn") VPN_NAME="$selected_option" && current_status=$(nmcli connection show --active | grep -q "$VPN_NAME" && echo "connected" || echo "disconnected") && case $current_status in connected) notify.sh "VPN Status for $VPN_NAME" "$(nmcli connection down id $VPN_NAME)" ;; disconnected) notify.sh "VPN Status for $VPN_NAME" "$(nmcli connection up id $VPN_NAME)" ;; esac ;;
# "bluetooth") bluetoothctl show | grep -q "Powered: yes" && notify.sh "Bluetooth turned off" "$(bluetoothctl power off)" || notify.sh "Bluetooth turned on" "$(bluetoothctl power on; bluetoothctl connect $selected_option && pactl set-sink-volume @DEFAULT_SINK@ 20%)" ;;
*) # these are used when no matches happen (if anything matches, then match is returned, if not what was typed), we input the identifier ourselves, and the remaining becomes the selected_option_1, for example search the selected_option_1
# can be used as a way to easily use ddg "bangs", but more flexible, and browser/search engine agnostic
identifier_1="$(printf "%s" "$selection" | cut -d' ' -f 1 | sed "s/^'//")" # && printf "%s" "$identifier_1" && printf "\n"
selected_option_1="$(printf "%s" "$selection" | cut -d' ' -f 2- | sed "s/^'//")" # && printf "%s" "$selected_option_1" && printf "\n"
wl-copy "$selected_option_1" # copying the selection, helps in rerunning the command (helpful in debugging, or for example with calculator or music, where you slightly messed it up)
case "$identifier_1" in
"unnote") del=$(($selected_option_1)) && sed -i "${del}d" "$savedir"/notes ;;
"note") (printf '%s' "- $selected_option_1" && printf "\n") >> "$savedir"/notes ;;
"execb") eval "$selected_option_1" ;;
"save") category="$(printf "%s" "$selected_option_1" | cut -d' ' -f 1)"
tobesaved="$(printf "%s" "$selected_option_1" | cut -d' ' -f 2)"
description=""
if [ "$(printf "%s" "$selected_option_1" | wc -w)" -gt 2 ]; then description="$(printf "%s" "$selected_option_1" | cut -d' ' -f 3-)" ; fi
sniptobesaved="$(printf "%s" "$selected_option_1" | cut -d' ' -f 2-)"
case "$category" in
"web") title="$(curl -s "$url" | grep -oP '(?<=<title>).*?(?=</title>)')"
printf "$tobesaved\t$title $description\n" >> "$savedir"/web
notify.sh "$tobesaved" "$title $description" ;;
"webp") title="$(curl -s "$tobesaved" | grep -oP '(?<=<title>).*?(?=</title>)')"
printf "$tobesaved\t$title $description\n" >> "$savedir"/webp
notify.sh "$tobesaved" "$title $description" ;;
"contact") printf "$tobesaved\t$description\n" >> "$savedir"/contact-details
notify.sh "$tobesaved" "$description" ;;
"file") printf "$tobesaved\t$description\n" >> "$savedir"/files
notify.sh "$tobesaved" "$description" ;;
"exec") printf "$sniptobesaved\n" >> "$savedir"/exec
notify.sh "$savedir/exec" "$sniptobesaved" ;;
"command") printf "$sniptobesaved\n" >> "$savedir"/snippets-autocomplete/commands-and-snippets
notify.sh "$savedir/snippets-autocomplete/commands-and-snippets" "$sniptobesaved" ;;
"random") printf "$sniptobesaved\n" >> "$savedir"/snippets-autocomplete/random-stuff
notify.sh "$savedir/snippets-autocomplete/random-stuff" "$sniptobesaved" ;;
*) notify.sh "Usage of save is changed" "do save [web/webp/contact/exec/command/random]"
esac ;;
"import") grep -o '<DT><A HREF="[^"]\+"[^>]\+>[^<]\+</A>' "$selected_option_1" |
sed 's/<DT><A HREF="\([^"]\+\)"[^>]*>\([^<]\+\)<\/A>/web\t\1\t\2/' >> "$savedir"/web.txt ;;
"rssadd") name="$( curl -s $selected_option_1 | grep -oP '(?<=<title>).*?(?=</title>)' | head -n1 )"
printf "$selected_option_1 \"$name\"\n" >> "$HOME"/.config/newsraft/feeds
notify.sh "Subscribed to rss feed $name" "$selected_option_1";;
"ytsub") channel_id="$(printf "%s" "$selected_option_1" | grep -oP '(?<=channel/)\K.*')"
name="$( curl -s https://www.youtube.com/channel/$channel_id | grep -oP '(?<=<title>).*?(?=</title>)' | sed -z 's/\ \-\ YouTube//g')"
printf "https://www.youtube.com/feeds/videos.xml?channel_id=$channel_id \"$name\"\n" >> "$HOME"/.config/newsraft/feeds
notify.sh "Subscribed to $name" "$channel_id";;
"compress") "$HOME"/.local/bin/compress "$selected_option_1" ;;
"mpv") mpv "$selected_option_1" ;;
"mpva") mpv --no-video --player-operation-mode=pseudo-gui --speed=1 "$selected_option_1" ;;
"ytdl") yt-dlp "$selected_option_1" && notify.sh "Download Completed" "$selected_option_1" ;;
"ytdla") yt-dlp -x "$selected_option_1" && notify.sh "Download Completed" "$selected_option_1" ;;
"expand") url="$(redive "$selected_option_1" 2>&1 | tail -n1 | cut -d'>' -f 2)"
wl-copy "$url" && notify.sh "Url expands to $url" " " ;;
"upload") url=$(curl -F'file=@'"$selected_option_1" -Fsecret= "https://envs.sh/")
wl-copy "$url" && notify.sh "File uploaded to $url" " " ;;
"qr") printf '%s' "$selected_option_1" | qrencode -o "$tmpoutput"
xdg-open "$tmpoutput" ;;
"download") aria2c "$selected_option_1" ;;
"rename") rename-bib.sh "$selected_option_1" ;;
"mdhtml") input_file_name="${selected_option_1%.*}" && pandoc -s --css="style.css" --highlight-style=haddock -f markdown -t html5 -o "$input_file_name".html "$selected_option_1" ;;
"calc") result=$(fish -c "math $selected_option_1")
wl-copy "$result" && notify.sh "$selected_option_1 = $result" " " ;;
"ytl") qb-open-url-in-instance.sh https://www.youtube.com/results?search_query="$selected_option_1" ;;
"ddg") qb-open-url-in-instance.sh https://html.duckduckgo.com/html?q="$selected_option_1" ;;
"sxpkg") qb-open-url-in-instance.sh https://my-fake-search-engine.sga/search?q="site:archlinux.org/packages/ bin/$selected_option_1" ;; # searching a file in arch packages
"wiki") qb-open-url-in-instance.sh https://wikipedia.org/wiki/Special:Search?search="$selected_option_1" ;;
*) if [ -n "$selection" ]; then qb-open-url-in-instance.sh https://my-fake-search-engine.sga/search?q="$selection" ; fi ;; # for some weird reason, i can not use the qb-open-url-in-instance.sh --search flag, it works, but it will always open a new window, something i do not like, so have to hard code the search engine (--new-tab does not work)
# *) if [ -n "$selection" ]; then qb-open-url-in-instance.sh http://127.0.0.1:8888/search?q="$selection" ; fi ;; # for some weird reason, i can not use the qb-open-url-in-instance.sh --search flag, it works, but it will always open a new window, something i do not like, so have to hard code the search engine (--new-tab does not work)
esac ;;
esac

How does this work

Dependencies

Discussion

Video Demo