TermRemoteCtl/apps/mobile_app/lib/features/terminal/terminal_screen_state.dart

122 lines
3.6 KiB
Dart

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<String> primaryLines;
final List<String> alternateLines;
factory TerminalScreenState.fromSnapshot(TerminalScreenSnapshot snapshot) {
List<String> materialize(TerminalScreenBuffer? buffer) {
final lines = List<String>.filled(snapshot.rows, '');
final viewport = buffer?.viewport ?? const <TerminalScreenLine>[];
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<String>.from(primaryLines, growable: false);
final nextAlternateLines = List<String>.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,
);
}
}