Как получить завершение bash для работы с псевдонимами?

140

Пример:

Я нахожусь на mac с bash v3.2.17, я использую git, установленный через macports с вариантом bash_completion.

Когда я набираю git checkout m<tab>. например, я завершаю его до master.

Однако у меня есть псевдоним git checkout, gco. Когда я набираю gco m<tab>, я не получаю автозаполнение имени ветки.

В идеале я хотел бы, чтобы автозаполнение просто волшебным образом работало для всех моих псевдонимов. Является ли это возможным? В противном случае я хотел бы настроить его вручную для каждого псевдонима. Итак, как мне обойтись?

  • 3
    завершено -o по умолчанию -o nospace -F в настоящее время не работает
  • 4
    Вопросы с большим количеством откликов, чем с верхним ответом, часто подразумевают большие запросы
Показать ещё 1 комментарий
Теги:
autocomplete

9 ответов

134
Лучший ответ

Как указано в комментариях выше,

complete -o default -o nospace -F _git_checkout gco

больше не будет работать. Однако существует функция __git_complete в git -completion.bash, которая может быть использована для настройки завершения для псевдонимов вроде:

__git_complete gco _git_checkout
  • 5
    Это единственный правильный ответ, который я видел среди многих неправильных.
  • 42
    Если вы используете глобальный псевдоним "g" для git, вы также можете добавить __git_complete g __git_main чтобы завершить выполнение кода для всех команд git.
Показать ещё 10 комментариев
42

Я столкнулся с этой проблемой и придумал этот фрагмент кода. Это автоматически даст вам завершение для всех псевдонимов. Запустите его после объявления всех (или любых) псевдонимов.

