Skip to content

Latest commit

 

History

History
128 lines (107 loc) · 8.65 KB

CONTRIBUTING.md

File metadata and controls

128 lines (107 loc) · 8.65 KB

This document is intended to lower the bar for contributing to complgen.

How it works

complgen is architected somewhat like a compiler: it has several transformation stages and data flows only in one direction like in a pipeline.

The stages are as follows:

  1. Parse a .usage file into a Rust data structure
  2. Convert the data structure into a regular expression (in the textbook sense, not in the programmar sense)
  3. Convert the regular expression into a Deterministic Finite Automaton (DFA)
  4. Minimize the DFA
    • For details, see Engineering a Compiler, 3rd edition, section "2.4.4 DFA to Minimal DFA"
    • And also section 3.9.6, "Minimizing the Number of States of a DFA" from The Dragon Book.
  5. Emit a shell completion script

complgen is based on compleat, so it may also be useful sometimes to reference it.

Visualizations

To ease understanding and debugging, some of the stages can generate visualizations (see output of complgen --help for the relevant option name).

For the following grammar:

grep [<OPTION>]... <PATTERNS> [<FILE>]...;

<OPTION> ::= --extended-regexp                      "PATTERNS are extended regular expressions"
           | --fixed-strings                        "PATTERNS are strings"
           | --basic-regexp                         "PATTERNS are basic regular expressions"
           | --perl-regexp                          "PATTERNS are Perl regular expressions"
           | --regexp                               "use PATTERNS for matching" <PATTERNS>
           | --file                                 "take PATTERNS from FILE" <FILE>
           | --ignore-case                          "ignore case distinctions in patterns and data"
           | --no-ignore-case                       "do not ignore case distinctions (default)"
           | --word-regexp                          "match only whole words"
           | --line-regexp                          "match only whole lines"
           | --null-data                            "a data line ends in 0 byte, not newline"
           | --no-messages                          "suppress error messages"
           | --invert-match                         "select non-matching lines"
           | --version                              "display version information and exit"
           | --help                                 "display this help text and exit"
           | --max-count                            "stop after NUM selected lines" <NUM>
           | --byte-offset                          "print the byte offset with output lines"
           | --line-number                          "print line number with output lines"
           | --line-buffered                        "flush output on every line"
           | --with-filename                        "print file name with output lines"
           | --no-filename                          "suppress the file name prefix on output"
           | --label                                "use LABEL as the standard input file name prefix" <LABEL>
           | --only-matching                        "show only nonempty parts of lines that match"
           | --quiet                                "suppress all normal output"
           | --silent                               "suppress all normal output"
           | --binary-files                         "assume that binary files are TYPE; TYPE is 'binary', 'text', or 'without-match'" <TYPE>
           | --text                                 "equivalent to --binary-files=text"
           | --directories                          "how to handle directories;" <ACTION-DIRECTORIES>
           | --devices                              "how to handle devices, FIFOs and sockets;" <ACTION-DEVICES>
           | --recursive                            "like --directories=recurse"
           | --dereference-recursive                "likewise, but follow all symlinks"
           | --include                              "search only files that match GLOB (a file pattern)" <GLOB>
           | --exclude                              "skip files that match GLOB" <GLOB>
           | --exclude-from                         "skip files that match any file pattern from FILE" <FILE>
           | --exclude-dir                          "skip directories that match GLOB" <GLOB>
           | --files-without-match                  "print only names of FILEs with no selected lines"
           | --files-with-matches                   "print only names of FILEs with selected lines"
           | --count                                "print only a count of selected lines per FILE"
           | --initial-tab                          "make tabs line up (if needed)"
           | --null                                 "print 0 byte after FILE name"
           | --before-context                       "print NUM lines of leading context" <NUM>
           | --after-context                        "print NUM lines of trailing context" <NUM>
           | --context NUM                          "print NUM lines of output context" <NUM>
           | --group-separator                      "print SEP on line between matches with context" <SEP>
           | --no-group-separator                   "do not print separator for matches with context"
           | --color                                "use markers to highlight the matching strings" [<WHEN>]
           | --colour                               "WHEN is 'always', 'never', or 'auto'" [<WHEN>]
           | --binary                               "do not strip CR characters at EOL (MSDOS/Windows)"
           ;

<ACTION-DIRECTORIES> ::= read | recurse | skip;

<ACTION-DEVICES> ::= read | skip;

<TYPE> ::= binary | text | without-match;

<WHEN> ::= always | never | auto;

<FILE> ::= { ls };

its abstract syntax tree can be visualized as a railroad diagram:

Railroad diagram

The DFA can be visualized as a Graphviz diagram:

DFA

Related Projects

  • clap
    • complgen is able to produce completions by executing an arbitrary shell command (e.g. cargo -Z <TAB>, complete test name in cargo test <TAB>)
    • All the grammar specification mechanisms are available for completing option parameters. That means complgen is able to complete DSLs of the likes of strace -e <TAB> or lsof -i <TAB>.
    • No recompilation and reloading necessary in shell integration mode -- just modify the grammar file and completions automatically reflect that.
    • There's a possibility of the program options and completion grammar diverging since they're maintained separately. On the plus side, complgen isn't tied to the implementation language and independent users can write their custom completion grammars suited for their own needs.
  • zsh-capture-completion
    • This must have been painful to implement but is indispensable to complgen!
  • argcomplete
  • Oil's shellac protocol
  • _regex_arguments and _regex_words completions
  • sh-manpage-completions
  • Little Language