bash completion should use shell-complete

Bug #84822 reported by Martin Pool on 2007-02-13
18
Affects Status Importance Assigned to Milestone
Bazaar
Medium
Unassigned
bzr (Debian)
Confirmed
Unknown

Bug Description

It'd be good to write and include a bash shell completion routine that uses the output from 'bzr shell-complete'.

At the moment the completion script shipped with ubuntu's bzr package greps through 'bzr help' and has hardcoded options for some commands.

Martin Pool (mbp) wrote :

A side effect of using the unofficial bzr help output is that this actually suggests many bogus words:

mbp@limpid:~$ bzr
Display all 231 possibilities? (y or n)
a copy id. patterns specified
about Create ignore patterns. standard
add current Ignore Perform status
Add dead ignored pqm. storage
all deleted in [pqmsubmit] Submit
an destination info pqm-submit summary.
and dialog information preferences supplied
annotate dialog. init previous tag
annotate. diff init-repository Print tags
another differences into pull tags.
archive. directive its push testament
as directories. last push. that
auto-merge directory latest reconcile the
......

(probably every word in 'bzr help commands')

description: updated
Changed in bzr:
importance: Undecided → Medium
status: Unconfirmed → Confirmed
clemens fischer (ino-news) wrote :

the bash-completer for bazaar was one of the easiest i ever got working!
this is due to the builtin support for it, although it might better suit
the zsh. --clemens

# scans args, returns 1st non-option or 1 if none
__get_1st_nonopt()
{
  _1st_nonopt=""
  shift
  for i in "$@"
  do
    case "$i" in
      --)
        return 1
        ;;
      -*)
        ;;
      *)
        _1st_nonopt="$i"
        return 0
        ;;
    esac
  done
  return 1
}
#
_bzr_commands()
{
  bzr s-c | sed -nE 's/^([^:]+):.*/\1/p'
}
_bzr_opts()
{
  bzr s-c "$1" | sed -nE 's/^.+(--[[:alnum:]_-]+).*/\1/p'
  bzr s-c "$1" | sed -nE 's/^.+(-[[:alnum:]]+).*/\1/p'|grep -v -- '-None'
}
_bzr()
{
  cur=${COMP_WORDS[COMP_CWORD]}
  prev=${COMP_WORDS[COMP_CWORD-1]}
  case ".${cur}" in
    .-*)
      __get_1st_nonopt "${COMP_WORDS[@]}" || : 'COMPREPLY=( $(compgen -f $cur) )'
      COMPREPLY=( $(compgen -W "$(_bzr_opts ${_1st_nonopt})" -- $cur) )
      ;;
    .*)
      case "$prev" in
        --)
          COMPREPLY=( $(compgen -f -- $cur) )
          ;;
        bzr)
          COMPREPLY=( $(compgen -W "$(_bzr_commands)" -- $cur))
          ;;
        help|\?|--help|-\?|-h)
          COMPREPLY=( $(compgen -W "$(_bzr_commands)" -- $cur)
            $(compgen -W "$(bzr help topics | sed -nE 's/^([^[:space:]]+).*/\1/p')" -- $cur) )
          ;;
      esac
      ;;
  esac
}
complete -F _bzr -o default bzr

clemens fischer (ino-news) wrote :

there's a difference between the bsd and the linux versions of sed(1): "sed -E" in freebsd is "sed -r" in linux. a portable way of determining which platform the completer runs on is possible but propably not worth the trouble. i suggest adding a comment:

# linux option for extended regular expressions: `-r'
# equivalent freebsd option: `-E'
__bzr_sed_opts="-En" # or "-rn" on linux

then use ``sed ${__bzr_sed_opts}'' everywhere.

Martin Pool (mbp) wrote :

clemens, should we move that file into the bzr distribution?

Changed in bzr:
status: Confirmed → In Progress

> Martin Pool:

> clemens, should we move that file into the bzr distribution?

yes. the only thing to consider is the sed-option for extended regular
expressions. if you have more linux- than bsd-customers, you'd make
`-r' the default instead of `-E'.

regards, clemens

Daniel Hahler (blueyed) wrote :

I've just filed bug 201935 about performance of bzr's bash completion, which can be improved drastically by using caching, i.e. write the output of e.g. "bzr s-c" into a bash variable and only fill it once.
This saves quite some calls to "bzr" itself and therefor makes completion faster (and more compelling to use).

Re "sed": you can replace e.g. "sed -nE 's/^([^[:space:]]+).*/\1/p'" with "grep -o ^([^[:space:]]+)".

But please create the cache on the first call, not when the completion scripts get loaded (like git does it currently).

Can you please create a branch for this, so it's easier to track status of this patch?

Thank you!

clemens fischer (ino-news) wrote :

> Daniel Hahler:

> I've just filed bug 201935 about performance of bzr's bash completion,
> which can be improved drastically by using caching, i.e. write the
> output of e.g. "bzr s-c" into a bash variable and only fill it
> once. This saves quite some calls to "bzr" itself and therefor makes
> completion faster (and more compelling to use).
>
> Re "sed": you can replace e.g. "sed -nE 's/^([^[:space:]]+).*/\1/p'"
> with "grep -o ^([^[:space:]]+)".

like "bzr s-c | egrep -o '^([^:]+)'"? this is certainly possible.

