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 initzet apizet envzet 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 lszet mvzet notezet openzet 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$PATHto 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)