From b2904998b8a7c32c7ab8a087cce4852f72be1ec1 Mon Sep 17 00:00:00 2001 From: arcan1s Date: Fri, 18 Jul 2014 00:05:48 +0400 Subject: [PATCH] add bash-comp-tut (ru) --- ...014-07-17-writting-own-completions-p1.html | 14 +- ...014-07-17-writting-own-completions-p2.html | 139 ++++++++++++++++++ 2 files changed, 146 insertions(+), 7 deletions(-) create mode 100644 ru/_posts/2014-07-17-writting-own-completions-p2.html diff --git a/ru/_posts/2014-07-17-writting-own-completions-p1.html b/ru/_posts/2014-07-17-writting-own-completions-p1.html index 25515be..0ec1f99 100644 --- a/ru/_posts/2014-07-17-writting-own-completions-p1.html +++ b/ru/_posts/2014-07-17-writting-own-completions-p1.html @@ -17,7 +17,7 @@ description: В данных статьях описываются некото

Рассмотрим на примере моего же приложения, часть справки к которому выглядит таким образом:

{% highlight bash %} netctl-gui [ -h | --help ] [ -e ESSID | --essid ESSID ] [ -с FILE | --config FILE ] - [ -o PROFILE | --open PROFILE ] [ -t NUM | --tab NUM ] [ --set-opts OPTIONS ] + [ -o PROFILE | --open PROFILE ] [ -t NUM | --tab NUM ] [ --set-opts OPTIONS ] {% endhighlight %}

Список флагов: @@ -35,7 +35,7 @@ netctl-gui [ -h | --help ] [ -e ESSID | --essid ESSID ] [ -с FILE | --config FI

В заголовке должно быть обязательно указано, что это файл дополнений и для каких приложений он служит (можно строкой, если в файле будет содержаться дополнение для нескольких команд): {% highlight bash %} -#compdef netctl-gui +#compdef netctl-gui {% endhighlight %} Дальше идет описание флагов, вспомогательные функции и переменные. Замечу, что функции и переменные, которые будут использоваться для дополнения должны возвращать массивы, а не строки. В моем случае схема выглядит примерно так (все функции и переменные в этой главе умышленно оставлены пустыми): @@ -45,14 +45,14 @@ netctl-gui [ -h | --help ] [ -e ESSID | --essid ESSID ] [ -с FILE | --config FI _netctl_gui_arglist=() _netctl_gui_settings=() _netctl_gui_tabs=() -_netctl_profiles() {} +_netctl_profiles() {} {% endhighlight %} Затем идут основные функции, которые будут вызываться для дополнения для определенной команды. В моем случае команда одна, и функция одна: {% highlight bash %} # work block -_netctl-gui() {} +_netctl-gui() {} {% endhighlight %} Далее без выделения в отдельную функцию идет небольшое шаманство, связанное с соотнесением приложения, которое было декларировано в первой строке, с функцией в теле скрипта: @@ -62,7 +62,7 @@ case "$service" in netctl-gui) _netctl-gui "$@" && return 0 ;; -esac +esac {% endhighlight %}

@@ -79,7 +79,7 @@ _netctl_gui_arglist=( {'(--open)-o','(-o)--open'}'[open profile]:select profile:->profiles' {'(--tab)-t','(-t)--tab'}'[open a tab with specified number]:select tab:->tab' {'--set-opts','--set-opts'}'[set options for this run, comma separated]:comma separated:->settings' -) +) {% endhighlight %}

