[Bash-completion-devel] completion for setxkbmap(1)

Raphaël Droz raphael.droz at gmail.com
Sat Jul 21 10:33:48 UTC 2012


retry

On Sun, Nov 20, 2011 at 10:06:58PM +0100, Raphaël Droz wrote:
> On Fri, Aug 19, 2011 at 11:24:23AM +0300, Ville Skyttä wrote:
> > On 08/18/2011 09:39 PM, Raphaël Droz wrote:
> > > attached, needs review
> > 
> > *Very* unthrorough one below:
> > 
> > >     sed -n '/! '"$1"'/{n; :a; /^!/q; p; n;b a;}' ${2:-$files}|awk '{print $1}'
> > 
> > How portable is this sed statement?  I don't know sed well enough to be
> > able to even read it ;).  Maybe it could be optimized to do also what
> > the awk does to get rid of one process?
> 
> I've added some explanation, I still have not taken the time to learn
> how awk works but I do agree that it's probably best suited for this
> kind of task.
> 
> > > _runtime_have() {
> > >     [[ -z "$1" ]] && return
> > >     return $(which "$1" &> /dev/null)
> > > }
> > 
> > This function should be just dropped and "type -P" used instead of it.
> 
> ok
> 
> > 
> > >             COMPREPLY=( $( compgen -W "$(sed -n 's/.*xkb_keycodes "\(.*\)".*/\1/p' $(grep -lrwm1 xkb_keycodes $Xdir/keycodes/*)|sort -u)" -- "$cur" ) )
> > >             COMPREPLY=( $( compgen -W "$(sed -n 's/.*xkb_geometry "\(.*\)".*/\1/p' $(grep -lrwm1 xkb_geometry $Xdir/geometry/*)|sort -u)" -- "$cur" ) )
> > 
> > The -m1 in those greps is not portable but I suppose it is not actually
> > needed with -l, and unfortunately -r is not portable either.  Maybe
> > these can be rewritten using "**" and without grep altogether (shopt
> > globstar needs to be in effect temporarily for that)?
> 
> I checked this, this keyboard settings are quite static over the
> years. as of today none of the subdirectories contains matching entries.
> 
> > >             _runtime_have xauth && COMPREPLY=( $( compgen -W "$(xauth -n list|sed -n 's/^[^:]*\(:[0-9]\+\).*/\1/p'|sort -u)" -- "$cur" ) )
> > >             _runtime_have xinput && COMPREPLY=( $( compgen -W "$(xinput list --short|sed -n '/keyboard/s/.*id=\([0-9]\+\).*/\1/p')" -- "$cur" ) )
> > 
> > The \+ in those seds is not portable.  Use \{1,\} instead (and see
> > test/runLint in git).
> 
> fixed, thanks for the pointer about runLink.
> 
> 
> regards
> 
> Raph
-------------- next part --------------
# setxkbmap(1) completion		-*- shell-script -*-

