mirror of
				https://github.com/ItsDrike/dotfiles.git
				synced 2025-11-04 01:16:35 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			338 lines
		
	
	
	
		
			8.8 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			338 lines
		
	
	
	
		
			8.8 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable file
		
	
	
	
	
#!/bin/bash
 | 
						|
 | 
						|
# Compatibility executable script for applications running dmenu, which
 | 
						|
# runs wofi in dmenu mode instead. Note: In many cases the arguments won't
 | 
						|
# be compatible and this will fail, however the primary way scripts use
 | 
						|
# dmenu is just for simple prompts, using the `-p` flag. and wofi does fully
 | 
						|
# support this usage.
 | 
						|
 | 
						|
# Wrapper script for menu application independent prompts. This script will pick 
 | 
						|
# the appropriate installed prompt tool (dmenu/rofi/wofi) and use run it accordingly
 | 
						|
# to picked usage option(s).
 | 
						|
 | 
						|
help() {
 | 
						|
  cat << EOF
 | 
						|
usage: menuprompt
 | 
						|
Menuprompt is a wrapper script for menu application independent prompt (dmenu/rofi/wofi)
 | 
						|
 | 
						|
options:
 | 
						|
  -h, --help                show this help message and exit
 | 
						|
  -p, --prompt [MESSAGE]    Prompt to be displayed in the menu
 | 
						|
  -a, --app [MENU_APP]      Overrides the app picked by default, must be one of supported apps
 | 
						|
  -v, --verbose             Show debug information (printed to stderr to retain pipeable stdout output)
 | 
						|
  -vv, --very-verbose       Show even more debug information
 | 
						|
  --dry-run                 Don't actually run the final menu command (only useful with --verbose)
 | 
						|
 | 
						|
actions:
 | 
						|
  -c, --choose
 | 
						|
      Basic pick prompt, picking from piped newline separated options
 | 
						|
      The picked option will be printed to stdout.
 | 
						|
      usage: printf 'No\nYes' | menuprompt -c -p 'Pick one: '
 | 
						|
  -yn, --yesno
 | 
						|
      Essentially an alias for printf 'No\nYes' | menuprompt -p "\$1", however instead of printing the result
 | 
						|
      to stdout, this instead exits with code 0 on success, 1 on failure, or 2 on getting other input. This
 | 
						|
      allows for easily combining it with other applications through chaining.
 | 
						|
      example: menuprompt --yesno && poweroff or menuprompt -yn -p "Do you really want to quit?" && killall Hyprland
 | 
						|
  -P, --password
 | 
						|
      Password prompt - hides the input characters
 | 
						|
      example: menuprompt -P -p "Enter password:" | xargs -I {} echo "Hah, got your password: {}"
 | 
						|
 | 
						|
supported menu applications and their actions:
 | 
						|
  dmenu:
 | 
						|
    - choose: supported
 | 
						|
    - yesno: supported
 | 
						|
    - password: supported, but requires password patch for -P argument
 | 
						|
  wofi:
 | 
						|
    - choose: supported
 | 
						|
    - yesno: supported
 | 
						|
    - password: supported, however setting --prompt won't have any effect
 | 
						|
  rofi:
 | 
						|
    - choose: supported
 | 
						|
    - yesno: supported
 | 
						|
    - password: not supported - no option for hidden input
 | 
						|
 | 
						|
 | 
						|
passing custom arguments to menu app:
 | 
						|
    Note that when passing extra arguments, you should always explicity specify the menu application to use
 | 
						|
    as it's not guaranteed that all supported args will support given extra argument(s), nor that if they do
 | 
						|
    their support is consistent and the same argument does the same thing.
 | 
						|
 | 
						|
    examples:
 | 
						|
        Make dmenu run on the bottom of the screen:
 | 
						|
        printf "A\nB\nC" menuprompt --app dmenu --choose -- -b
 | 
						|
 | 
						|
        Run wofi with 20% width on the yesno prompt:
 | 
						|
        menuprompt --yesno -p "Do you really want to quit?" --app wofi -- --width=20%
 | 
						|
 | 
						|
 | 
						|
exit codes:
 | 
						|
  0:    Menu app ran successfully, action completed
 | 
						|
  1-2:  Action specific
 | 
						|
  3:    User error - invalid usage
 | 
						|
  4:    Unable to pick menu app (no usable menu app installed?)
 | 
						|
  5:    Internal menuprompt error, report this!
 | 
						|
EOF
 | 
						|
}
 | 
						|
 | 
						|
