ソースを参照

Some code comments

devmil 4 年 前
コミット
ee1c19b138

+ 1 - 1
lib/frontend/terminal_view.dart

@@ -531,7 +531,7 @@ class TerminalPainter extends CustomPainter {
   }
 
   void _paintCursor(Canvas canvas) {
-    final screenCursorY = terminal.cursorY + terminal.scrollOffset;
+    final screenCursorY = terminal.cursorY + terminal.scrollOffsetFromBottom;
     if (screenCursorY < 0 || screenCursorY >= terminal.terminalHeight) {
       return;
     }

+ 0 - 1
lib/terminal/terminal.dart

@@ -203,7 +203,6 @@ class Terminal with Observable implements TerminalUiInteraction {
 
   int get cursorX => buffer.cursorX;
   int get cursorY => buffer.cursorY;
-  int get scrollOffset => buffer.scrollOffsetFromBottom;
 
   void setScrollOffsetFromBottom(int scrollOffset) {
     final oldOffset = _buffer.scrollOffsetFromBottom;

+ 17 - 0
lib/terminal/terminal_backend.dart

@@ -1,11 +1,28 @@
+import 'package:xterm/terminal/terminal_isolate.dart';
+
+/// interface for every Terminal backend
 abstract class TerminalBackend {
+  /// initializes the backend
+  /// This can be used to instantiate instances that are problematic when
+  /// passed to a Isolate.
+  /// The [TerminalIsolate] will pass the backend to the [Terminal] that then
+  /// executes [init] from inside the Isolate.
+  /// So when your backend needs any complex instances (most of them will)
+  /// then strongly consider instantiating them here
   void init();
 
+  /// Stream for data that gets read from the backend
   Stream<String> get out;
+
+  /// Future that fires when the backend terminates
   Future<int> get exitCode;
 
+  /// writes data to this backend
   void write(String input);
+
+  /// notifies the backend about a view port resize that happened
   void resize(int width, int height);
 
+  /// terminates this backend
   void terminate();
 }

+ 27 - 9
lib/terminal/terminal_isolate.dart

@@ -41,6 +41,7 @@ enum _IsolateEvent {
   exit,
 }
 
+/// main entry for the terminal isolate
 void terminalMain(SendPort port) async {
   final rp = ReceivePort();
   port.send(rp.sendPort);
@@ -49,6 +50,7 @@ void terminalMain(SendPort port) async {
   var _needNotify = true;
 
   await for (var msg in rp) {
+    // process incoming commands
     final _IsolateCommand action = msg[0];
     switch (action) {
       case _IsolateCommand.sendPort:
@@ -117,8 +119,8 @@ void terminalMain(SendPort port) async {
         }
         if (_terminal.dirty) {
           final newState = TerminalState(
-            _terminal.buffer.scrollOffsetFromBottom,
-            _terminal.buffer.scrollOffsetFromTop,
+            _terminal.scrollOffsetFromBottom,
+            _terminal.scrollOffsetFromTop,
             _terminal.buffer.height,
             _terminal.invisibleHeight,
             _terminal.viewHeight,
@@ -131,7 +133,6 @@ void terminalMain(SendPort port) async {
             _terminal.showCursor,
             _terminal.theme.cursor,
             _terminal.getVisibleLines(),
-            _terminal.scrollOffset,
           );
           port.send([_IsolateEvent.newState, newState]);
           _needNotify = true;
@@ -146,6 +147,9 @@ void terminalMain(SendPort port) async {
   }
 }
 
+/// This class holds the initialization data needed for the Terminal.
+/// This data has to be passed from the UI Isolate where the TerminalIsolate
+/// class gets instantiated into the Isolate that will run the Terminal.
 class TerminalInitData {
   PlatformBehavior platform;
   TerminalTheme theme;
@@ -154,6 +158,9 @@ class TerminalInitData {
   TerminalInitData(this.backend, this.platform, this.theme, this.maxLines);
 }
 
+/// This class holds a complete TerminalState as needed by the UI.
+/// The state held here is self-contained and has no dependencies to the source
+/// Terminal. Therefore it can be safely transferred across Isolate boundaries.
 class TerminalState {
   int scrollOffsetFromTop;
   int scrollOffsetFromBottom;
@@ -176,8 +183,6 @@ class TerminalState {
 
   List<BufferLine> visibleLines;
 
-  int scrollOffset;
-
   bool consumed = false;
 
   TerminalState(
@@ -195,7 +200,6 @@ class TerminalState {
     this.showCursor,
     this.cursorColor,
     this.visibleLines,
-    this.scrollOffset,
   );
 }
 
@@ -203,6 +207,22 @@ void _defaultBellHandler() {}
 void _defaultTitleHandler(String _) {}
 void _defaultIconHandler(String _) {}
 
+/// The TerminalIsolate class hosts an Isolate that runs a Terminal.
+/// It handles all the communication with and from the Terminal and implements
+/// [TerminalUiInteraction] as well as the terminal and therefore can simply
+/// be exchanged with a Terminal.
+/// This class is the preferred use of a Terminal as the Terminal logic and all
+/// the communication with the backend are happening outside the UI thread.
+///
+/// There is a special constraints in using this class:
+/// The given backend has to be built so that it can be passed into an Isolate.
+///
+/// This means in particular that it is not allowed to have any closures in its
+/// object graph.
+/// It is a good idea to move as much instantiation as possible into the
+/// [TerminalBackend.init] method that gets called after the backend instance
+/// has been passed and is therefore allowed to instantiate parts of the object
+/// graph that do contain closures.
 class TerminalIsolate with Observable implements TerminalUiInteraction {
   final _receivePort = ReceivePort();
   SendPort? _sendPort;
@@ -244,9 +264,6 @@ class TerminalIsolate with Observable implements TerminalUiInteraction {
   @override
   int get scrollOffsetFromTop => _lastState!.scrollOffsetFromTop;
 
-  @override
-  int get scrollOffset => _lastState!.scrollOffset;
-
   @override
   int get bufferHeight => _lastState!.bufferHeight;
 
@@ -364,6 +381,7 @@ class TerminalIsolate with Observable implements TerminalUiInteraction {
   }
 
   void stop() {
+    terminateBackend();
     _isolate.kill();
   }
 

+ 66 - 1
lib/terminal/terminal_ui_interaction.dart

@@ -5,39 +5,99 @@ import 'package:xterm/mouse/selection.dart';
 import 'package:xterm/terminal/platform.dart';
 import 'package:xterm/util/observable.dart';
 
+/// this interface describes what a Terminal UI needs from a Terminal
 abstract class TerminalUiInteraction with Observable {
+  /// the ViewPort scroll offset from the bottom
   int get scrollOffsetFromBottom;
+
+  /// the ViewPort scroll offset from the top
   int get scrollOffsetFromTop;
-  int get scrollOffset;
+
+  /// the total buffer height
   int get bufferHeight;
+
+  /// terminal height (view port)
   int get terminalHeight;
+
+  /// terminal width (view port)
   int get terminalWidth;
+
+  /// the part of the buffer that is not visible (scrollback)
   int get invisibleHeight;
+
+  /// object that describes details about the current selection
   Selection? get selection;
+
+  /// [true] when the cursor shall be shown, otherwise [false]
   bool get showCursor;
+
+  /// returns the visible lines
   List<BufferLine> getVisibleLines();
+
+  /// cursor y coordinate
   int get cursorY;
+
+  /// cursor x coordinate
   int get cursorX;
+
+  /// current line
   BufferLine? get currentLine;
+
+  /// color code for the cursor
   int get cursorColor;
+
+  /// color code for the background
   int get backgroundColor;
+
+  /// flag that indicates if the terminal is dirty (since the last time this
+  /// flag has been queried)
   bool get dirty;
+
+  /// platform behavior for this terminal
   PlatformBehavior get platform;
+
+  /// selected text defined by [selection]
   String? get selectedText;
 
+  /// flag that indicates if the Terminal is ready
   bool get isReady;
 
+  /// refreshes the Terminal (notifies listeners and sets it to dirty)
   void refresh();
+
+  /// clears the selection
   void clearSelection();
+
+  /// notify the Terminal about a mouse tap
   void onMouseTap(Position position);
+
+  /// notify the Terminal about a pan start
   void onPanStart(Position position);
+
+  /// notify the Terminal about a pan update
   void onPanUpdate(Position position);
+
+  /// sets the scroll offset from bottom (scrolling)
   void setScrollOffsetFromBottom(int offset);
+
+  /// converts the given view line (view port line) index to its position in the
+  /// overall buffer
   int convertViewLineToRawLine(int viewLine);
+
+  /// notifies the Terminal about user input
   void raiseOnInput(String input);
+
+  /// writes data to the Terminal
   void write(String text);
+
+  /// paste clipboard content to the Terminal
   void paste(String data);
+
+  /// notifies the Terminal about a resize that happened. The Terminal will
+  /// do any resize / reflow logic and notify the backend about the resize
   void resize(int newWidth, int newHeight);
+
+  /// notifies the Terminal about key input
   void keyInput(
     TerminalKey key, {
     bool ctrl = false,
@@ -47,7 +107,12 @@ abstract class TerminalUiInteraction with Observable {
     // bool meta,
   });
 
+  /// Future that fires when the backend has exited
   Future<int> get backendExited;
+
+  /// terminates the backend. If already terminated, nothing happens
   void terminateBackend();
+
+  /// flag that indicates if the backend is already terminated
   bool get isTerminated;
 }