Configuration
cy is not really a terminal multiplexer. It's actually an API for making terminal multiplexers that happens to come with a decent default configuration. This is because cy was designed to be as configurable as possible:
- Features are first built to expand the functionality available in the API.
- They then are incorporated into the default configuration where appropriate.
As a result, cy is the best choice for users who enjoy tinkering with the tools they use.
cy uses Janet as its configuration language. Janet is a fun, embeddable Lisp-like language that is easy to learn. If you are new to Janet, I recommend starting out with its documentation and Ian Henry's fantastic Janet for Mortals.
Why Janet?
This might come as a surprise, but I am far from being a Lisp zealot and have never seriously used
emacs. I found Janet several years ago and enjoyed experimenting with it. The language avoids most of the scary levels of abstraction present in some Lisps and strikes a balance between functional programming orthodoxy and practical imperative programming needs.
Configuration files
On startup, cy will search for and execute the first file containing Janet source code that it finds in the following locations. cy adheres to the XDG base directory specification.
$XDG_CONFIG_HOME/cy/cyrc.janet$XDG_CONFIG_HOME/cyrc.janet$XDG_CONFIG_HOME/.cy.janet$HOME/cy/cyrc.janet$HOME/cyrc.janet$HOME/.cy.janet$HOME/.config/cy/cyrc.janet$HOME/.config/cyrc.janet$HOME/.config/.cy.janet
You can reload your configuration at any time using action/reload-config, which by default is bound to ctrl+a r [?].
Example configuration
An example configuration that uses functionality from this API is shown below. You may also refer to the default configuration for examples of more advanced API usage.
# Define a new action (which is just a function) with the name toast-pane-path
(key/action
# the name of the function by which it can be referenced in the current
# scope
toast-pane-path
# a (required) docstring for the action
"show the path of the current pane"
# all subsequent statements are executed when this action is invoked (usually
# by a key binding)
#
# (pane/current): gets the ID of the current pane
# (cmd/path): gets the path of the pane with the given ID
# (msg/toast): shows a toast popup in the top-right corner of the screen
(msg/toast :info (cmd/path (pane/current))))
# Bind a key sequence to this function
(key/bind :root ["ctrl+a" "g"] toast-pane-path)
Execution context
The Janet code executed in cy can be executed in two different contexts:
- The context of the server: This is the context in which your configuration file is run, because when the
cyserver starts up, there are no clients. - The context of a client: When a client invokes an action or types a keybinding sequence, the executed Janet code can see what client ran the action and respond appropriately.
Because of this, some API functionality can only be used in a keybinding or action. This is because some kinds of state, such as the state that (layout/*) family of functions uses to work, only makes sense in the context of a user.
To run code in the context of a client when it first connects, you can use hooks.
Hooks
Hooks allow you to run Janet code in response to events in cy. If you define a function with a specific name, cy will call it automatically when the corresponding event occurs.
hook/init
The hook/init function is called when a new client connects to the server. It runs in the context of that client, so you can use client-specific API functions like cy/id and layout/set.
This is useful for:
- Setting client-specific parameters
- Displaying a welcome message
- Customizing the layout for each client
(defn hook/init []
# Show a welcome message
(msg/toast :info (string "Welcome, client #" (cy/id) "!"))
# Disable animations for this client
(param/set :client :animate false))
If hook/init is not defined, no error occurs; hooks are optional.
Error handling
If an uncaught error is thrown while running Janet code, cy will send all connected users a toast with that error and log the error to the /logs pane, which you can attach to like any other pane.