pick_menu_app() {
 | 
						|
  if [ -n "$MENU_APP" ]; then
 | 
						|
    if command -v "$MENU_APP" >/dev/null; then
 | 
						|
      echo "$MENU_APP"
 | 
						|
      return 0
 | 
						|
    else
 | 
						|
      >&2 echo "Specified menu app by (set by \$MENU_APP) isn't a valid command \`$MENU_APP\`"
 | 
						|
      exit 3
 | 
						|
    fi
 | 
						|
  fi
 | 
						|
 | 
						|
  if [ "$XDG_SESSION_TYPE" = "x11" ]; then
 | 
						|
    if command -v dmenu >/dev/null; then
 | 
						|
      echo "dmenu"
 | 
						|
    elif command -v rofi >/dev/null; then
 | 
						|
      echo "rofi"
 | 
						|
    else
 | 
						|
      >&2 echo "Menu application for x11 not found, neither dmenu nor rofi available."
 | 
						|
      exit 3
 | 
						|
    fi
 | 
						|
 | 
						|
  elif [ "$XDG_SESSION_TYPE" = "wayland" ]; then
 | 
						|
    if command -v wofi >/dev/null; then
 | 
						|
      echo "wofi"
 | 
						|
    else
 | 
						|
      >&2 echo "Menu application for wayland not found, wofi not available."
 | 
						|
      exit 3
 | 
						|
    fi
 | 
						|
 | 
						|
  else
 | 
						|
    >&2 echo "Unknown session type, expected \$XDG_SESSION_TYPE to be \`wayland\` or \`x11\`, got \`$XDG_SESSION_TYPE\`."
 | 
						|
    exit 3
 | 
						|
  fi
 | 
						|
}
 | 
						|
 | 
						|
# Runs picked menu application with 
 | 
						|
# $1    pipe STDIN if set to "1", runs normally if "0"
 | 
						|
# $2    app to use (result of pick_menu_app)
 | 
						|
# $3    prompt to be shown (can be empty)
 | 
						|
# $4-   extra args to pass to given menu app
 | 
						|
runmenu() {
 | 
						|
  pipe_stdin="$1"
 | 
						|
  app="$2"
 | 
						|
  prompt="$3"
 | 
						|
  shift 3
 | 
						|
 | 
						|
  if [ "$VERBOSITY" -ge 2 ]; then
 | 
						|
    if [ $# -gt 0 ]; then
 | 
						|
      >&2 echo "Making menu command for app: \`$app\`, with prompt: \`$prompt\` and extra args: \`$*\`"
 | 
						|
    else
 | 
						|
      >&2 echo "Making menu command for app: \`$app\`, with prompt: \`$prompt\` (no extra args)"
 | 
						|
    fi
 | 
						|
  fi
 | 
						|
 | 
						|
  if [ "$app" = "dmenu" ] && [ "$pipe_stdin" -eq 0 ]; then
 | 
						|
    >&2 echo "Dmenu can only be used with piped STDIN (forgot --choose?)"
 | 
						|
    exit 3
 | 
						|
  fi
 | 
						|
 | 
						|
  args=()
 | 
						|
  case "$app" in
 | 
						|
    dmenu)
 | 
						|
      args+=("-i")
 | 
						|
      ;;
 | 
						|
    wofi)
 | 
						|
      args+=("--dmenu")
 | 
						|
      ;;
 | 
						|
    rofi)
 | 
						|
      args+=("-dmenu")
 | 
						|
      ;;
 | 
						|
    *)
 | 
						|
      >&2 echo "Unsupported menu app: $app"
 | 
						|
      exit 4
 | 
						|
      ;;
 | 
						|
  esac
 | 
						|
 | 
						|
  if [ -n "$prompt" ]; then
 | 
						|
    if [ "$app" = "wofi" ] && [ "$pipe_stdin" -eq 0 ]; then
 | 
						|
      >&2 echo "WARNING: wofi prompt can only be displayed with piped STDIN (forgot --choose?)"
 | 
						|
    fi
 | 
						|
    args+=("-p" "$prompt")
 | 
						|
  fi
 | 
						|
 | 
						|
  if [ "$VERBOSITY" -ge 1 ]; then
 | 
						|
    >&2 echo "Generated command: \`$app ${args[*]} $*\`"
 | 
						|
  fi
 | 
						|
 | 
						|
  if [ "$DRY_RUN" -ne 1 ]; then
 | 
						|
    if [ "$pipe_stdin" -eq 1 ]; then
 | 
						|
      cat | $app "${args[@]}" "$@"
 | 
						|
    elif [ "$pipe_stdin" -eq 0 ]; then
 | 
						|
      $app "${args[@]}" "$@"
 | 
						|
      return $?
 | 
						|
    else
 | 
						|
      >&2 echo "Internal error, pipe_stdin set to invalid value: \`$pipe_stdin\`"
 | 
						|
      exit 5
 | 
						|
    fi
 | 
						|
  else
 | 
						|
    return 0
 | 
						|
  fi
 | 
						|
}
 | 
						|
 | 
						|
