import 'terminal_screen_patch.dart'; import 'terminal_screen_snapshot.dart'; /// Experiment-only state reducer for backend-authored screen snapshots and patches. class TerminalScreenState { const TerminalScreenState({ required this.sessionId, required this.screenVersion, required this.sourceSequence, required this.rows, required this.columns, required this.cursorRow, required this.cursorColumn, required this.cursorVisible, required this.activeBuffer, required this.primaryLines, required this.alternateLines, }); final String sessionId; final int screenVersion; final int sourceSequence; final int rows; final int columns; final int cursorRow; final int cursorColumn; final bool cursorVisible; final String activeBuffer; final List primaryLines; final List alternateLines; factory TerminalScreenState.fromSnapshot(TerminalScreenSnapshot snapshot) { List materialize(TerminalScreenBuffer? buffer) { final lines = List.filled(snapshot.rows, ''); final viewport = buffer?.viewport ?? const []; for (final line in viewport) { if (line.index >= 0 && line.index < lines.length) { lines[line.index] = line.text; } } return lines; } return TerminalScreenState( sessionId: snapshot.sessionId, screenVersion: snapshot.screenVersion, sourceSequence: snapshot.sourceSequence, rows: snapshot.rows, columns: snapshot.columns, cursorRow: snapshot.cursorRow, cursorColumn: snapshot.cursorColumn, cursorVisible: snapshot.cursorVisible, activeBuffer: snapshot.activeBuffer, primaryLines: materialize(snapshot.primaryBuffer), alternateLines: materialize(snapshot.alternateBuffer), ); } bool canApplyPatch(TerminalScreenPatch patch) { return sessionId == patch.sessionId && screenVersion == patch.baseScreenVersion; } TerminalScreenState applyPatch(TerminalScreenPatch patch) { final nextPrimaryLines = List.from(primaryLines, growable: false); final nextAlternateLines = List.from( alternateLines, growable: false, ); final targetLines = patch.activeBuffer == 'alternate' ? nextAlternateLines : nextPrimaryLines; for (final operation in patch.operations) { if (operation.type != 'replace_lines') { continue; } for (var index = 0; index < operation.lines.length; index += 1) { final row = operation.startRow + index; if (row >= 0 && row < targetLines.length) { targetLines[row] = operation.lines[index]; } } } return TerminalScreenState( sessionId: sessionId, screenVersion: patch.screenVersion, sourceSequence: patch.sourceSequence, rows: patch.rows, columns: patch.columns, cursorRow: patch.cursorRow, cursorColumn: patch.cursorColumn, cursorVisible: patch.cursorVisible, activeBuffer: patch.activeBuffer, primaryLines: nextPrimaryLines, alternateLines: nextAlternateLines, ); } String toDisplayText() { final lines = activeBuffer == 'alternate' ? alternateLines : primaryLines; return renderTerminalScreenText( lines: lines, cursorRow: cursorRow, cursorColumn: cursorColumn, cursorVisible: cursorVisible, ); } String toReplaySequence() { final lines = activeBuffer == 'alternate' ? alternateLines : primaryLines; return buildTerminalScreenReplay( lines: lines, cursorRow: cursorRow, cursorColumn: cursorColumn, cursorVisible: cursorVisible, ); } }