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

#!/bin/sh
payload=$({
  cliphist list | while read -r line ; do printf "Clipboard\t$line\n" ; done
  cat $XDG_STATE_HOME/application_cache $HOME/Backups/bookmarks
  find $HOME/Music $HOME/Videos/Movies $HOME/.local/bin -name "*" | while read -r line ; do printf "File\t$line\n" ; done
})
# 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 )

# Using fzf(via term-dmenu), which by default does fuzzy search, searching for online stuff or playing media or youtube links requires exactness, and fzf --exact is to strict(like it will search full input string, not the terms like dmenu). We can apply special modifiers to term - ' for exact, ^ for prefix exact, . for suffix exact, ! for inverse (reject) and combinations, so trimming them from 1st and second terms (which seems to be enough to make search good) This function strips the few specified symbols from the front of input, this is used for selection and also for selected_option_1
remove_first_char() {
  local input="$@"
  case "$(printf %.1s "$input")" in
    \'|'^'|'!'|'*')
      printf "%s" "$input" | cut -c2-;;
    *)
      printf "%s" "$input";;
  esac
}

# uncomment the printf statements for debugging
selection=$(remove_first_char "$selection") # && printf "%s" "$selection" && printf "\n"
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
  "Copy") wl-copy --trim-newline "$selected_option" ;;
  "Type") wtype "$selected_option" ;; # stuff to be auto-typed anywhere you want (currrently using to write long commands)
  "Exec") eval "$selected_option" ;;
  "ExecCopy") eval "$selected_option" | wl-copy --trim-newline ;;
  "ExecType") eval "$selected_option" | wtype - ;;
  "Clipboard") printf "%s" "$selection" | cut -f 2- | cliphist decode | wl-copy --trim-newline ;;
  # replace librewolf, with default browser, or your prefered browser
  "Web") exec librewolf "$selected_option" ;;
  "Firefox") exec librewolf "$selected_option" ;; # for librewolf specific pages like about: stuff, i have bookmarked ab:config/profile for quick access
  "Edit") exec editor-terminal "$selected_option" ;;
  "File") exec xdg-open "$selected_option" ;;
  *)
    # 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)"
    selected_option_1="$(printf "%s" "$selection" | cut -d' ' -f 2-)"
    selected_option_1="$(remove_first_char "$selected_option_1")"
    # printf "%s" "$identifier_1" && printf "\n"
    # 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
      "save") url="$(printf "%s" "$selected_option_1" | cut -d' ' -f 1)"
        description="$(printf "%s" "$selected_option_1" | cut -d' ' -f 2-)"
        printf "Web\t$url\t$description\n" >> /home/sg/Backups/bookmarks
        notify-send "Bookmark added $url" "$description" ;;
      "ytsub") channel_id="$(printf "%s" "$selected_option_1" | grep -oP '(?<=channel/)\K.*')"
        printf "https://www.youtube.com/feeds/videos.xml?channel_id=$channel_id" >> /home/sg/.config/newsboat/urls ;;
      "wiki") librewolf https://wikipedia.org/wiki/Special:Search?search="$selected_option_1" ;;
      "compress") /home/sg/.local/bin/compress "$selected_option_1" ;;
      "ddg") librewolf https://html.duckduckgo.com/html?q="$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" ;;
      "ytdl") yt-dlp "$selected_option_1" ;;
      "expand") url=$(curl http://urlxray.com/display.php?url="$selected_option_1" | rg title | cut -d'>' -f 3 | cut -d'<' -f 1 | cut -d' ' -f 2)
        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" ;;
      "download") aria2c "$selected_option_1" ;;
      "teams") teams-for-linux --url "$selected_option_1" ;;
      "calc") result=$(qalc +u8 --terse "$selected_option_1")
        wl-copy "$result" && notify-send "$selected_option_1 = $result" "Result copied to clipboard" ;;
      "sxpkg") librewolf https://search.sapti.me/search?q="site:archlinux.org/packages/ bin/$selected_option_1" ;; # searching a file in arch packages
      *) if [ -n "$selection" ]; then librewolf https://search.sapti.me/search?q="$selection" ; fi ;; # for some wierd reason, i can not use the librewolf --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