Автодополнение Zsh из переменной

Вопрос или проблема

Общий обзор

Мне нужно настроить автозаполнение значений в zsh для команды (в следующем минимальном примере я покажу это с помощью testcmd).
Так что мой текущий код работает довольно хорошо с жестко закодированными значениями:

Текущий код автозаполнения (тот, который работает)

function testcmd()
{
    echo "Нечего делать, просто тестовая команда"
}


_test_complete() {
    _values \
        "Возможные значения" \
        foo'[Foo]' \
        bar'[Bar baz]' \
}

compdef _test_complete testcmd

Текущее поведение автозаполнения

Когда я набираю testcmd <tab>, я правильно получаю следующее ожидаемое отображение:

$ testcmd
Возможные значения
bar  -- Bar baz
foo  -- Foo

Какой цели я хочу достичь

Но, как вы видите, значения жестко закодированы внутри функции, в идеале функция должна их получать из переменной.

Что я уже пробовал

Поэтому естественно, я поместил значения в переменную values_variable следующим образом:

Попробованный код (тот, который не работает)

function testcmd()
{
    echo "Нечего делать, просто тестовая команда"
}


_test_complete() {
    local values_variable
    values_variable="foo'[Foo]' \
        bar'[Bar baz]' \ "
    _values \
        "Возможные значения" \
        ${values_variable}
}

compdef _test_complete testcmd

Поведение попробованного кода

Но затем, когда я пытаюсь testcmd <tab>, это полностью проваливается:

$ testcmd
_values:compvalues:11: неверное определение значения: foo'[Foo]' \t\tbar'[Bar baz]' \
_values:compvalues:11: неверное определение значения: foo'[Foo]' \t\tbar'[Bar baz]' \
_values:compvalues:11: неверное определение значения: foo'[Foo]' \t\tbar'[Bar baz]' \
$ testcmd 

Что я также сделал

  • Я пытался экранировать пробелы с помощью echo ${values_variable} | sed "s/ /\\ /g" ;
  • Я пытался использовать $values_variable с командой eval, чтобы имитировать, как будто его содержимое было напрямую набрано внутри определения _values ;
  • Я пытался использовать как eval, так и экранирование с помощью eval $(echo ${values_variable} | sed "s/ /\\ /g") ;
  • Я пытался прочитать строку за строкой с помощью цикла:
echo "$values_variable" | while read -r line; do
    eval "$line"
  done
  • Расширение с ${(@f)values_variable}̀ ;
  • Множество других идей. Но это тоже не сработало.

Ближайшее решение, которое я нашел

В Как передать содержимое файла с использованием cat в _values (zsh completion) ветке я нашел решение для значений, импортированных из внешнего файла, но пользователь кажется столкнулся с той же проблемой экранирования пробелов. Однако я не могу адаптировать его к случаю с внутренней переменной $values_variables.

Я естественно попробовал это, что тоже не работает:

_test_complete() {
    local values_variable
    values_variable="foo'[Foo]' \
        bar'[Bar baz]' \ "
    OLD_IFS=$IFS
    IFS=$'\n'
    _values \
        "Возможные значения" \
        ${values_variable}
    IFS=$OLD_IFS
}

Вопрос

Как я могу загрузить значения для передачи в _values внутри функции автозаполнения из переменной?

Вы можете использовать переменную массив:

_test_complete() {
    local -a values_variable=(
        'foo[Foo]'
        'bar[Bar baz]'
    )
    _values 'Возможные значения' "${values_variable[@]}"
}
compdef _test_complete testcmd

Тогда testcmd TAB покажет:

bar  -- Bar baz
foo  -- Foo

Ответ или решение

Значительная часть работы системного администратора или специалиста в области информационных технологий — это настройка окружения так, чтобы с ним было легко и удобно взаимодействовать. Одной из таких важных частей удобства работы в командной строке является автодополнение. Оно позволяет значительно сократить время ввода команд и снижает вероятность ошибок. В данной статье будет рассмотрен пример настроек автодополнения для Zsh (Z shell), который является одной из самых популярных оболочек для UNIX-подобных операционных систем.

Общее представление

Перед нами стоит задача настроить автодополнение в Zsh для команды testcmd, используя значения, заданные в переменной. Ранее использованная настройка работает, но имеет значительное ограничение: значения жестко зашиты в код функции. Это создает неудобства, если понадобится изменить или расширить перечень значений, поскольку для этого придется вносить изменения непосредственно в код функции автодополнения.

Текущая работающая конфигурация:

function testcmd() {
    echo "Nothing to do, just a test command"
}

_test_complete() {
    _values \
        "Possible values" \
        foo'[Foo]' \
        bar'[Bar baz]'
}

compdef _test_complete testcmd

При вводе testcmd и нажатии клавиши TAB пользователю предлагаются варианты:

$ testcmd
Possible values
bar  -- Bar baz
foo  -- Foo

Цель

Основная цель заключается в том, чтобы заменить жестко прописанные внутри функции _test_complete значения на использование переменной. Это бы упростило процесс обновления и поддержки автодополнения, позволяя вынести значения в более доступную для редактирования область. В идеале, значения должны извлекаться из переменной values_variable.

Попытки решения

Было предпринято несколько попыток:

  • Использование переменной values_variable строкового типа, содержащей значения:
_test_complete() {
    local values_variable
    values_variable="foo'[Foo]' \
        bar'[Bar baz]'"

    _values \
        "Possible values" \
        ${values_variable}
}

compdef _test_complete testcmd

Этот метод не сработал, выдав ошибку: _values:compvalues:11: invalid value definition.

  • Проводились разные методы для манипуляции строками, такие как использование eval, попытка экранирования пробелов с sed, разбор строки по частям с помощью циклов. Однако все эти методики не привели к положительному результату.

Лучше всего предложенное решение

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

_test_complete() {
    local -a values_variable=(
        'foo[Foo]'
        'bar[Bar baz]'
    )
    _values 'Possible values' "${values_variable[@]}"
}
compdef _test_complete testcmd

Практическая реализация

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

При использовании testcmd с нажатием TAB пользователь увидит тот же список:

bar  -- Bar baz
foo  -- Foo

Выводы

Настройка автодополнения в оболочке Zsh с помощью массивов — это удобный и гибкий способ упростить взаимодействие пользователя с командной строкой. Массивы позволяют абстрагировать значения от основной логики, повышая ее гибкость и удобство поддержки, что особенно полезно в корпоративной среде, где изменения могут требоваться часто или неожиданно.

Оцените материал
Добавить комментарий

Капча загружается...