Custom Commands
Core vs Non-core
There are 2 types of zet subcommands: 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. This includes some commands which are bundled with zet. These subcommands 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 one
as a set of local-specific data directory and system-specific data
directory:
- (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 subcommands. 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 subcommands and will be listed on
zet commands
screen.
Writing own subcommands
To add your own subcommand, simply drop 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 subcommands outside of zet's execution environment.
Environment
When Zet calls any subcommand, it parses zet.toml and exports all variables
in each [[notebooks]]
section into subcommand'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
.
API
To ease the task of writing your own subcommands, 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 subcommand 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 --as-selectors)
set -- "${args[@]}"
fi
readarray -t paths <<< $(zet api list "$@")
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 subcommands. Each subcommand 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:
subcommand: description
Example
Suppose that ZET_MODULES_PATH=$HOME/zetmodules
and that inside this
directory there are 2 subcommands: zet-foo
and zet-bar
. To add
descriptions for them, have to 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
Subcommand 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)