> But please create the cache on the first call, not when the completion
> scripts get loaded (like git does it currently).

i can't do this either, because completions run in a subshell.
variables, like a cache, set in the subshell cease existing when that
subshell terminates. this is the reason git does some of the completion
work on loading.

then again, a few seconds after sending off this reply i might find
a way to transport results up one level of shell-invocations ...

but no sooner!

> Can you please create a branch for this, so it's easier to track
> status of this patch?

i'm afraid not. i don't use nor track bzr ATM.

should i find a solution to this problem, i'll have to send a patch.

> Thank you!

thank you for the idea.

regards, clemens

clemens fischer (ino-news) wrote :

> clemens fischer:

> > Daniel Hahler:
>
> > But please create the cache on the first call, not when the
> > completion scripts get loaded (like git does it currently).
>
> i can't do this either, because completions run in a subshell.
> variables, like a cache, set in the subshell cease existing when
> that subshell terminates. this is the reason git does some of the
> completion work on loading.

this is nonsense, but i didn't see it when staring at the code.

> then again, a few seconds after sending off this reply i might find a
> way to transport results up one level of shell-invocations ...

ok, the few seconds passed. the code completes three cases:

1. options to any bzr commands. it is not feasible to cache the
    options to every command. i decided against it.

2. files coming after the (artificial) "end-of-options" token "--".
    obviously, caching these is impractical. bash handles these.

3. simple commands. this is quite easy to cache, see attached.

4. commands and topics. the commands are cached, the topics are not,
    but this could be changed. i didn't bother to go for more than the
    commands.

# scans args, returns 1st non-option or 1 if none or zero-length.
# 1st arg is the actual command to look out for, its index is returned
# in $__nonopts_start, the nonopts are returned in array ${__nonopts[]}.
#
declare -a __nonopts
__get_nonopts()
{
  local index=0
  local startcmd="$1"
  shift
  __nonopts=()
  __nonopts_start=0
  for i in "$@"
  do
    [[ "${startcmd}" == "${i}" ]] && __nonopts_start=${index}
    case "$i" in
      -*)
        ;;
      *)
        __nonopts[${index}]="$i"
        #index=$((${index}+1))
        index=$((index++))
        ;;
    esac
  done
  [[ ${#__nonopts[*]} -eq 0 ]] && return 1
  return 0
}

_bzr_opts()
{
  [[ -z "${__bzr_opts_cache}" ]] &&
    __bzr_opts_cache="$(
      bzr s-c "$1" | sed -E 's/^.+(--[[:alnum:]_-]+).*/\1/'
      bzr s-c "$1" | sed -E 's/^.+(-[[:alnum:]]+).*/\1/'|grep -v -- '-None'
    )"
  echo "${__bzr_opts_cache}"
}
__bzr_command_cache=""
_bzr()
{
  local cur=${COMP_WORDS[COMP_CWORD]}
  local prev=${COMP_WORDS[COMP_CWORD-1]}
  case ".${cur}" in
    .-*)
      __get_nonopts "bzr" "${COMP_WORDS[@]}" || : 'COMPREPLY=( $(compgen -f $cur) )'
      COMPREPLY=(
        $(compgen -W '$(_bzr_opts ${__nonopts[$((${__nonopts_start}+1))]})' -- $cur)
      )
      ;;
    .*)
      case "$prev" in
        --)
          COMPREPLY=( $(compgen -f -- $cur) )
          ;;
        bzr)
          [[ -z "${__bzr_command_cache}" ]] &&
            __bzr_command_cache="$(bzr s-c | egrep -o '^([^:]+)')"
          COMPREPLY=( $(compgen -W '${__bzr_command_cache}' -- $cur))
          ;;
        help|\?|--help|-\?|-h)
          [[ -z "${__bzr_command_cache}" ]] &&
            __bzr_command_cache="$(bzr s-c | egrep -o '^([^:]+)')"
          COMPREPLY=( $(compgen -W '${__bzr_command_cache}' -- $cur)
            $(compgen -W '$(bzr help topics | egrep -o "^([^[:space:]]+)")' -- $cur) )
          ;;
      esac
      ;;
  esac
}
complete -o filenames -F _bzr bzr

regards, clemens

Alexandre Garnier (zigarn) wrote :

Just a suggestion : escape calls to some commands like grep.
In my case I have an alias on grep='grep --color=always' and it breaks all the bash_completion : the use of \grep instead of grep solve the problem.

Martin von Gagern (gagern) wrote :

Maybe you are interested in the bzr-bash-completion plugin I wrote.
See http://pypi.python.org/pypi/bzr-bash-completion

Using a lazy initialization approach, a small completion function calls the plugin to generate the full initialization function the first time it is required. After that, the full function servers as the cache, avoiding subsequent calls to bzr.

Jelmer Vernooij (jelmer) on 2011-02-01
tags: added: bash
John A Meinel (jameinel) wrote :

The last update to this was in 2008, and as pointed out there is "bzr-bash-completion" which is a better solution for this.
I'm taking this out of In Progress, but I'm wondering if we should just mark it as "Won't Fix" in favor of the bzr-bash-completion plugin's solution?

Changed in bzr:
status: In Progress → Confirmed
Changed in bzr (Debian):
status: Unknown → Confirmed
To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Duplicates of this bug

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.