Launcher for Everything*

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

23 June, 2024

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, please help yourself with Table of contents

A terminal window with fzf opened showing options to select from clipboard

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 krunner, 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, C, 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 may have to make changes.

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

#!/usr/bin/env sh
llamadir="$HOME/data/local-installations/llama.cpp"
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 with fend and convert units ctof ftoc oC oF\naddtime\tadd time in human formats expects [h:]m:]s,  example:  tsum  04:20  39:42  1:23:45\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/' ; \
  find "$HOME"/.password-store/ -name "*.gpg" -type f -printf "%P\n" | sed 's/^/pass\t/' ; \
  find "$HOME"/gallery/memes/reactions/ -type f | sed 's/^/drag-file\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/admin -type f -name "*" && find "$HOME"/.config/ -maxdepth 2 -type f -name "*" && sed '/^$/d' "$savedir"/files) | sed 's/^/file\t/' ; \
  ls /usr/share/applications | sed 's/^/application\t/')"
# 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" | term-dmenu)
# selection=$(printf "%s" "$payload" | tofi)
# selection=$(printf "%s" "$payload" | fuzzel --dmenu --no-icons --background-color=000000ff --text-color=ddddddff --width 60 --match-color=1690dfff --selection-color=111111ff --selection-text-color=ffffffff --selection-match-color=1690dfff --match-mode=exact --font="DejaVu Sans Mono 10")

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

tsum() { # https://ocv.me/doc/unix/oneliners/
  local p='s/0?([0-9]+):0?([0-9]+)/\1*60+\2/'
  local ts=0 h=0 m=0 s=0
  for orig in "$@"; do
    s=$(echo "$orig" | sed -r "$p" | bc)
    ts=$((ts + s))
    h=$((ts / (60 * 60)))
    s=$((ts - h * 60 * 60))
    m=$((s / 60))
    s=$((s - m * 60))
    printf '%7s  %d:%02d:%02d  %d\n' "$orig" $h $m $s $ts
  done
}

# uncomment the printf statements for debugging
identifier=$(printf "%s" "$selection" | cut -f 1) # && printf "%s" "$identifier" && printf "\n"
selected_option=$(printf "%s" "$selection" | cut -f 2) # && 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" ;;
  "drag-file") dragon-drop "$selected_option" ;;
  "exec") output="$(eval "$selected_option" 2>&1)"
    notify-send "Command executed and its output" "$selected_option\n------\nOutput\n------\n$output" ;;
  "execsu") output="$(pass local/falls | head -n 1 | sudo -SE bash -c "$selected_option" 2>&1)"
    notify-send "Command executed and its output" "$selected_option\n------\nOutput\n------\n$output" ;;
  "execcopy") eval "$selected_option" | wl-copy --trim-newline ;;
  "exectype") eval "$selected_option" | wtype - ;;
  "execterm") footclient -e bash -c "$selected_option" ;;
  "clipboard") printf "%s" "$selection" | cut -f 2- | cliphist decode | wl-copy --trim-newline ;;
  "web") qutebrowser "$selected_option" ;; # replace qutebrowser, with default browser, or your preferred browser
  "edit") editor-terminal "$selected_option" ;;
  "file") xdg-open "$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 show "$file" >| "$tmpoutput" && xdg-open "$tmpoutput" && \rm -rf "$tmpoutput";;
      # "save") pass show "$file" >| "$HOME/downloads/$(basename $file)" ;; 
      "copy otp") pass otp "$file" | tr -d '\n' | wl-copy ;; 
      "copy login id") pass "$file" | head -2 | tail -1 | tr -d '\n' | cut -d' ' -f 2- | wl-copy ;; 
      "copy password") pass "$file" | head -1 | tr -d '\n' | wl-copy ;; 
      "edit") footclient -e pass edit "$file" ;; 
      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"
    footclient -e bash -c "cd /tmp && $llamadir/build/bin/llama-cli -m $modelsdir/$selected_option --multiline-input --temp 0.6 --ctx-size 4096 --conversation" ;;
  *) # 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)" # && printf "%s" "$identifier_1" && printf "\n"
    selected_option_1="$(printf "%s" "$selection" | cut -d' ' -f 2-)" # && 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-send "Bookmark added $tobesaved" "$title $description" ;;
          "webp") title="$(curl -s "$tobesaved" | grep -oP '(?<=<title>).*?(?=</title>)')" 
            printf "$tobesaved\t$title $description\n" >> "$savedir"/web-public 
            notify-send "Bookmark added $tobesaved" "$title $description" ;;
          "contact") printf "$tobesaved\t$description\n" >> "$savedir"/contact-details 
            notify-send "Bookmark added $tobesaved" "$description" ;;
          "file") printf "$tobesaved\t$description\n" >> "$savedir"/files 
            notify-send "Bookmark added $tobesaved" "$description" ;;
          "exec") printf "$sniptobesaved\n" >> "$savedir"/exec 
            notify-send "Bookmark added $savedir/exec" "$sniptobesaved" ;;
          "command") printf "$sniptobesaved\n" >> "$savedir"/snippets-autocomplete/commands-and-snippets
            notify-send "Bookmark added to $savedir/snippets-autocomplete/commands-and-snippets" "$sniptobesaved" ;;
          "random") printf "$sniptobesaved\n" >> "$savedir"/snippets-autocomplete/random-stuff
            notify-send "Bookmark added to $savedir/snippets-autocomplete/random-stuff" "$sniptobesaved" ;;
          *) notify-send "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-send "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-send "Subscribed to $name" "$channel_id";;
      "compress") "$HOME"/.local/bin/compress "$selected_option_1" ;;
      "yts") footclient --app-id floating-terminal -e ytfzf --detach --notify-playing --force-youtube "$selected_option_1" ;;
      "play") footclient --app-id floating-terminal -e ytfzf --detach --notify-playing --force-youtube -m "$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-send "Download Completed" "$selected_option_1" ;;
      "ytdla") yt-dlp -x "$selected_option_1" && notify-send "Download Completed" "$selected_option_1" ;;
      "expand") url="$(curl -vL "$selected_option_1" 2>&1 | grep "location: " | grep -v "onion" | cut -d':' -f2-)"
        wl-copy "$url" && notify-send "Url expands to $url" "Url copied to clipboard" ;;
      "upload") url=$(curl -F'file=@'"$selected_option_1" -Fsecret= "https://envs.sh/")
        wl-copy "$url" && notify-send "File uploaded to $url" "Url copied to clipboard" ;;
      "qrencode") 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" ;;
      "teams") teams-for-linux --url "$selected_option_1" ;;
      "calc") result=$(fend "$selected_option_1")
        wl-copy "$result" && notify-send "$selected_option_1 = $result" "Result copied to clipboard" ;;
      "addtime") result="$(tsum $selected_option_1)" # expects [h:]m:]s,  example:  tsum  04:20  39:42  1:23:45
        wl-copy "$result" && notify-send "$selected_option_1" "$result \n\n Result copied to clipboard" ;;
      "ddg") qutebrowser https://html.duckduckgo.com/html?q="$selected_option_1" ;;
      "sxpkg") qutebrowser http://127.0.0.1:8888/search?q="site:archlinux.org/packages/ bin/$selected_option_1" ;; # searching a file in arch packages
      "wiki") qutebrowser https://wikipedia.org/wiki/Special:Search?search="$selected_option_1" ;;
      *) if [ -n "$selection" ]; then qutebrowser http://127.0.0.1:8888/search?q="$selection" ; fi ;; # for some weird reason, i can not use the qutebrowser --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