Custom Commands
Core vs Non-core
There are 2 types of zet commands: core and non-core. Core commands are built
into zet. They cannot be changed or replaced. Their list is available by
running zet --help
. Some examples of core commands are:
zet init
zet api
zet env
zet commands
Non-core commands are all the other commands, including the ones bundled with zet. They can be removed or replaced. Some examples are:
zet ls
zet mv
zet note
zet open
zet sync
Search Paths
When you run a non-core zet command, zet searches for it inside the
following directories: ${ZET_MODULES_PATH}:${PATH}
. If
$ZET_MODULES_PATH
environment variable is not defined, zet defines it by
itself:
- (Linux)
${XDG_DATA_HOME:-$HOME/.local/share}/zet/modules
- (macOS)
$HOME/Library/Application Support/zet/modules
- (Windows)
{FOLDERID_RoamingAppData}/zet/modules
- (Linux, macOS)
/usr/share/zet/modules
You can see the values of $PATH
and $ZET_MODULES_PATH
by running
zet env
.
If you redefine $ZET_MODULES_PATH
, zet might loose the possibility to
run bundled non-core commands. If it isn't what you intended, first
check the default $ZET_MODULES_PATH
calculated by zet and use it:
export ZET_MODULES_PATH=/my/dir1:/my/dir2:$HOME/.local/share/zet/modules:/usr/share/zet/modules
All executables found in these directories which start with zet-
prefix are considered zet non-core commands and will be listed on
zet commands
screen.
Writing own commands
To add your own non-core command, simply put an executable (for example a
shell script) in your $ZET_MODULES_PATH
or $PATH.
You should prefer
$ZET_MODULES_PATH
to not clobber the $PATH
and to avoid the risk of
accidentally running a command outside of zet's execution environment.
Environment
When Zet calls any non-core command, it parses zet.toml and exports all
variables in each [[notebooks]]
section into command's environment.
Variables are named after notebook's name and prefixed with ZET_NOTEBOOK_
.
For example, if there exists a notebook named "My Notebook", there will be at
least ZET_NOTEBOOK_MY_NOTEBOOK_NAME
and ZET_NOTEBOOK_MY_NOTEBOOK_PATH
exported.
List of notebook names will be exported as ZET_NOTEBOOKS
colon-separated
list.
You can inspect all Zet-specific environment variables by running zet env
.
For easier access to environment variables, you may use zet api getenvnb
and zet api getenvnbsel
commands.
API
To ease the task of writing your own commands, zet provides the api
core
command, which you should use for some common tasks. See zet api --help
and
zet api <api-command> --help
for in-depth description of what's availale.
For example, your command might need an access to the files using the
selector syntax, defaulting to all the files inside all the notebooks. You
can use zet api list
and zet api notebooks
to access all relevant
informations:
#!/bin/bash
# usage: zet command [selectors...]
if (( ! $# )); then
# readarray handles possible spaces inside the paths returned by api calls
readarray -t args <<< $(zet api notebooks --selector)
set -- "${args[@]}"
fi
readarray -t paths <<< $(zet api list --absolute "$@")
for p in "${paths[@]}"; do
echo "$p"
done
Libraries
Zet exposes libraries for some languages inside $ZET_LIB_DIR
directory. These libraries are language-specific and contain helper
functions which are useful for commands written in a particular
language. Libraries are stored in separate directories, e.g. Bash
library is in $ZET_LIB_DIR/bash
and Python library is in
$ZET_LIB_DIR/python
.
Descriptions
zet commands
lists all found non-core commands. Each command may
additionally have a short, one-line description which will be shown to user
by zet commands
. These descriptions are gathered from command-list.txt
files found in $ZET_MODULES_PATH
directories. Typically, each
command-list.txt should have descriptions of all zet commands in the same
directory.
Only directories in
$ZET_MODULES_PATH
(and not in$PATH
) are used to gather command-list.txt files. It means that if you use$PATH
to maintain your collection of submodules, you won't be able to set their descriptions.
Format of each line in these files is:
command: description
Example
Suppose that we set ZET_MODULES_PATH=$HOME/zetmodules
. Inside this
directory there are 2 commands: zet-foo
and zet-bar
. To add descriptions
for them, we should create $HOME/zetmodules/command-list.txt
file with the
following contents:
foo: foo your notes by fooing them all at once
bar: make barring sound from your notes
Command Templates
Bash
#!/bin/bash
#/ usage: zet mycommand [options] <selector>
#/
#/ Foo a bar
#/
#/ Arguments:
#/ selector
#/ foos a bar without blahing
#/
#/
#/ Options:
#/ --help
#/ show this help message
set -o errexit
set -o nounset
set -o pipefail
. "${ZET_LIB_DIR}/bash/zetlib.bash"
opt_short="h"
opt_long=("help")
parse_opts "$@"
set -- "${OPTRET[@]}"; unset OPTRET
while (( $# )); do
case $1 in
-h|--help) usage ; exit 0 ;;
--) posargs=() ;;
*) posargs+=("$1") ;;
esac
shift
done
zet api paths "${posargs[@]}"
Python
#!/usr/bin/env python3
import os
import sys
import argparse
sys.path.append(os.path.join(os.environ["ZET_LIB_DIR"], "python"))
from pyzet import api_paths
def prepare_args():
parser = argparse.ArgumentParser(description="Foo a bar")
parser.add_argument("selector", help="foos a bar without blahing")
return parser.parse_args()
def main():
args = prepare_args()
lines = api_paths(args.selector)
print(*lines)
try:
sys.exit(main())
except KeyboardInterrupt:
sys.exit(15)