# $1    app to use (result of pick_menu_app)
 | 
						|
# $2    prompt to be shown (can be empty)
 | 
						|
# $2-   extra arguments to pass to given menu app
 | 
						|
password() {
 | 
						|
  app="$1"
 | 
						|
  prompt="$2"
 | 
						|
  shift 2
 | 
						|
 | 
						|
  if [ "$VERBOSITY" -ge 2 ]; then
 | 
						|
    >&2 echo "Prompting for password..."
 | 
						|
  fi
 | 
						|
 | 
						|
  if [ "$app" = "dmenu" ]; then
 | 
						|
    if ! runmenu "0" "$app" "$prompt" -P "$@"; then
 | 
						|
      >&2 echo "To use dmenu for passwords, you need to apply the password patch."
 | 
						|
      exit 3
 | 
						|
    fi
 | 
						|
  elif [ "$app" = "wofi" ]; then
 | 
						|
    runmenu "0" "$app" "$prompt" -P "$@"
 | 
						|
  elif [ "$app" = "rofi" ]; then
 | 
						|
    >&2 echo "Rofi doesn't support password/hidden input."
 | 
						|
    exit 3
 | 
						|
  else
 | 
						|
    >&2 echo "Unsupported menu application picked: \`$app\`"
 | 
						|
    exit 4
 | 
						|
  fi
 | 
						|
}
 | 
						|
 | 
						|
# $1    app to use (result of pick_menu_app)
 | 
						|
# $2    prompt to be shown (can be empty)
 | 
						|
# $3-   extra arguments to pass to the menu app
 | 
						|
yesno() {
 | 
						|
  app="$1"
 | 
						|
  prompt="$2"
 | 
						|
  shift 2
 | 
						|
 | 
						|
  if [ "$VERBOSITY" -ge 2 ]; then
 | 
						|
    >&2 echo "Prompting for yesno..."
 | 
						|
  fi
 | 
						|
 | 
						|
  temp="$(printf "No\nYes" | runmenu "1" "$app" "$prompt" "$@")"
 | 
						|
 | 
						|
  if [ "$VERBOSITY" -ge 2 ]; then
 | 
						|
    >&2 echo "Yesno prompt answer: \`$temp\`"
 | 
						|
  fi
 | 
						|
 | 
						|
  if [ "$temp" = "Yes" ]; then
 | 
						|
    return 0
 | 
						|
  elif [ "$temp" = "No" ]; then
 | 
						|
    return 1
 | 
						|
  else
 | 
						|
    return 2
 | 
						|
  fi
 | 
						|
}
 | 
						|
 | 
						|
#@  - extra args to pass to picked menu app
 | 
						|
