diff options
Diffstat (limited to 'doc')
-rw-r--r-- | doc/Makefile.am | 10 | ||||
-rw-r--r-- | doc/api-and-naming.md | 232 | ||||
-rw-r--r-- | doc/bash_completion.txt | 66 | ||||
l--------- | doc/bashrc | 1 | ||||
-rw-r--r-- | doc/configuration.md | 149 | ||||
l--------- | doc/inputrc | 1 | ||||
-rw-r--r-- | doc/main.txt | 18 | ||||
-rwxr-xr-x | doc/makeHtml.sh | 4 | ||||
-rw-r--r-- | doc/styleguide.md | 232 | ||||
-rw-r--r-- | doc/styleguide.txt | 134 | ||||
-rw-r--r-- | doc/testing.md | 80 | ||||
-rw-r--r-- | doc/testing.txt | 112 |
12 files changed, 696 insertions, 343 deletions
diff --git a/doc/Makefile.am b/doc/Makefile.am index 6930b9c..8bac9e8 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,8 +1,4 @@ EXTRA_DIST = \ - bash_completion.txt \ - bashrc \ - inputrc \ - main.txt \ - makeHtml.sh \ - styleguide.txt \ - testing.txt + configuration.md \ + styleguide.md \ + testing.md diff --git a/doc/api-and-naming.md b/doc/api-and-naming.md new file mode 100644 index 0000000..59b2c36 --- /dev/null +++ b/doc/api-and-naming.md @@ -0,0 +1,232 @@ +# API and naming + +## General API conventions + +Most of the functions in bash-completion generate completions and directly +inject them to the `COMPREPLY` array variable, as required for completions to +work. + +Most other functions make use of "output" variables, i.e. assign values to +them. The name of an output variable should be basically in lowercase. +Consult the commentary before each function in the source to find out the +specific names. `local`izing output variables before invoking a function that +populates them is the caller's responsibility. Note that if calling multiple +functions that assign output to the same variable during one completion +function run, each result should be copied to another variable between the +calls to avoid it possibly being overwritten and lost on the next call. Also, +the variables should also be ensured to be clear before each call that +references the value, variable name, or their existence, typically by `unset +-v`ing them when multiple such calls are used, to avoid them interfering with +each other. + +The most common output variable is named `REPLY`. The use of the uppercase is +unconventional, but this choice of the name is intended to be consistent with +the value substitutions `${| func; }`, which is originally supported by mksh +and will be supported by Bash >= 5.3. The value substitutions are replaced by +the contents of the output variable `REPLY` set by `func`. Although we cannot +currently assume Bash 5.3 in the codebase, but we can switch to the value +substitutions at the point Bash <= 5.2 disappear from the market. + +Everything in fallback completion files (ones starting with an underscore) +is considered private and is to be named accordingly. Fallback files are not +intended to be explicitly used with `_comp_xfunc`, and completion files having +precedence over them may have a different API. + +## Availability + +All public API functions and variables are marked with a `@since VERSION` +comment, where `VERSION` is the bash-completion version the thing was +introduced in. + +Similarly, deprecated functions and variables are either marked with a +`@deprecated VERSION ...` comment, or deprecated using the +`_comp_deprecate_func VERSION OLD_NAME NEW_NAME` function. +`VERSION` in both cases is the bash-completion version the thing was +deprecated in. + +## Naming + +Due to its nature, bash-completion adds a number of functions and variables in +the shell's environment. + +| | `bash_completion` | `completions/*` | +|:------------------------------------|:--------------------|:--------------------------------------------------------------------------------------| +| public configuration variables | `BASH_COMPLETION_*` | `BASH_COMPLETION_CMD_${Command^^}_${Config^^}` | +| private non-local variables | `_comp__*` | `_comp_cmd_${Command}__${Data}` | +| private non-local mutable variables | `_comp__*_mut_*` | `_comp_cmd_${Command}__mut_${Data}` | +| exporter function local variables | `_*` (not `_comp*`) | `_*` (not `_comp*`) | +| public/exported functions | `_comp_*` | `_comp_xfunc_${Command}_${Utility}` (functions for use with `_comp_xfunc`) | +| - completers (for `complete -F`) | `_comp_complete_*` | `_comp_cmd_${Command}` | +| - generators | `_comp_compgen_*` | `_comp_xfunc_${Command}_compgen_${Name}` (generators for use with `_comp_compgen -x`) | +| private/internal functions | `_comp__*` | `_comp_cmd_${Command}__${Utility}` (utility functions) | +| - generators | | `_comp_cmd_${Command}__compgen_${Name}` (generators for use with `_comp_compgen -i`) | + +`${Command}` refers to a command name (with characters not allowed in POSIX +function or variable names replaced by an underscore), `${Config}` the name of +a configurable thing, `^^` means uppercase, `${Data}` is an identifier for the +data contained in the variable, and `${Utility}` describes the typical usage of +the function. + +Variables and functions affecting multiple completions are usually defined +in the main `bash_completion` file and do not require any additional files to +be sourced. Variables and functions in command specific completion files in +`completions/*` follow a slightly different naming scheme; they include +`cmd` in their name as well as the name of the command. + +Public configuration variables are shell ones that affect the runtime behavior +of various completions. As a rule of thumb, we lean towards not providing +customizability but rather strive to provide great completion behavior out of +the box. But there are some, see [configuration](configuration.md). + +Variables and functions whose name contains a double underscore (`__`) anywhere +in their name are private implementation details, not part of the stable API, +and not intended to be used outside of their defining context. Internally, the +double underscores serve as privacy scope delimiters; there can be more than one +pair of them in a name, and functions and variables are intended to reference +and call other functions and variables within that scope, one level deep, +sharing a common prefix. For example, a function named `_comp_foo` is "allowed" +to access `_comp_foo__*` where `*` does not contain any double underscores, +i.e. it should not access `_comp_foo__something__*` despite the common prefix. + +Private non-local variables are considered readonly by default. When a +completion function needs to change variables for e.g. caching purposes, the +variables should contain the infix `*_mut_*` anywhere in their names. This is +needed to tell the test framework to allow these variables changing. +Nevertheless, the completion results should be consistent among different calls +and unaffected by the state of the cache variables when it is called. + +Internal local variables of functions that "export" their results using a +variable name that is passed in start with an underscore and do not start with +`_comp`. The variable names that are passed in for this purpose must not start +with an underscore. + +Functions with names prefixed with `_comp_xfunc_` are intended to be used +through the `_comp_xfunc` function from files other than the one they are +defined in. From the same file they can be used directly using their complete +name. + +Function names start with an underscore in order to avoid them being +included in completions of command names. (Except naturally when a command +starting with an underscore is being completed.) The underscore prefix does +not have anything to do with whether the thing is considered public or +private in the API, nor anything else really. + +The `BASH_COMPLETION_` prefix provides a namespace and makes it clear what +these variables relate to. The `_comp` in other names serves a similar purpose, +but because these are used a lot in the code (unlike the public configuration +variables), using something shorter is beneficial. We hope and believe this is +distinctive and clash free enough. + +It is known that a lot of functions and variables in the tree do not follow +these naming rules yet. Things introduced after version 2.11 should, and we are +evaluating our options for handling older ones. + +## Exported functions (xfunc) + +Exported functions (xfunc) are the functions defined in completion files for +specific commands but exposed to other completion files. The xfuncs have the +name `_comp_xfunc_CMD_NAME` where `CMD` is the name of the associated command, +and `NAME` is the name of the utility. The other functions defined in specific +completion files are considered private and should not be called outside the +file. + +The xfuncs can be called by `_comp_xfunc CMD NAME ARGS` from external files. +The xfuncs are supposed to be directly called as `_comp_xfunc_CMD_NAME ARGS` +from the same file where they are defined, or if they wrap a `_comp_cmd_NAME__*` +function, that one should be called directly instead. + +Note: The name `xfunc` was initially the name of a utility function, `_xfunc`, +to call "eXternal FUNCtions" that are defined in other completion files. The +concept is later extended to also mean "eXported". + +## Generator functions + +The generator functions, which have names of the form `_comp_compgen_NAME`, are +used to generate completion candidates. A generator function is supposed to be +called by `_comp_compgen [OPTS] NAME ARGS` where `OPTS = -aRl|-v var|-c cur|-C +dir|-F sep` are the options to modify the behavior (see the code comment of +`_comp_compgen` for details). When there are no `opts`, the generator function +is supposed to be directly called as `_comp_compgen_NAME ARGS`. The result is +stored in the target variable (which is `COMPREPLY` by default but can be +specified by `-v var` in `OPTS`). + +### Implementing a generator function + +To implement a generator function, one should generate completion candidates by +calling `_comp_compgen` or other generators. + +To avoid conflicts with the options specified to `_comp_compgen`, one should +not directly modify or reference the target variable. When post-filtering is +needed, store them in a local array, filter them, and finally append them by +`_comp_compgen -- -W '"${_arr[@]}"'`. To split the output of commands and +append the results to the target variable, use `_comp_compgen_split -- "$(cmd +...)"` instead of using `_comp_split COMPREPLY "$(cmd ...)"`. + +A generator function should replace the existing content of the variable by +default. When the appending behavior is favored, the caller should specify it +through `_comp_compgen -a NAME`. The generator function do not need to process +it because internal `_comp_compgen` calls automatically reflects the option +`-a` specified to the outer calls of `_comp_compgen`. + +The exit status is implementation-defined. + +- The `_comp_compgen -- COMPGEN_ARGS` returns whether there is at least one + completion. This is useful when one wants to reuse the array content with + `"${tmp[@]}"` avoiding `nounset` error. +- Some use other rules for the exit status. E.g., `help` and `usage` return + whether there were options *before* filtering by cur. This is used for + `_comp_compgen_help || _comp_compgen_usage`. + +Whether to clear the target variable on runtime error (when `-a` is not +specified in `OPTS`) is implementation-defined. On the other hand, the +generator function should not leave any side effects in the target variable on +usage error. Note that the target variable might be cleared by the internal +calls of `_comp_compgen`. To explicitly clear the target variable, +`_comp_compgen_set` can be called without arguments. + +Exported generators are defined with the names `_comp_xfunc_CMD_compgen_NAME` +and called by `_comp_compgen [opts] -x CMD NAME args`. Internal generators are +defined with the names `_comp_cmd_CMD__compgen_NAME` and called by +`_comp_compgen [opts] -i CMD NAME args`. + +#### Local variables of generator and `_comp_compgen -U var` + +A generator should basically define local variables with the names starting +with `_`. However, a generator sometimes needs to use local variable names +that do not start with `_`. When the child generator call with a variable name +(such as `local var; _comp_compgen -v var`) is used within the generator, the +local variable can unexpectedly mask a local variable of the upper call. + +For example, the following call fails to obtain the result of generator +`mygen1` because the array `arr` is masked by the same name of a local variable +in `_comp_compgen_mygen1`. + +```bash +# generator with a problem +_comp_compgen_mygen1() +{ + local -a arr=(1 2 3) + _comp_compgen -av arr -- -W '4 5 6' + _comp_compgen_set "${arr[@]/#p}" +} + +_comp_compgen -v arr mygen1 # fails to get the result in array `arr` +``` + +To avoid this, a generator that defines a local variable with its name not +starting with `_` can use the option `-U var` to unlocalize the variable on +assigning the final result. + +```bash +# properly designed generator +_comp_compgen_mygen1() +{ + local -a arr=(1 2 3) + _comp_compgen -av arr -- -W '4 5 6' + _comp_compgen -U arr set "${arr[@]/#p}" +} +``` + +To avoid unexpected unlocalization of previous-scope variables, a generator +should specify `-U var` to a child generator (that attempts to store results to +the current target variable) at most once. diff --git a/doc/bash_completion.txt b/doc/bash_completion.txt deleted file mode 100644 index e67f98b..0000000 --- a/doc/bash_completion.txt +++ /dev/null @@ -1,66 +0,0 @@ -Bash completion -=============== - -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. - -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. diff --git a/doc/bashrc b/doc/bashrc deleted file mode 120000 index e22ec0e..0000000 --- a/doc/bashrc +++ /dev/null @@ -1 +0,0 @@ -../test/config/bashrc
\ No newline at end of file diff --git a/doc/configuration.md b/doc/configuration.md new file mode 100644 index 0000000..186ac9a --- /dev/null +++ b/doc/configuration.md @@ -0,0 +1,149 @@ +# 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. + +Available since version 2.7. + +### `$XDG_CONFIG_HOME/bash_completion` + +Sourced by the `bash_completion.sh` `profile.d` script. This file is +suitable for definitions of all `COMP*` shell variables below. +If `$XDG_CONFIG_HOME` is unset or null,`~/.config` is +used instead of it. + +Available since version 1.90. + +## Shell variables + +### `BASH_COMPLETION_COMPAT_DIR` + +Directory for pre-dynamic loading era (pre-2.0) and other backwards +compatibility completion files that are loaded eagerly from `bash_completion` +when it is loaded. If unset or null, the default compatibility directories to +use are `/etc/bash_completion.d`, and `bash_completion.d` relative to +`bash_completion` location. + +Available since version 1.1. + +### `BASH_COMPLETION_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. + +Available since version 2.12. +Deprecated alias: `COMP_FILEDIR_FALLBACK` + +### `BASH_COMPLETION_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. + +Available since version 2.12. +Deprecated alias: `COMP_KNOWN_HOSTS_WITH_AVAHI` + +### `BASH_COMPLETION_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. + +Available since version 2.12. +Deprecated alias: `COMP_KNOWN_HOSTS_WITH_HOSTFILE` + +### `BASH_COMPLETION_COMPAT_IGNORE` + +Files in `BASH_COMPLETION_COMPAT_DIR` (the compat dir) to ignore, specified by +a glob pattern. The completion files in the compat dir whose basename matches +with this pattern will not be sourced by `bash_completion` at its load time. +This variable can be used to suppress the problematic completions. Note that +backup files and Makefiles in the compat dir are by default ignored regardless +of this setting. + +One example is `acroread.sh` which is installed by some versions of Adobe +Reader, overrides `_filedir` with an incompatible version, and causes +various problems. To recover this `_filedir`, another completion file +`redefine_filedir` had been placed in the compat dir, which could also +cause another incompatibility when the user uses their own version of +bash-completion instead of the systemwide version. To suppress these files +one can set the following value: + +```bash +export BASH_COMPLETION_COMPAT_IGNORE='@(acroread.sh|redefine_filedir)' +``` + +- <https://bugzilla.redhat.com/677446> +- <http://forums.adobe.com/thread/745833> +- <https://bugzilla.redhat.com/show_bug.cgi?id=1171396#c27> +- <https://github.com/scop/bash-completion/pull/667> + +Available since version 2.12. + +### `BASH_COMPLETION_CMD_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. + +Available since version 2.12. +Deprecated alias: `COMP_CONFIGURE_HINTS` + +### `BASH_COMPLETION_CMD_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. + +Available since version 2.12. +Deprecated alias: `COMP_CVS_REMOTE` + +### `BASH_COMPLETION_CMD_IWCONFIG_SCAN` + +If set and not null, `iwconfig` completion will try to complete on +available wireless networks identifiers. Default is unset. + +Available since version 2.12. +Deprecated alias: `COMP_IWLIST_SCAN` + +### `BASH_COMPLETION_CMD_SMBTREE_SCAN` + +If set and not null, various samba related tool completions perform +a network scan to complete domains and hosts. Default is unset. + +Available since version 2.12. +Deprecated alias: `COMP_SAMBA_SCAN` + +### `BASH_COMPLETION_CMD_TAR_INTERNAL_PATHS` + +If set and not null _before sourcing_ the `tar` completion, it will do +correct path completion for tar file _contents_. If unset or null, +_paths to_ tar files will be correctly completed. Unfortunately we do not +have a way to make both Just Work properly at the moment. We consider it +more important to have proper completion of paths to tar files than it is +to have completion for their contents, so the default is unset. + +Available since version 2.12. +Deprecated alias: `COMP_TAR_INTERNAL_PATHS` + +## Shell options + +### `no_empty_cmd_completion` + +If on, completions producing command names do not do anything if the command to +be completed is empty. This can be useful on systems where generating the +entire list of commands takes a long time. + +Available since version 2.12. diff --git a/doc/inputrc b/doc/inputrc deleted file mode 120000 index b6f22e6..0000000 --- a/doc/inputrc +++ /dev/null @@ -1 +0,0 @@ -../test/config/inputrc
\ No newline at end of file diff --git a/doc/main.txt b/doc/main.txt deleted file mode 100644 index d8a3076..0000000 --- a/doc/main.txt +++ /dev/null @@ -1,18 +0,0 @@ -Bash-completion -=============== -Freddy Vulto (FVu) -v1.0, Mar 2009 - -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. - -// include::intro.txt[] -include::bash_completion.txt[] - -include::styleguide.txt[] -include::testing.txt[] diff --git a/doc/makeHtml.sh b/doc/makeHtml.sh deleted file mode 100755 index 79780eb..0000000 --- a/doc/makeHtml.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -eu - -[ -d html~ ] || mkdir html~ -a2x -D html~ -d book -f xhtml --asciidoc-opts="--unsafe" main.txt diff --git a/doc/styleguide.md b/doc/styleguide.md new file mode 100644 index 0000000..46c4b4d --- /dev/null +++ b/doc/styleguide.md @@ -0,0 +1,232 @@ +# Coding style guide + +## 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. + +## Indentation + +Indent step should be 4 spaces, no tabs. + +## 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. + +## `[[ ]]` vs `[ ]` + +Always use `[[ ]]` instead of `[ ]`. Rationale: the former is less error +prone, more featureful, and slightly faster. + +## `$x` and `! $x` vs `-n $x` and `-z $x` + +Use `[[ $x ]]` and `[[ ! $x ]]` instead of `[[ -n $x ]]` and `[[ -z $x ]]`, +and similarly with the `test` builtin. +Rationale: no strong technical reasons to prefer either style, but the former +is subjectively slightly more readable and it was traditionally more common in +the codebase before this style item was standardized. + +## 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. + +## `$( )` vs backticks + +When you need to do some code substitution in your completion script, +you _MUST_ use the `$(...)` construct, rather than backticks. 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. + +## `-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. + +## `[[ ${COMPREPLY-} == *= ]] && compopt -o nospace` + +The above is functionally a shorthand for: + +```bash +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`. + +## `[[ $was_split ]] && return` + +Should be used in completions using the `-s` flag of `_comp_initialize`, +or other similar cases where `_comp__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. + +## Use arithmetic evaluation + +When dealing with numeric data, take advantage of arithmetic evaluation. +In essence, use `(( ... ))` whenever it can replace `[[ ... ]]` because the +syntax is more readable; no need for `$`-prefixes, numeric comparison etc +operators are more familiar and easier on the eye. + +## Array subscript access + +Array subscripts are arithmetic expressions, take advantage of that. +E.g. write `${foo[bar]}`, not `${foo[$bar]}`, and similarly `${foo[bar+1]}` +vs `${foo[((bar+1))]}` or `${foo[$((bar+1))]}`, `${foo[--i]}` vs +`${foo[((--i))]}`. + +## Loop variable names + +Use `i`, `j`, `k` for loop-local indices; `n` and `m` for lengths; some other +descriptive name typically based on array name but in singular when looping +over actual values. If an index or value is to be accessed later on instead of +being just locally for looping, use a more descriptive and specific name for +it. + +## Function and variable names + +See [API and naming](api-and-naming.md). + +## Quoting of words + +To avoid unexpected word splitting and pathname expansions, an argument of +commands needs to be properly quoted when it contains shell expansions such as +`$var`, `$(cmd)`, and `$((expr))`. + +When one intentionally wants word splitting and pathname expansions, one should +consider using the utility functions provided by bash-completion. To safely +split a string without being affected by non-standard `IFS` and pathname +expansions, use the shell function `_comp_split`. To safely obtain filenames +by pathname expansions without being affected by `failglob`, etc., use the +shell function `_comp_expand_glob`. Note that `_comp_expand_glob` should be +always used for the pathname patterns even if the pattern does not contain +shell expansions. + +In the following contexts, the quoting to suppress word splitting and pathname +expansions are not needed. + +- The right-hand sides of variable assignments ... `v=WORD` (e.g. `v=$var`) +- The arguments of conditional commands ... `[[ WORD ]]` (e.g. `[[ $var ]]`) +- The argument specified to `case` statement ... `case WORD in foo) ;; esac` + (e.g. `case $var in foo) ;; esac`) + +In bash-completion, we do not quote them by default. However, there are +exceptions where the quoting is still needed for other reasons. + +- When the word *directly* contains shell special characters (space, tab, + newline, or a character from ``;|&()<>\\$`'"#!~{``), these characters need to + be quoted. The "*directly*" means that the special characters produced by + shell expansions are excluded here. For example, when one wants to include a + whitespace as a part of the value of the word, the right-hand side can be + quoted as `v="a b"`. +- An empty word (i.e., the word whose value is an empty string) is specified by + `""`. The right-hand side of an assignment technically can be an empty + string as `var=`, but we still use `var=""` there because `shellcheck` + suggests that e.g. `var= cmd` is confusing with `var=cmd`. +- `$*` and `${array[*]}` need to be always quoted because they can be affected + by the word splitting in bash <= 4.2 even in the above contexts. +- In the following contexts, double-quoting of shell expansions is needed + unless the result of expansions is intentionally treated as glob patterns or + regular expressions. + - The right-hand sides of `==`, `!=`, and `=~` in the conditional commands + ... `[[ word == "$var" ]]` + - The case patterns ... `case word in "$var") ;; esac` + +Note: Here strings `cat <<<$var` are also supposed to be safe against word +splitting and pathname expansions without quoting, but bash <= 4.3 has a bug +[1], so they need to be quoted for as long as we support bash 4.3. + +- [koalaman/shellcheck#1009 (comment)](https://github.com/koalaman/shellcheck/issues/1009#issuecomment-488395630) + +There are also preferences on the type of quoting, which are though not too +strict. We prefer to use double quotes over single quotes by default. When +the value contains `$`, `` ` ``, `\`, and `"`, we can use single quotes to +avoid backslash escaping or use the one that minimizes the use of backslash +escaping. When the value contains control characters such as a tab and a +newline, we do not directly include them but we use backslash escape sequences +such as `\t` and `\n` in the escape string `$'...'`. + +### `patsub_replacement` for array elements + +There is a subtlety in quoting of the array expansions with a pattern +replacement when `shopt -s patsub_replacement` (Bash >= 5.2) is +enabled (which is the default of Bash >= 5.2). + +For example, the array expansions with a pattern replacement may be +used to add a prefix to every element in an array: + +```bash +# problem in bash >= 5.2 +arr=("${arr[@]/#/$prefix}") +``` + +However, this has the problem. The characters `&` contained in +`$prefix`, if any, will be replaced with the matched string. The +unexpected `patsub_replacement` may be suppressed by quoting the +replacement as + +```bash +# problem with bash <= 4.2 or "shopt -s compat42" +arr=("${arr[@]/#/"$prefix"}") +``` + +However, this has another problem in bash < 4.3 or when `shopt -s +compat42` is turned on. The inner double quotations are treated +literally so that the `PREFIX` instead of ``"PREFIX"` is prefixed to +elements. To avoid this situation, the outer double quotations might +be removed, but this has even another problem of the pathname +expansions and `IFS`. + +Specifically for prefixing and suffixing, we may instead use +`_comp_compgen -- -P prefix` and `_comp_compgen -- -S suffix`. + +```bash +# solution for prefixing +_comp_compgen -Rv arr -- -P "$prefix" -W '"${arr[@]}"' +``` + +In a general case, one needs to modify each array element in a loop, +where only the replacement is quoted. + +```bash +# general solution +for i in "${!arr[@]}"; do + arr[i]=${arr[i]//pat/"$rep"} +done +``` diff --git a/doc/styleguide.txt b/doc/styleguide.txt deleted file mode 100644 index 2251e77..0000000 --- a/doc/styleguide.txt +++ /dev/null @@ -1,134 +0,0 @@ -Coding Style Guide -================== - -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. - -Indentation ------------ -Indent step should be 4 spaces, no tabs. - -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. - -[[ ]] vs [ ] ----------------- - -Always use [[ ]] instead of [ ]. Rationale: the former is less error -prone, more featureful, and slightly faster. - -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. - -$(...) 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. - --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. - -[[ ${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. - -$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. - -Use arithmetic evaluation -------------------------- - -When dealing with numeric data, take advantage of arithmetic evaluation. -In essence, use (( ... )) whenever it can replace [[ ... ]] because the -syntax is more readable; no need for $-prefixes, numeric comparison etc -operators are more familiar and easier on the eye. - -Array subscript access ----------------------- - -Array subscripts are arithmetic expressions, take advantage of that. -E.g. write ${foo[bar]}, not ${foo[$bar]}, and similarly ${foo[bar+1]} -vs ${foo[((bar+1))]} or ${foo[$((bar+1))]}, ${foo[--i]} vs ${foo[((--i))]}. - -Loop variable names -------------------- - -Use i, j, k for loop-local indices; n and m for lengths; some other descriptive -name typically based on array name but in singular when looping over actual -values. If an index or value is to be accessed later on instead of being just -locally for looping, use a more descriptive and specific name for it. - -///////////////////////////////////////// -case/esac vs if ---------------- - -quoting -------- - -awk vs cut for simple cases ---------------------------- - -variable and function naming ----------------------------- - -///////////////////////////////////////// diff --git a/doc/testing.md b/doc/testing.md new file mode 100644 index 0000000..99db290 --- /dev/null +++ b/doc/testing.md @@ -0,0 +1,80 @@ +# Automated testing + +## 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 test suite is written in Python, using [pytest](https://pytest.org/) +and [pexpect](https://pexpect.readthedocs.io/). + +## Coding style + +For the Python part, all of it is checked and formatted using +[Ruff](https://docs.astral.sh/ruff/). + +## Installing dependencies + +Installing dependencies should be easy using your local package manager or +`pip`. Python 3.6 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: + +```shell +python3 -m pip install -r test/requirements.txt +``` + +### Debian/Ubuntu + +On Debian/Ubuntu you can use `apt-get`: + +```shell +sudo apt-get install python3-pytest python3-pexpect +``` + +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. + +### Fedora/RHEL/CentOS + +On Fedora and RHEL/CentOS (with EPEL) you can try `yum` or `dnf`: + +```shell +sudo yum install python3-pytest python3-pexpect +``` + +This should also install the necessary dependencies. At time of writing, only +Fedora 29 comes with recent enough pytest. + +## Structure + +Tests are in the `t/` subdirectory, with `t/test_*.py` being completion +tests, and `t/unit/test_unit_*.py` unit tests. + +## Running the tests + +Tests are run by calling `pytest` on the desired test directories or +individual files, for example in the project root directory: + +```shell +pytest test/t +``` + +See `test/docker/entrypoint.sh` for how and what we run and test in CI. + +### 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. + +## Maintenance + +### 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. diff --git a/doc/testing.txt b/doc/testing.txt deleted file mode 100644 index 3ec7c97..0000000 --- a/doc/testing.txt +++ /dev/null @@ -1,112 +0,0 @@ -Automated testing -================= - -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 test suite is written in Python, using https://pytest.org/[pytest] -and https://pexpect.readthedocs.io/[pexpect]. - - -Coding Style Guide ------------------- - -For the Python part, all of it is formatted using -https://github.com/ambv/black[Black], and we also run -https://flake8.pycqa.org/[Flake8] on it. - - -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 ------------------------------------- - - -Debian/Ubuntu -~~~~~~~~~~~~~ - -On Debian/Ubuntu you can use `apt-get`: -------------- -sudo apt-get install python3-pytest python3-pexpect -------------- -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. - -Fedora/RHEL/CentOS -~~~~~~~~~~~~~~~~~~ - -On Fedora and RHEL/CentOS (with EPEL) you can try `yum` or `dnf`: -------------- -sudo yum install python3-pytest python3-pexpect -------------- -This should also install the necessary dependencies. At time of writing, only -Fedora 29 comes with recent enough pytest. - - - -Structure ---------- - -Tests are in the `t/` subdirectory, with `t/test_\*.py` being completion -tests, and `t/unit/test_unit_\*.py` unit tests. - - -Running the tests ------------------ - -Tests are run by calling `pytest` on the desired test directories or -individual files, for example in the project root directory: ------------------------ -pytest test/t ------------------------ - -See `test/docker/docker-script.sh` for how and what we run and test in CI. - - -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. - - -Maintenance ------------ - - -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. - -Rationale ---------- - - -Naming conventions -~~~~~~~~~~~~~~~~~~ - -Test suite or testsuite -^^^^^^^^^^^^^^^^^^^^^^^ -The primary Wikipedia page is called -https://en.wikipedia.org/wiki/Test_suite[test suite] and not testsuite, so -that's what this document sticks to. - -script/generate -^^^^^^^^^^^^^^^ -The name and location of this code generation script come from Ruby on Rails' -https://en.wikibooks.org/wiki/Ruby_on_Rails/Tools/Generators[script/generate]. |