1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
# Layouts
A project's window layout can be defined programatiicaly (and checked in/managed with version control):
```kdl
layout {
tab name="api" cwd="~/dev/api" {
pane command="nvim"
pane split="rows" {
pane command="npm run dev" suspended=true
pane
}
}
}
```
```bash
slosh --layout project.layout
```
## What to call them
**`*.layout`**, and a project's is `slosh.layout`. The syntax is the same KDL
subset the config uses. Point your editor's KDL highlighting at `*.layout`.
## How to verify them
```
$ slosh --check project.layout
project.layout: ok, a layout
```
```
$ slosh --check broken.layout
broken.layout:2: unknown pane property: cmd
broken.layout:3: split is cols or rows, not `diagonal`
broken.layout:4: weight is a number of 150 or more, not `40`
broken.layout:5: suspended takes true or false, not `yes`
broken.layout:6: purpose is ignored on a pane with panes in it
broken.layout:8: a pane holds panes, not `wobble`
broken.layout: 6 problems
```
Those are the mistakes a layout can make that still parses. `this layout
declares no tabs` comes last rather than first, so it reads as the summary it
is.
Loading is the other half of the same answer:
```
$ slosh --layout ~/.config/slosh/config.kdl
slosh: config.kdl: this is a config, not a layout: `gap` is a setting
```
A config handed to `--layout` is named for what it is instead of refused for
having no tabs, which is true of it in the least useful way.
## The layout nodes
- `tab`: one per tab, in strip order. `name=`, `cwd=`, `purpose=`,
`active=true` for the one you land in.
- `pane`: a leaf, or a split when it has `pane` children. `split="cols"|"rows"`
says which way it divides; `weight=` is its share of the parent (even shares
are equal weights, so leaving it out means "even").
- `command=`: what it runs. Without one, a pane runs your shell.
- `cwd=`: where it starts. Inherited from the tab when the pane does not say.
- `suspended=true`: laid out but running nothing until you touch it, so twelve
checked-out projects are not twelve running dev servers. The pane shows what it
_would_ run.
- `focus=true`: the pane you start in, within its tab.
- `floating=true`: the pane starts [floating](panes.md#floating-a-pane), with
`x=` `y=` `w=` `h=` as its wanted rect in cells. All four absent takes the centred default.
- `purpose=`: a label for tooling; see below.
**A relative `cwd=` in a layout _file_ resolves against that file's own
directory**, never against the directory you started the session from. It is
the same rule [`include`](config.md#include) already follows. A layout with no `cwd=` anywhere
starts in the file's directory too, so the common case needs no `cwd=` at all. An
absolute path is unchanged, and `~` is still your home directory.
That is what lets a layout be checked in beside the project it describes and mean
the same thing in everybody's clone:
```kdl
// ~/dev/api/slosh.layout, no absolute path in it anywhere
layout {
tab name="api" cwd="." {
pane command="nvim"
pane split="rows" {
pane cwd="src"
pane command="npm run dev" suspended=true
}
}
}
```
A full annotated example is `config/example.layout`.
## Purposes
A pane or tab can carry a `purpose=` label (`agent:main`, `logs`, `db`) for
tooling to find it by. A purpose declared in a layout or over the control API is
_locked_: a program inside the pane cannot overwrite it, so identity comes from
the layout rather than from whatever the program decides to print.
The [finder](panes.md#finding-a-pane) matches on purposes as well as titles, and
`{"cmd":"panes"}` reports them.
## When the layout is found rather than named
Everything above assumes you name the file. When it lives _in_ the project,
`slosh.layout` beside the `.git`, you do not have to: `C-a w` lists the
projects under the roots you configured and opening one applies the layout it
found there, or a default layout bound to that directory when the project has
none, and `C-a W` writes this tab back out as that file. Same syntax, same
checker, same dump; the only difference is that the path comes from the project
instead of from your command line. That is [workspaces](workspaces.md).
|