# $1: the type of data to extract from rules/*.lst files
# (layout, model, variant, option, ...)
# $2: optional: files to process (absolutes paths)
_setxkbmap_extract_data() {
    [[ -z $1 ]] && return;
    local files=/usr/share/X11/xkb/rules/*.lst
    local regexp="
/! $1/{		# find the line containing '! <data>, eg "layout", "variant", ... '
n;		# skip it
:a;		# label
/^!/q;		# '!' line => quit
p; n; b a;	# print, go next line, loop to ':a'
}"
    sed -n "$regexp" ${2:-$files}|awk '{print $1}'
}

_setxkbmap_get_layout() {
    local let i=1
    for (( i=1; i < ((${#COMP_WORDS[@]}-1)); i++)); do
        # -layout specified
        [[ ${COMP_WORDS[$i]} = -layout ]] && echo ${COMP_WORDS[(($i+1))]} && return 0
        # skip these options
        [[ ${COMP_WORDS[$i]} =~ -compat|-symbols|-types|-\?|-help|-print|-query|synch ]] && continue
        # skip these options and their value
        [[ ${COMP_WORDS[$i]} = -* ]] && ((i++)) && continue;
        # hopefully here it is:
        echo ${COMP_WORDS[$i]} && return 0
    done
    # it may be here (as the last argument of the command line)
    # but we may be currently in the process of completing it, so: forget
    # [[ ${COMP_WORDS[$i]} && ${COMP_WORDS[$i]} != -* ]] && echo ${COMP_WORDS[$i]} && return 0

    # not found
    return 1
}

# $1: mandatory the current value for "layout", it will help
# in the search for the variant
_setxkbmap_get_variant() {
    [[ -z $1 ]] && return 1
    local let i=1 found_layout=0
    for (( i=1; i < ((${#COMP_WORDS[@]}-1)); i++)); do
        # -variant specified
        [[ ${COMP_WORDS[$i]} = -variant ]] && echo ${COMP_WORDS[(($i+1))]} && return 0
        [[ ${COMP_WORDS[$i]} = $1 ]] && found_layout=1 && continue
        # still behind the value of the layout, variant is still far away in the command line
        [[ found_layout -eq 0 ]] && continue
        # hopefully it is here:
        echo ${COMP_WORDS[$i]} && return 0
    done
    # it may be here (as the last argument of the command line)
    # but we may be currently in the process of completing it, so: forget
    # [[ ${COMP_WORDS[$i]} && ${COMP_WORDS[$i]} != -* ]] && echo ${COMP_WORDS[$i]} && return 0

    # not found
    return 1
}

# $1: mandatory the current value for "variant", it will help
# in the search for the option
_setxkbmap_get_option() {
    [[ -z $1 ]] && return 1
    local i found_variant=0
    for (( i=1; i < ((${#COMP_WORDS[@]}-1)); i++)); do
        # -variant specified
        [[ ${COMP_WORDS[$i]} = -option ]] && echo ${COMP_WORDS[(($i+1))]} && return 0
        [[ ${COMP_WORDS[$i]} = $1 ]] && found_variant=1 && continue
        # still behind the value of the variant, variant is still far away in the command line
        [[ found_variant -eq 0 ]] && continue
        # hopefully it is here:
        echo ${COMP_WORDS[$i]} && return 0
    done
    # it may be here (as the last argument of the command line)
    # but we may be currently in the process of completing it, so: forget
    # [[ ${COMP_WORDS[$i]} && ${COMP_WORDS[$i]} != -* ]] && echo ${COMP_WORDS[$i]} && return 0

    # not found
    return 1
}

_setxkbmap()
{
    local cur prev words cword
    _init_completion || return

    local Xdir=/usr/share/X11/xkb
    local current_layout current_variant current_option

    case $prev in
        -v|-verbose)
            COMPREPLY=( $( compgen -W '{0..10}' -- "$cur" ) )
            return 0
            ;;
        -config)
            _filedir
            return 0
            ;;
        -I)
            _filedir -d
            return 0
            ;;

        -layout)
            #COMPREPLY=( $( compgen -W "$(command ls $Xdir/symbols/)" -- "$cur" ) )
            COMPREPLY=( $( compgen -W "$(_setxkbmap_extract_data layout)" -- "$cur" ) )
            return 0
            ;;
        -model)
            # TODO: _setxkbmap_get_layout, then find the "files" to use
            COMPREPLY=( $( compgen -W "$(_setxkbmap_extract_data model)" -- "$cur" ) )
            return 0
            ;;
        -variant)
            # TODO: _setxkbmap_get_layout, then find the "files" to use
            COMPREPLY=( $( compgen -W "$(_setxkbmap_extract_data variant)" -- "$cur" ) )
            return 0
            ;;
        -option)
            # TODO: options contains ':'; remove this export the day bash support a per-completion value
	    export COMP_WORDBREAKS=${COMP_WORDBREAKS//:/}
            # TODO: _setxkbmap_get_layout, then find the "files" to use
            COMPREPLY=( $( compgen -W "$(_setxkbmap_extract_data option)" -- "$cur" ) )
            return 0
            ;;

        -keycodes)
            #COMPREPLY=( $( compgen -W "$(command ls $Xdir/keycodes/|sed '/^README/d')" -- "$cur" ) )
            COMPREPLY=( $( compgen -W "$(sed -n 's/.*xkb_keycodes "\(.*\)".*/\1/p' $(grep -lw xkb_keycodes $Xdir/keycodes/*)|sort -u)" -- "$cur" ) )
            return 0
            ;;
        -keymap)
            COMPREPLY=( $( compgen -W "$(command ls $Xdir/keymap/|sed '/^README/d')" -- "$cur" ) )
            return 0
            ;;
        -geometry)
            #COMPREPLY=( $( compgen -W "$(command ls $Xdir/geometry/|sed '/^README/d')" -- "$cur" ) )
            COMPREPLY=( $( compgen -W "$(sed -n 's/.*xkb_geometry "\(.*\)".*/\1/p' $(grep -lw xkb_geometry $Xdir/geometry/*)|sort -u)" -- "$cur" ) )
            return 0
            ;;
        -rules)
            COMPREPLY=( $( compgen -W "$(command ls $Xdir/rules/|sed -ne '/lst/s/\.lst$//p')" -- "$cur" ) )
            return 0
            ;;
        -display)
            type -P xauth &>/dev/null && COMPREPLY=( $( compgen -W "$(xauth -n list|sed -n 's/^[^:]*\(:[0-9]\{1,\}\).*/\1/p'|sort -u)" -- "$cur" ) )
            return 0
            ;;
        -device)
            type -P xinput &>/dev/null && COMPREPLY=( $( compgen -W "$(xinput list --short|sed -n '/keyboard/s/.*id=\([0-9]\{1,\}\).*/\1/p')" -- "$cur" ) )
            return 0
            ;;
        -compat|-symbols|-types)
            return 0;
            ;;
        # -\?|-help|-print|-query|synch  # don't take arg
    esac

    if [[ "$cur" == -* ]]; then
        COMPREPLY=( $( compgen -W '$(_parse_help $1 -help) -help -verbose' -- "$cur" ) )
        return 0
    fi

    current_layout=$(_setxkbmap_get_layout)
    # "layout" not (yet) found on the command line, just offer available completion for it
    if [[ $? -ne 0 ]]; then
        COMPREPLY=( $( compgen -W "$(_setxkbmap_extract_data layout)" -- "$cur" ) )
    # "layout" found, has "variant" already been specified too ?
    else
        current_variant=$(_setxkbmap_get_variant $current_layout)
        if [[ $? -ne 0 ]]; then
            COMPREPLY=( $( compgen -W "$(_setxkbmap_extract_data variant)" -- "$cur" ) )
        else
            current_option=$(_setxkbmap_get_option $current_variant)
            [[ $? -ne 0 ]] && {
                # TODO: options contains ':'; remove this export the day bash
                # supports a per-completion value COMP_WORDBREAKS value
	        export COMP_WORDBREAKS=${COMP_WORDBREAKS//:/}
                COMPREPLY=( $( compgen -W "$(_setxkbmap_extract_data option)" -- "$cur" ) )
            }
        fi
    fi

    COMPREPLY+=( $( compgen -W '-' -- "$cur" ) )
    [[ "${#COMPREPLY}" -eq 1 ]] && compopt -o nospace
    return 0
} &&
complete -F _setxkbmap setxkbmap

# Local variables:
# mode: shell-script
# sh-basic-offset: 4
# sh-indent-comment: t
# indent-tabs-mode: nil
# End:
# ex: ts=4 sw=4 et filetype=sh


More information about the Bash-completion-devel mailing list