@@ -141,6 +141,6 @@ _netctl-gui() {

Заключение

-

Файл хранится в директории /usr/share/zsh/site-functions с произвольным в общем-то именем с префиксом _. Файл примера полностью может быть найден в моем репозитории.

+

Файл хранится в директории /usr/share/zsh/site-functions/ с произвольным, в общем-то, именем с префиксом _. Файл примера полностью может быть найден в моем репозитории.

Дополнительная информация может быть найдена в репозитории zsh-completions. Например, там есть такой How-To. А еще там есть много примеров.

diff --git a/ru/_posts/2014-07-17-writting-own-completions-p2.html b/ru/_posts/2014-07-17-writting-own-completions-p2.html new file mode 100644 index 0000000..3ca8c6b --- /dev/null +++ b/ru/_posts/2014-07-17-writting-own-completions-p2.html @@ -0,0 +1,139 @@ +--- +category: ru +type: paper +hasTr: true +layout: paper +tags: linux, разработка +title: Написание собственных дополнений для Shell. Bash +short: writting-own-completions-p2 +description: В данных статьях описываются некоторые основы создания файлов автодополнений для собственной программы. +--- +

Преамбула

+

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

+ +

Введение

+

Bash, в отличие от zsh, требует к себе некоторого велосипедостроения в отношении дополнений. Бегло погуглив, я не нашел более-менее нормальных туториалов, потому за основу были взяты имеющиеся в системе файлы дополнений для pacman.

+ +

Рассмотрим на примере все того же моего приложения. Я напомню, что часть справки к которому выглядит таким образом:

+{% highlight bash %} +netctl-gui [ -h | --help ] [ -e ESSID | --essid ESSID ] [ -с FILE | --config FILE ] + [ -o PROFILE | --open PROFILE ] [ -t NUM | --tab NUM ] [ --set-opts OPTIONS ] +{% endhighlight %} + +

Список флагов: +

+

+ +

Структура файла

+

Здесь все переменные должны возвращать массив. Каких-либо особых форматов тут уже нет. Сначала опишем флаги, потом уже все остальные переменные. Я напомню (так как ниже я уже не буду приводить функции более подробно), что _netctl_profiles(), в отличие от других переменных, должна возвращать актуальный на данный момент массив: + +{% highlight bash %} +# variables +_netctl_gui_arglist=() +_netctl_gui_settings=() +_netctl_gui_tabs=() +_netctl_profiles() {} +{% endhighlight %} + +Затем идут основные функции, которые будут вызываться для дополнения для определенной команды. В моем случае команда одна, и функция одна: + +{% highlight bash %} +# work block +_netctl-gui() {} +{% endhighlight %} + +Далее, опять, без выделения в отдельную функцию делаем соответствие функция-команда: + +{% highlight bash %} +complete -F _netctl_gui netctl-gui +{% endhighlight %} +

+ +

Массивы переменных

+

Приведу только функцию, которая в zsh выглядела таким образом: + +{% highlight bash %} +_netctl_profiles() { + print $(find /etc/netctl -maxdepth 1 -type f -printf "%f\n") +} +{% endhighlight %} + +В bash так не получится, пришлось чуть-чуть изменить: + +{% highlight bash %} +_netctl_profiles() { + echo $(find /etc/netctl -maxdepth 1 -type f -printf "%f\n") +} +{% endhighlight %} +

+ +

Флаги

+

Как было сказано выше, особого формата тут нет, доступные флаги располагаются просто массивом: + +{% highlight bash %} +_netctl_gui_arglist=( + '-h' + '--help' + '-e' + '--essid' + '-c' + '--config' + '-o' + '--open' + '-t' + '--tab' + '--set-opts' +) +{% endhighlight %} +

+ +

Тело функции

+

За дополнение в bash отвечает переменная COMPREPLY. Для отслеживания текущего состояния нужно вызвать функцию _get_comp_words_by_ref с параметрами cur (текущая опция) и prev (предыдущая, собственно состояние). Ну и нужно несколько точек, на которых сворачивать в определенную часть case (переменные want*). Для генерации дополнения используется compgen. После флага -W ему подается список слов. (Есть еще флаг -F, который вызывает функцию, но у меня он помимо этого еще и ворнинг выдает.) Последним аргументом идет текущая строка, к которой и нужно генерировать дополнение.

+ +

Таким образом, наша функция выглядит так: + +{% highlight bash %} +_netctl_gui() { + COMPREPLY=() + wantfiles='-@(c|-config)' + wantprofiles='-@(o|-open|s|-select)' + wantsettings='-@(-set-opts)' + + wanttabs='-@(t|-tab)' + _get_comp_words_by_ref cur prev + + if [[ $prev = $wantstring ]]; then + # не делать дополнения, ждать введенной строки + COMPREPLY=() + elif [[ $prev = $wantfiles ]]; then + # дополнение по существующим файлам + _filedir + elif [[ $prev = $wantprofiles ]]; then + # дополнение из функции + COMPREPLY=($(compgen -W '${_netctl_profiles[@]}' -- "$cur")) + elif [[ $prev = $wanttabs ]]; then + # дополнение из массива + COMPREPLY=($(compgen -W '${_netctl_gui_tabs[@]}' -- "$cur")) + elif [[ $prev = $wantsettings ]]; then + # дополнение из массива + # -S вставит запятую после, но вот мультивыбор не включил =( + COMPREPLY=($(compgen -S ',' -W '${_netctl_gui_settings[@]}' -- "$cur")) + else + # вывести доступные аргументы + COMPREPLY=($(compgen -W '${_netctl_gui_arglist[@]}' -- "$cur")) + fi + + true +} +{% endhighlight %} +

+ +

Заключение

+

Файл хранится в директории /usr/share/bash-completion/completions/ с произвольным именем. Файл примера полностью может быть найден в моем репозитории.