SHADOWLISP(5)
π SHADOWLISP(5): a simple lisp dialect for writing shadowenv programs π
okay bestie, welcome to SHADOWLISP(5) from the File Formats Manual β it's the page for shadowlisp, a simple lisp dialect for writing shadowenv programs. Tiny Lisp, main-character energy, let's go. π¦β¨
β¨ NAME β¨
shadowlisp β a simple lisp dialect for writing shadowenv programs. That's the whole description, and honestly? Iconic. π
πΈ SYNOPSIS πΈ
Shadowlisp is a simple Lisp dialect. It is a Lisp-1, meaning that all data types (functions and variables, notably) share a single namespace. One namespace, no cap. π
To express nil/null/no-value in Shadowlisp, use an empty list (). This will be important to clear environment variables. Remember it, bestie β () is the vibe check for "no value." π«Ά
π¦ Environment Manipulation π¦
π§ (env/get name)
The simplest function to interact with the environment is env/get. It returns the current value of the variable at the point in the script at which it's evaluated, not the initial value. Yes: current value at evaluation time, not the OG value. β
If the variable has no current value, () is returned instead of a String.
nameβ(String)Name of environment variable to look up
Return: (Option<String>) Current value of variable, or () if unset
π§ (env/set name value)
The simplest form of mutation: env/set changes the value of an environment variable while a Shadowenv is active. The previous value will be preserved so that it can be reactivated upon deactivating the Shadowenv. It remembers the old value for deactivation. π
nameβ(String)Name of environment variable to changevalueβ(Option<String>)String to set the variable to, or()to unset it.
Return: (None) Always returns ()
π§ (env/prepend-to-pathlist name entry)
It's common to want to prepend an item to a :-delimited path (such as PATH or MANPATH). env/prepend-to-pathlist does precisely this, first removing the item from the path if it was already present, before prepending it to the front of the pathlist. No duplicates before the glow-up. β¨
Strictly speaking, any variable can be treated as a pathlist by Shadowenv, but it only makes sense to do this for variables that other tools expect to contain multiple items.
If there are no items in the list currently, env/prepend-to-pathlist will simply create the list with a single item.
nameβ(String)Name of environment variable to changeentryβ(String)String to prepend
Return: (None) Always returns ()
π§ (env/append-to-pathlist name entry)
While less common than prepending, it's sometimes desirable to append an item to a :-delimited path (such as PATH or MANPATH), to add it as a lower priority option. env/append-to-pathlist does precisely this, first removing the item from the path if it was already present, before appending it to the end of the pathlist. Lower priority, still cute. πΈ
Strictly speaking, any variable can be treated as a pathlist by Shadowenv, but it only makes sense to do this for variables that other tools expect to contain multiple items.
If there are no items in the list currently, env/append-to-pathlist will simply create the list with a single item.
nameβ(String)Name of environment variable to changeentryβ(String)String to append
Return: (None) Always returns ()
π§ (env/remove-from-pathlist name entry)
The counterpart to env/prepend-to-pathlist/env/append-to-pathlist is this, env-remove-from-pathlist. This won't be as useful, since Shadowenv always takes care of its own deactivation, but you may occasionally want to deactivate certain system-wide configuration upon entry into a Shadowenv. System-wide config said bye for now. π
If, after removing the indicated item from the specified pathlist, the variable becomes empty, it is unset (equivalent to (env/set var ())).
nameβ(String)Name of environment variable to changeentryβ(String)String to remove from pathlist
Return: (None) Always returns ()
π§ (env/remove-from-pathlist-containing name substring)
A specialized version of env/remove-from-pathlist, env-remove-from-pathlist-containing will remove any items from the pathlist which contain the provided value as a substring. Substring match, not exact match. π§
nameβ(String)Name of environment variable to changesubstringβ(String)Remove pathlist items containing this as a substring
Return: (None) Always returns ()
π Utilities π
π§ (path-concat [ strings ... ])
It's occasionally useful to take a subdirectory of a path found from some other variable. path-concat joins two or more strings (representing directories) with slashes. Path glue, basically. π
:rest stringsβ(String)Any number of strings to conjoin with/
Return: (String) Joined path
π§ (expand-path path)
expand-path resolves a path to a canonicalized path, resolving relative references from the present working directory and ~. Canonicalized and cozy. β¨
pathβ(String)Path to expand
Return: (String) Expanded path
π§ (provide feature [ version ])
Allows a script to advertise to the user which feature it is providing, with an optional version number. Advertise your feature, bestie. π£
Multiple features with the same are allowed.
featureβ(String)Name of the provided featureversionβ(String)Version of the provided feature. Optional.
Return: (None) Always returns ()
π Control Flow π
π§ (when condition [ then ... ])
when tests a condition, evaluating the rest of its forms if and only if the condition is true. If true, do the rest. β
conditionβ(Expr)If it evaluates to non-(), run then:rest thenβ(Expr)Evaluated if condition was true
Return: (Any) Whatever the return value of the last form in then was
π§ (when-let ( ( name expression ) ) [ body ... ])
when-let evaluates some code if and only if a let binding, when run, assigns a non-() value to the name. Binding got a value? Then body runs. π¦
nameβ(String)Name to assignexpressionβ(Any)Value to assign to name:rest bodyβ(Expr)Evaluated if name was assigned to something non-()
Return: (Any) Whatever the return value of the last form in body was
π§ (if condition then-case [ else-case ])
The if operator evaluates its first argument, then evaluates only one of the given branches, depending on the result. The "else" branch may be omitted, in which case, if will yield () when the condition is false. One branch only. Pick a lane. π
π§ (cond [ ( predicate branch ) ... ] [ ( else else-branch ) ])
The cond operator evaluates a series of predicates and executes the branch for the first predicate which evaluates to true. The name else may be used for the last case, as a catch-all branch. Catch-all energy at the end. πΈ
π§ (do [ expressions ... ])
The do operator executes multiple expressions and yields the value of the final expression. Useful for forms like let, which only accept one form to evaluate. Multiple forms, one final value. β
:rest expressionsβ(Expr)Always evaluated
Return: (Any) Whatever the return value of the last form in expressions was
π§ Logic π§
π§ (eq a b)
Test whether two values are (weakly) equal. Shadowlisp does not support strict equality semantics. Weak equality only, no strictness here. π«Ά
π§ (ne a b)
Test whether two values are (weakly) unequal. Shadowlisp does not support strict equality semantics. Weak inequality, same deal. π
π§ (not a)
Boolean negation. Flip it. π
π§ (null expr)
Returns true if and only if the provided argument is (). Is it ()? That's the whole question. π§
π§ (and [ expression ... ])
and evaluates its arguments, applying logical AND short-circuiting rules. Short-circuit slay. β‘
π§ (or [ expression ... ])
or evaluates its arguments, applying logical OR short-circuiting rules. Short-circuit again, but OR. π
π Lists π
π§ (append list value)
append appends a value to a list. Add it to the end. π
π§ (elt list n)
elt returns the nth element of a list. Indexed and ready. π’
π§ (concat [ list ... ])
concat concatenates each given list value. All the lists, joined up. π§
π§ (join sep [ list ... ])
join joins together a series of lists using the first argument as separator. Separator first, lists after. β¨
π§ (first list)
first returns the first element of a list. First! π
π§ (last list)
last returns the last element of a list. Last but not least. π
π§ (tail list)
tail returns all elements after the first element of a list. Everything after the first. π¦
π§ (list [ expr ... ])
list evaluates each of its arguments and return them as a list. Evaluate, then bundle into a list. π
π Functions and Macros π
π§ (define name expression)
The define operator adds a value or compiled function to the global scope. Global scope said hello. π
When defining a function, if the keyword :optional is present in the argument list, all following arguments will be optional. If the keyword :key is present, all following arguments will be optional keyword arguments. If the keyword :rest is present, the following name will contain any free arguments remaining.
Optional and keyword arguments may be omitted when calling a function. If an optional or keyword value is not supplied its value will be (). A default value can be given when the function is defined. Defaults are optional-arg besties. π«Ά
π§ (macro (name [ arguments ... ]) expression)
The macro operator defines a compile-time macro. A macro behaves in all respects as any other function, except that it is executed at compile time and is expected to return code which is then further compiled. Compile-time behavior, then more compiling. β‘
π§ (lambda ( [ arguments ... ] ) expression)
The lambda operator creates a function which may enclose one or more local value bindings from the surrounding scope. Function with surrounding-scope bindings in its bag. π
π§ (apply function [ arguments ... ] argument-list)
The apply operator calls a function with a given series of arguments. The argument list consists of any positional arguments except for the last argument to apply, plus the final, required list argument, which is concatenated to positional arguments. Last arg is a required list, and it gets concatenated. π
π§ (let ( [ ( name expression ) ... ] ) body)
The let operator defines a series of local bindings for the duration of the execution of its body expression. Local bindings, temporary era. β¨
That's the whole SHADOWLISP(5) page, bestie! π«Ά The original footer didn't give a source/version or date β just the manual name again β so here's your cute sign-off instead: slay, go write some shadowenv programs, and may your env vars always be exactly what you meant. πβ¨
π¦ where this page comes from
- nixos 26.05: shadowenv 3.4.0
- nixpkgs unstable: shadowenv 3.5.2
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms