// Copyright (c) 2026 Storm Dragon // SPDX-License-Identifier: GPL-3.0-or-later package reader import ( "git.stormux.org/storm/fenrir/internal/presentation" "git.stormux.org/storm/fenrir/internal/screen" "slices" ) // Cursor feedback requires unchanged composer text. Comparing masked snapshots // allows simultaneous tool/status redraws outside the input field to stay quiet. func input_cursor_feedback(previous, next screen.Snapshot) []presentation.Message { if !slices.Equal(previous.Cells, next.Cells) { return nil } return changes(previous, next, true) } // SessionState preserves shortcut-only state as well as configuration. Screen, // input timestamps and detached review positions are deliberately not restored. type SessionState struct { automatic bool mode, attributeConfigured, attributeMode, attributeResumeMode string regions *terminalRegions } func clone_regions(source *terminalRegions) *terminalRegions { if source == nil { return nil } result := *source clone := func(region *screen.Region) *screen.Region { if region == nil { return nil } value := *region return &value } result.window = clone(source.window) for index, region := range source.live { result.live[index] = clone(region) } return &result } func (r *Reader) Capture_session() SessionState { return r.Capture_terminal_session(r.screen.Terminal) } func (r *Reader) Capture_terminal_session(terminal int) SessionState { return SessionState{r.automatic, r.trackingMode, r.attributeConfigured, r.attributeMode, r.attributeResumeMode, clone_regions(r.regions[terminal])} } func (r *Reader) Restore_session(state SessionState, terminal int) { r.automatic = state.automatic r.Configure_tracking(state.mode) r.attributeConfigured, r.attributeMode, r.attributeResumeMode = state.attributeConfigured, state.attributeMode, state.attributeResumeMode if r.regions == nil { r.regions = make(map[int]*terminalRegions) } r.regions[terminal] = clone_regions(state.regions) r.regionRevision++ r.attributeKnown, r.indentKnown = false, false r.Reset_progress() } func (r *Reader) Clear_session_regions(terminal int) { delete(r.regions, terminal) r.regionRevision++ } func input_snapshot(snapshot screen.Snapshot, region screen.Region) screen.Snapshot { snapshot.Cells = slices.Clone(snapshot.Cells) for row := range snapshot.Rows { for col := range snapshot.Cols { if !region.Contains(col, row, snapshot.Cols) { snapshot.Cells[row*snapshot.Cols+col] = ' ' } } } return snapshot }