Add ability to set boot layout.
This commit is contained in:
@@ -4,7 +4,7 @@ A proof-of-concept workspace built on
|
||||
[libghostty-vt](https://github.com/ghostty-org/ghostty) and GTK4/libadwaita:
|
||||
**vertical tabs**, each holding a split tree of terminal and web panes, with
|
||||
**saved layouts** that open a whole arrangement — directories, scripts and all —
|
||||
in one go.
|
||||
in one go, and a **startup list** that opens the ones you always want.
|
||||
|
||||
The sidebar holds the window controls, a new-tab button, one row per tab, and a
|
||||
settings gear at its foot — the layout Zen Browser uses for vertical tabs —
|
||||
@@ -124,8 +124,8 @@ Pty.zig openpt/fork/exec, controlling terminal setup
|
||||
script.zig runs a command for `$(...)` in a layout's directory
|
||||
key.zig GDK keyval -> libghostty-vt key mapping
|
||||
theme.zig colors libghostty-vt has no opinion about, per scheme
|
||||
Settings.zig preferences: model, JSON on disk
|
||||
SettingsDialog.zig the settings page
|
||||
Settings.zig preferences: theme and startup tabs, JSON on disk
|
||||
SettingsDialog.zig the settings page, including the startup list editor
|
||||
TabSettingsDialog.zig one tab's own settings, and the emoji picker
|
||||
emoji.zig generated: every emoji the picker offers, and the search over them
|
||||
```
|
||||
@@ -288,6 +288,55 @@ A node is a split if it has a `split` key and a leaf otherwise. Saves are
|
||||
atomic — written to a temporary and renamed — so an interrupted write leaves
|
||||
the previous layouts intact rather than a file that won't parse.
|
||||
|
||||
## Startup tabs
|
||||
|
||||
Opening the same three layouts against the same three worktrees every morning is
|
||||
the kind of thing the app should be doing for you. **Settings → Startup** is a
|
||||
list of tabs to open at launch: one row per tab, each naming a saved layout, the
|
||||
values to fill its parameters in with, and optionally a name and an emoji to pin
|
||||
on the row.
|
||||
|
||||
The fastest way to fill it in is *Use current tabs*: arrange the window you want,
|
||||
then say that this is the window you always want. It writes down one entry per
|
||||
open tab, in sidebar order, with whatever each was opened with.
|
||||
|
||||
What is saved is the **recipe, not the session**. An entry is the layout's name
|
||||
and a handful of values, so it is a few lines you can read, edit and keep — and
|
||||
the layout itself stays the thing you maintain. Nothing here restores a
|
||||
scrollback, a running command, or a shell that has since wandered into another
|
||||
directory; launching re-runs the arrangement, and that was the tedious part.
|
||||
|
||||
Rows in the list can be reordered, and the first one is the tab you land in. An
|
||||
entry with no layout picked opens a plain shell, which is worth having — a
|
||||
startup list is often two configured tabs and one ordinary shell to work in. An
|
||||
entry naming a layout that has since been renamed or deleted is skipped with a
|
||||
warning rather than silently costing you a tab, and the settings page keeps
|
||||
showing it — with *This layout is no longer saved* under it — so the values you
|
||||
typed for it survive until you deal with it.
|
||||
|
||||
Parameters that the entry doesn't mention open at the layout's own default, which
|
||||
is the same rule the parameter prompt follows. So an entry only has to carry the
|
||||
values that differ from what the layout already suggests.
|
||||
|
||||
The list lives in `settings.json` beside the theme:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 1,
|
||||
"theme": "dark",
|
||||
"startup": [
|
||||
{ "layout": "Project", "name": "signal", "emoji": "🚀",
|
||||
"parameters": { "path": "~/src/signal" } },
|
||||
{ "layout": "Project", "parameters": { "path": "~/src/playpen" } },
|
||||
{ "name": "scratch" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
With no `startup` list the app opens a single shell, exactly as it did before
|
||||
this existed — and if a list opens nothing at all, that is what you get too,
|
||||
since a window you can't type in is not an outcome worth being faithful for.
|
||||
|
||||
Two design choices worth calling out:
|
||||
|
||||
**No IO thread.** The PTY is read on the GLib main loop through a unix fd
|
||||
@@ -324,6 +373,9 @@ in principle, but a terminal grid is small.
|
||||
- **Saved layouts**: whole tabs — panes, splits, ratios, per-pane directories
|
||||
and scripts — opened in one go, parameterised by `{{name}}`, authored by
|
||||
arranging a tab and saving it. See [Layouts](#layouts)
|
||||
- **A startup list**: the tabs to open at launch, each a layout with its
|
||||
parameters filled in, fillable from the tabs you have open now. See
|
||||
[Startup tabs](#startup-tabs)
|
||||
- **Pane status in the tab strip**, driven by OSC 9;4, so a tab can say whether
|
||||
it is working, waiting on you, or finished and still unanswered. See
|
||||
[Agent status](#agent-status)
|
||||
@@ -566,16 +618,18 @@ the tab simply keeps the name it had.
|
||||
|
||||
Deep navy surfaces with Signal's ultramarine (`#3a76f0`) as the accent, in a
|
||||
light and a dark scheme. `Ctrl+,` or the gear at the foot of the sidebar opens
|
||||
**Settings**, which currently holds one choice: light, dark, or **system**,
|
||||
which is the default and follows the desktop.
|
||||
**Settings**, whose Appearance section holds the choice: light, dark, or
|
||||
**system**, which is the default and follows the desktop.
|
||||
|
||||
The preference lives in `~/.config/playpen/settings.json` (or
|
||||
`$XDG_CONFIG_HOME`), beside `layouts.json`:
|
||||
`$XDG_CONFIG_HOME`), beside `layouts.json`, alongside the
|
||||
[startup tabs](#startup-tabs):
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 1,
|
||||
"theme": "system"
|
||||
"theme": "system",
|
||||
"startup": []
|
||||
}
|
||||
```
|
||||
|
||||
@@ -632,8 +686,10 @@ This is a proof of concept, and the following are deliberately absent:
|
||||
nothing else: no bookmarks, history, downloads, devtools, or find-in-page,
|
||||
and each pane uses WebKit's default context, so nothing is persisted between
|
||||
runs. Links that ask for a new window are ignored rather than opening a pane.
|
||||
- **Restoring a session.** Layouts save arrangements you open deliberately;
|
||||
nothing restores the tabs you happened to have open when the app closed.
|
||||
- **Restoring a session.** [Startup tabs](#startup-tabs) reopen the
|
||||
arrangement you asked for, but nothing captures the state a session got itself
|
||||
into: no scrollback, no running commands, no directories a shell wandered off
|
||||
to. A tab comes back as its layout, not as you left it.
|
||||
- **Kitty graphics, hyperlinks, tab reordering.**
|
||||
- **Custom terminfo.** `TERM` is reported as `xterm-256color` rather than
|
||||
`ghostty`, since we don't install a terminfo entry.
|
||||
|
||||
Reference in New Issue
Block a user