• Bug#262247: zsh: Improved make completion

    From Wayne Davison@1:229/2 to Hugo Haas on Sat Aug 21 21:30:26 2004
    From: [email protected]

    On Wed, Aug 18, 2004 at 11:07:36AM -0400, Hugo Haas wrote:
    Attached is an attempt at doing this. It seems to work, though I only
    enabled it for the gnu case.

    I tried your patch, and it ignored targets that had dependencies (since
    it only matched a colon at the end of the line). Here's my attempt at a zsh-only verson of _make. It not only follows include files, but it
    expands variables too. I tried to make it handle both gnu and non-gnu
    include files, but I assume that the ".include <...>" form needs more
    code to handle where the include really resides.

    Since the patch was larger than the new _make script, I'm just attaching
    the new _make script here. Give it a try and see how you like it.

    Also, feel free to suggest how to improve it (for instance, I'd like to
    know if the eval statements can be replaced with something else).

    ..wayne..

    #compdef make gmake pmake dmake

    local prev="$words[CURRENT-1]" file expl tmp is_gnu cmdargs dir incl

    expandVars() {
    local open close var val tmp=$1 ret=$1
    while :; do
    var=${tmp#*\$}
    if [[ $var != $tmp ]]; then
    tmp=$var
    case $var in
    (\(*)
    open='('
    close=')'
    ;;
    ({*)
    open='{'
    close='}'
    ;;
    ([[:alnum:]]*)
    open=''
    close=''
    var=${(s::)var[1]}
    ;;
    (*)
    continue
    ;;
    esac
    if [[ $open != '' ]]; then
    var=${var#$open}
    var=${var%%$close*}
    fi
    case $var in
    ([[:alnum:]_]#)
    eval val=\${$var}
    val=$(expandVars $val)
    ret=${ret//\$$open$var$close/$val}
    ;;
    esac
    else
    print $ret
    return
    fi
    done
    }

    parseMakefile() {
    local input var val TAB=$'\t' dir=$1

    while read input; do
    case "$input " in
    ([[:alnum:]][^$TAB:= ]#[ $TAB]#=*)
    var=${input%%[ $TAB]#=*}
    val=${input#*=}
    val=${val##[ $TAB]#}
    eval $var=\$val
    ;;
    ([[:alnum:]][^$TAB:= ]#[ $TAB]#:=*)
    var=${input%%[ $TAB]#:=*}
    val=${input#*=}
    val=${val##[ $TAB]#}
    val=$(expandVars $val)
    eval $var=\$val
    ;;
    ([[:alnum:]][^$TAB:=]#:[^=]*)
    input=${input%%:*}
    print $(expandVars $input)
    ;;
    ($incl *)
    local f=${input##$incl ##}
    if [[ $incl = '.include' ]]; then
    f=${f#[\"<]}
    f=${f%[\">]}
    fi
    f=$(expandVars $f)
    case $f in
    (/*) ;;
    (*) f=$dir/$f ;;
    esac
    if [ -r $f ]; then
    parseMakefile ${f%%/[^/]##} < $f
    fi
    ;;
    esac
    done
    }

    _pick_variant -r is_gnu gnu=GNU unix -v -f

    if [[ $is_gnu = gnu ]]; then
    incl=include
    else
    incl=.include
    fi
    if [[ "$prev" = -[CI] ]]; then
    _files -/
    elif [[ "$prev" = -[foW] ]]; then
    _files
    else
    file="$words[(I)-f]"
    if (( file )); then
    file="$words[file+1]"
    elif [[ -e Makefile ]]; then
    file=Makefile
    elif [[ -e makefile ]]; then
    file=makefile
    elif [[ $is_gnu = gnu && -e GNUmakefile ]]; then
    file=GNUmakefile
    else
    file=''
    fi

    if [[ -n "$file" ]] && _tags targets; then
    if [[ $is_gnu = gnu ]] &&
    zstyle -t ":completion:${curcontext}:targets" call-command; then
    tmp=( $(_call_program targets "$words[1]" -nsp --no-print-directory -f "$file" .PHONY 2> /dev/null | parseMakefile $PWD) )
    else
    tmp=( $(parseMakefile $PWD < $file) )
    fi
    _wanted targets expl 'make target' compadd -a tmp && return 0
    fi
    compstate[parameter]="${PREFIX%%\=*}"
    compset -P 1 '*='
    _value "$@"
    fi

    --- SoupGate-Win32 v1.05
    * Origin: you cannot sedate... all the things you hate (1:229/2)
  • From Hugo Haas@1:229/2 to All on Wed Aug 18 17:30:13 2004
    From: [email protected]

    --hABqaeELJqnDDeDE
    Content-Type: text/plain; charset=utf-8
    Content-Disposition: inline
    Content-Transfer-Encoding: quoted-printable

    * Hugo Haas <[email protected]> [2004-07-30 18:51+0200]
    * Clint Adams <[email protected]> [2004-07-30 11:30-0400]
    Attached is a Perl script that can be used as a replacement of the
    Perl script appearing in the make completion code (_make) to follow include statements in Makefiles.

    You mean it should replace the expression

    '@matches = /^(?:([a-zA-Z0-9]+[^\/\t=\s]+)\s*)+:/ and
    print join(" ", @matches);
    if (/^\.include\s+\<bsd\.port\.(subdir\.|pre\.)?mk>/ ||
    /^\.include\s+\".*mk\/bsd\.pkg\.(subdir\.)?mk\"/) {
    print "fetch fetch-list extract patch configure build install reinstall dein
    stall package describe checkpatch checksum makesum\n";
    }
    '

    in _make?

    Yes, it basically does the same, but follows include statements. It
    doesn't work for something like "include $(MYFILE)", but works for
    "include myfile" — resolving variable seemed complex.

    Maybe the perl and awk bits should be replaced by some native Z-Shell parsing.

    I agree, but that sounds complex to do. :-)

    Attached is an attempt at doing this. It seems to work, though I only
    enabled it for the gnu case.

    Let me know what you think.

    Regards,

    Hugo

    --
    Hugo Haas - http://larve.net/people/hugo/

    --hABqaeELJqnDDeDE
    Content-Type: text/plain; charset=us-ascii
    Content-Disposition: attachment; filename=patch-make
    Content-Transfer-Encoding: quoted-printable

    --- _make 2004-08-18 10:10:24.000000000 -0400
    +++ /usr/share/zsh/4.2.0/functions/Completion/Unix/_make 2004-08-18 11:03:52.000000000 -0400
    @@ -1,5 +1,26 @@
    #compdef make gmake pmake dmake

    +parseMakefile() {
    + local input
    + while read input; do
    + case $input in
    + [[:alnum:]]##:)
    + echo $input| cut -d: -f1
    + ;;
    + include\ *)
    + local f
    + f=$(echo $input| cut -d\ -f2)
    + if [ $f != '/*' ]; then
    + f=$dir/$f
    + fi
    + if [ -r $f ]; then
    + parseMakefile < $f
    + fi
    + ;;
    + esac
    + done
    +}
    +
    local prev="$words[CURRENT-1]" file expl tmp is_gnu cmdargs useperl

    zstyle -t ":completion:${curcontext}:" use-perl && useperl=1
    @@ -24,14 +45,10 @@
    fi

    if [[ -n "$file" ]] && _tags targets; then
    - if [[ $is_gnu = gnu ]] &&
    -