Tab Completion

fortsh provides intelligent tab completion for commands, files, and custom completions.

Source: src/scripting/completion.f90, src/io/readline.f90:2757-2868

Basic Completion

Press Tab to complete:

gi<Tab>         # → git (command)
/ho<Tab>        # → /home/ (path)
$HO<Tab>        # → $HOME (variable)

Multiple Matches

When multiple matches exist:

  • Single Tab: Complete common prefix
  • Double Tab: List all matches
git co<Tab>      # Lists: commit  config  ...
git com<Tab>     # → git commit

Completion Types

Commands

Complete executables in PATH and builtins:

sys<Tab>        # systemctl, sysctl, ...

Files and Directories

Complete paths:

cat /etc/pas<Tab>    # → cat /etc/passwd
cd ~/Doc<Tab>        # → cd ~/Documents/

Variables

Complete shell and environment variables:

echo $PA<Tab>   # → echo $PATH
echo ${HO<Tab>  # → echo ${HOME

Users and Groups

chown us<Tab>:  # → chown user:

Programmable Completion

Define custom completions for specific commands.

complete Builtin

Source: completion.f90:24-53

complete [options] command

Options

OptionDescription
-F funcUse function for completions
-W wordsComplete from word list
-A actionUse built-in action
-X patternFilter out matches
-P prefixAdd prefix to completions
-S suffixAdd suffix to completions
-o optionModify behavior

Word List Completion (-W)

complete -W "start stop restart status" systemctl
systemctl st<Tab>    # start stop status

Function Completion (-F)

_git_complete() {
    local cur="${COMP_WORDS[COMP_CWORD]}"
    case "${COMP_WORDS[1]}" in
        commit) COMPREPLY=($(compgen -W "-m -a --amend" -- "$cur")) ;;
        branch) COMPREPLY=($(compgen -W "-d -D -m -M" -- "$cur")) ;;
        *) COMPREPLY=($(compgen -W "add commit push pull branch" -- "$cur")) ;;
    esac
}
complete -F _git_complete git

Built-in Actions (-A)

ActionCompletes
aliasAlias names
builtinBuiltin commands
commandCommands (PATH + builtins)
directoryDirectories only
fileFiles and directories
functionShell functions
hostnameHostnames
variableShell variables
userUsernames
groupGroup names
keywordShell keywords
complete -A directory cd
complete -A file cat
complete -A variable export

Options (-o)

OptionEffect
defaultFall back to default completion
dirnamesComplete directories when no matches
filenamesQuote filenames with spaces
nospaceDon't add space after completion
nosortDon't sort completions
complete -o nospace -W "http:// https:// ftp://" curl

Filter Pattern (-X)

Remove matches:

# Complete files except .o and .a
complete -f -X '*.@(o|a)' gcc

Completion Variables

When a completion function runs, these variables are set:

VariableDescription
COMP_LINECurrent command line
COMP_POINTCursor position
COMP_WORDSArray of words on line
COMP_CWORDIndex of current word
COMPREPLYArray to fill with completions

Source: completion.f90:475-506

compgen Builtin

Generate completions without installing them:

compgen -W "one two three" -- o    # one
compgen -A command -- gi           # git, gist, ...
compgen -d /usr/                   # /usr/bin, /usr/lib, ...

Managing Completions

List Completions

complete -p            # Show all completions
complete -p git        # Show git completion

Remove Completion

complete -r git        # Remove git completion
complete -r            # Remove all completions

Implementation Details

Completion Spec Type

Source: completion.f90:24-53

type :: completion_spec_t
  character(len=256) :: command
  character(len=256) :: word_list(50)
  character(len=256) :: function_name
  character(len=256) :: filter_pattern
  character(len=256) :: prefix, suffix
  logical :: use_default
  logical :: use_dirnames, use_filenames
  logical :: nospace, nosort
  ! Built-in completers
  logical :: builtin_alias, builtin_command
  logical :: builtin_directory, builtin_file
  ! ... and more
end type

Generation Pipeline

Source: completion.f90:757-826

  1. Check for function-based completion
  2. Try word list completion
  3. Apply built-in completers
  4. Filter and sort results

Enhanced Tab Completion

Source: readline.f90:2757-2868

subroutine enhanced_tab_complete(state, shell)
  ! Detects command position
  ! Integrates with completion specs
  ! Falls back to default completion
end subroutine

Writing Completion Functions

Template

_mycommand_complete() {
    local cur prev words cword
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"

    case "$prev" in
        -f|--file)
            COMPREPLY=($(compgen -f -- "$cur"))
            return
            ;;
        -d|--dir)
            COMPREPLY=($(compgen -d -- "$cur"))
            return
            ;;
    esac

    if [[ "$cur" == -* ]]; then
        COMPREPLY=($(compgen -W "--help --version --file --dir" -- "$cur"))
    else
        COMPREPLY=($(compgen -W "action1 action2 action3" -- "$cur"))
    fi
}
complete -F _mycommand_complete mycommand

Dynamic Completions

_docker_images() {
    local cur="${COMP_WORDS[COMP_CWORD]}"
    local images=$(docker images --format '{{.Repository}}:{{.Tag}}' 2>/dev/null)
    COMPREPLY=($(compgen -W "$images" -- "$cur"))
}
complete -F _docker_images docker

Tips

Bash-Completion Compatibility

Many bash completion scripts work with fortsh. Install and source them:

# Source bash-completion
[[ -r /usr/share/bash-completion/bash_completion ]] && \
    source /usr/share/bash-completion/bash_completion

Debug Completions

set -x                    # Enable trace
mycommand <Tab>           # See what runs
set +x                    # Disable trace