run() {
 | 
						|
  app="$(pick_menu_app)"
 | 
						|
 | 
						|
  if [ "$VERBOSITY" -ge 2 ]; then
 | 
						|
    >&2 echo "ACTION: \`$ACTION\`"
 | 
						|
    >&2 echo "PROMPT_ARG: \`$PROMPT_ARG\`"
 | 
						|
    >&2 echo "picekd app: \`$app\`"
 | 
						|
    >&2 echo "Extra args: \`$*\`"
 | 
						|
  fi
 | 
						|
 | 
						|
  if [ -z "$ACTION" ]; then
 | 
						|
    runmenu "0" "$app" "$PROMPT_ARG" "$@"
 | 
						|
    return $?
 | 
						|
  elif [ "$ACTION" = "choose" ]; then
 | 
						|
    runmenu "1" "$app" "$PROMPT_ARG" "$@"
 | 
						|
    return $?
 | 
						|
  elif [ "$ACTION" = "yesno" ]; then
 | 
						|
    yesno "$app" "$PROMPT_ARG" "$@"
 | 
						|
    return $?
 | 
						|
  elif [ "$ACTION" = "password" ]; then
 | 
						|
    password "$app" "$PROMPT_ARG" "$@"
 | 
						|
    return $?
 | 
						|
  fi
 | 
						|
 | 
						|
  >&2 echo "Huh? How did you get here?"
 | 
						|
  >&2 echo "Rerun this command with the --verbose flag and submit a report with the captured output."
 | 
						|
  exit 5
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
ACTION=""
 | 
						|
PROMPT_ARG=""
 | 
						|
MENU_APP="${MENU_APP-""}"
 | 
						|
VERBOSITY=0
 | 
						|
DRY_RUN=0
 | 
						|
while [ "$1" ]; do
 | 
						|
  case "$1" in
 | 
						|
    # options
 | 
						|
    -h|--help)
 | 
						|
      help
 | 
						|
      exit 0
 | 
						|
      ;;
 | 
						|
    -a|--app)
 | 
						|
      MENU_APP="$2"
 | 
						|
      shift 2
 | 
						|
      ;;
 | 
						|
    -p|--prompt)
 | 
						|
      PROMPT_ARG="$2"
 | 
						|
      shift 2
 | 
						|
      ;;
 | 
						|
    -v|--verbose)
 | 
						|
      VERBOSITY=1
 | 
						|
      shift
 | 
						|
      ;;
 | 
						|
    -vv|--very-verbose)
 | 
						|
      VERBOSITY=2
 | 
						|
      shift
 | 
						|
      ;;
 | 
						|
    --dry-run)
 | 
						|
      DRY_RUN=1
 | 
						|
      shift
 | 
						|
      ;;
 | 
						|
 | 
						|
    # actions
 | 
						|
    -c|--choose)
 | 
						|
      if [ -n "$ACTION" ]; then
 | 
						|
        >&2 echo "Action already set, can't specify multiple actions"
 | 
						|
        exit 3
 | 
						|
      fi
 | 
						|
      ACTION="choose"
 | 
						|
      shift
 | 
						|
      ;;
 | 
						|
    -yn|--yesno)
 | 
						|
      if [ -n "$ACTION" ]; then
 | 
						|
        >&2 echo "Action already set, can't specify multiple actions"
 | 
						|
        exit 3
 | 
						|
      fi
 | 
						|
      ACTION="yesno"
 | 
						|
      shift
 | 
						|
      ;;
 | 
						|
    -P|--password)
 | 
						|
      if [ -n "$ACTION" ]; then
 | 
						|
        >&2 echo "Action already set, can't specify multiple actions"
 | 
						|
        exit 3
 | 
						|
      fi
 | 
						|
      ACTION="password"
 | 
						|
      shift
 | 
						|
      ;;
 | 
						|
    --)
 | 
						|
      shift
 | 
						|
      run "$@"
 | 
						|
      exit $?
 | 
						|
      ;;
 | 
						|
 | 
						|
    # err
 | 
						|
    *) 
 | 
						|
      >&2 echo "Unrecognized argument: $1"
 | 
						|
      >&2 echo "use -h or --help for help"
 | 
						|
      exit 4
 | 
						|
      ;;
 | 
						|
  esac
 | 
						|
done
 | 
						|
 | 
						|
run
 |