navi/docs/cheatsheet/syntax/README.md
alexis-opolka 6d52bcd120 Fixes some typos and rendering issues
Signed-off-by: alexis-opolka <53085471+alexis-opolka@users.noreply.github.com>
2025-03-29 10:49:44 +01:00

8.6 KiB
Raw Permalink Blame History

The syntax of a Navi cheatsheet

Syntax overview

Cheats are described in cheatsheet files.
A cheatsheet is a file that has a .cheat or .cheat.md extension and looks like this:

% git, code

# Change branch
git checkout <branch>

$ branch: git branch | awk '{print $NF}'

A cheatsheet can have the following elements:

Element Syntax Description
Tags as cheat titles % Lines starting with this character are considered the start of a new cheat command and should contain tags.
Cheat Description # Lines starting with this character should be the description of the cheat you're writing.
Cheat Comments (or Metacomments) ; Lines starting with this character will be ignored by navi but they can be great as editor's comments.
Pre-defined variables $ Lines starting with this character should contain commands that generate a list of possible values.

See #variables for more details.
Extended cheats @ Lines starting with this character should contain tags associated to other defined cheats.

See #extending-cheats for more details.
Executable commands N/A All other non-empty lines are considered as executable commands.

Tip

If you are editing cheatsheets in Visual Studio Code, you could enable syntax highlighting by installing this extension: @yanivmo/navi-cheatsheet-language.

Variables

Variables are defined with brackets inside executable commands (e.g. <branch>).
Variable names should only include alphanumeric characters and _.

You can show suggestions by using the Pre-defined variable lines (i.e. lines starting with$).
Otherwise, the user will be able to type any value for it.

Advanced variable options

For Pre-Defined variable lines, you can use --- to customize the behavior of fzf or how the value is going to be used.

Below are examples of such customization:

  • We define what column to use, the number of header lines and a delimiter between values.

    # This will pick the 3rd column and use the first line as header
    docker rmi <image_id>
    
    $ image_id: docker images --- --column 3 --header-lines 1 --delimiter '\s\s+'
    
  • We modify the output values of a command

    # Even though "false/true" is displayed, this will print "0/1"
    echo <mapped>
    
    $ mapped: echo 'false true' | tr ' ' '\n' --- --map "grep -q t && echo 1 || echo 0"
    

The supported parameters are:

Parameter Description
--column <number> <number> is the column number to extract from the result.
--map <bash_code> [EXPERIMENTAL] <bash_code> is a map function to apply to the variable value.
--prevent-extra [EXPERIMENTAL] This parameter will limit the user to select one of the suggestions.
--fzf-overrides <arg> [EXPERIMENTAL] <arg> is an arbitrary argument to override fzf behaviour.
--expand [EXPERIMENTAL] This parameter will convert each line into a separate argument.

In addition, it's possible to forward the following parameters to fzf:

Parameter forwarded to fzf
--multi
--header-lines <number>
--delimiter <regex>
--query <text>
--filter <text>
--header <text>
--preview <bash_code>
--preview-window <text>

Variable dependency

Pre-Defined variables can refer other pre-defined variables in two different ways, an implicit and explicit way.

Implicit dependencies

An implicit dependency is when you refer another variable with the same syntax used in executable commands (i.e. <variable>).

Below is an example of using implicit dependencies to construct a path:

# Should print /my/pictures/wallpapers
echo "<wallpaper_folder>"

$ pictures_folder: echo "/my/pictures"
$ wallpaper_folder: echo "<pictures_folder>/wallpapers"

Explicit dependencies

An explicit dependency is when you prepend a dollar sign (i.e. $) to the variable name.

Below is an example of using explicit dependencies to give multiple choices:

# If you select "hello" for <x>, the possible values of <y> will be "hello foo" and "hello bar"
echo <x> <y>

# If you want to ignore the contents of <x> and only print <y>
: <x>; echo <y>

$ x: echo "hello hi" | tr ' ' '\n'
$ y: echo "$x foo;$x bar" | tr ';' '\n'

Variable as multiple arguments

Variables can have multiple arguments, below is an example of using multiple arguments to cat multiple files at the same time.

# This will result into: cat "file1.json" "file2.json"
cat <jsons>

$ jsons: find . -iname '*.json' -type f -print --- --multi --expand

Extending cheats

Navi allows you to extend a cheat context with Extended cheats lines (i.e. starting with @).
If you put the same tags from another cheat, you will be able to share the same context and will be able to use the same variables, for example.

% dirs, common

$ pictures_folder: echo "/my/pictures"

% wallpapers
@ dirs, common

# Should print /my/pictures/wallpapers
echo "<pictures_folder>/wallpapers"

% screenshots
@ dirs, common

# Should print /my/pictures/screenshots
echo "<pictures_folder>/screenshots"

Multiline commands/snippets

Commands can be multiline, we call them snippets.

  • You can write them as follows:

    % bash, foo
    
    # This will output "foo\nyes"
    echo foo
    true \
       && echo yes \
       || echo no
    
  • Or, you can place them inside Markdown code blocks, delimited by triple backticks (```):

    % git, code
    
    # Change branch
    ```sh
    git checkout <branch>
    ```
    
    $ branch: git branch | awk '{print $NF}'
    

Aliases

navi doesn't have support for aliases as first-class citizens at the moment.
However, it is easy to create aliases using navi + a few conventions.

Caution

The examples below will only work if you use navi as a shell scripting tool.

See /docs/usage/shell-scripting for more details.

For example, suppose you decide to end some of your commands with :: <some_alias>:

% aliases

# This is one command :: el
echo lorem ipsum

# This is another command :: ef
echo foo bar

You could add something similar to this in your .bashrc-like file:

navialias() {
    navi --query ":: $1" --best-match
}

alias el="navialias el"
alias ef="navialias ef"

If you don't want to use these conventions, you can even add full comments in your aliases:

navibestmatch() {
    navi --query "$1" --best-match
}

alias el="navibestmatch 'This is one command'"
alias ef="navibestmatch 'This is another command'"