Bash-completion

Freddy Vulto (FVu)

Revision History
Revision 1.0Mar 2009FV(

Table of Contents

Preface
I. Bash completion
1. Configuration files
2. Environment variables
II. Coding Style Guide
3. Introduction
4. Indentation
5. Globbing in case labels
6. [[ ]] vs [ ]
7. Line wrapping
8. $(…) vs `…`
9. -o filenames
10. [[ $COMPREPLY == *= ]] && compopt -o nospace
11. $split && return
III. Automated testing
12. Introduction
13. Coding Style Guide
14. Installing dependencies
14.1. Debian/Ubuntu
14.2. Fedora/RHEL/CentOS
15. Structure
16. Running the tests
16.1. Specifying bash binary
17. Maintenance
17.1. Adding a completion test
18. Rationale
18.1. Naming conventions

Preface

Bash completion extends bashs standard completion behavior to achieve complex command lines with just a few keystrokes. This project was conceived to produce programmable completion routines for the most common Linux/UNIX commands, reducing the amount of typing sysadmins and programmers need to do on a daily basis.

Part I. Bash completion

Chapter 1. Configuration files

$BASH_COMPLETION_USER_FILE
Sourced late by bash_completion, pretty much after everything else. Use this file for example to load additional completions, and to remove and override ones installed by bash_completion. Defaults to ~/.bash_completion if unset or null.
$XDG_CONFIG_HOME/bash_completion
Sourced by the bash_completion.sh profile.d script. This file is suitable for definitions of all COMP_* environment variables below. If $XDG_CONFIG_HOME is unset or null, ~/.config is used instead of it.

Chapter 2. Environment variables

BASH_COMPLETION_COMPAT_DIR
Directory for pre-dynamic loading era (pre-2.0) backwards compatibility completion files that are loaded eagerly from bash_completion when it is loaded. If unset or null, the default compatibility directory to use is /etc/bash_completion.d.
COMP_CONFIGURE_HINTS
If set and not null, configure completion will return the entire option string (e.g. --this-option=DESCRIPTION) so one can see what kind of data is required and then simply delete the descriptive text and add one’s own data. If unset or null (default), configure completion will strip everything after the = when returning completions.
COMP_CVS_REMOTE
If set and not null, cvs commit completion will try to complete on remotely checked-out files. This requires passwordless access to the remote repository. Default is unset.
COMP_FILEDIR_FALLBACK
If set and not null, completions that look for filenames based on their "extensions" will fall back to suggesting all files if there are none matching the sought ones.
COMP_IWLIST_SCAN
If set and not null, iwconfig completion will try to complete on available wireless networks identifiers. Default is unset.
COMP_KNOWN_HOSTS_WITH_HOSTFILE
If set and not null (default), known hosts completion will complement hostnames from ssh’s known_hosts files with hostnames taken from the file specified by the HOSTFILE shell variable (compgen -A hostname). If null, known hosts completion will omit hostnames from HOSTFILE. Omitting hostnames from HOSTFILE is useful if HOSTFILE contains many entries for local web development or ad-blocking.
COMP_KNOWN_HOSTS_WITH_AVAHI
If set and not null, known hosts completion will try to use avahi-browse for additional completions. This may be a slow operation in some setups. Default is unset.
COMP_TAR_INTERNAL_PATHS
If set and not null before sourcing bash_completion, ‘tar` completion will do correct path completion for tar file contents. If unset or null, `tar’ completion will do correct completion for paths to tar files. See also README.

Part II. Coding Style Guide

Chapter 3. Introduction

This document attempts to explain the basic styles and patterns that are used in the bash completion. New code should try to conform to these standards so that it is as easy to maintain as existing code. Of course every rule has an exception, but it’s important to know the rules nonetheless!

This is particularly directed at people new to the bash completion codebase, who are in the process of getting their code reviewed. Before getting a review, please read over this document and make sure your code conforms to the recommendations here.

Chapter 4. Indentation

Indent step should be 4 spaces, no tabs.

Chapter 5. Globbing in case labels

Avoid "fancy" globbing in case labels, just use traditional style when possible. For example, do "--foo|--bar)" instead of "--@(foo|bar))". Rationale: the former is easier to read, often easier to grep, and doesn’t confuse editors as bad as the latter, and is concise enough.

Chapter 6. [[ ]] vs [ ]

Always use [[ ]] instead of [ ]. Rationale: the former is less error prone, more featureful, and slightly faster.

Chapter 7. Line wrapping

Try to wrap lines at 79 characters. Never go past this limit, unless you absolutely need to (example: a long sed regular expression, or the like). This also holds true for the documentation and the testsuite. Other files, like ChangeLog, or COPYING, are exempt from this rule.

Chapter 8. $(…) vs `…`

When you need to do some code substitution in your completion script, you MUST use the $(…) construct, rather than the `…`. The former is preferable because anyone, with any keyboard layout, is able to type it. Backticks aren’t always available, without doing strange key combinations.

Chapter 9. -o filenames

As a rule of thumb, do not use "complete -o filenames". Doing it makes it take effect for all completions from the affected function, which may break things if some completions from the function must not be escaped as filenames. Instead, use "compopt -o filenames" to turn on "-o filenames" behavior dynamically when returning completions that need that kind of processing (e.g. file and command names). The _filedir and _filedir_xspec helpers do this automatically whenever they return some completions.

Chapter 10. [[ $COMPREPLY == *= ]] && compopt -o nospace

The above is functionally a shorthand for:

if [[ ${#COMPREPLY[@]} -eq 1 && ${COMPREPLY[0]} == *= ]]; then
    compopt -o nospace
fi

It is used to ensure that long options' name won’t get a space appended after the equal sign. Calling compopt -o nospace makes sense in case completion actually occurs: when only one completion is available in COMPREPLY.

Chapter 11. $split && return

Should be used in completions using the -s flag of _init_completion, or other similar cases where _split_longopt has been invoked, after $prev has been managed but before $cur is considered. If $cur of the form --foo=bar was split into $prev=--foo and $cur=bar and the $prev block did not process the option argument completion, it makes sense to return immediately after the $prev block because --foo obviously takes an argument and the remainder of the completion function is unlikely to provide meaningful results for the required argument. Think of this as a catch-all for unknown options requiring an argument.

Note that even when using this, options that are known to require an argument but for which we don’t have argument completion should be explicitly handled (non-completed) in the $prev handling block because --foo=bar options can often be written without the equals sign, and in that case the long option splitting does not occur.

Part III. Automated testing

Chapter 12. Introduction

The bash-completion package contains an automated test suite. Running the tests should help verifying that bash-completion works as expected. The tests are also very helpful in uncovering software regressions at an early stage.

The original, "legacy" bash-completion test suite is written on top of the DejaGnu testing framework. DejaGnu is written in Expect, which in turn uses Tcl — Tool command language.

Most of the test framework has been ported over to use pytest and pexpect. Eventually, all of it should be ported.

Chapter 13. Coding Style Guide

For the Python part, all of it is formatted using Black, and we also run Flake8 on it.

The legacy test suite tries to adhere to this Tcl Style Guide.

Chapter 14. Installing dependencies

Installing dependencies should be easy using your local package manager or pip. Python 3.4 or newer is required, and the rest of the Python package dependencies are specified in the test/requirements.txt file. If using pip, this file can be fed directly to it, e.g. like:

pip install -r test/requirements.txt

14.1. Debian/Ubuntu

On Debian/Ubuntu you can use apt-get:

sudo apt-get install python3-pytest python3-pexpect dejagnu tcllib

This should also install the necessary dependencies. Only Debian testing (buster) and Ubuntu 18.10 (cosmic) and later have an appropriate version of pytest in the repositories.

14.2. Fedora/RHEL/CentOS

On Fedora and RHEL/CentOS (with EPEL) you can try yum or dnf:

sudo yum install python3-pytest python3-pexpect dejagnu tcllib

This should also install the necessary dependencies. At time of writing, only Fedora 29 comes with recent enough pytest.

Chapter 15. Structure

Pytest tests are in the t/ subdirectory, with t/test_\*.py being completion tests, and t/unit/test_unit_\*.py unit tests.

Legacy tests are grouped into different areas, called tool in DejaGnu:

completion
Functional tests per completion.
install
Functional tests for installation and caching of the main bash-completion package.
unit
Unit tests for bash-completion helper functions.

Chapter 16. Running the tests

Python based tests are run by calling pytest on the desired test directories or individual files, for example in the project root directory:

pytest test/t

Legacy tests are run by calling runtest command in the test directory:

runtest --outdir log --tool completion
runtest --outdir log --tool install
runtest --outdir log --tool unit

The commands above are already wrapped up in shell scripts within the test directory:

./runCompletion
./runInstall
./runUnit

To run a particular test, specify file name of your test as an argument to runCompletion script:

./runCompletion ssh.exp

That will run test/completion/ssh.exp.

See test/docker/docker-script.sh for how and what we run and test in CI.

16.1. Specifying bash binary

The test suite standard uses bash as found in PATH. Export the bashcomp_bash environment variable with a path to another bash executable if you want to test against something else.

Chapter 17. Maintenance

17.1. Adding a completion test

You can run cd test && ./generate cmd to add a test for the cmd command. Additional arguments will be passed to the first generated test case. This will add the test/t/test_cmd.py file with a very basic test, and add it to test/t/Makefile.am. Add additional tests to the generated file.

Chapter 18. Rationale

18.1. Naming conventions

18.1.1. Test suite or testsuite

The primary Wikipedia page is called test suite and not testsuite, so that’s what this document sticks to.

18.1.2. script/generate

The name and location of this code generation script come from Ruby on Rails' script/generate.