Создать скрипт завершения bash для автозаполнения путей после знака равенства?


11

Я хочу создать скрипт завершения bash, который распознает аргументы формы --argи --some-arg=file.

После прочтения этого урока и нескольких примеров /usr/share/bash_completion/completions/я написал следующий скрипт (чтобы сэкономить время при наборе некоторых флагов с помощью Chromium):

_chromium() 
{
    local cur prev opts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"

    # Some interesting options
    opts="
--disable-web-security
--easy-off-store-extension-install
--incognito
--load-extension=
--pack-extension=
--pack-extension-key=
--user-data-dir=
"
    # Handle --xxxxxx=file
    if [[ ${cur} == "--"*"=" ]] ; then
        # Removed failures (is my logic OK?)
        return 0
    fi

    # Handle other options
    if [[ ${cur} == -* ]] ; then
        COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
        return 0
    fi
}
complete -F _chromium chromium

Я сохранил его ~/bash_completions/chromiumи создал символическую ссылку, используя sudo ln -s ~/bash_completions/chromium /usr/share/bash_completion/completions/chromium.
Затем я загрузил его, используя . /usr/share/bash_completions/completions/chromium.

Сейчас я испытываю две проблемы:

  • chromium --u<TAB>расширяется до chromium --user-data-dir=<SPACE>(я не хочу места).
  • Пути (каталоги и файлы) больше не завершены.

Как я могу решить эти проблемы?


Является ли переключение на Zsh вариант?
Жиль "ТАК - перестань быть злым"

Ответы:


11

Я нашел решение обеих проблем!

  1. Чтобы не добавлять пробел, используйте nospaceопцию. Это можно сделать двумя способами:

    • Передайте это complete:
      complete -o nospace -F _chromium chromium
    • Используйте compoptвстроенное:
      compopt -o nospace(чтобы включить опцию)
      compopt +o nospace(чтобы отключить опцию)

    Я нашел это в документации по Bash на gnu.org, 8.7 Встроенные функции программируемого завершения .

  2. Завершение файлов.
    • Петер предложил использовать -fфлаг с compgen. Я последовал этому совету и реализовал его как COMPREPLY=( $(compgen -f "$cur") ). Это работало нормально, пока я не попытался завершить путь, содержащий пробелы.
      На переполнении стека я нашел этот ответ, который рекомендует создавать список завершения вручную (без использования compgen). Этот подход работал нормально.
    • Используйте filenamesопцию, чтобы сообщить Readline, что compspec генерирует имена файлов, чтобы он мог:
      • выполнять любую специфичную для имени файла обработку (например, добавлять косую черту в имена каталогов, заключать в кавычки специальные символы или подавлять завершающие пробелы)
      • использовать разные цвета для указания типа файла (с colored-statsвключенным)

С помощью манипуляций со строками Bash (для расширения ~и обработки пробелов) я создал сценарии завершения bash, которые соответствуют всем критериям, изложенным в вопросе.

_chromium() 
{
    local cur prev opts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"

    # Some interesting options
    opts="
--disable-web-security
--easy-off-store-extension-install
--incognito
--load-extension=
--pack-extension=
--pack-extension-key=
--user-data-dir=
"
    # Handle --xxxxxx=
    if [[ ${prev} == "--"* && ${cur} == "=" ]] ; then
        compopt -o filenames
        COMPREPLY=(*)
        return 0
    fi
    # Handle --xxxxx=path
    if [[ ${prev} == '=' ]] ; then
        # Unescape space
        cur=${cur//\\ / }
        # Expand tilder to $HOME
        [[ ${cur} == "~/"* ]] && cur=${cur/\~/$HOME}
        # Show completion if path exist (and escape spaces)
        compopt -o filenames
        local files=("${cur}"*)
        [[ -e ${files[0]} ]] && COMPREPLY=( "${files[@]// /\ }" )
        return 0
    fi

    # Handle other options
    COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
    if [[ ${#COMPREPLY[@]} == 1 && ${COMPREPLY[0]} != "--"*"=" ]] ; then
        # If there's only one option, without =, then allow a space
        compopt +o nospace
    fi
    return 0
}
complete -o nospace -F _chromium chromium

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

1

Чтобы завершить имена файлов, попробуйте перейти -fк compgen.

Боюсь, вы не сможете избавиться от пробелов после опций, поскольку именно так работает завершение - как только оно находит уникальное совпадение, оно завершает его полностью.


Спасибо за предложение -f. Я пробовал, но он не правильно обрабатывает пробелы: путь /tmp/foo barприводит к двум записям завершения /tmp/fooи bar. О нежелательном --arg=<SPACE>: я нашел решение этого и разместил его в ответе ниже .
Роб W
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.