Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/cgabriel5/nodecliac

Easy Bash completion for CLI programs.
https://github.com/cgabriel5/nodecliac

bash bash-completion cli

Last synced: 2 days ago
JSON representation

Easy Bash completion for CLI programs.

Awesome Lists containing this project

README

        

nodecliac



nodecliac logo

Easy Bash completion for CLI programs


## Install

```sh
$ bash <(curl -Ls git.io/nodecliac) && source ~/.bashrc
```

More installation methods


**curl Install** (_explicit defaults_):

```sh
$ bash <(curl -Ls git.io/nodecliac) --installer= --branch=master --rcfile=~/.bashrc && source ~/.bashrc
```

**wget Install** (_defaults_):

```sh
$ bash <(wget -qO- git.io/nodecliac) && source ~/.bashrc
```

**Manual Install**: One can also install manually.

1. First download the GitHub nodecliac [repository](https://github.com/cgabriel5/nodecliac/archive/master.zip).
2. Next unzip the folder via `$ unzip nodecliac-*.zip` or by right-clicking and using the OS provided extractor utility.
3. `cd` into the repository and install: `$ sudo chmod +x install.sh && ./install.sh --manual && source ~/.bashrc`
4. Delete the downloaded `zip` folder, its extracted folder, and start using.

**Checksum Install**: If desired, the install script file's integrity can be verified before running.

[install.sh](https://raw.githubusercontent.com/cgabriel5/nodecliac/master/install.sh) `sha256sum` checksum: `2b4f37dae3cbe5cc81a0ce52f55a5d300445e3e3a68d9d7e97040504e1aec9da`

Create an executable shell file called `install.sh`, add the following, and run it.

```sh
#!/bin/bash

# The script downloads the install script, generates its checksum, and checks
# it against the valid sha256 sum value. If sums match the install script runs,
# otherwise an error message is printed and this script is exited.

install() {
url="git.io/nodecliac"
is="$([[ "$(command -v curl)" ]] && sudo curl -Ls "$url" || sudo wget -qO- "$url")"
x=($([[ "$OSTYPE" == "darwin"* ]] && shasum -a 256 <<< "$is" || sha256sum <<< "$is"))
c="2b4f37dae3cbe5cc81a0ce52f55a5d300445e3e3a68d9d7e97040504e1aec9da"
err="\033[1;31mError\033[0m: Verification failed: checksums don't match."
[[ "$c" == "$x" ]] && bash <(echo "$is") \
--installer= \
--branch=master \
--rcfile=~/.bashrc \
&& source ~/.bashrc || echo -e "$err" && exit 1
} && install
```

Installation options


- `--installer`: The installer to use. (default: `yarn` > `npm` > `binary`)
- `yarn`: Uses [yarn](https://yarnpkg.com/en/) to install.
- `npm`: Uses [Node.js](https://nodejs.org/en/)'s [npm](https://www.npmjs.com/get-npm) to install.
- `binary`: Uses nodecliac's [Nim](https://nim-lang.org/) Linux/macOS CLI tools.
- `--branch`: An _existing_ nodecliac branch name to install. (default: `master`)
- `--rcfile`: `bashrc` file to install nodecliac to. (default: `~/.bashrc`)
- `--yes`: Automate install by saying yes to any prompt(s).
- `--packages`: Install [collection](https://github.com/cgabriel5/nodecliac/tree/master/resources/packages) of pre-made completion packages.
- `--manual`: Let's install script to take manual install route.
- `--update`: Let's install script to take update router over fresh install route.

Requirements


- [Perl](https://www.perl.org/get.html) `v5+`.
- [Node.js](https://nodejs.org/en/) `v8+` if installing via `npm` or `yarn`.
- [bash-completion](https://github.com/scop/bash-completion) `v1.3+`, preferably `v.2.1+`.
- [Bash](https://www.gnu.org/software/bash/) `v4.3+`.
- `macOS`: Stock Bash is outdated (`v3.2`). Update via [Homebrew](https://brew.sh/) to [`v4.3+`](https://akrabat.com/upgrading-to-bash-4-on-macos/).

Uninstall


```sh
$ nodecliac uninstall
```

If a custom rcfile path was used during install provide it again during uninstall.

```sh
$ nodecliac uninstall --rcfile=path/to/.bashrc
```

## What Is nodecliac?

[`bash-completion`](https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion.html) is awesome. It enhances the user experience by completing paths, file names, commands, flags, etc. Ironically enough, having to use [`Bash`](https://www.gnu.org/software/bash/) to add it to one's program puts some off from using it.

nodecliac's approach is different. Rather than _directly_ using Bash, nodecliac provides a layer of abstraction. It lets one easily _map_ a program's commands with their flags in an **a**uto-**c**ompletion **map** (`.acmap`) file. Merely write the program's `.acmap`, compile to `.acdef`, and let nodecliac handle the rest. That's it.

If Bash _is_ needed, `.acmap` files are flexible enough to run shell code to generate matches. Better yet, write the necessary completion logic in a familiar language like [`Perl`](https://www.perl.org/), [`Python`](https://www.python.org/), [`Ruby`](https://www.ruby-lang.org/en/), etc., and use Bash as [glue code](https://en.wikipedia.org/wiki/Scripting_language#Glue_languages) to tie it all together.

In all, this project aims to `1` minimize the effort needed to add bash-completion so more programs support it, `2` provide a uniform bash-completion experience, and `3` to ultimately build a collection of community made completion packages for all to enjoy.

_Why the name nodecliac?_ Originally it was made in mind for [Node.js](https://nodejs.org/en/) programs. However, as development continued it proved useful for non Node.js programs as well.

## How It Works

The idea is simple. nodecliac uses two file types: **a**uto-**c**ompletion **map** (`.acmap`) and **a**uto-**c**ompletion **def**inition (`.acdef`). Those familiar with CSS preprocessors will quickly understand. Similar to how `.sass` and `.less` files are compiled to `.css` — `.acmap` files must be compiled to `.acdef`.

Therefore, an `.acmap` is a user generated file that uses a simple syntax to _map_ a program's commands with their flags. While an `.acdef` is a nodecliac generated _definition_ file. It's this file nodecliac uses to provide completions.

Ok, `1` but where do these files go? `2` How does nodecliac use them? Good questions. `1` **Files** will end up in the command's [completion package](./docs/packages/creating.md); a _folder_ containing the necessary files needed to provide completions for a command. `2` **Completion packages** will end up in nodecliac's [registry](#registry) (nodecliac's _collection_ of completion packages).

With that, nodecliac can provide Bash completions for programs by using their respective completion package stored in the registry.

Expand section

nodecliac CLI diagram

With the program's [completion package created](https://github.com/cgabriel5/nodecliac/blob/docs/docs/packages/creating.md) and stored in the [registry](#registry) the following is possible:

1. **Tab key pressed**: Bash completion invokes nodecliac's completion function for the program.

2. **CLI input analysis**: Input is parsed for commands, flags, positional arguments, etc.

3. `.acdef` **lookup**: The program's `.acdef` is compared against the CLI input to return possible completions.

_Complete details/events are oversimplified and condensed to get the main points across._

## CLI

CLI commands/flags

###### Commands:

- Main:
- [`make`](#cli-command-make)
- [`format`](#cli-command-format)
- Helper:
- [`init`](#cli-command-init)
- [`bin`](#cli-command-bin)
- [`cache`](#cli-command-cache)
- [`setup`](#cli-command-setup)
- [`status`](#cli-command-status)
- [`uninstall`](#cli-command-uninstall)
- [`print`](#cli-command-print)
- [`registry`](#cli-command-registry)
- Package:
- [`add`](#cli-command-add)
- [`remove`](#cli-command-remove)
- [`link`](#cli-command-link)
- [`unlink`](#cli-command-unlink)
- [`enable`](#cli-command-enable)
- [`disable`](#cli-command-disable)
- [`refresh`](#cli-command-refresh)

---

make

> Compile `.acdef`.

- `--source=`: (**required**): Path to `.acmap` file.
- `--print`: Log output to console.

###### Usage

```sh
$ nodecliac make --source path/to/program.acmap # Compile .acmap file to .acdef.
```

Test/debugging flags (internal)

- `--trace`: Trace parsers (_for debugging_).
- `--test`: Log output without file headers (_for tests_).

---

format

> Format (prettify) `.acmap` file.

- `--source=`: (**required**): Path to `.acmap` file.
- `--strip-comments`: Remove comments when formatting.
- `--indent="(s|t):Number"`: Formatting indentation string:
- `s` for spaces or `t` for tabs followed by amount-per-indentation level.
- `t:1`: Use 1 tab per indentation level (_default_).
- `s:2`: Use 2 spaces per indentation level.
- `--print`: Log output to console.

###### Usage

```sh
# Prettify using 2 spaces per indentation level and print output.
$ nodecliac format --source path/to/program.acmap --print --indent "s:2"
```

Test/debugging flags (internal)

- `--trace`: Trace parsers (_for debugging_).
- `--test`: Log output without file headers (_for tests_).

---

init

> Starts nodecliac's completion package generator to easily scaffold a completion package.

- `--force`: Overwrites existing folder of the same name.

###### Usage

```sh
$ nodecliac init
```

---

bin

> Prints nodecliac's bin location.

- _No arguments_

###### Usage

```sh
$ nodecliac bin # Binary location.
```

---

cache

> Interact with nodecliac's [cache system](#caching).

- `--clear`: Clears cache.
- `--level=`:
- _Without_ argument it prints the current cache level.
- _With_ argument it sets cache level to provide level.
- Levels: `0`, `1`, `2`

###### Usage

```sh
$ nodecliac cache --clear # Clear cache.
$ nodecliac cache --level # Print cache level.
$ nodecliac cache --level 1 # Set cache level to 1.
```

---

setup

> Setup nodecliac.

- `--force`: (**required** _if nodecliac is already setup)_: Overwrites old nodecliac setup and installs anew.
- `--yes`: Automate install by saying yes to any prompt(s).
- `--rcfile`: By default `~/.bashrc` is used. If another rcfile should be used provide its path.
- **Note**: Setup appends `ncliac=~/.nodecliac/src/main/init.sh; [ -f "$ncliac" ] && . "$ncliac";` to rcfile.

###### Usage

```sh
$ nodecliac setup # Setup nodecliac.
$ nodecliac setup --force # Force nodecliac setup.
$ nodecliac setup --force --yes # Force nodecliac setup and assume yes to any prompt(s).
```

---

status

> Returns status of nodecliac (enabled or disabled).

- `--enable`: Enables nodecliac.
- `--disable`: Disables nodecliac.

###### Usage

```sh
$ nodecliac status # Get nodecliac's status.
$ nodecliac status --enable # Enable nodecliac.
$ nodecliac status --disable # Disable nodecliac.
```

---

uninstall

> Uninstalls nodecliac.

- `--rcfile`: Path of rcfile used in setup to remove changes from.

###### Usage

```sh
$ nodecliac uninstall # Remove nodecliac.
```

---

print

> Print acmap/def file contents for files in registry.

- `--command=`: Name of command (uses available packages in registry).
- **Note**: Command is rather pointless and is primarily used to showcase `command-string`s.

###### Usage

```sh
$ nodecliac print --command= # Print .acdef for given command.
```

---

registry

> Lists packages in [registry](#registry).

- _No arguments_

###### Usage

```sh
$ nodecliac registry # Print packages in registry.
```

---

add

> Adds package to registry.

- `--path`: Path to completion package.
- `--repo`: Repo to install completion package from.
- Github: Repo only (`master`): `/`
- Github: Repo branch (default: `master`): `/<#branch_name>`
- Github: Repo sub-directory: `//trunk/`
- Github: Repo branch + sub-directory: `/<#branch_name>/trunk/`
- Or GitHub, GitLab, or BitBucket URL to completion package: ``
- URL must start with `git@` or `htttp://` and end with `.git`.
- `--allow-size`: Disables local repo package `10MB` size check, letting for any size.
- Meant as a safeguard to prevent accidentally copying large folders.
- `--allow-structure`: Disables valid base completion package structure checks.
- `--allow-overwrite`: Disables overwrite warning of same name package in registry.
- `--force`: Skip all guards/checks (size, structure, overwrite).
- `--size`: Size of local repo is no longer checked when copying to registry.
- `--structure`: Basic completion package structure checks are disabled.
- `--overwrite`: Same name completion package overwriting is allowed.

###### Usage

```sh
$ nodecliac add # Copies cwd folder (completion package) to registry.
$ nodecliac add --path ~/Desktop/subl # Installs completion package at specified path.

$ nodecliac add --repo cgabriel5/nodecliac # Install completion package from a GitHub repo.
# Install completion package from a specific branch (defaults to master branch).
$ nodecliac add --repo cgabriel5/nodecliac#master
# Install completion package from a specific directory in a GitHub repo.
$ nodecliac add --repo cgabriel5/nodecliac/trunk/resources/packages/yarn
# Install completion package from a specific directory + branch (defaults to master branch).
$ nodecliac add --repo cgabriel5/nodecliac#dev/trunk/resources/packages/yarn

# Install completion package via GitHub, GitLab, BitBucket URL.
$ nodecliac add --repo
```

---

remove

> Removes package(s) from registry.

- Takes n-amount of package names as arguments.
- `--all`: Removes all packages in registry.

###### Usage

```sh
$ nodecliac remove # Removes cwd folder (completion package) from registry.
$ nodecliac remove --all # Removes all packages from registry.
```

---

link

> Creates soft [symbolic](https://linuxize.com/post/how-to-create-symbolic-links-in-linux-using-the-ln-command/) link of package in registry.

- `--path`: Path to completion package.

###### Usage

```sh
$ nodecliac link # Symlinks cwd folder (completion package) to registry.
$ nodecliac link --path ~/Desktop/subl # Symlinks completion package at specified path.
```

---

unlink

> Alias to [`remove`](#cli-command-remove) command.

- See [`remove`](#cli-command-remove) command.

###### Usage

```sh
$ nodecliac unlink # Removes cwd folder (completion package) from registry.
$ nodecliac unlink --all # Removes all packages from registry.
```

---

enable

> Enables completions for package(s).

- Takes n-amount of package names as arguments.
- `--all`: Enables all packages in registry.

###### Usage

```sh
$ nodecliac enable # Enables disabled package(s).
$ nodecliac enable --all # Enables all disabled packages.
```

---

disable

> Disables completions for package(s).

- Takes n-amount of package names as arguments.
- `--all`: Disables all packages in registry.

###### Usage

```sh
$ nodecliac disable # Disables enabled package(s).
$ nodecliac disable --all # Disables all enabled packages.
```

---

refresh

> Fetches and updates the list of nodecliac completion packages.

- _No arguments_

###### Usage

```sh
$ nodecliac refresh
```

---

CLI quick usage

#### Compile `.acmap` files to `.acdef`.

```sh
$ nodecliac make --source path/to/program.acmap
```

#### Prettify `.acmap` file

```sh
# Prettify using 2 spaces per indentation level and print output.
$ nodecliac format --source path/to/program.acmap --print --indent "s:2"
```

CLI anatomy breakdown


nodecliac assumes following CLI program [design](http://programmingpractices.blogspot.com/2008/04/anatomy-of-command-line.html) pathway:

- `program-name` → [`subcommands`](https://github.com/mosop/cli/wiki/Defining-Subcommands) → `short-flags`/`long-flags` → `positional-parameters`

```
$ program [subcommand ...] [-a | -b] [--a-opt | --b-opt ] [file ...]
^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^
| \ \ | /
CLI program's Program Program Program long Program's (flag-less)
command. subcommands. short flags. flags. positional parameters.
```

## Syntax

acmap (auto-completion map) is a simple domain-specific language which maps a program's commands to their flags in .acmap files.

###### Constructs:

- [Comments](#syntax-comments)
- [Settings](#syntax-settings)
- [Variables](#syntax-variables)
- [Command Chains](#syntax-cc)
- [Flags](#syntax-flags)

#### Comments

- Comments begin with a number-sign (#) and continue to the end of the line.
- Whitespace indentation can precede a comment.
- Trailing comments are allowed.
- Multi-line comments are _not_ supported.

```acmap
# This is a comment.
# Whitespace can precede comment.
program.command = --flag # A trailing comment.
```

#### Settings

- Settings begin with an at-sign (`@`) followed by the setting name.
- Setting values are assigned with `=` followed by the setting value.
- Any amount of whitespace before and after `=` is allowed.
- Whitespace indentation can precede a setting declaration.
- **Note**: Settings can be declared _anywhere_ within your `.acmap` file.
- However, it's best if declared at the start of file to quickly spot them.

```acmap
# Available settings.
@compopt = "default"
@filedir = ""
@disable = false
@placehold = true
```

###### Available Settings:

- `@compopt`: [`comp-option`](https://gerardnico.com/lang/bash/edition/complete#o_comp-option) ([`-o`](https://www.thegeekstuff.com/2013/12/bash-completion-complete/)) value to Bash's builtin [`complete`](https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion-Builtins.html#Programmable-Completion-Builtins) function.
- Values: `false` (no value), `true` (default: `false`)
- `@filedir`: [Pattern](https://unix.stackexchange.com/a/108646) to provide [bash-completion](https://github.com/scop/bash-completion/)'s `_filedir` function.
- Values: A string value (i.e. `"@(acmap)`, `"-d"`) (default: `""`)


- `@disable`: Disables bash-completion for command.
- Values: `false`, `true` (default: `false`)
- `@placehold`: Placehold long `.acdef` rows to provide faster file lookups.
- Values: `false`, `true` (default: `false`)
- **Note**: Used only when compiling `.acdef` files.

#### Variables

- Variables begin with a dollar-sign (`$`) followed by the variable name.
- Variable name _must_ start with an underscore (`_`) or a letter (`a-zA-Z`).
- Variable values are assigned with `=` followed by the variable value.
- A variable's value must be enclosed with quotes.
- Any amount of whitespace before and after `=` is allowed.
- Whitespace indentation can precede a variable declaration.
- **Note**: Variables can be declared _anywhere_ within your `.acmap`.

```acmap
$scriptpath = "~/path/to/script1.sh"
$scriptpath="~/path/to/script2.sh"
$scriptpath = "~/path/to/script3.sh"

# Note: `$scriptpath` gets declared 3 times.
# It's final value is: "~/path/to/script3.sh"
```

Variable Interpolation

#### Variable Interpolation

- Variables are intended to be used inside quoted strings.
- Interpolation has the following structure:
- Start with `${` and close with `}`.
- Any amount of space between opening/closing syntax is allowed.
- The string between the closing/starting syntax is the variable name.

```acmap
$mainscript = "~/.nodecliac/registry/yarn/init.sh"

yarn.remove = default $("${mainscript} remove")
yarn.run = default $("${mainscript} run")
```

Variable Builtins

#### Variable Builtins

`acmap`s provide the following builtin variables:

- `$OS`: The user's platform: `linux`, `macosx`
- `$HOME`: The user's home directory.
- `$COMMAND`: The command being completed.
- `$PATH`: The command's nodecliac registry path:
- For example: `~/.nodecliac/registry/`

#### Command Chains

- Commands/subcommands should be viewed as chains which read from left to right.
- They start with the CLI program's name, are followed by any commands/subcommands, and are dot (`.`) delimited.
- If a (sub)command happens to use a dot then simply escape the dot. Non escaped dots will be used as delimiters.
- Whitespace indentation can precede a command chain.

**Example**: Say the CLI program `program` has two commands `install` and `uninstall`. It's `.acmap` will be:

```acmap
program.install
program.uninstall
```

Command default documentation

#### Command Chain Default

A command chain's `default` `command-string` (a runable shell command string) can be used to dynamically generate auto-completion items. This `command-string` is run when no completion items (commands/flags) are returned. Think of it as a fallback.

- Start by using the keyword `default` followed by a whitespace character.
- Follow that with the `command-string`:
- A command string is denoted with starting `$(` and closing `)`.
- The string between the closing/starting syntax is the `command-string`.
- **Example**: `default $("./path/to/script.sh arg1 arg2")`

```acmap
program.command = [
default $("./path/to/script.sh arg1 arg2")
]
```

Command-string example


For example, say we are implementing an `.acmap` file for the dependency manager [yarn](https://yarnpkg.com/en/) and would like to return the names of installed packages when removing a package (i.e.`$ yarn remove...`). Essentially, we want to extract the `package.json`'s `dependency` and `devDependency` entries and supply them to nodecliac. Using a `command-string` one can run a script/shell command to do just that.

```acmap
yarn.remove = [
# The command will run on '$ yarn remove [TAB]'. The script 'script.sh' should contain the
# logic needed to parse package.json to return the installed (dev)dependency package names.
default $("~/.nodecliac/registry/yarn/script.sh")
]
```

Command-string escaping


#### Varying Levels Of Escaping.

- **Level 0**: Hypothetical `script.sh` with the following contents. _No extra escaping when running a script._

```sh
for f in ~/.nodecliac/registry/yarn/hooks/*.*; do
[[ "${f##*/}" =~ ^(pre-parse)\.[a-zA-Z]+$ ]] && echo "$f"
done
```

- **Code Breakdown**

- The code will loop over the `~/.nodecliac/registry/yarn/hooks` directory.
- File names matching the pattern (`^(pre-parse).[a-zA-Z]+$`) will print to console.

- **Level 1**: If `bash` is one's default shell, copy/paste and run this one-liner in a Terminal:

```bash
for f in ~/.nodecliac/registry/yarn/hooks/*.*; do [[ "${f##*/}" =~ ^(pre-parse)\.[a-zA-Z]+$ ]] && echo "$f"; done
```

- **Level 2**: Now say we want to run the same line of code via `bash -c`. Run the following in a Terminal:

```bash
bash -c "for f in ~/.nodecliac/registry/yarn/hooks/*.*; do [[ \"\${f##*/}\" =~ ^(pre-parse)\\.[a-zA-Z]+$ ]] && echo \"\$f\"; done;"
```

- **Level 3**: How about using `Perl` to run `bash -c` to execute the command?

```bash
perl -e 'print `bash -c "for f in ~/.nodecliac/registry/yarn/hooks/*.*; do [[ \\\"\\\${f##*/}\\\" =~ ^(pre-parse)\\.[a-zA-Z]+\$ ]] && echo \"\\\$f\"; done;"`';
```

As shown, the more programs involved the more escaping required due to the string being passed from program to program. Escaping can get cumbersome. If so, running the code from a file will be the easiest alternative.

**Example**: Command-string escaping.

Now let's make a `command-string` to print all `.acdef` file names (without extension) in the nodecliac registry:

```bash
$ s="";for f in ~/.nodecliac/registry/*/*.acdef; do s="$s$f\n"; done; echo -e "$s" | LC_ALL=C perl -ne "print \"\$1\n\" while /(?! \/)([^\/]*)\.acdef$/g"
```

Using the following `.acmap` contents the `command-string` would be the following:

- **Note**: Ensure the `|` and `\` characters are escaped.

```acmap
# The escaped command-string.
$cmdstr = 's="";for f in ~/.nodecliac/registry/*/*.acdef; do s="$s$f\\n"; done; echo -e "$s" \| LC_ALL=C perl -ne "print \"\$1\\n\" while /(?! \\/)([^\\/]*)\\.acdef$/g"'

nodecliac.print = --command=$('${cmdstr}')
```

Compiling to `.acdef`, an `.acdef` file with the following contents will be generated:

```acdef
# DON'T EDIT FILE —— GENERATED: Mon Mar 02 2020 14:15:13 (1583187313)

--
.print --command=|--command=$('s="";for f in ~/.nodecliac/registry/*/*.acdef; do s="$s$f\\n"; done; echo -e "$s" \| LC_ALL=C perl -ne "print \"\$1\\n\" while /(?! \\/)([^\\/]*)\\.acdef$/g"')
```


#### Ignoring Options

Letting the completion engine know an option should be ignored (not displayed) is simple. Merely prefix the option with an exclamation-mark (`!`). This is meant to be used when an option has already been used and therefore doesn't need to be shown again as a possible completion item.

**Note**: For more information about `command-string`s take a look at `acmap Syntax > Flags > Flag Variants > Flags (dynamic values)`. The section contains more details for `command-string`s like special character escaping caveats, dynamic/static arguments, and examples with their breakdowns. Keep in mind that the section uses the term `command-flag` due it being used for flags but `command-flag` and `command-string` are effectively the same thing — _just a runable shell command string_. The naming (`command-{string|flag}`) is based on its application (i.e. for command-chains or flags).

Command chain grouping

#### Command Chain Grouping

Command chains can be grouped. It is not necessary but doing may help condense acmaps.

- A command group is denoted with starting `{` and closing `}`.
- The commands are found in between the closing/starting syntax.
- Commands are comma delimited.

For example, take the following:

```acmap
program.deploy-keys.add
program.deploy-keys.list
program.deploy-keys.rm
```

Grouping can reduce it to:

```acmap
program.deploy-keys.{add,list,rm}
```

#### Flags

To define flags we need to extend the [command chain](#command-chains) syntax.

- Flags are wrapped with `= [` and a closing `]`.
- The `= [` must be on the same line of the command chain.
- The closing `]` must be on its own line and man have any amount of indentation.

Building on the [command chain](#command-chains) section example, say the `install` command has the flags: `destination/d` and `force/f`. Code can be updated to:

```acmap
program.install = [
--destination
-d
--force
-f
]
program.uninstall
```

However, it can be cleaned up a bit by using the flag `alias` syntax:

```acmap
program.install = [
--destination::d
--force::f
]
program.uninstall
```

Flag variants

###### Types:

- [Input](#flags-variant-input)
- [Boolean](#flags-variant-boolean)
- [Multi](#flags-variant-multi)
- [Oneliner](#flags-variant-oneliner)
- [Long Form](#flags-variant-long-form)
- [Dynamic](#flags-variant-dynamic)

###### Keywords:

- [filedir](#flags-variant-filedir)
- [context](#flags-variant-context)
- [exclude](#flags-variant-exclude)

#### Flags (input)

- If flag requires user input append `=` to the flag.

```acmap
program.command = [
--flag=
]
```

#### Flags (boolean)

- If flag is a switch (boolean) append a `?` to the flag to let the completion engine know the flag doesn't require value completion.

```acmap
program.command = [
--flag?
]
```

#### Flags (multi-flag)

- Sometimes a flag can be supplied multiple times.
- Let the completion engine know this by using the multi-flag indicator `*`.

```acmap
program.command = [
# Allow user to provide multiple file paths.
--file=*

# Hard-coded values.
--colors=*(red green yellow)
]
```

#### Flags (one liner)

- This method should be used when the flag value list can be kept to a single line.
- **Note**: Values must be delimited with spaces.
- **Note**: When a flag has many values a [long form list](#flags-variant-long-form) should be used for clarity's sake.

```acmap
program.command = [
# Supply 1, "2", false, 4 as hard-coded values.
--flag=(1 "2" false 4)

# If multiple values can be supplied to program use the multi-flag indicator '*'.
# This allows --flag to be used multiple times until all values have been used.
--flag=*(1 "2" false 4)
]
```

#### Flags (long form)

- Flag long form lists are wrapped with starting `=(` and a closing `)`.
- The `=(` must be on the same line as the flag.
- The closing `)` must be on its own line and man have any amount of indentation.
- A flag value option starts with - (a hyphen + a space) followed by the value.
- Any amount of whitespace indentation can precede the flag value option - sequence.

```acmap
program.command = [
--flag=(
- 1
- "2"
- false
- 4
)

# Allow flag to be used multiple times.
--flag=*(
- 1
- "2"
- false
- 4
)
]
program.uninstall
```

#### Flags (dynamic values)

Sometimes static values are not enough so a `command-flag` can be used. A `command-flag` is just a runnable shell command.

`command-flag` syntax:

- Begins with starting `$(`, followed by command, and ends with closing `)`.
- Output: a newline (`\n`) delimited list is expected.
- Each completion item should be on its own line.
- Example: `$("cat ~/colors.text")`
- **Note**: Command must be quoted (double or single).

_static_ or _dynamic_ arguments may be provided.

- Example: `$("cat ~/colors.text", "!red", $"cat ~/names.text")`:
- This provides the _static_ `!red` and _dynamic_ `cat ~/names.text` arguments.
- `!red` will be argument `0` and the output of `cat ~/names.text` will be argument `1`.
- **Note**: _dynamic_ arguments must be dollar-sign prefixed (`$`).

**Escaping**: `$` and `|` are used internally so require escaping when used.

- `--flag=$("echo \$0-\$1", $"echo 'john'", "doe")`:
- The `$`s in the command are escaped.
- `--flag=$("nodecliac registry \| grep -oP \"(?<=─ )([-a-z]*)\"")`:
- The `|` gets escaped here.
- **Note**: Inner quotes are also escaped like one would on the command-line.

**Example**: Showcases _dynamic_ and _static_ values.

```acmap
program.command = [
# '*' denotes the flag is a multi-flag.
--flag=*
--flag=(
- index.js
- ':task:js'
- "some-thing"
# Dynamic values get combined with hard-coded values.
- $("cat ~/values.text")
)

# Same as above.
--flag=*(
- index.js
- ':task:js'
- "some-thing"
- $("cat ~/values.text")
)
]
program.uninstall
```

#### Keyword (filedir)

When no completion items are found bash-completion's `_filedir` function is used as a fallback. `_filedir` performs file/directory completion. By default it returns both file and directory names. However, this can be controlled to only return directory names or files of certain types.

- Start by using the keyword `filedir` followed by a whitespace character.
- Follow that with a string:
- To only return directories use `"-d"`.
- To filter file type extensions provide a [pattern](https://unix.stackexchange.com/a/108646) like `"@(acmap)"`.
- **Example**: `filedir "@(acmap)"`

```acmap
program.command = [
filedir "@(acmap)"
]
```

**Note**: This `filedir` usage is per command chain. If this is not needed, a global `filedir` value can be provided via the `@filedir` setting like so: `@filedir = "@(acmap)"`. Both can be used but precedence is as follows:

- If a command uses `filedir` use that.
- If not, look for `@filedir` setting.
- If neither are provided all files/directories are returned (_no filtering_).

#### Keyword (context)

The `context` keyword provides the ability to disable flags and deal with mutual flag exclusivity.

- Start by using the keyword `context` followed by a whitespace character.
- Follow that with a string:
- **Conditional Example**: `context "!help: #fge0"`
- **Mutual Exclusivity Example**: `context "{ json | yaml | csv }`

#### Context String (conditional):

Conditional context strings have their own grammar: `" : "`. If each `` results in `true` the `` are enabled/disabled.

##### Flag grammar

- A flag is represented without the hyphens.
- Example: For the flag `--help` it would just be `help`.
- If the flag needs to be disabled, prepend a `!`.
- Example: `help` (If conditions are `true` flag will be _enabled_)
- Example: `!help` (If conditions are `true` flag will be _disabled_)

##### Condition grammar

- Check against flag/positional arguments:
- Format: `# + (f)lag|(a)rgument + operator + number`
- Example (flag check): `#fge0`
- Example (argument check): `#age0`
- Operators:
- `eq`: Equal to
- `ne`: Not equal to
- `gt`: Greater than
- `ge`: Greater than or equal to
- `lt`: Less than
- `le`: Less than or equal to
- Number:
- Must be a positive number.
- Inversion: Tests can be _inverted_ by prepending a `!`.

###### Example 1

Disable `help` and `version` flags when used flag count is greater or equal to 0.

```acmap
program.command = [
--help?
--version?
context "!help, !version: #fge0"
]
```

###### Example 2

Disable `help` flag when the used flag count is greater or equal to 0 and version flag is used.

```acmap
program.command = [
--help?
--version?
context "!help: #fge0, version"
]
```

#### Context String (mutual exclusivity):

Mutual exclusivity is represented like so: `"{ flag1 | flagN }"`. Once a grouped flag is used the other(s) are disabled.

###### Example 1

For example, say the `--json`, `--csv`, and `--text` flags are allowed but the `--json` flag is used. The remaining flags `--text` and `--csv` won't be shown as completion items.

```acmap
program.command = [
--json=,
--csv=,
--text=(false true)
context "{ json | csv | text }"
]
```

###### Example 2

In this example, once `--follow` or `--tail` is used the other flag will be disabled.

```acmap
program.command = [
--follow=,
--tail=(false true)
context "{follow | tail}"
]
```

This is equivalent to the previous example.

```acmap
program.command = [
--follow=,
--tail=(false true)
context "!follow: tail"
context "!tail: follow"
]
```

#### Combine Context Strings

Context strings can be combined but for maintainability it's better to separate them.

###### Example 1: Separate Context Strings

```acmap
program.command = [
--help?
--version?
context "!help, !version: #fge0"

--json=,
--csv=,
--text=(false true)
context "{ json | csv | text }"

--follow=,
--tail=(false true)
context "{follow | tail}"

--hours=
--minutes=
--seconds=
--service=

--job-id=
--target=
context "{ job-id | target }"
]
```

###### Example 1: Combined Context Strings

Context strings can be combined by delimiting them with `;`.

```acmap
program.command = [
--help?
--version?

--json=,
--csv=,
--text=(false true)

--follow=,
--tail=(false true)

--hours=
--minutes=
--seconds=
--service=

--job-id=
--target=

context "!help, !version: #fge0; { json | csv | text }; { follow | tail }; { job-id | target }"
]
```

**Note**: Context strings are evaluated on every completion cycle. Therefore, using too many may slow down the 'perceived completion feel' as it takes time to evaluate all provided contexts.

#### Keyword (exclude)

The `exclude` keyword is only allowed in a _wildcard_ command block. It serves to easily give all command strings the same (universal/shared) flags. Although this can be done manually, this can help reduce the acmap and make it easier to maintain.

Let's look at an example. All command strings but `program.cache` share the `--help` flag.

```acmap
program = [
--help?
--version
]

program.make = [
--help?
--extensions=*(js html css)
]

program.format = [
--help?
--extensions=*(js html css)
--indentation
]

program.cache = [
--clear?
]
```

Now let's use a wildcard block and exclude the `program.cache` command string.

```acmap
* = [
exclude "program.cache"
--help?
]

program = [
--version
]

program.make = [
--extensions=*(js html css)
]

program.format = [
--extensions=*(js html css)
--indentation
]

program.cache = [
--clear?
]
```

If desired it can even be condensed to.

```acmap
* = --help?|exclude "program.cache"
program = --version
program.make,
program.format = --extensions=*(js html css)
program.format = --indentation
program.cache = --clear?
```


acdef (auto-completion definition) is a subset of acmap syntax, is auto-generated, and is used to perform Bash completion lookups.

###### Constructs:

- [Header](#syntax-header)
- [Command/Flags](#syntax-command-flags)
- [Command Fallbacks](#syntax-command-fallbacks)
- [Placeholders](#syntax-placeholders)

#### `.acdef` Anatomy

The following example `.acdef` will be used to explain how to read `.acdef` files.

```acdef
# DON'T EDIT FILE —— GENERATED: Mon Mar 02 2020 14:15:13 (1583187313)

--cache-folder|--check-files|--cwd|--disable-pnp
.access --
.add --audit|--dev|--exact|--ignore-workspace-root-check|--optional|--peer|--tilde
.autoclean --force|--init
.bin --
.cache --
.upgrade --caret|--exact|--latest|--pattern|--scope|--tilde
.why --
.workspace --
.workspaces --
.workspaces.info --
.workspaces.run --

.upgrade default $("~/.nodecliac/registry/command/scripts/init.sh upgrade")
.why default $("command list --depth=0 \| perl -wln -e \"/(?! ─ )([-\/_.@(?)a-zA-Z0-9]*)(?=\@)/ and print $&;\"")
.workspace default $("~/.nodecliac/registry/command/scripts/init.sh workspace")
.workspaces.run default $("~/.nodecliac/registry/command/scripts/init.sh run")
```

#### Header

- The first line is the file's header.
- It is the only comment in the document.
- It contains a warning to not modify the file and the file's creation information.

```acdef
# DON'T EDIT FILE —— GENERATED: Mon Mar 02 2020 14:15:13 (1583187313)

...
```

#### Commands/Flags

- The following section contains the command-chains and their respective flags.
- Each line represents a _row_ which starts with the command chain and is followed by a single space.
- Whatever comes after the single space are the command's flags.
- Flags are delimited by pipe (`|`) characters.
- Rows that do not have flags will contain two hyphens (`--`) after the single space character.

```acdef
...

--cache-folder|--check-files|--cwd|--disable-pnp
.access --
.add --audit|--dev|--exact|--ignore-workspace-root-check|--optional|--peer|--tilde
.autoclean --force|--init
.bin --
.cache --
.upgrade --caret|--exact|--latest|--pattern|--scope|--tilde
.why --
.workspace --
.workspaces --
.workspaces.info --
.workspaces.run --

...
```

**Note**: Command chain lines, lines starting with a single space or a dot (`.`) character, have the program's name removed.
For example, the line `.workspaces.run --` can be viewed as `command.workspaces.run --`.

#### Command Fallbacks

- The bottom section of an `.acdef` file will contain any command chain fallbacks.

```acdef
...

.upgrade default $("~/.nodecliac/registry/command/scripts/init.sh upgrade")
.why default $("command list --depth=0 \| perl -wln -e \"/(?! ─ )([-\/_.@(?)a-zA-Z0-9]*)(?=\@)/ and print $&;\"")
.workspace default $("~/.nodecliac/registry/command/scripts/init.sh workspace")
.workspaces.run default $("~/.nodecliac/registry/command/scripts/init.sh run")
```

#### Placeholders

- Depending how complex an `.acmap` is sometimes placeholders are needed. They are used internally to speed up reading, what would otherwise be large, `.acdef` files.
- Placeholder syntax:
- Begin with `--p#` and are followed by a fixed number of hexadecimal characters.
- **Example**: `--p#d2eef1`

The following example `.acdef` showcase placeholders.

```acdef
# DON'T EDIT FILE —— GENERATED: Thu Apr 09 2020 10:4:22 (1586451862)

--help|--version
.buildIndex --p#07d43e
.c --p#07d43e
.cc --p#07d43e
.check --p#07d43e
.compile --p#07d43e
.compileToC --p#07d43e
.compileToCpp --p#07d43e
.compileToOC --p#07d43e
.cpp --p#07d43e
.ctags --p#07d43e
.doc --p#07d43e
.doc2 --p#07d43e
.dump --p#07d43e
.e --p#07d43e
.genDepend --p#07d43e
.js --p#07d43e
.jsondoc --p#07d43e
.objc --p#07d43e
.rst2html --p#07d43e
.rst2tex --p#07d43e
```

## Registry

Simply put, the registry (`~/.nodecliac/registry`) is where completion packages are stored. Completion packages are stored in the form: `~/.nodecliac/registry/`.

## Packages

Package documentation is divided into their own sections.

|
[Create](/docs/packages/creating.md) |
[Add / Link](/docs/packages/adding.md) |
[Remove / Unlink](/docs/packages/removing.md) |
[Enable / Disable](/docs/packages/state.md) |
| ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |

Pre-made completion packages for several programs of varying complexity are [available](https://github.com/cgabriel5/nodecliac/tree/master/resources/packages) for reference.

## Hooks

Hooks are _just regular executable shell scripts_ that run at specific points along a completion cycle when a completion is attempted. They let one modify internal aspects of nodecliac's completion logic and behavior.

Expand hook section

#### Available Hooks

1. `hooks/pre-parse.sh`: Modifies select initialization variables before running [completion script](/src/scripts/ac).
1. `hooks/post-parse.sh`: Modifies final completions before terminating the completion cycle and printing suggestions.

#### `hooks/` Directory

In the command's completion package create a `hooks/` directory. All hook scripts will be stored here.

```sh
/
├── .acmap
├── .acdef
├── ..config.acdef
└── hooks/
```

#### Environment Variables

Hook scripts are provided parsing information via environment variables.

Bash provided variables but exposed by nodecliac


- `NODECLIAC_COMP_LINE`: Original (unmodified) CLI input.
- `NODECLIAC_COMP_POINT`: Caret index when Tab key was pressed.

nodecliac provided variables


- `NODECLIAC_MAIN_COMMAND`: The command auto completion is being performed for.
- `NODECLIAC_COMMAND_CHAIN`: The parsed command chain.
- `NODECLIAC_COMP_INDEX`: The index where completion is being attempted.
- `NODECLIAC_LAST`: The last parsed word item.
- **Note**: Last word item could be a _partial_ word item.
- This happens when the Tab key gets pressed _within_ a word item. For example, take the following input:`$ program command`. If theTab key was pressed like so: \$ program commTaband, the last word item is `comm`. Thus a _partial_ word with a remainder string of `and`. Resulting in finding completions for `comm`.
- `NODECLIAC_PREV`: The word item preceding the last word item.
- `NODECLIAC_INPUT`: CLI input from start to caret (Tab key press) index.
- `NODECLIAC_INPUT_ORIGINAL`: Original unmodified CLI input.
- `NODECLIAC_INPUT_REMAINDER`: CLI input from start to caret index.
- `NODECLIAC_LAST_CHAR`: Character before caret.
- `NODECLIAC_NEXT_CHAR`: Character after caret.
- **Note**: If char is _not_ `''` (empty) then the last word item (`NODECLIAC_LAST`) is a _partial_ word.
- `NODECLIAC_COMP_LINE_LENGTH`: Original CLI input's length.
- `NODECLIAC_INPUT_LINE_LENGTH`: CLI input length from string beginning to caret position.
- `NODECLIAC_ARG_COUNT`: Amount of arguments parsed in `NODECLIAC_INPUT` string.
- `NODECLIAC_ARG_N`: Parsed arguments can be individually accessed with this variable.
- First argument is `NODECLIAC_ARG_0` and will _always_ be the program's command.
- Because input is variable all other arguments can be retrieved with a loop.
- Use `NODECLIAC_ARG_COUNT` as max loop iteration.
- **Example**: Given the CLI input: `$ yarn remove chalk prettier`
- Arguments would be:
- `NODECLIAC_ARG_0`: `yarn`
- `NODECLIAC_ARG_1`: `remove`
- `NODECLIAC_ARG_2`: `chalk`
- `NODECLIAC_ARG_3`: `prettier`
- `NODECLIAC_USED_DEFAULT_POSITIONAL_ARGS`: Collected positional arguments.

#### Writing Pre Hook Script

Take yarn's [`pre-parse.sh`](/resources/packages/yarn/hooks/pre-parse.sh) script as an example:

```sh
#!/bin/bash

# Initialization variables:
#
# cline # CLI input.
# cpoint # Index of caret position when [TAB] key was pressed.
# command # Program for which completions are for.
# acdef # The command's .acdef file contents.

output="$("$HOME/.nodecliac/registry/$command/hooks/pre-parse.pl" "$cline")"

# Remaining lines are package.json's script entries.
mapfile -ts1 lines < <(echo -e "$output")
printf -v output '%s\n' "${lines[@]}" && acdef+=$'\n'"$output"
```

- The Bash script is [glue code](https://en.wikipedia.org/wiki/Scripting_language#Glue_languages). It runs the Perl script [`pre-parse.pl`](/resources/packages/yarn/hooks/pre-parse.pl) to retrieve the cwd `package.json` `scripts` and determine whether yarn is being used in a workspace.
- Using the Perl script's output the Bash script overwrites the `cline` variable and appends the `package.json` `scripts` to the `acdef` variable. Adding them as their [own commands](https://yarnpkg.com/en/docs/cli/run#toc-yarn-run).
- nodecliac uses the new values to determine completions.

#### Writing Post Hook Script

Take m-cli's [`post-parse.sh`](/resources/packages/m-cli/hooks/post-parse.sh) script as an example:

```sh
#!/bin/bash

function completion_logic() {
COMP_CWORD="$NODECLIAC_COMP_INDEX"
prev="$NODECLIAC_PREV"
cmd="$NODECLIAC_ARG_1"
sub="$NODECLIAC_ARG_2"
case "$cmd" in
dir)
case "$prev" in
delete) echo -e "empty\ndsfiles"; return ;;
dsfiles) echo -e "on\noff"; return ;;
esac
;;
disk)
case "$sub" in
# _m_disk
verify|repair) [[ $COMP_CWORD == 3 ]] && echo -e "disk\nvolume"; return ;;
format)
case $COMP_CWORD in
3) echo -e "ExFAT\nJHFS+\nMS-DOS\nvolume" ;;
4) [[ "$NODECLIAC_ARG_3" == "volume" ]] && echo -e "ExFAT\nJHFS+\nMS-DOS" ;;
esac
return
;;
rename) [[ $COMP_CWORD == 3 ]] && \
echo -e "$(grep -oE '(disk[0-9s]+)' <<< "$(diskutil list)")"; return ;;

# _m_dock
autohide) [[ $COMP_CWORD == 3 ]] && echo -e "YES\nNO"; return ;;
magnification) [[ $COMP_CWORD == 3 ]] && echo -e "YES\nNO"; return ;;
position) [[ $COMP_CWORD == 3 ]] && echo -e "BOTTOM\nLEFT\nRIGHT"; return ;;
esac
;;
dock)
case "$sub" in
autohide) [[ $COMP_CWORD == 3 ]] && echo -e "YES\nNO"; return ;;
magnification) [[ $COMP_CWORD == 3 ]] && echo -e "YES\nNO"; return ;;
position) [[ $COMP_CWORD == 3 ]] && echo -e "BOTTOM\nLEFT\nRIGHT"; return ;;
esac
;;
finder) [[ $COMP_CWORD == 3 ]] && echo -e "YES\nNO"; return ;;
screensaver) [[ $sub == "askforpassword" && $COMP_CWORD == 3 ]] && echo -e "YES\nNO"; return ;;
esac
}
completion_logic
```

- The post hook script is written in Bash but any language may be used. As shown, the script makes use of the provided `NODECLIAC_*` environment variables to determine what completion items to add. Each completion item must be returned on its own line.

## Caching

To return quicker results completions are cached.

Expand cache section

##### Cache Levels:

- `0`: No caching.
- `1`: Cache all but `command-string` (dynamic) completions. (`default`)
- `2`: Cache everything.

```sh
$ nodecliac cache --clear # Clear cache.
$ nodecliac cache --level 0 # Turn cache off.
```

## Testing

nodecliac provides a way to test completions for your program.

Expand testing section

#### Creating tests:

Creating tests is done directly from the program's acmap via `@test`. Start with `@test =` followed by the test string `" ; "`.

- Test entire completion output (including meta data):
- _Does the output contain_ `format`_?_: `@test = "program --; *format*`
- _Does the output omit_ `format`_?_: `@test = "program --; !*format*`
- Test individual completion items:
- _Do any completion items contain_ `format`_?_: `@test = "program --; *:*format*`
- _Does the first completion item contain_ `format`_?_: `@test = "program --; 1:*format*`
- _Does the first completion item start with_ `--for`_?_: `@test = "program --; 1:--for*`
- _Does the first completion item end with_ `format`_?_: `@test = "program --; 1:*format`
- _Does the first completion item equal_ `--format`_?_: `@test = "program --; 1:--format`
- Test completion items count:
- _Is there at least 1 completion item?_: `@test = "program --; #cgt0`
- _Are there 3 completion items?_: `@test = "program --; #ceq3`
- Format: `# + (c)ount + operator + number`
- Operators:
- `eq`: Equal to
- `ne`: Not equal to
- `gt`: Greater than
- `ge`: Greater than or equal to
- `lt`: Less than
- `le`: Less than or equal to
- Number:
- Must be a positive number.
- Inversion: Any test can be _inverted_ by preceding the test with a `!`.

###### Example 1

Take the following example acmap. It contains a couple commands and their respective flags.

```acmap
program.make = --source
program.format = --source

@test = "program make --; *source*"
@test = "program format --for; *format*"
```

###### Example 2

Multiple tests can be provided to test a single completion string. Simply delimit them with `;`.

```acmap
program.make = --source
program.format = --source

@test = "program make --; *source* ; #ceq1"
@test = "program format --for; *format* ; #ceq1"
```

#### Running tests:

Running tests is done by running a built in command: `$ nodecliac test `. As an example, try running nodecliac's tests. With nodecliac installed, enter `nodecliac test nodecliac` into a Terminal and press Enter. Note, for tests to run the program's completion package _must_ exist in the [registry](#registry) to be able to run tests. Running `$ nodecliac registry` will list installed completion packages.

## Debugging

Like with testing completion strings, nodecliac also provides a way to debug completions. This is useful when creating a completion package. To start debugging simply enable it. When enabled pressing the Tab key will output debugging information instead of providing bash completions.

Expand debugging section

#### Enabling debugging:

Run: `$ nodecliac debug --enable`

#### Disabling debugging:

Run: `$ nodecliac debug --disable`

#### Picking Debug Script

nodecliac's auto-completion script is written in `Nim` and `Perl`. The Nim version supports Linux/macOS while Perl is used as a fallback. When both versions are installed it's possible to use one over the other to debug. This is done with the `--script` flag like so:

- Explicitly use Nim script: `$ nodecliac debug --enable --script nim`
- Explicitly use Perl script: `$ nodecliac debug --enable --script perl`

#### Debug mode

To get the debug mode: `$ nodecliac debug`

- `0`: Disabled
- `1`: Enabled
- `2`: Enabled + use Perl script
- `3`: Enabled + use Nim script

## Support

OS Support

- Made using Node.js `v8.16.0` on a Linux machine running `Ubuntu 16.04.5 LTS`.
- Tested and working on:
- `macOS Mojave (v10.14.4)`.
- `Windows 10 - Untested`.

Shell Support

- nodecliac only works with Bash.
- Support for other shells (Zsh, Fish, etc.) may be added with increased usage.

Editor Support

- `.acmap`/`.acdef` [grammar packages](/resources/editors) available for [Sublime Text 3](https://www.sublimetext.com/3), [VSCode](https://code.visualstudio.com/), and [Atom](https://atom.io/) text editors.
- **Note**: `README.md` files are found next to each package explaining how to install it.
- Packages are stored under [`resources/editors`](/resources/editors).

## Contributing

Contributions are welcome! Found a bug, feel like documentation is lacking/confusing and needs an update, have performance/feature suggestions or simply found a typo? Let me know! :)

See how to contribute [here](/CONTRIBUTING.md).

## License

This project uses the [MIT License](/LICENSE.txt).