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
  • Andy@programming.dev
    link
    fedilink
    arrow-up
    8
    ·
    7 months ago

    Glad you have it working. This may also work:

    _stfu () {
      shift words
      (( CURRENT-=1 ))
      _normal -P
    }
    compdef _stfu stfu
    
    • fool@programming.devOP
      link
      fedilink
      arrow-up
      4
      ·
      edit-2
      7 months ago

      Stunningly simple, solely a shift. I love MVPs… we can possibly even remove the -P completion func switch :P