diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-09-16 09:39:59 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-09-16 09:39:59 +0200 |
| commit | 6ef83d6bdfb6120f9e1fbd145e0bc463196103d1 (patch) | |
| tree | 8eee1f2c29dcbef4ed96b23b08273d42ba0b5d49 /gui/internal/model/plan.go | |
| parent | 27eb6353030953e91a45b0104bd0567e53622090 (diff) | |
| download | krino-6ef83d6bdfb6120f9e1fbd145e0bc463196103d1.tar.gz krino-6ef83d6bdfb6120f9e1fbd145e0bc463196103d1.zip | |
gui: History and undo tab; each plan and undo is its own run
Diffstat (limited to 'gui/internal/model/plan.go')
| -rw-r--r-- | gui/internal/model/plan.go | 41 |
1 files changed, 25 insertions, 16 deletions
diff --git a/gui/internal/model/plan.go b/gui/internal/model/plan.go index 4066eae..86acab7 100644 --- a/gui/internal/model/plan.go +++ b/gui/internal/model/plan.go @@ -54,18 +54,26 @@ type Counts struct { // chooses, and no other krino moves the files under them (GUI design §3). // A directory another run is already working in is not planned at all: the // error is lock.ErrHeld, naming the directory. -func Plan(ctx context.Context, sess *engine.Session, d *engine.Dir) (*PlanTab, error) { +// +// Each plan gets its own session, so applying it is one run of krino with +// its own run id in the log - the same shape a command line invocation +// writes. A window is not a run: one that sorted a directory and later +// undid something must not log both under one id, which would make the run +// the undo of itself. +func Plan(ctx context.Context, e *engine.Engine, d *engine.Dir) (*PlanTab, error) { + sess, err := e.NewSession(false) + if err != nil { + return nil, err + } l, err := sess.Lock(ctx, d, false) if err != nil { + sess.Close() return nil, fmt.Errorf("%s: %w", d.Name, err) } - // Start from what this run has actually landed: a name a plan the user - // closed had reserved is free again, so looking twice never creeps up - // through name-1, name-2 (spec §7.4). - sess.FinishDirectory() dp, err := sess.Plan(ctx, d) if err != nil { l.Release() + sess.Close() return nil, err } t := &PlanTab{Dir: d, sess: sess, dp: dp, lock: l} @@ -73,17 +81,22 @@ func Plan(ctx context.Context, sess *engine.Session, d *engine.Dir) (*PlanTab, e return t, nil } -// Close releases the directory's lock, which Apply also does once the plan -// is history. The session outlives the tab, so closing one plan to open -// another keeps the run - and its claims - going. Closing twice is not an -// error. +// Run is the run id this plan was applied under, "" until Apply. +func (t *PlanTab) Run() string { return t.sess.Run() } + +// Close releases the directory's lock and ends the run, which Apply also +// does once the plan is history. Closing twice is not an error. func (t *PlanTab) Close() error { if t.lock == nil { return nil } l := t.lock t.lock = nil - return l.Release() + err := l.Release() + if cerr := t.sess.Close(); err == nil { + err = cerr + } + return err } // fill turns the engine's plan into rows and counts. @@ -218,12 +231,8 @@ func (t *PlanTab) Apply(ctx context.Context) (*engine.ApplyResult, error) { } res, err := t.sess.Apply(ctx, t.dp, approved) t.Applied = true - // The disk is now the truth: a destination this plan reserved but never - // used is free again, while one it did use stays protected for the rest - // of the run (spec §7.4). - t.sess.FinishDirectory() - // An applied plan is history, so the directory is free again without - // closing the window (GUI design §3). + // An applied plan is history: the run is over and the directory free + // again, without closing the window (GUI design §3). t.Close() if res != nil { t.record(res) |
