Add ability to restore previous layout.
This commit is contained in:
@@ -441,6 +441,81 @@ GPU. Here, each frame walks the visible rows, groups cells into runs of
|
||||
identical style, and hands each run to Pango. That is far more work per frame
|
||||
in principle, but a terminal grid is small.
|
||||
|
||||
## Restoring a session
|
||||
|
||||
Quitting in the middle of something should not cost you the arrangement you were
|
||||
in the middle of. Every exit writes a **session snapshot** — a photograph of the
|
||||
window as it stood — and the next launch that finds one puts a banner at the foot
|
||||
of the sidebar: *Restore session*, and how many tabs are in it. Click it and
|
||||
those tabs come back; press the ✕ and it goes away. Doing nothing is the same as
|
||||
dismissing it.
|
||||
|
||||
This is the counterpart to the [startup list](#startup-tabs), not a replacement
|
||||
for it, and the difference is the whole point. A startup entry is a **recipe** you
|
||||
maintain: open this layout against these values, written down once because you
|
||||
want it every morning. A snapshot is a **photograph** nobody asked for, of
|
||||
wherever the tabs had actually got to. A recipe cannot describe a shell that has
|
||||
been `cd`-ed three directories deep, and a photograph is not something you would
|
||||
ever sit down and edit — so the app keeps both.
|
||||
|
||||
What is in the photograph is each tab's split tree: the shape, the divider
|
||||
ratios, every terminal's working directory, every web pane's URL, the repository
|
||||
a review was bound to, and the name and emoji the row was wearing. What is
|
||||
deliberately not in it is anything that was *running* — scrollback, shell
|
||||
history, a half-typed command, the processes themselves. Restoring puts the
|
||||
arrangement back and leaves the prompts empty. That is the honest version of the
|
||||
feature: a snapshot that claimed to bring a build back would be lying about the
|
||||
first thing you would check.
|
||||
|
||||
Restoring **replaces** the tabs the window opened for itself, rather than adding
|
||||
to them — a window holding both your startup tabs and the session they were
|
||||
standing in for is two of everything. That is also why the offer only stands
|
||||
until the tab set changes: open or close a tab yourself and the banner goes,
|
||||
because "the tabs the window opened" has stopped being a set anyone can point at,
|
||||
and closing it would be closing your work. The banner is the launch-time gesture
|
||||
it looks like.
|
||||
|
||||
Closing every tab by hand takes the snapshot with it. That route out is a
|
||||
deliberate one — there is nothing left worth offering to put back, and a banner
|
||||
at the next launch offering the session before that would be answering a question
|
||||
nobody asked.
|
||||
|
||||
The file is `session.json`, and it lives in the **state** directory rather than
|
||||
beside `layouts.json` and `settings.json`:
|
||||
|
||||
```
|
||||
~/.local/state/playpen/session.json ($XDG_STATE_HOME/playpen/session.json)
|
||||
```
|
||||
|
||||
Those two are files a person writes; this one is written behind your back on
|
||||
every exit, and putting that much churn in a config directory — which plenty of
|
||||
people keep in version control — would make every quit look like an edit. Its
|
||||
per-tab `root` is the same split-tree grammar a saved layout's is, so the two can
|
||||
never drift into dialects of one shape, with the difference that a snapshot is
|
||||
taken *after* parameter substitution: every path in it is literal, because it is
|
||||
the directory a shell was really sitting in.
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 1,
|
||||
"tabs": [
|
||||
{ "name": "signal", "emoji": "🚀", "layout": "Project",
|
||||
"root": {
|
||||
"split": "horizontal", "ratio": 0.35,
|
||||
"first": { "kind": "terminal", "cwd": "/home/you/src/signal" },
|
||||
"second": { "kind": "review", "cwd": "/home/you/src/signal" }
|
||||
} },
|
||||
{ "name": "scratch",
|
||||
"root": { "kind": "terminal", "cwd": "/home/you" } }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The `layout` a tab came from rides along even though it is not what reopens it.
|
||||
It is there so that a restored window can still be captured by *Use current
|
||||
tabs* — without it, restoring a session and then asking to keep those tabs at
|
||||
launch would quietly write down a window of plain shells.
|
||||
|
||||
## Quitting
|
||||
|
||||
Closing the window asks first, and does so by default. A window here is not one
|
||||
@@ -509,6 +584,11 @@ to closing the moment the window manager says so:
|
||||
- **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)
|
||||
- **A session to pick up where you left off**: every exit photographs the
|
||||
window, and the next launch offers it back from a banner at the foot of the
|
||||
sidebar — click to reopen those tabs, or dismiss it and carry on. Unlike the
|
||||
startup list this is the arrangement you actually had, directories and all.
|
||||
See [Restoring a session](#restoring-a-session)
|
||||
- **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)
|
||||
|
||||
Reference in New Issue
Block a user