#!/bin/bash # Run a command, or fall back to a web search if it isn't one. # fuzzel --dmenu prints the typed string as-is when nothing matches, # which is what makes the search fallback work. browser_app_id="google-chrome" search_url="https://duckduckgo.com/?q=" # Executables in PATH. Deliberately not `compgen -c`: that also lists shell # builtins and keywords (cd, alias, if, ...), which `command -v` reports as # found but `exec` cannot run. list_path_bins() { local IFS=: dir file for dir in $PATH; do [[ -d $dir ]] || continue for file in "$dir"/*; do [[ -f $file && -x $file ]] && printf '%s\n' "${file##*/}" done done | sort -u } result=$(list_path_bins | fuzzel --dmenu) [[ -z $result ]] && exit 0 # type -P looks only at PATH, so builtins and keywords correctly fall through # to the search branch instead of failing silently in exec. if type -P "${result%% *}" >/dev/null 2>&1; then exec $result fi query=$(jq -rn --arg q "$result" '$q|@uri') xdg-open "$search_url$query" & # Wait for the browser window instead of guessing at a fixed sleep: a cold # start takes well over half a second, while an already-running Chrome is # ready almost immediately. for _ in $(seq 40); do if swaymsg -t get_tree | jq -e --arg id "$browser_app_id" \ 'recurse(.nodes[]?, .floating_nodes[]?) | select(.app_id == $id)' >/dev/null; then swaymsg "[app_id=\"$browser_app_id\"] focus" >/dev/null exit 0 fi sleep 0.05 done