arcanis.me/_posts/2014-07-17-writting-own-completions-p2.html
2014-08-25 23:58:38 +04:00

137 lines
6.3 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
category: en
type: paper
hastr: true
layout: paper
tags: linux, development
title: Writting own Shell completions. Bash
short: writting-own-completions-p2
description: <figure class="img"><img src="/resources/papers/bash_completion.png" alt="bash_completion"></figure> Some basics of creating a completion files for own application are described in these articles.
---
<h2><a href="#preamble" class="anchor" id="preamble"><span class="octicon octicon-link"></span></a>Preamble</h2>
<p>While developing <a href="/ru/projects/netctl-gui" title="Netctl-gui project page">one of my projects</a> I have wanted to add completion files. I have already tried to create these files, but I was too lazy to read some manuals about it.</p>
<h2><a href="#introduction" class="anchor" id="introduction"><span class="octicon octicon-link"></span></a>Introduction</h2>
<p>Bash, <a href="/ru/2014/07/17/writting-own-completions-p1" title="Zsh completions paper">unlike zsh</a>, demands some dirty workarounds for completions. Cursory have Googled, I have not found a more or less normal tutorials, so it is based on the available <code>pacman</code> completion files in my system.</p>
<p>Lets consider the example of the same my application. I remind you that a part of help message is as follows:</p>
{% 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 %}
<p>Here is a flag list:</p>
<ul>
<li>flags <code>-h</code> and <code>--help</code> do not require any arguments;</li>
<li>flags <code>-e</code> and <code>--essid</code> require a string argument without completion;</li>
<li>flags <code>-c</code> and <code>--config</code> require a string argument, which is a file;</li>
<li>flags <code>-o</code> and <code>--open</code> require a string argument, there is a completion from files in the specified directory;</li>
<li>flags <code>-t</code> and <code>--tab</code> require a string argument, there is a completion from the specified array;</li>
<li>flag <code>--set-opts</code> requires a string argument, there is a completion from the specified array comma separated;</li>
</ul>
<h2><a href="#file" class="anchor" id="file"><span class="octicon octicon-link"></span></a>The file pattern</h2>
<p>Here <b>all</b> variables must return an array. And there no specific formats. First we declare the flags and then we describe all other variables. As I am not going to describe the functions in more detail below I remind you that <code>_netctl_profiles()</code> should be generated each time:</p>
{% highlight bash %}
# variables
_netctl_gui_arglist=()
_netctl_gui_settings=()
_netctl_gui_tabs=()
_netctl_profiles() {}
{% endhighlight %}
<p>Then there are main functions, which will be called for completion of specific application. In my case this there is only one applications, so there is only one function:</p>
{% highlight bash %}
# work block
_netctl-gui() {}
{% endhighlight %}
<p>And finally again <b>without isolation in a separate function</b> we create a dependence "function-application":</p>
{% highlight bash %}
complete -F _netctl_gui netctl-gui
{% endhighlight %}
<h2><a href="#flags" class="anchor" id="flags"><span class="octicon octicon-link"></span></a>Flags</h2>
<p>As it was said above there is no specific format, so all available flags declare by array:</p>
{% highlight bash %}
_netctl_gui_arglist=(
'-h'
'--help'
'-e'
'--essid'
'-c'
'--config'
'-o'
'--open'
'-t'
'--tab'
'--set-opts'
)
{% endhighlight %}
<h2><a href="#variables" class="anchor" id="variables"><span class="octicon octicon-link"></span></a>Arrays of variables</h2>
<p>I just give a function that looked like this in zsh:</p>
{% highlight bash %}
_netctl_profiles() {
print $(find /etc/netctl -maxdepth 1 -type f -printf "%f\n")
}
{% endhighlight %}
<p>Bash does not allow to do so, so this function should be a little changed:</p>
{% highlight bash %}
_netctl_profiles() {
echo $(find /etc/netctl -maxdepth 1 -type f -printf "%f\n")
}
{% endhighlight %}
<h2><a href="#body" class="anchor" id="body"><span class="octicon octicon-link"></span></a>Function</h2>
<p>The variable <code>COMPREPLY</code> responds for completion in Bash. To keep track of the current state function <code>_get_comp_words_by_ref</code> must be called with parameters <code>cur</code> (current flag) and <code>prev</code> (previous flag, it is the state). Also some point for case are needed (variables <code>want*</code>). Function <code>compgen</code> is used for completion generation. A list of words is given after flag <code>-W</code>. (Also there is flag <code>-F</code> which requires a function as argument, but it gives warning for me.) The last argument is a current string to which you want to generate completion.</p>
<p>So, here is our function:</p>
{% 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
# do not completion, wait for string
COMPREPLY=()
elif [[ $prev = $wantfiles ]]; then
# completion from files in this directory
_filedir
elif [[ $prev = $wantprofiles ]]; then
# completion from function
COMPREPLY=($(compgen -W '${_netctl_profiles[@]}' -- "$cur"))
elif [[ $prev = $wanttabs ]]; then
# completion from array
COMPREPLY=($(compgen -W '${_netctl_gui_tabs[@]}' -- "$cur"))
elif [[ $prev = $wantsettings ]]; then
# completion from array
# flag -S add a comma after completion, but does not enable multi-selection =(
COMPREPLY=($(compgen -S ',' -W '${_netctl_gui_settings[@]}' -- "$cur"))
else
# show all available flags
COMPREPLY=($(compgen -W '${_netctl_gui_arglist[@]}' -- "$cur"))
fi
true
}
{% endhighlight %}
<h2><a href="#conclusion" class="anchor" id="conclusion"><span class="octicon octicon-link"></span></a>Conclusion</h2>
<p>File should be places to <code>/usr/share/bash-completion/completions/</code> with any name. You may found the example <a href="https://raw.githubusercontent.com/arcan1s/netctl-gui/master/sources/gui/bash-completions" title="File" type="text/plain">in my repository</a>.</p>