WebShellHost constructor

WebShellHost({
  1. required TerminalView term,
  2. required ShellSessionPort session,
  3. required String principal,
  4. required String nodeId,
  5. DateTime? startedAt,
  6. LocalCommandRegistry? commands,
  7. ClientRuntime? client,
  8. Future<List<String>> onComplete(
    1. String word,
    2. bool isCommand,
    3. String? cwd
    )?,
  9. NodeDescriptor? nodeInfo()?,
  10. Principal? principalInfo,
  11. RemoteSession? remoteSession,
  12. CommandHistory? history,
  13. bool resumedInAltScreen = false,
  14. void onSessionExit()?,
  15. void onSessionDetached()?,
})

Creates the host over term and session, wires the LineEditor + InteractiveShellController, and starts them.

Implementation

//
// The plain `_field = param` initializers below are intentional: a private
// named parameter can't be an initializing formal, so `this._x` is illegal.
// The lint is suppressed per-line (constructor only) rather than file-wide.
WebShellHost({
  required TerminalView term,
  required ShellSessionPort session,
  required String principal,
  required String nodeId,
  DateTime? startedAt,
  LocalCommandRegistry? commands,
  ClientRuntime? client,
  Future<List<String>> Function(String word, bool isCommand, String? cwd)?
  onComplete,
  NodeDescriptor? Function()? nodeInfo,
  Principal? principalInfo,
  RemoteSession? remoteSession,
  CommandHistory? history,
  bool resumedInAltScreen = false,
  void Function()? onSessionExit,
  void Function()? onSessionDetached,
}) : _history = history ?? CommandHistory.inMemory(),
     // ignore: prefer_initializing_formals
     _resumedInAltScreen = resumedInAltScreen,
     _startedAt = startedAt ?? DateTime.now(),
     // ignore: prefer_initializing_formals
     _term = term,
     // ignore: prefer_initializing_formals
     _principal = principal,
     // ignore: prefer_initializing_formals
     _nodeId = nodeId,
     // ignore: prefer_initializing_formals
     _commands = commands,
     // ignore: prefer_initializing_formals
     _client = client,
     // ignore: prefer_initializing_formals
     _onComplete = onComplete,
     // ignore: prefer_initializing_formals
     _nodeInfo = nodeInfo,
     // ignore: prefer_initializing_formals
     _principalInfo = principalInfo,
     // ignore: prefer_initializing_formals
     _remoteSession = remoteSession,
     // ignore: prefer_initializing_formals
     _onSessionExit = onSessionExit,
     // ignore: prefer_initializing_formals
     _onSessionDetached = onSessionDetached {
  _editor = LineEditor(
    input: _input.stream,
    output: (s) => _term.write(utf8.encode(s)),
    history: _history,
    // The editor repaints across wrapped rows using the terminal width; keep
    // it current via [setWidth] in [_onResize]. Without it a wrapped prompt
    // (narrow phone terminals) staircases a fresh prompt per keystroke.
    width: _term.size.cols,
    // The browser terminal is always "raw" (xterm delivers keystrokes
    // verbatim); there is no mode to toggle.
    setRawMode: null,
    onInterrupt: _interruptRemote,
    onEof: () => unawaited(close()),
    onRaw: _onRaw,
    onComplete: _onComplete == null ? null : _completeAdapter,
    onLine: _onLine,
  );
  _controller = InteractiveShellController(
    session: session,
    // Resuming a session whose program is in the alternate screen (nano, vim,
    // claude, …): start in passthrough and DON'T prime the prompt — priming
    // would run cwd/marker commands that corrupt the full-screen program. The
    // replayed output repaints it and its queued marker restores the prompt on
    // exit. Mirrors the CLI's `resumedInAltScreen` wiring.
    resumedInAltScreen: _resumedInAltScreen,
    // Remote output repaints around the input line (matching the CLI), so a
    // backgrounded job's bytes appear above the prompt rather than tangled
    // with it. While a program owns the screen (passthrough) it just emits.
    onOutput: (bytes) => _editor.printAbove(() => _term.write(bytes)),
    onPrompt: _onPrompt,
    onPassthrough: (active) {
      _passthrough = active;
      _editor.setPassthrough(active);
    },
    onExit: _onExit,
  );
  _term.onInput((data) => _feed(utf8.encode(data)));
  _term.onResize(_onResize);
  final size = _term.size;
  if (size.cols > 0 && size.rows > 0) {
    _controller.resize(size.cols, size.rows);
  }
  _editor.start();
  _controller.start();
}