# wrap_alias takes three arguments:
# $1: The name of the alias
# $2: The command used in the alias
# $3: The arguments in the alias all in one string
# Generate a wrapper completion function (completer) for an alias
# based on the command and the given arguments, if there is a
# completer for the command, and set the wrapper as the completer for
# the alias.
function wrap_alias() {
  [[ "$#" == 3 ]] || return 1

  local alias_name="$1"
  local aliased_command="$2"
  local alias_arguments="$3"
  local num_alias_arguments=$(echo "$alias_arguments" | wc -w)

  # The completion currently being used for the aliased command.
  local completion=$(complete -p $aliased_command 2> /dev/null)

  # Only a completer based on a function can be wrapped so look for -F
  # in the current completion. This check will also catch commands
  # with no completer for which $completion will be empty.
  echo $completion | grep -q -- -F || return 0

  local namespace=alias_completion::

  # Extract the name of the completion function from a string that
  # looks like: something -F function_name something
  # First strip the beginning of the string up to the function name by
  # removing "* -F " from the front.
  local completion_function=${completion##* -F }
  # Then strip " *" from the end, leaving only the function name.
  completion_function=${completion_function%% *}

  # Try to prevent an infinite loop by not wrapping a function
  # generated by this function. This can happen when the user runs
  # this twice for an alias like ls='ls --color=auto' or alias l='ls'
  # and alias ls='l foo'
  [[ "${completion_function#$namespace}" != $completion_function ]] && return 0

  local wrapper_name="${namespace}${alias_name}"

  eval "
function ${wrapper_name}() {
  let COMP_CWORD+=$num_alias_arguments
  args=( \"${alias_arguments}\" )
  COMP_WORDS=( $aliased_command \${args[@]} \${COMP_WORDS[@]:1} )
  $completion_function
  }
"

  # To create the new completion we use the old one with two
  # replacements:
  # 1) Replace the function with the wrapper.
  local new_completion=${completion/-F * /-F $wrapper_name }
  # 2) Replace the command being completed with the alias.
  new_completion="${new_completion% *} $alias_name"

  eval "$new_completion"
}

# For each defined alias, extract the necessary elements and use them
# to call wrap_alias.
eval "$(alias -p | sed -e 's/alias \([^=][^=]*\)='\''\([^ ][^ ]*\) *\(.*\)'\''/wrap_alias \1 \2 '\''\3'\'' /')"

unset wrap_alias
  • 6
    строка let COMP_CWORD+=$num_alias_arguments по какой-то причине не работала в Mac OS X. Замена его на ((COMP_CWORD+=$num_alias_arguments)) исправила это
  • 5
    Вау, это круто - спасибо! wrap_alias душит двойные кавычки в определении псевдонима, и я думаю, что это не имеет особого смысла для псевдонимов с несколькими командами ( alias 'foo=bar; baz' ), поэтому я помещаю дополнительную | grep -v '[";|&]' после alias -p . Кроме того, он становится немного медленным для сотен определений псевдонимов, но я рад подтвердить, что использую echo вместо eval и отправляем вывод в кеш Файл (который затем может быть eval за один раз) работает отлично и работает очень быстро.
Показать ещё 16 комментариев
17

В git-completion.bash есть строка:

complete -o default -o nospace -F _git git

Глядя на эту строку (и функцию _git), вы можете добавить эту строку в свой .bash_profile:

complete -o default -o nospace -F _git_checkout gco
  • 4
    некоторые функции git * bash больше не работают с этим методом
  • 0
    Да, раньше это прекрасно работало, пока что-то не изменилось в git_completion.bash ... Теперь он работает с полной командой, но не с псевдонимом.
Показать ещё 3 комментария
14

У меня есть aliased g = 'git', и в сочетании с моими алиасами git я печатаю такие вещи, как

$ g co <branchname>

Более простым решением для моего конкретного случая использования было добавление отдельной строки в git -completion.

Прямо под этой строкой:

__git_complete git _git

Я добавил эту строку для обработки моего одиночного псевдонима "g":

__git_complete g _git
  • 2
    (Я использую Cygwin.) Я не смог найти файл git-completion /etc/bash_completion.d/git или эту строку в /etc/bash_completion.d/git , но я добавил complete -o default -o nospace -F _git g после своего псевдонима в .bash_aliases и это сработало!
  • 0
    Помните, что если вы отредактируете файл в /etc/bash-completion.d/ или заново в /usr/share/bash-completion/ , вы потеряете свои изменения всякий раз, когда этот файл обновляется с помощью менеджера пакетов.
8

В идеале я хотел бы, чтобы автозаполнение просто волшебным образом работало для всех моих псевдонимов. Возможно ли это?

Да, это возможно с проектом complete-alias.

  • 3
    Большое спасибо, это намного лучше, чем выяснить, как каждая утилита в мире реализует завершение bash.
  • 1
    Действительно, сэкономил мне время на настройку дополнений для псевдонимов.
Показать ещё 2 комментария
5

Эта страница форума показывает решение.

Поместите эти строки в .bashrc или .bash_profile:

# Author.: Ole J
# Date...: 23.03.2008
# License: Whatever

# Wraps a completion function
# make-completion-wrapper <actual completion function> <name of new func.>
#                         <command name> <list supplied arguments>
# eg.
#   alias agi='apt-get install'
#   make-completion-wrapper _apt_get _apt_get_install apt-get install
# defines a function called _apt_get_install (that $2) that will complete
# the 'agi' alias. (complete -F _apt_get_install agi)
#
function make-completion-wrapper () {
    local function_name="$2"
    local arg_count=$(($#-3))
    local comp_function_name="$1"
    shift 2
    local function="
function $function_name {
    ((COMP_CWORD+=$arg_count))
    COMP_WORDS=( "$@" \${COMP_WORDS[@]:1} )
    "$comp_function_name"
    return 0
}"
    eval "$function"
}

# and now the commands that are specific to this SO question

alias gco='git checkout'

# we create a _git_checkout_mine function that will do the completion for "gco"
# using the completion function "_git"
make-completion-wrapper _git _git_checkout_mine git checkout

# we tell bash to actually use _git_checkout_mine to complete "gco"
complete -o bashdefault -o default -o nospace -F _git_checkout_mine gco

Это решение похоже на balshetzer script, но только этот на самом деле работает для меня. (balshetzer script имел проблемы с некоторыми из моих псевдонимов.)

  • 0
    Это почти работает - я получаю пару ошибок, но завершение проходит. Что-нибудь еще, что я могу сделать? -bash: eval: line 28: unexpected EOF while looking for matching ''' -bash: eval: line 29: syntax error: unexpected end of file
  • 0
    @pforhan Я вижу проблемы с цитированием выше ... " кавычки внутри строки function должны быть заключены в кавычки \" . Это , вероятно , ест один из ваших ' кавычек где - то вдоль линии.
5

Вы также можете попробовать использовать псевдонимы Git. Например, в моем файле ~/.gitconfig у меня есть раздел, который выглядит так:

[alias]
        co = checkout

Итак, вы можете ввести git co m<TAB>, и это должно быть расширено до git co master, что является командой git checkout.

  • 9
    да, я делаю это уже, но я хочу печатать еще меньше.
2

Еще один вариант - использовать файл ~/.bash_completion. Чтобы создать псевдоним gco для git checkout, просто поставьте его здесь:

_xfunc git __git_complete gco _git_checkout

Затем в ~/.bashrc вам нужно просто поставить псевдоним:

alias gco='git checkout'

Две строки. Это.

Объяснение:

~/bash_completion получает источник в конце основного файла bash_completion script. В gentoo я нашел главный script в /usr/share/bash-completion/bash_completion.

Бит _xfunc git заботится о поиске файла git-completion для вас, поэтому вам не нужно вставлять что-либо еще в ~/.bashrc.

Принятый ответ требует, чтобы вы скопировали .git-completion.sh и отправили его из своего файла ~/.bashrc, который я нахожу хромым.


PS: Я все еще пытаюсь понять, как не вывести весь git-completion script в мою среду bash. Просьба прокомментировать или отредактировать, если вы найдете способ.

  • 0
    Почему требуется _xfunc git ?
  • 0
    @ TomHale Я пытался улучшить ответ. Вместо того, чтобы делать source ~/.git-completion.sh _xfunc я позволил _xfunc сделать это для меня. Просто приятнее и чище делать это исключительно в ~/.bash_completion . Без _xfunc (или источника) функция __git_complete не существует.
Показать ещё 1 комментарий
1

Вам просто нужно найти команду complete и дублировать строку с именем псевдонима.

У меня есть alias d-m="docker-machine". В словах d-m должен быть псевдоним для docker-machine.

Итак, на Mac (через brew) файлы завершения находятся в cd `brew --prefix`/etc/bash_completion.d/.
В моем случае я редактировал файл под названием docker-machine.
Весь путь внизу:

complete -F _docker_machine docker-machine

Итак, я добавил еще одну строку с моим псевдонимом:

complete -F _docker_machine docker-machine
complete -F _docker_machine d-m
  • 0
    Это лучшее решение для простых (один к одному) псевдонимов, таких как docker псевдонимом d . Хотя для примера в вопросе git checkout псевдонимом gco более сложен.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню