I have a little helper command in ~/.zshrc called stfu.

stfu() {
    if [ -z "$1" ]; then
        echo "Usage: stfu <program> [arguments...]"
        return 1
    fi

    nohup "$@" &>/dev/null &
    disown
}
complete -W "$(ls /usr/bin)" stfu

stfu will run some other command but also detach it from the terminal and make any output shut up. I use it for things such as starting a browser from the terminal without worrying about CTRL+Z, bg, and disown.

$ stfu firefox -safe-mode
# Will not output stuff to the terminal, and
# I can close the terminal too.

Here’s my issue:

On the second argument and above, when I hit tab, how do I let autocomplete suggest me the arguments and command line switches for the command I’m passing in?

e.g. stfu ls -<tab> should show me whatever ls’s completion function is, rather than listing every /usr/bin command again.

# Intended completion
$ stfu cat -<TAB>
-e                      -- equivalent to -vE                                                                                                                                                     
--help                  -- display help and exit                                                                                                                                                 
--number            -n  -- number all output lines                                                                                                                                               
--number-nonblank   -b  -- number nonempty output lines, overrides -n                                                                                                                            
--show-all          -A  -- equivalent to -vET                                                                                                                                                    
--show-ends         -E  -- display $ at end of each line                                                                                                                                         
--show-nonprinting  -v  -- use ^ and M- notation, except for LFD and TAB                                                                                                                         
--show-tabs         -T  -- display TAB characters as ^I                                                                                                                                          
--squeeze-blank     -s  -- suppress repeated empty output lines                                                                                                                                  
-t                      -- equivalent to -vT                                                                                                                                                     
-u                      -- ignored  

# Actual completion
$ stfu cat <tab>
...a list of all /usr/bin commands
$ stfu cat -<tab>
...nothing, since no /usr/bin commands start with -

(repost, prev was removed)

EDIT: Solved.

I needed to set the curcontext to the second word. Below is my (iffily annotated) zsh implementation, enjoy >:)

stfu() {
  if [ -z "$1" ]; then
    echo "Usage: stfu <program> [arguments...]"
    return 1
  fi

  nohup "$@" &>/dev/null &
  disown
}
#complete -W "$(ls /usr/bin)" stfu
_stfu() {
  # Curcontext looks like this:
  #   $ stfu <tab>
  #   :complete:stfu:
  local curcontext="$curcontext" 
  #typeset -A opt_args # idk what this does, i removed it

  _arguments \
    '1: :_command_names -e' \
    '*::args:->args'

  case $state in
    args)
      # idk where CURRENT came from
      if (( CURRENT > 1 )); then
        # $words is magic that splits up the "words" in a shell command.
        #   1. stfu
        #   2. yourSubCommand
        #   3. argument 1 to that subcommand
        local cmd=${words[2]}
        # We update the autocompletion curcontext to
        # pay attention to your subcommand instead
        curcontext="$cmd"

        # Call completion function
        _normal
      fi
      ;;
  esac
}
compdef _stfu stfu

Deduced via docs (look for The Dispatcher), this dude’s docs, stackoverflow and overreliance on ChatGPT.

EDIT: Best solution (Andy)

stfu() {
  if [ -z "$1" ]; then
    echo "Usage: stfu <program> [arguments...]"
    return 1
  fi

  nohup "$@" &>/dev/null &
  disown
}
_stfu () {
  # shift autocomplete to right
  shift words
  (( CURRENT-=1 ))
  _normal
}
compdef _stfu stfu
  • hallettj@leminal.space
    link
    fedilink
    English
    arrow-up
    4
    arrow-down
    1
    ·
    6 months ago

    All I can tell you is that this is done differently for each shell. So decide whether you want completions for bash, zsh, fish, all of the above, or whatever, and look at the docs for the relevant shells.