Skip to content

ADR 0111: Session restore

Status

Accepted

Context

Reopening a project meant reopening every file in it by hand, and scrolling back to where you were. The roadmap has listed this under "table stakes of a daily driver" since it was written.

Decision

A file beside config.ase, in the same shape

<config dir>/session.ase records the open files, the caret offset and scroll line in each, and which one was in front:

ASE-SESSION 1
active = 2
file = /home/u/one.c
cursor = 42
scroll = 3

file opens an entry and cursor/scroll fill in the one most recently opened, so a value arriving before any file is ignored rather than misfiled. Everything after file = is the path, = and spaces included, so only a path containing a newline cannot be represented — such a path is left out rather than written as something that reads back wrong.

No text is stored. The files are on disk, and anything unsaved is ADR 0110's problem.

Only when started bare

ase foo.c means foo.c, not "and the eleven things I had open last week". Launching with no argument is the only case that restores.

The session then records whatever ends up open, including after a launch with an argument — the session is "what was open", with no special cases. That does mean opening a single file and quitting leaves a one-file session. restore_session = false turns the whole thing off.

Written whenever the buffer list changes, and every five seconds

Buffer changes write immediately. The caret moving is far too hot to write on, so a five-second timer catches it — and writes nothing unless something actually moved, so an idle editor does no I/O. A SIGTERM, a logout or a crash then costs at most a few seconds of scroll position rather than the whole session.

Writing only in closeEvent was the first attempt and it is wrong: SIGTERM does not run it, which the end-to-end test found immediately by terminating the editor and getting no session file at all.

Missing files are skipped

A session should not refuse to start because a file was deleted, nor resurrect one that no longer exists. If nothing survives, the editor falls back to the usual empty buffer and its welcome greeting.

Consequences

Twelve core tests, six of which were checked by mutation: removing the header check, accepting trailing junk in a number, writing a path with a newline, and misfiling cursor/scroll onto the wrong entry are each caught.

Two of those tests were written wrong the first time and passed against a broken implementation. test_headerless_file_is_rejected fed a file whose first line was the file = entry, which the loader consumes as a header line either way — so with the check removed the result was still "nothing to restore". Fixed by giving the junk file a second line. The lesson is the same one the recovery suite gave: a test that passes immediately is a claim, not evidence.

Restoring the caret is queued rather than done inline, because addBuffer runs before the window is shown and ensureCursorVisible would scroll against a viewport with no real height yet. Without that, the scroll came back as 22 where 17 was saved.

Unnamed buffers are not recorded, since there is nothing to reopen.