fuzzel-run-or-search.sh 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. #!/bin/bash
  2. # Run a command, or search the web for it.
  3. #
  4. # Enter run it if it is an executable, otherwise search for it
  5. # Alt+Enter always search, even if it looks like a command
  6. #
  7. # The second one exists because deciding by "is the first word a binary?" gets
  8. # it wrong for ordinary phrases: test, who, which, sort, time and file are all
  9. # real executables. Alt+Enter is bound to fuzzel's custom-1, which is dmenu-only
  10. # and exits with code 10 (see [key-bindings] in fuzzel.ini).
  11. browser_app_id="google-chrome"
  12. search_url="https://duckduckgo.com/?q="
  13. # Executables in PATH. Deliberately not `compgen -c`: that also lists shell
  14. # builtins and keywords (cd, alias, if, ...), which `command -v` reports as
  15. # found but `exec` cannot run.
  16. list_path_bins() {
  17. local IFS=: dir file
  18. for dir in $PATH; do
  19. [[ -d $dir ]] || continue
  20. for file in "$dir"/*; do
  21. [[ -f $file && -x $file ]] && printf '%s\n' "${file##*/}"
  22. done
  23. done | sort -u
  24. }
  25. search_web() {
  26. local query
  27. query=$(jq -rn --arg q "$1" '$q|@uri')
  28. xdg-open "$search_url$query" &
  29. # Wait for the browser window instead of guessing at a fixed sleep: a cold
  30. # start takes well over half a second, while an already-running Chrome is
  31. # ready almost immediately.
  32. local _
  33. for _ in $(seq 40); do
  34. if swaymsg -t get_tree |
  35. jq -e --arg id "$browser_app_id" \
  36. 'recurse(.nodes[]?, .floating_nodes[]?) | select(.app_id == $id)' >/dev/null; then
  37. swaymsg "[app_id=\"$browser_app_id\"] focus" >/dev/null
  38. return 0
  39. fi
  40. sleep 0.05
  41. done
  42. }
  43. result=$(list_path_bins | fuzzel --dmenu)
  44. status=$?
  45. [[ -z $result ]] && exit 0
  46. case $status in
  47. # Alt+Enter: search regardless of what the text looks like.
  48. 10)
  49. search_web "$result"
  50. ;;
  51. # Enter: run it if it really is an executable. type -P looks only at PATH,
  52. # so builtins and keywords fall through to the search instead of failing
  53. # silently in exec.
  54. 0)
  55. if type -P "${result%% *}" >/dev/null 2>&1; then
  56. exec $result
  57. fi
  58. search_web "$result"
  59. ;;
  60. # Escape, or fuzzel failed to start.
  61. *)
  62. exit 0
  63. ;;
  64. esac