Documentation
¶
Overview ¶
Package workspace loads tmuxp-style YAML workspace files and builds them with the tmux package.
It is a consumer of the tmux module rather than part of it: the tmux module takes no runtime dependency, while parsing YAML needs one, so this lives in its own module. Compatibility with tmuxp is deliberate but partial. The fields below are the ones tmuxp's own examples use; anything else in a file is rejected rather than silently ignored, so a workspace that loads is a workspace that was understood.
tmuxp features that require a Python runtime are out of scope and stay rejected: plugins loads Python classes, and before_script runs an external script through tmuxp's own process handling.
Example ¶
Load a tmuxp-style document and build the session it describes.
package main
import (
"context"
"fmt"
"time"
"github.com/libtmux/libtmux-go/tmux"
"github.com/libtmux/libtmux-go/workspace"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
server := tmux.NewServer(tmux.ServerOptions{
SocketName: "libtmux-go-example-workspace",
})
defer killExampleServer(server)
document := []byte(`
session_name: review
windows:
- window_name: editor
panes:
- shell_command: printf 'ready\n'
- window_name: tests
panes:
- shell_command: printf 'ready\n'
- shell_command: printf 'ready\n'
`)
parsed, err := workspace.Parse(document)
if err != nil {
fmt.Println("parse:", err)
return
}
session, err := workspace.Build(ctx, server, parsed)
if err != nil {
fmt.Println("build:", err)
return
}
name, _ := session.Name()
windows, err := session.SearchWindows(ctx, nil)
if err != nil {
fmt.Println("search windows:", err)
return
}
fmt.Println(name, len(windows))
}
// killExampleServer stops an example's server on a context of its own, since an
// example's own context may already be spent by the time it returns.
func killExampleServer(server tmux.Server) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_ = server.Kill(ctx)
}
Output: review 2
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrInvalidWorkspace = errors.New("workspace: invalid workspace")
ErrInvalidWorkspace identifies a workspace file that could not be decoded or that Validate rejects. It is matched by errors.Is.
It does not cover a failure tmux reports while Build runs. tmux refusing a layout name or an option name is a command failure, so classify those with the tmux package's own errors rather than with this one.
Functions ¶
func Build ¶
Build creates the workspace on server and returns the created session.
Build is not atomic. tmux has no transaction, so a failure partway through leaves the windows and panes created so far in place; the returned session identifies them so a caller can inspect or kill what exists. Build uses strict errors regardless of server's setting, because a workspace that half exists is never the caller's intent.
Build runs over a control connection, which carries a tmux command without starting a process for it and takes most of the cost out of a workspace. The connection is a tmux client for the length of the call: it appears in list-clients, counts toward session_attached, and fires a client-attached hook. Hand Build a server carrying tmux.Server.SubprocessEngine to decline it, which is what a tmux configuration that reacts to attachment wants.
A pane's commands are its workspace, window, and pane shell_command_before entries in that order, then its own shell_command entries. sleep_before and sleep_after pause Build rather than the pane, matching tmuxp: the delay exists to let a previous command settle before the next is typed.
Types ¶
type Bool ¶
type Bool bool
Bool is a YAML boolean that also accepts tmuxp's quoted spellings, because tmuxp workspaces in the wild write focus: "true" as often as focus: true.
It is exported so that every field holding one can be written in Go as well as read from a file: an optional setting is a *Bool, and a pointer to an unexported type is not something a caller outside this package can make.
type Command ¶
type Command struct {
// Command is the text typed into the pane.
Command string `yaml:"cmd"`
// SleepBefore delays this command without delaying the ones before it.
// YAML writes it as a number of seconds, matching tmuxp, so 0.5 is half a
// second; it is not a duration string, which is why it is decoded rather
// than taken from this field.
SleepBefore time.Duration `yaml:"-"`
// SleepAfter delays the commands that follow this one, in the same units.
SleepAfter time.Duration `yaml:"-"`
// Enter reports whether to press Enter after the command. Nil presses it,
// matching tmuxp, where omitting enter runs the command.
Enter *Bool `yaml:"enter"`
}
Command is one command to run in a pane. YAML accepts either a bare string or a mapping, so "echo hi" and {cmd: echo hi, sleep_before: 2} are both commands.
type Pane ¶
type Pane struct {
// Commands run in the pane, in order.
Commands []Command `yaml:"-"`
// CommandsBefore run before Commands, after the window's.
CommandsBefore []Command `yaml:"-"`
// StartDirectory overrides the window directory for this pane.
StartDirectory string `yaml:"start_directory"`
// Shell replaces the command this pane runs. On a window's first pane it
// is the window's command, because tmux creates that pane with the window;
// setting it alongside window_shell is rejected rather than resolved.
Shell string `yaml:"shell"`
// Focus selects this pane once its window is built.
Focus Bool `yaml:"focus"`
// SuppressHistory overrides the window setting for this pane.
SuppressHistory *Bool `yaml:"suppress_history"`
// Environment is set on the session before this pane is created. It is the
// session's environment rather than the pane's, so a name used by more
// than one pane keeps the last value written, including for panes the user
// opens afterwards.
Environment map[string]string `yaml:"environment"`
// Enter applies to every command in this pane unless the command sets its
// own. Nil presses Enter, matching tmuxp.
Enter *Bool `yaml:"enter"`
// SleepBefore delays before each of this pane's commands. YAML writes it
// as a number of seconds, matching tmuxp, so 0.5 is half a second.
SleepBefore time.Duration `yaml:"-"`
// SleepAfter delays after each of this pane's commands, in the same units.
SleepAfter time.Duration `yaml:"-"`
}
Pane is one pane in a window. YAML accepts either a bare command string or a mapping, so "echo hello" and {shell_command: echo hello} are equivalent.
type Window ¶
type Window struct {
// Name is the window name. Empty lets tmux choose.
Name string `yaml:"window_name"`
// Index requests an explicit winlink index. Nil uses the next free index.
Index *int `yaml:"window_index"`
// Layout is a tmux layout name applied after the panes exist.
Layout string `yaml:"layout"`
// StartDirectory overrides the workspace directory for this window.
StartDirectory string `yaml:"start_directory"`
// Shell replaces the command the window's first pane runs.
Shell string `yaml:"window_shell"`
// Focus selects this window once the workspace is built.
Focus Bool `yaml:"focus"`
// SuppressHistory overrides the workspace setting for this window's panes.
SuppressHistory *Bool `yaml:"suppress_history"`
// Options are window options applied before this window's panes are created.
Options map[string]string `yaml:"options"`
// OptionsAfter are window options applied once the panes exist, for settings
// that a later split would otherwise overwrite.
OptionsAfter map[string]string `yaml:"options_after"`
// Environment is set on the session before this window is created. tmux
// keeps one environment per session rather than one per window, so a name
// used by more than one window keeps the last value written and every
// process started later in that session sees it.
Environment map[string]string `yaml:"environment"`
// CommandsBefore run in each of this window's panes before the pane's own
// commands, after the workspace's.
CommandsBefore []Command `yaml:"-"`
// Panes are created in order. The first pane is the window's initial pane;
// each later one splits the window.
Panes []Pane `yaml:"panes"`
// contains filtered or unexported fields
}
Window is one window in a workspace.
type Workspace ¶
type Workspace struct {
// SessionName names the created session. It is required.
SessionName string `yaml:"session_name"`
// StartDirectory is the default working directory for every window and pane
// that does not set its own.
StartDirectory string `yaml:"start_directory"`
// Environment is set on the session before its windows are created.
Environment map[string]string `yaml:"environment"`
// Options are applied to the session after it exists. Keys are tmux option
// names. A name from tmux's window table, such as main-pane-height, is
// accepted here as tmux accepts it, and lands on the session's current
// window the way tmux would put it there.
Options map[string]string `yaml:"options"`
// GlobalOptions are applied at tmux's global scope before the windows are
// created, so a window can inherit them.
GlobalOptions map[string]string `yaml:"global_options"`
// CommandsBefore run in every pane before that pane's own commands. Window
// and pane entries add to this list rather than replacing it.
CommandsBefore []Command `yaml:"-"`
// SuppressHistory prefixes commands with a space unless a window or pane
// overrides it.
SuppressHistory Bool `yaml:"suppress_history"`
// Windows are created in order. A workspace needs at least one.
Windows []Window `yaml:"windows"`
}
Workspace is one tmuxp-style session description.
func Parse ¶
Parse decodes one workspace document. Unknown fields are rejected so a misspelled key fails loudly instead of being dropped.
Example (UnknownField) ¶
A misspelled key fails the parse rather than being dropped, so a workspace that does not do what its author meant says so before anything is built.
package main
import (
"fmt"
"github.com/libtmux/libtmux-go/workspace"
)
func main() {
_, err := workspace.Parse([]byte("session_name: review\nwindow:\n - {}\n"))
fmt.Println(err != nil)
}
Output: true
func (Workspace) MissingDirectories ¶
MissingDirectories reports the start directories the workspace names that do not exist, in the order they appear.
It is separate from Workspace.Validate because a missing directory is not necessarily a mistake: a workspace whose shell_command_before creates one is ordinary, and rejecting it would refuse a file that works. tmux does not report one either. It starts the pane in the user's home directory and reports success, so a workspace naming a directory absent on this machine builds and puts panes somewhere other than where its file says.
Call it before Build to turn that silence into something a caller can report. A name beginning with ~ is resolved against the current user's home directory, as tmux resolves it.
func (*Workspace) UnmarshalYAML ¶
UnmarshalYAML decodes the workspace, then its shell_command_before, which accepts one command or a list.
func (Workspace) Validate ¶
Validate reports whether the workspace describes something buildable.
Every problem it finds is reported, not the first, because fixing a file one complaint per run is the slowest way to learn what is wrong with it. The result matches ErrInvalidWorkspace however many problems it carries.
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
build-workspace
command
Command build-workspace loads a tmuxp-style YAML workspace and builds it, then reports what tmux actually created.
|
Command build-workspace loads a tmuxp-style YAML workspace and builds it, then reports what tmux actually created. |