summaryrefslogtreecommitdiffstats
path: root/doc
diff options
context:
space:
mode:
Diffstat (limited to 'doc')
-rw-r--r--doc/Makefile.am10
-rw-r--r--doc/api-and-naming.md232
-rw-r--r--doc/bash_completion.txt66
l---------doc/bashrc1
-rw-r--r--doc/configuration.md149
l---------doc/inputrc1
-rw-r--r--doc/main.txt18
-rwxr-xr-xdoc/makeHtml.sh4
-rw-r--r--doc/styleguide.md232
-rw-r--r--doc/styleguide.txt134
-rw-r--r--doc/testing.md80
-rw-r--r--doc/testing.txt112
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.
-
-&#91;[ ]] 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.
-
-&#91;[ ${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].