# Completion Authoring Guide CJ's Shell ships with a hybrid completion engine: built-ins are documented in-code, while external commands learn their options and subcommands automatically by reading their manual pages. This guide explains how that pipeline works and how to author or override completion data when you need to fill in gaps or add custom behaviour. At an empty or whitespace-only prompt, `Tab` shows unique history entries up to the `cjshopt set-completion-max` limit (default: 1000), ordered by most recent use and then frequency for matching timestamps. Empty-prompt completion shows no candidates when history is disabled or no eligible history entries exist. ## How automatic completions are generated - **On-demand scraping:** The first time you request completions for an external command that resolves in `PATH`, cjsh invokes `man -P cat ` (falling back to `man `) and scrapes the result. The parser looks for `OPTIONS`, `COMMANDS`, or `SUBCOMMANDS` sections, pulls out option switches and subcommand names, preserves option aliases and value metavariables, and condenses their descriptions to a single line. - **Caching:** Parsed data is written to `~/.cache/cjsh/generated_completions/.txt`. The next completion request loads this cache instead of invoking `man` again. Cache entries also store a short summary that feeds inline help and completion source hints. - **Nested commands:** When a completion entry includes subcommands, cjsh will look for additional caches named `-.txt` and merge their contents. This is how `git-remote` completions are chained into `git`. - **Bulk generation:** The `generate-completions` builtin pre-populates caches for an entire `PATH` or a list of commands. By default it forces regeneration (`--force`); pass `--no-force` to keep existing manual edits. Use `--subcommands` to also pre-generate discovered nested command caches, `-j/--jobs` to parallelise scraping, and `--quiet` to suppress per-command status output. ### Controlling automatic learning Scraping man pages on the fly is convenient, but it can consume CPU, spawn short-lived `man` processes, and keep memory allocations around until the session ends. When you prefer a predictable footprint, turn learning off and rely exclusively on whatever is already cached (or on `generate-completions`). - Run `cjshopt completion-learning off` during a session to stop future man-page lookups. The toggle persists across restarts if you add `cjshopt completion-learning off` to `~/.cjshrc`. - Launch cjsh with `--no-completion-learning` (or add `cjshopt login-startup-arg --no-completion-learning` to `~/.cjprofile`) to start with learning disabled from the first prompt. - The `generate-completions` builtin continues to work either way, so you can keep caches warm with a one-time run and leave learning off during normal interactive use. - When `CJSH_MAN_PATH` is set, cjsh always uses that `man` binary (even outside secure mode). - In secure mode (`--secure`), cjsh only uses `CJSH_MAN_PATH`. If it is unset or invalid, scraping is skipped and cjsh relies on cached data. If a man page cannot be read (missing `man`, atypical formatting, or sandbox restrictions), cjsh creates an empty cache entry. You can delete that file or replace it with a manual definition. ## Cache layout and file format Each cache file is a versioned, tab-separated completion specification: ``` generated by cjsh from man page for git format: 2 summary: the stupid content tracker path: /usr/bin/git E O --output Write output to a file -o required file FILE --stdout --format 0 0 project-files 0 0 either E S remote Manage remote repositories none none 0 0 0 0 space E P remote BRANCH Branch to operate on required branch BRANCH 0 0 git-branches 1 0 space ``` Key points: - The header line must stay exactly `generated by cjsh from man page for ` or cjsh will ignore the file. - `format: 2` selects the rich format. Version 1 `O` and `S` records remain readable for backward compatibility; newly generated files use version 2. - `summary:` and `path:` supply display metadata. Either value may be empty. - Rich entries begin with `E`. Their tab-separated fields are, in order: record marker, kind (`O` option, `S` subcommand, or `P` positional), parent subcommand scope, canonical text, description, aliases, value requirement, value type, value name, enum choices, conflicts, dependencies, repeatable, deprecated, dynamic provider, positional index, variadic, and value separator. - Lists use commas. Literal percent signs, commas, tabs, and newlines inside fields are encoded as `%25`, `%2C`, `%09`, and `%0A` respectively. - A subcommand's nested entries name it in the scope field. Multiple scope components describe a deeper tree, for example `remote,add`. - Value requirements are `none`, `required`, or `optional`. Separators are `space`, `equals`, or `either`. - Value types are `none`, `text`, `file`, `directory`, `enum`, `command`, `branch`, `process`, or `custom`. Enum candidates come from the choices field. Other dynamic values use the named provider hook, or the provider convention matching their value type. - Conflicts hide an entry when any named conflicting entry was already used. Dependencies hide an entry until every named dependency is present. Non-repeatable entries disappear after use. - Deprecated entries remain available but are labeled as deprecated in the completion menu. - Values are case-insensitive in matching but should be written the way you want them to appear to users. - File names are normalised to lower-case with non-alphanumeric characters translated to `_`. Let `generate-completions` create the skeleton once if you are unsure about the exact spelling. Dynamic providers are registered in-process with `register_dynamic_completion_provider()` from `completion_spec.h`. The request includes the command path, arguments, cursor argument, current value, working directory, and declared value metadata. Providers return value/description pairs. Complete in-memory specifications can similarly be installed with `register_command_doc()`. These are the extension points intended for future Bash and Zsh compatibility workers. ## Authoring or overriding completions manually 1. **Create the cache directory (once):** `generate-completions` or the first automatic scrape will do this, but you can also `mkdir -p ~/.cache/cjsh/generated_completions` yourself. 2. **Seed a template (optional):** Run `generate-completions --no-force ` to create the cache without overwriting existing edits. Even if scraping fails, the command establishes the correct file name for you to edit. 3. **Edit the cache file:** Open `~/.cache/cjsh/generated_completions/.txt` and adjust the summary or add new lines using the format above. 4. **Add multi-level entries:** For subcommand-specific completions (e.g. `kubectl get`), use the scope field to keep the nested tree in one rich specification. Separate legacy files such as `kubectl-get.txt` remain supported and are stitched together automatically. 5. **Preserve your changes:** Future runs of `generate-completions` default to `--force`. Use `generate-completions --no-force ...` when you want to refresh other commands without clobbering manual content, or keep a copy of the file under version control and reapply as needed. You can delete a cache file to force cjsh to rescrape the man page on the next completion request. This is useful after upgrading a tool with new options. ## Tips and troubleshooting - **Commands without man pages:** Some utilities only provide `--help`. Create the cache file manually or point `generate-completions` at a packaged man page (for example, install the corresponding `*-doc` package). - **Unusual formatting:** If the parser misses options, check the rendered man page. Options that do not start with `-` or subcommands listed outside dedicated sections may need to be added manually. - **Custom summaries:** Inline help uses the summary line. Tailor it to the way you present the command in your prompts or completion preview. - **Refreshing everything:** Remove `~/.cache/cjsh/generated_completions` or run `generate-completions --force` to rebuild all caches. Beware this overwrites manual edits. - **Sandboxed environments:** If `man` is unavailable, completions fall back to whatever data already exists. Consider bundling cache files with your dotfiles so they can be copied into the cache directory during provisioning. - **Too many matches?** Reduce menu noise with `cjshopt set-completion-max ` (any value >= 1). With these tools you can match or exceed the curated completion sets provided by fish, bash, or zsh while keeping cjsh's minimal-runtime-dependency footprint.