Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

More fun with _su



On Dec 27, 12:22am, Bart Schaefer wrote:
}
} I'm working on improving _su, mainly so that it'll call _normal on the
} argument of the -c flag, the way _sh does.

So what follows is what I have so far.

Fiddling with $first is to address another _arguments problem; completing

   su someuser -f <TAB>

it fails to recognize that the "first non-option argument", "someuser", is
already present on the line, and insists on completing user names again if
'1:user name:_users' is seen.  It's as if the count of non-option arguments
is reset to zero by the interposition of an option argument.

There are three other things that still have me stumped:

(1) I can't figure out how to tell _arguments that it should omit the -l
    and --login options when a solitary "-" is already present.  Yes, I
    could hack it, similar to what I did for $shell and $first, but it
    seems as if it should be possible another way.

(2) When calling _dispatch with -default- at the end, which is about the
    only thing I tried to keep from the previous _su, the listing of file
    names is sometimes doubled.  I traced this as far as discovering that
    _files is called at least twice, once to populate the "files" group
    and again to populate the "globbed-files" group, and both get the same
    list of files -- but why this happens, and why specifically it only
    appears to happen when completing after some shell paths given with -s
    (and not when completing after other shell paths or after --shell=...),
    remains mysterious.

    I think this is related to the matcher-list problem mentioned in the
    other thread, but it happens whether or not the matcher-list style is
    set.

(3) When completing after --command=, compset -q insists on removing quotes
    and adding backslashes instead.  This is somewhat annoying.  Completing
    in a separate word, as when after -c, allows the quotes to remain.

No point in sending a patch, it's almost entirely rewritten.

------------
#compdef su

local -A opt_args
local -a args state context
local shell=${words[(i)(-s|--shell=*)]} first='1:user name:_users'
local usr=root line

if _pick_variant gnu="Free Software Foundation" unix --version; then
  args=(
    '(--command)-c[pass command to shell]:command string:->command'
    '(-c)--command=-[pass command to shell]:command string:->command'
    '-f[pass -f to shell (csh)]'
    '(--login)-l[use a login shell]'
    '(-l)--login[use a login shell]'
    '(-p --preserve-environment)-m[do not reset environment]'
    '(-m --preserve-environment)-p[do not reset environment]'
    '(-m -p)--preserve-environment[do not reset environment]'
    '(--shell)-s[run the specified shell]:shell:->shell'
    '(-s)--shell=-[run the specified shell]:shell:->shell'
  )
else
  args=(
    '-c[pass command to shell]:command string:->command'
    '-l[use a login shell]'
    '-s[run the specified shell]:shell:->shell'
  )
fi

if [[ $#words -ge 2 && $words[2] != -* && CURRENT -ne 2 ]]; then
    usr=$words[2]
    first=
fi

[[ $words[shell] == -s ]] && ((shell++))

if [[ CURRENT -ne shell && -n ${words[shell]} ]]; then
    shell=${words[shell]#*=}
else
    shell="${${(M@)${(@f)$(</etc/passwd)}:#$usr*}##*:}"
fi

[[ -z $first ]] && compset -n 2

_arguments : $args[@] $first "*:${shell:t} arguments:->rest" && return

case $state in
    (command)
        compset -q
        _normal && return
        ;;
    (shell)
        compadd ${(f)^"$(</etc/shells)"}(N) && return
        ;;
    (rest)
        if [[ -z $shell ]]; then
            _arguments "-s[run the specified shell, $usr has no shell]" ||
                _message "-s option required, $usr has no shell"
            compstate[insert]=
        else
            # Something wrong here: doubles the file listing sometimes
            _dispatch $shell:t $shell $shell:t -default- && return
        fi
        ;;
esac

return 1



Messages sorted by: Reverse Date, Date, Thread, Author