Можно ли определить спецификацию завершения для menu-complete? - PullRequest
1 голос
/ 15 апреля 2020

У меня есть папка ~/builds, которая содержит следующие подкаталоги:

> tree ~/builds
~/builds
├── projectA
│   ├── build_2020_04_10_ok
│   ├── build_2020_04_11_ko
│   ├── build_2020_04_12_ok
│   └── ...
└── projectB
    ├── build_2020_04_10_ok
    ├── build_2020_04_11_ok
    ├── build_2020_04_12_ok
    └── ...

В настоящее время, когда я пишу команду, которая принимает одну из подпапок в качестве аргумента, и я использую авто -completion, bash перечисляет всех кандидатов:

> mycmd ~/builds/projectA/[TAB]
> mycmd ~/builds/projectA/build_2020_04_1[TAB][TAB]
build_2020_04_10_ok build_2020_04_11_ko build_2020_04_12_ok ...

Это не то поведение, которое я хочу.

То, что я хочу, больше похоже на Windows -подобное автозаполнение. Я знаю, что могу использовать его, изменив мой .bashrc таким образом:

bind '"\C-g": menu-complete'

Теперь вот что происходит, когда я нажимаю Ctrl+g:

> mycmd ~/builds/projectA/[Ctrl+g]
> mycmd ~/builds/projectA/build_2020_04_10_ok[Ctrl+g]
> mycmd ~/builds/projectA/build_2020_04_11_ko[Ctrl+g]
> mycmd ~/builds/projectA/build_2020_04_12_ok

Это почти то, что Я хочу. Я хотел бы изменить порядок отображения подпапок (сначала самые новые, затем старые и старые). Также я хотел бы отказаться от всех сборок ko. Другими словами, я хочу, чтобы порядок, определенный этой командой:

ls -dr build*ok
build_2020_04_12_ok/  build_2020_04_10_ok/

Поэтому я хотел бы определить спецификацию завершения для menu-complete, чтобы выполнить желаемое поведение только для подкаталогов ~/builds. Я видел, что это можно сделать за complete, и я не нашел информации, чтобы сделать это на menu-complete.

Возможно ли это?

1 Ответ

5 голосов
/ 30 апреля 2020

Как сказал @chepner, menu-complete делегирует те же завершения, что и complete (см. man readline). Поэтому изначально я не думал, что можно будет по-разному конфигурировать завершения в зависимости от того, проходит ли он complete или menu-complete. Но я проверил, установлены ли какие-либо другие значения в зависимости от того, какой хук вызывается и что-то выделяется:

# Get the current set of environment variables
# the sed expression strips functions to just print variables
# There's probably a better way to do this...
bash-5.0$ get_env() {
  set | sed -n '/^[^=]*$/q;p' | sort
}

# Define a function to use as a completion that simply prints the changes
# in the environment between the normal shell and from within a completion
bash-5.0$ diff_env() {
  echo # extra echo's for readability
  sdiff -s /tmp/env.txt <(get_env)
}
# Register it as a completion (the command doesn't actually need to exist)
bash-5.0$ complete -F diff_env foo

bash-5.0$ bind '"\C-g": menu-complete'

# Persist the initial environment
bash-5.0$ get_env > /tmp/env.txt

bash-5.0$ foo [TAB]
BASH_LINENO=([0]="12")            |    BASH_LINENO=([0]="1" [1]="13")
BASH_SOURCE=([0]="main")          |    BASH_SOURCE=([0]="main" [1]="main")
                                  >    COMP_CWORD=1
                                  >    COMP_KEY=9
                                  >    COMP_LINE='foo '
                                  >    COMP_POINT=4
                                  >    COMP_TYPE=9
                                  >    COMP_WORDS=([0]="foo" [1]="")
                                  >    _=echo
FUNCNAME=([0]="get_env")          |    FUNCNAME=([0]="get_env" [1]="diff_env")
_=get_env                         <

^C
bash-5.0$ foo [Ctrl+g]
BASH_LINENO=([0]="12")            |    BASH_LINENO=([0]="1" [1]="14")
BASH_SOURCE=([0]="main")          |    BASH_SOURCE=([0]="main" [1]="main")
                                  >    COMP_CWORD=1
                                  >    COMP_KEY=9
                                  >    COMP_LINE='foo '
                                  >    COMP_POINT=4
                                  >    COMP_TYPE=37
                                  >    COMP_WORDS=([0]="foo" [1]="")
                                  >    _=echo
FUNCNAME=([0]="get_env")          |    FUNCNAME=([0]="get_env" [1]="diff_env")
_=get_env                         <
^C

Найдите это? COMP_TYPE отличается! man bash объясняет, что оно установлено в целое число в зависимости от поведения завершения; описание немного непрозрачно, но значением является ASCII-кодовая точка (9 для tab , 37 для %) для данного типа завершения.

Таким образом, мы можем определить функция завершения, которая проверяет это значение, чтобы изменить его поведение:

bash-5.0$ clever_complete() {
  case "$COMP_TYPE" in
    9) COMPREPLY=("tab!") ;;
    37) COMPREPLY=("ctrl-g!") ;;
    # should probably behave the same as [TAB], but I split it out to demonstrate
    *) COMPREPLY=("IDK... $COMP_TYPE") ;;
  esac
}
bash-5.0$ complete -F clever_complete bar
bash-5.0$ bar [TAB]tab! ^C
bash-5.0$ bar [Ctrl+g]ctrl-g! ^C

Надеюсь, этого достаточно для включения go :), если вам нужна помощь в написании функции complete с поведением, которое вы описали I Я бы предложил начать отдельный вопрос с текущей реализацией (используйте complete -p [command], чтобы увидеть текущее завершение, и type [function-name], чтобы увидеть реализацию завершения), будет просто отрегулировать существующее поведение оттуда.

...