it-swarm.com.ru

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

Дело в точке: 

Я на Mac с Bash v3.2.17, я использую Git, установленный через MacPort с вариантом Bash_completion.

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

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

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

176
kch

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

complete -o default -o nospace -F _git_checkout gco

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

__git_complete gco _git_checkout
162
chris_sutter

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

# 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
52
Hesky Fisher

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

complete -o default -o nospace -F _git git

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

complete -o default -o nospace -F _git_checkout gco
18
Chris Lloyd

Я использовал псевдоним g = 'git' и в сочетании с псевдонимами git набираю такие вещи, как 

$ g co <branchname>

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

Прямо под этой линией:

__git_complete git _git

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

__git_complete g _git
15
wonderfulthunk

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

Да, это возможно в проекте complete-alias (в Linux). Поддержка Mac является экспериментальной, но пользователи сообщают об успехе.

12
Cyker

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

Поместите эти строки в свой .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's $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=( "[email protected]" \${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 , но только это на самом деле работает для меня. (У сценария Бальшецера были проблемы с некоторыми из моих псевдонимов.)

5
hcs42

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

[alias]
        co = checkout

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

4
mipadi

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

_xfunc git __git_complete gco _git_checkout

Затем в ~/.bashrc вы должны поместить только псевдоним: 

alias gco='git checkout'

Две строчки Вот и все. 

Объяснение:

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

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

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


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

4
kub1x

Вам просто нужно найти команду 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
2
luckydonald

Есть много ответов на этот вопрос, и я, как и я, держу пари, что многие смущенные читатели. В моем случае у меня также было требование, чтобы мои dotfiles работали на нескольких платформах с разными версиями Git. Я также не alias g=git, но вместо этого g определен как функция.

Чтобы добиться этого, мне пришлось собрать воедино разные ответы в одном решении. Хотя это повторяет ответы уже, я думал, что кто-то в моей лодке мог бы счесть этот сборник полезным, как я сделал бы, когда я впервые пришел к этому вопросу.

Это предполагает более старое и новое завершение Git, значения по умолчанию Ubuntu и brew install git в MacOS. В последнем случае установленные дополнения brew не обрабатывались bash (что я буду диагностировать позже).

# Alias g to git

g() {
  if [[ $# > 0 ]]; then
    git "[email protected]"
  else
    git status -sb
  fi
}

# Preload git completion in Ubuntu which is normally lazy loaded but we need
# the __git_wrap__git_main function available for our completion.
if [[ -e /usr/share/bash-completion/completions/git ]]; then
  source /usr/share/bash-completion/completions/git
Elif [[ -e /usr/local/etc/bash_completion.d/git-completion.bash ]]; then
  source /usr/local/etc/bash_completion.d/git-completion.bash
fi

if command_exists __git_complete; then
  __git_complete g _git
Elif command_exists __git_wrap__git_main; then
  complete -o bashdefault -o default -o nospace -F __git_wrap__git_main g
fi
0
Sukima

Сначала посмотрите исходную команду завершения. Пример:

$ complete | grep git

complete -o bashdefault -o default -o nospace -F __git_wrap__git_main git

Теперь добавьте их в свой скрипт запуска (например, ~/.bashrc):

# copy the original statement, but replace the last command (git) with your alias (g)
complete -o bashdefault -o default -o nospace -F __git_wrap__git_main g

# load dynamically loaded completion functions (may not be required)
_completion_loader git

Строка _completion_loader может не потребоваться. Но в некоторых ситуациях функция завершения загружается динамически только после ввода команды и первого нажатия клавиши TAB. Так что, если вы не использовали исходную команду и попробовали псевдоним + TAB, вы можете получить сообщение об ошибке типа «bash: завершение: функция« _docker »не найдена».

0
wisbucky

Если вы используете alias g='git', я добавлю эту строку кода в .bash_aliases

complete -o default -o nospace -F _git g
0
Druta Ruslan