@floegence/floeterm-terminal-web 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/README.md +25 -1
  2. package/dist/core/TerminalCore.d.ts +8 -1
  3. package/dist/core/TerminalCore.d.ts.map +1 -1
  4. package/dist/core/TerminalCore.js +141 -69
  5. package/dist/core/TerminalCore.js.map +1 -1
  6. package/dist/core/TerminalScrollbarOverlay.d.ts +63 -0
  7. package/dist/core/TerminalScrollbarOverlay.d.ts.map +1 -0
  8. package/dist/core/TerminalScrollbarOverlay.js +493 -0
  9. package/dist/core/TerminalScrollbarOverlay.js.map +1 -0
  10. package/dist/index.d.ts +1 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/internal/GhosttyScrollbackCompat.d.ts +16 -0
  14. package/dist/internal/GhosttyScrollbackCompat.d.ts.map +1 -0
  15. package/dist/internal/GhosttyScrollbackCompat.js +43 -0
  16. package/dist/internal/GhosttyScrollbackCompat.js.map +1 -0
  17. package/dist/internal/GhosttyScrollbarCompat.d.ts +10 -0
  18. package/dist/internal/GhosttyScrollbarCompat.d.ts.map +1 -0
  19. package/dist/internal/GhosttyScrollbarCompat.js +94 -0
  20. package/dist/internal/GhosttyScrollbarCompat.js.map +1 -0
  21. package/dist/internal/TerminalResourceLoader.d.ts +27 -2
  22. package/dist/internal/TerminalResourceLoader.d.ts.map +1 -1
  23. package/dist/internal/TerminalResourceLoader.js +112 -47
  24. package/dist/internal/TerminalResourceLoader.js.map +1 -1
  25. package/dist/types.d.ts +13 -0
  26. package/dist/types.d.ts.map +1 -1
  27. package/dist/types.js.map +1 -1
  28. package/dist/utils/themeColor.d.ts +12 -0
  29. package/dist/utils/themeColor.d.ts.map +1 -0
  30. package/dist/utils/themeColor.js +88 -0
  31. package/dist/utils/themeColor.js.map +1 -0
  32. package/package.json +4 -3
package/README.md CHANGED
@@ -53,6 +53,27 @@ const core = new TerminalCore(
53
53
  await core.initialize();
54
54
  ```
55
55
 
56
+ Floeterm projects one renderer-neutral DOM scrollbar for both canvas and WebGL terminals while Ghostty remains the only scrollback and viewport owner:
57
+
58
+ ```ts
59
+ const core = new TerminalCore(container, {
60
+ rendererType: 'webgl',
61
+ fit: { scrollbarReservePx: 15 },
62
+ scrollbar: {
63
+ visibility: 'persistent', // "auto" by default, or "hidden"
64
+ minThumbPx: 24,
65
+ ariaLabel: 'Terminal history',
66
+ },
67
+ });
68
+
69
+ // Keep a long-lived Core aligned with a runtime locale change.
70
+ core.setScrollbarOptions({ ariaLabel: localizedTerminalHistoryLabel });
71
+ ```
72
+
73
+ The scrollbar uses a 12px visual and fine-pointer rail. Reserve at least 12px when the last terminal column must remain fully unobstructed; the default 15px reserve provides a stable gutter. An explicit `scrollbarReservePx: 0` remains supported as an overlay mode and may cover the rightmost 12px. The visual overlay itself never owns pointer hit testing: Floeterm captures fine-pointer track and thumb gestures at the viewport boundary, while wheel and touch events continue to target Ghostty's terminal surface exactly once. `persistent` automatically behaves as `auto` on coarse-pointer-only devices. Mixed-pointer devices keep mouse and pen interaction without creating a dead touch strip.
74
+
75
+ `auto` reveals on terminal wheel activity, keyboard focus, or fine-pointer movement into the right-edge rail, then fades after 1,200ms of inactivity. `persistent` remains visible on fine-pointer layouts and `hidden` removes the control from pointer, tab, and accessibility access. Alternate-screen programs and empty buffers also hide it. Theme-derived idle and hover/focus colors meet 3:1 and 4.5:1 contrast targets. Drag color targets 7:1; when that ratio is mathematically impossible against the configured background, Floeterm chooses whichever of black or white provides the highest available contrast. Forced-colors and reduced-motion preferences are honored.
76
+
56
77
  After a host-owned layout transition or history recovery, request an explicit
57
78
  presentation fence before declaring the terminal surface ready:
58
79
 
@@ -129,7 +150,10 @@ the foreground revision that was active at that exact byte boundary.
129
150
  ## Notes
130
151
 
131
152
  - You must provide a `TerminalTransport` and `TerminalEventSource` for the managed controller.
132
- - `ghostty-web` needs a one-time `init()`; `TerminalCore` handles that internally.
153
+ - Each `TerminalCore` owns an isolated `ghostty-web` WASM runtime; consumers must not provide or share a Ghostty runtime.
154
+ - `scrollback` is measured in terminal buffer rows, including separately wrapped rows, and accepts integers from 1 through 10,000. Within the supported geometry, Floeterm preserves at least the requested number of buffer rows; it does not trim to an exact physical row count. Floeterm maps that contract to a bounded byte budget for the exact pinned `ghostty-web@0.4.0-next.14.g6a1a50d` release, which currently interprets the value as bytes. The 81,920,000-byte cap limits Ghostty's scrollback arena, not the total memory of a WASM runtime. The mapping is temporary and must be reviewed and removed or updated with any Ghostty upgrade.
155
+ - Supported terminal geometry is limited to 500 columns. Explicit dimensions above that limit fail, while automatic fitting reports at most 500 columns.
156
+ - Consumer dependency overrides for `ghostty-web` are unsupported. Floeterm's compatibility guard requires the exact package pin so an upstream behavior change cannot silently apply the row-to-byte mapping twice or reactivate the native canvas scrollbar beneath the renderer-neutral DOM control.
133
157
  - `TerminalCore` bridges the hidden textarea used by `ghostty-web`, so soft-keyboard and composition input continue to work on touch devices.
134
158
  - The hidden terminal input is mounted in the document viewport plane and anchored from rendered cursor geometry, so native IME candidate windows stay aligned without expanding transformed terminal hosts.
135
159
  - Programmatic terminal focus uses no-scroll focus by default, keeping embedded terminals stable inside scaled, projected, or otherwise transformed host surfaces.
@@ -1,9 +1,11 @@
1
- import { TerminalState, type Logger, type TerminalConfig, type TerminalCopySelectionResult, type TerminalCopySelectionSource, type TerminalDimensions, type TerminalEventHandlers, type TerminalFocusOptions, type TerminalAppearance, type TerminalLinkProvider, type TerminalRuntimeLineSnapshot, type TerminalRestorableSnapshot, type TerminalRestorableSnapshotOptions, type TerminalResourceEstimate, type TerminalTouchScrollRuntime, type TerminalInitializationOptions, type TerminalVisualSuspendHandle, type TerminalVisualSuspendOptions } from '../types.js';
1
+ import { TerminalState, type Logger, type TerminalConfig, type TerminalCopySelectionResult, type TerminalCopySelectionSource, type TerminalDimensions, type TerminalEventHandlers, type TerminalFocusOptions, type TerminalAppearance, type TerminalLinkProvider, type TerminalScrollbarOptions, type TerminalRuntimeLineSnapshot, type TerminalRestorableSnapshot, type TerminalRestorableSnapshotOptions, type TerminalResourceEstimate, type TerminalTouchScrollRuntime, type TerminalInitializationOptions, type TerminalVisualSuspendHandle, type TerminalVisualSuspendOptions } from '../types.js';
2
2
  export { preloadTerminalResources } from '../internal/TerminalResourceLoader.js';
3
3
  export declare class TerminalCore {
4
4
  private container;
5
5
  private config;
6
6
  private terminal;
7
+ private ownedRuntime;
8
+ private ownedRuntimeMemory;
7
9
  private fitAddon;
8
10
  private needsFullRenderOnNextWrite;
9
11
  private demandRenderForceAll;
@@ -22,6 +24,7 @@ export declare class TerminalCore {
22
24
  private inputElement;
23
25
  private viewportHost;
24
26
  private renderHost;
27
+ private scrollbarOverlay;
25
28
  private resizeObserver;
26
29
  private resizeDebounceTimer;
27
30
  private resizeRaf;
@@ -48,6 +51,8 @@ export declare class TerminalCore {
48
51
  private pendingPresentationScale;
49
52
  private suppressResizeNotifications;
50
53
  private clearResizeSuppressionRaf;
54
+ private readonly scrollbackRows;
55
+ private scrollbarOptions;
51
56
  private hasFocus;
52
57
  private resizeNotifySeq;
53
58
  private lastNotifiedSize;
@@ -76,6 +81,7 @@ export declare class TerminalCore {
76
81
  private loadAddons;
77
82
  private openTerminal;
78
83
  private mountInputElement;
84
+ private mountScrollbarOverlay;
79
85
  private installLinkDetector;
80
86
  private installFitAddonGeometryPatch;
81
87
  private proposeFitDimensions;
@@ -213,6 +219,7 @@ export declare class TerminalCore {
213
219
  private forceResizeAndWaitForCommittedFrame;
214
220
  setFixedDimensions(dimensions: TerminalDimensions | null): void;
215
221
  setAppearance(appearance: TerminalAppearance): void;
222
+ setScrollbarOptions(options: Partial<TerminalScrollbarOptions>): void;
216
223
  setTheme(theme: Record<string, unknown>): void;
217
224
  setFontSize(size: number): void;
218
225
  setPresentationScale(scale: number): void;
@@ -1 +1 @@
1
- {"version":3,"file":"TerminalCore.d.ts","sourceRoot":"","sources":["../../src/core/TerminalCore.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TerminalCore.d.ts","sourceRoot":"","sources":["../../src/core/TerminalCore.ts"],"names":[],"mappings":"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"}
@@ -4,15 +4,18 @@ import { cursorToFabricCursor, renderReasonFromForce, terminalLiveFabric, themeT
4
4
  import { terminalFabricCoordinator } from '../fabric/TerminalFabricCoordinator.js';
5
5
  import { TerminalState, } from '../types.js';
6
6
  import { terminalInitializationScheduler, } from '../internal/TerminalInitializationScheduler.js';
7
- import { getGhosttyFitAddonConstructor, getGhosttyLinkConstructors, getGhosttyTerminalConstructor, loadGhosttyModules, waitWithAbort, } from '../internal/TerminalResourceLoader.js';
7
+ import { acquireGhosttyRuntime, getGhosttyFitAddonConstructor, getGhosttyLinkConstructors, getGhosttyTerminalConstructor, inspectGhosttyRuntimeMemory, loadGhosttyModules, waitWithAbort, } from '../internal/TerminalResourceLoader.js';
8
+ import { capAutoFitTerminalColumns, mapGhosttyScrollbackRowsForPinnedVersion, validateTerminalColumns, validateTerminalScrollbackRows, } from '../internal/GhosttyScrollbackCompat.js';
9
+ import { installPinnedGhosttyAlternateScreenProjection, suppressPinnedGhosttyScrollbarBeforeOpen, suppressPinnedGhosttyScrollbarRenderer, } from '../internal/GhosttyScrollbarCompat.js';
8
10
  import { createUnicodeSafeUrlProviderTerminal, } from '../internal/UnicodeSafeUrlProvider.js';
9
11
  import { resolveTerminalInputElement, TerminalInputBridge } from './TerminalInputBridge.js';
10
12
  import { terminalRenderScheduler } from './TerminalRenderScheduler.js';
11
13
  import { scheduleUiTurn } from '../internal/scheduleUiTurn.js';
14
+ import { parseThemeColor } from '../utils/themeColor.js';
15
+ import { normalizeTerminalScrollbarOptions, TerminalScrollbarOverlay, } from './TerminalScrollbarOverlay.js';
12
16
  const TERMINAL_SNAPSHOT_VERSION = 1;
13
17
  const DEFAULT_TERMINAL_SNAPSHOT_MAX_BYTES = 2 * 1024 * 1024;
14
18
  const ESTIMATED_RENDERER_BYTES = 4 * 1024 * 1024;
15
- const ESTIMATED_CELL_BYTES = 16;
16
19
  const SNAPSHOT_RESET_PREFIX = '\x1bc\x1b[2J\x1b[H';
17
20
  const encodedByteLength = (value) => new TextEncoder().encode(value).byteLength;
18
21
  const TERMINAL_SEARCH_MAX_RESULTS = 5000;
@@ -131,41 +134,6 @@ const mapThemeToGhostty = (theme) => {
131
134
  }
132
135
  return mapped;
133
136
  };
134
- function normalizeThemeColor(value) {
135
- if (!value) {
136
- return null;
137
- }
138
- const trimmed = value.trim();
139
- const shortHex = /^#([0-9a-fA-F]{3})$/.exec(trimmed);
140
- if (shortHex) {
141
- const [r, g, b] = shortHex[1].split('');
142
- return `#${r}${r}${g}${g}${b}${b}`.toLowerCase();
143
- }
144
- if (/^#[0-9a-fA-F]{6}$/.test(trimmed)) {
145
- return trimmed.toLowerCase();
146
- }
147
- const rgb = /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/.exec(trimmed);
148
- if (!rgb) {
149
- return null;
150
- }
151
- const channels = rgb.slice(1).map(channel => Number(channel));
152
- if (channels.some(channel => !Number.isInteger(channel) || channel < 0 || channel > 255)) {
153
- return null;
154
- }
155
- return `#${channels.map(channel => channel.toString(16).padStart(2, '0')).join('')}`;
156
- }
157
- function parseThemeColor(value) {
158
- const normalized = normalizeThemeColor(value);
159
- if (!normalized) {
160
- return null;
161
- }
162
- const hex = normalized.slice(1);
163
- return {
164
- r: Number.parseInt(hex.slice(0, 2), 16),
165
- g: Number.parseInt(hex.slice(2, 4), 16),
166
- b: Number.parseInt(hex.slice(4, 6), 16),
167
- };
168
- }
169
137
  function colorKey(color) {
170
138
  return `${color.r},${color.g},${color.b}`;
171
139
  }
@@ -255,14 +223,14 @@ function canSkipNativeCanvasRowRender(renderer, row, fabricActive) {
255
223
  function samePresentationScale(left, right) {
256
224
  return Math.abs(left - right) <= PRESENTATION_SCALE_EPSILON;
257
225
  }
258
- function normalizeTerminalDimensions(value) {
226
+ function normalizeTerminalDimensions(value, columnsLabel = 'fixedDimensions.cols') {
259
227
  const raw = (typeof value === 'object' && value) ? value : null;
260
228
  if (!raw) {
261
229
  return null;
262
230
  }
263
- const cols = Math.floor(Number(raw.cols));
231
+ const cols = validateTerminalColumns(raw.cols, columnsLabel);
264
232
  const rows = Math.floor(Number(raw.rows));
265
- if (!Number.isFinite(cols) || !Number.isFinite(rows) || cols <= 0 || rows <= 0) {
233
+ if (!Number.isFinite(rows) || rows <= 0) {
266
234
  return null;
267
235
  }
268
236
  return { cols, rows };
@@ -341,6 +309,8 @@ export class TerminalCore {
341
309
  this.container = container;
342
310
  this.config = config;
343
311
  this.terminal = null;
312
+ this.ownedRuntime = null;
313
+ this.ownedRuntimeMemory = null;
344
314
  this.fitAddon = null;
345
315
  this.needsFullRenderOnNextWrite = false;
346
316
  this.demandRenderForceAll = false;
@@ -357,6 +327,7 @@ export class TerminalCore {
357
327
  this.inputElement = null;
358
328
  this.viewportHost = null;
359
329
  this.renderHost = null;
330
+ this.scrollbarOverlay = null;
360
331
  this.resizeObserver = null;
361
332
  this.resizeDebounceTimer = null;
362
333
  this.resizeRaf = null;
@@ -406,14 +377,27 @@ export class TerminalCore {
406
377
  pendingResizeReason: null,
407
378
  pendingSearchOverlayRender: false,
408
379
  };
380
+ const explicitCols = config?.cols;
381
+ if (explicitCols !== undefined) {
382
+ validateTerminalColumns(explicitCols);
383
+ }
384
+ this.scrollbackRows = validateTerminalScrollbackRows(config?.scrollback === undefined ? 1000 : config.scrollback);
409
385
  this.eventHandlers = eventHandlers;
410
386
  this.clipboard = TerminalCore.normalizeClipboardConfig(config?.clipboard);
411
387
  this.fit = TerminalCore.normalizeFitConfig(config?.fit);
388
+ this.scrollbarOptions = normalizeTerminalScrollbarOptions(config?.scrollbar);
412
389
  this.logger = logger ?? noopLogger;
413
390
  this.responsive = TerminalCore.normalizeResponsiveConfig(config?.responsive);
414
391
  this.logicalFontSize = TerminalCore.normalizeFontSize(config?.fontSize);
415
392
  this.presentationScale = TerminalCore.normalizePresentationScale(config?.presentationScale);
416
393
  this.fixedDimensions = normalizeTerminalDimensions(config?.fixedDimensions);
394
+ this.config = {
395
+ ...config,
396
+ ...(explicitCols === undefined ? {} : { cols: explicitCols }),
397
+ fixedDimensions: this.fixedDimensions,
398
+ scrollback: this.scrollbackRows,
399
+ scrollbar: this.scrollbarOptions,
400
+ };
417
401
  this.renderTask = {
418
402
  id: TerminalCore.nextRenderTaskId,
419
403
  run: forceAll => {
@@ -457,6 +441,11 @@ export class TerminalCore {
457
441
  promise: Promise.resolve(),
458
442
  };
459
443
  operation.promise = (async () => {
444
+ const assertInitializationActive = () => {
445
+ if (this.isDisposed)
446
+ throw new Error('Cannot initialize a disposed TerminalCore');
447
+ lifecycleAbortController.signal.throwIfAborted();
448
+ };
460
449
  const permit = await request.permit;
461
450
  if (!permit) {
462
451
  if (this.isDisposed)
@@ -467,20 +456,21 @@ export class TerminalCore {
467
456
  }
468
457
  operation.started = true;
469
458
  try {
470
- if (this.isDisposed)
471
- throw new Error('Cannot initialize a disposed TerminalCore');
459
+ assertInitializationActive();
472
460
  await loadGhosttyModules(this.logger, lifecycleAbortController.signal);
473
- if (this.isDisposed)
474
- throw new Error('Cannot initialize a disposed TerminalCore');
461
+ assertInitializationActive();
462
+ const ownedRuntime = await acquireGhosttyRuntime(this.logger);
463
+ assertInitializationActive();
464
+ const ownedRuntimeMemory = inspectGhosttyRuntimeMemory(ownedRuntime);
465
+ assertInitializationActive();
466
+ this.ownedRuntime = ownedRuntime;
467
+ this.ownedRuntimeMemory = ownedRuntimeMemory;
475
468
  await this.createTerminalInstance(lifecycleAbortController.signal);
476
- if (this.isDisposed)
477
- throw new Error('Cannot initialize a disposed TerminalCore');
469
+ assertInitializationActive();
478
470
  await this.loadAddons();
479
- if (this.isDisposed)
480
- throw new Error('Cannot initialize a disposed TerminalCore');
471
+ assertInitializationActive();
481
472
  await this.openTerminal(lifecycleAbortController.signal);
482
- if (this.isDisposed)
483
- throw new Error('Cannot initialize a disposed TerminalCore');
473
+ assertInitializationActive();
484
474
  this.setupEventListeners();
485
475
  this.setupResponsiveListeners();
486
476
  this.startSizeWatching();
@@ -517,14 +507,26 @@ export class TerminalCore {
517
507
  return;
518
508
  settled = true;
519
509
  operation.waiters = Math.max(0, operation.waiters - 1);
520
- if (operation.waiters === 0 && !operation.started && !operation.cancelled) {
521
- operation.cancelled = true;
522
- operation.request.cancel();
523
- if (this.initializationOperation === operation) {
524
- this.initializationOperation = null;
525
- if (!this.isDisposed)
526
- this.setState(TerminalState.IDLE);
510
+ if (operation.waiters !== 0 || operation.cancelled)
511
+ return;
512
+ if (operation.started) {
513
+ if (this.initializationOperation === operation
514
+ && !this.isDisposed
515
+ && this.state === TerminalState.INITIALIZING) {
516
+ operation.cancelled = true;
517
+ // Ghostty.load() cannot be cancelled. Abort the Core lifecycle so the
518
+ // owned runtime is discarded when that load settles, while the
519
+ // initialization permit remains held by the operation's finally path.
520
+ operation.lifecycleAbortController.abort();
527
521
  }
522
+ return;
523
+ }
524
+ operation.cancelled = true;
525
+ operation.request.cancel();
526
+ if (this.initializationOperation === operation) {
527
+ this.initializationOperation = null;
528
+ if (!this.isDisposed)
529
+ this.setState(TerminalState.IDLE);
528
530
  }
529
531
  };
530
532
  return waitWithAbort(operation.promise, signal).finally(releaseWaiter);
@@ -536,10 +538,14 @@ export class TerminalCore {
536
538
  this.resizeObserver = null;
537
539
  this.disposeInputBridge();
538
540
  this.disposeTerminalEventListeners();
541
+ this.scrollbarOverlay?.dispose();
542
+ this.scrollbarOverlay = null;
539
543
  this.fabricView?.dispose();
540
544
  this.fabricView = null;
541
545
  this.terminal?.dispose();
542
546
  this.terminal = null;
547
+ this.ownedRuntimeMemory = null;
548
+ this.ownedRuntime = null;
543
549
  this.inputElement?.remove();
544
550
  this.inputElement = null;
545
551
  this.fitAddon = null;
@@ -552,6 +558,9 @@ export class TerminalCore {
552
558
  if (!TerminalCtor) {
553
559
  throw new Error('ghostty-web module not loaded');
554
560
  }
561
+ if (!this.ownedRuntime) {
562
+ throw new Error('ghostty-web runtime not acquired');
563
+ }
555
564
  const defaultConfig = {
556
565
  cols: 80,
557
566
  rows: 24,
@@ -586,13 +595,14 @@ export class TerminalCore {
586
595
  cursorBlink: typeof finalConfig.cursorBlink === 'boolean' ? finalConfig.cursorBlink : undefined,
587
596
  cursorStyle: typeof finalConfig.cursorStyle === 'string' ? finalConfig.cursorStyle : undefined,
588
597
  theme: initialTheme,
589
- scrollback: typeof finalConfig.scrollback === 'number' ? finalConfig.scrollback : undefined,
598
+ scrollback: mapGhosttyScrollbackRowsForPinnedVersion(this.scrollbackRows),
590
599
  fontSize: this.resolveEffectiveFontSize(),
591
600
  fontFamily: typeof finalConfig.fontFamily === 'string' ? finalConfig.fontFamily : undefined,
592
601
  allowTransparency: typeof finalConfig.allowTransparency === 'boolean' ? finalConfig.allowTransparency : undefined,
593
602
  convertEol: typeof finalConfig.convertEol === 'boolean' ? finalConfig.convertEol : undefined,
594
603
  disableStdin: typeof finalConfig.disableStdin === 'boolean' ? finalConfig.disableStdin : undefined,
595
- smoothScrollDuration: typeof finalConfig.smoothScrollDuration === 'number' ? finalConfig.smoothScrollDuration : undefined
604
+ smoothScrollDuration: typeof finalConfig.smoothScrollDuration === 'number' ? finalConfig.smoothScrollDuration : undefined,
605
+ ghostty: this.ownedRuntime,
596
606
  });
597
607
  }
598
608
  async loadAddons() {
@@ -616,7 +626,11 @@ export class TerminalCore {
616
626
  const renderHost = this.ensurePresentationHosts();
617
627
  this.applyPresentationScaleStyles();
618
628
  this.installDemandRenderPatchBeforeOpen();
629
+ suppressPinnedGhosttyScrollbarBeforeOpen(this.terminal);
619
630
  this.terminal.open(renderHost);
631
+ installPinnedGhosttyAlternateScreenProjection(this.terminal);
632
+ const renderer = this.terminal.renderer;
633
+ suppressPinnedGhosttyScrollbarRenderer(renderer ?? {});
620
634
  this.installLinkDetector();
621
635
  if (this.config.rendererType === 'webgl') {
622
636
  const canvas = this.terminal
@@ -630,6 +644,7 @@ export class TerminalCore {
630
644
  this.patchSelectionManagerClipboardBehavior();
631
645
  this.patchSelectionManagerRenderingBehavior();
632
646
  this.setupInputBridge(renderHost);
647
+ this.mountScrollbarOverlay();
633
648
  this.applyRegisteredLinkProviders();
634
649
  void this.refreshFontMetricsAfterLoad('open');
635
650
  }
@@ -645,6 +660,30 @@ export class TerminalCore {
645
660
  body.appendChild(input);
646
661
  this.inputElement = input;
647
662
  }
663
+ mountScrollbarOverlay() {
664
+ if (!this.terminal || !this.viewportHost || !this.renderHost) {
665
+ throw new Error('Terminal scrollbar requires an initialized presentation host');
666
+ }
667
+ this.scrollbarOverlay?.dispose();
668
+ const terminal = this.terminal;
669
+ const surfaceId = `${this.fabricViewId}-surface`;
670
+ this.renderHost.id = surfaceId;
671
+ this.scrollbarOverlay = new TerminalScrollbarOverlay(this.viewportHost, {
672
+ get rows() {
673
+ return terminal.rows;
674
+ },
675
+ getScrollbackLength: () => terminal.getScrollbackLength(),
676
+ getViewportY: () => terminal.getViewportY(),
677
+ isAlternateScreen: () => terminal.isAlternateScreen(),
678
+ scrollToLine: line => terminal.scrollToLine(line),
679
+ scrollToTop: () => terminal.scrollToTop(),
680
+ scrollToBottom: () => terminal.scrollToBottom(),
681
+ scrollLines: amount => terminal.scrollLines(amount),
682
+ scrollPages: amount => terminal.scrollPages(amount),
683
+ focusTerminal: () => this.scheduleInputSurfaceRefocus({ preventScroll: true }),
684
+ }, this.scrollbarOptions, surfaceId);
685
+ this.scrollbarOverlay.setBackgroundColor(this.terminalThemeSource.background);
686
+ }
648
687
  installLinkDetector() {
649
688
  if (!this.terminal) {
650
689
  throw new Error('Terminal instance not created');
@@ -693,7 +732,7 @@ export class TerminalCore {
693
732
  const availableWidth = Math.max(0, width - paddingLeft - paddingRight - this.fit.scrollbarReservePx);
694
733
  const availableHeight = Math.max(0, height - paddingTop - paddingBottom);
695
734
  return {
696
- cols: Math.max(MIN_TERMINAL_COLS, Math.floor(availableWidth / cellWidth)),
735
+ cols: capAutoFitTerminalColumns(Math.max(MIN_TERMINAL_COLS, Math.floor(availableWidth / cellWidth))),
697
736
  rows: Math.max(MIN_TERMINAL_ROWS, Math.floor(availableHeight / cellHeight)),
698
737
  };
699
738
  }
@@ -705,13 +744,19 @@ export class TerminalCore {
705
744
  if (!geometry) {
706
745
  return null;
707
746
  }
708
- const cols = Math.floor(Number(geometry.cols));
747
+ const cellWidth = Number(geometry.cellWidth);
748
+ const hostWidth = Number(this.viewportHost?.clientWidth ?? this.container.clientWidth);
749
+ const visibleCellWidth = cellWidth / this.presentationScale;
750
+ const cols = Number.isFinite(hostWidth) && hostWidth > 0
751
+ && Number.isFinite(visibleCellWidth) && visibleCellWidth > 0
752
+ ? Math.floor(Math.max(0, hostWidth - this.fit.scrollbarReservePx) / visibleCellWidth)
753
+ : Math.floor(Number(geometry.cols));
709
754
  const rows = Math.floor(Number(geometry.rows));
710
755
  if (!Number.isFinite(cols) || !Number.isFinite(rows) || cols <= 0 || rows <= 0) {
711
756
  return null;
712
757
  }
713
758
  return {
714
- cols: Math.max(MIN_TERMINAL_COLS, cols),
759
+ cols: capAutoFitTerminalColumns(Math.max(MIN_TERMINAL_COLS, cols)),
715
760
  rows: Math.max(MIN_TERMINAL_ROWS, rows),
716
761
  };
717
762
  }
@@ -1529,6 +1574,8 @@ export class TerminalCore {
1529
1574
  if (typeof this.terminal.onScroll === 'function') {
1530
1575
  const disposable = this.terminal.onScroll(() => {
1531
1576
  this.syncImeInputAnchor();
1577
+ this.scrollbarOverlay?.reveal();
1578
+ this.scrollbarOverlay?.sync();
1532
1579
  this.requestDemandRender(false);
1533
1580
  });
1534
1581
  this.trackTerminalEventDisposable(disposable);
@@ -1816,6 +1863,7 @@ export class TerminalCore {
1816
1863
  else {
1817
1864
  this.requestDemandRender(shouldForceAfterWrite);
1818
1865
  }
1866
+ this.scrollbarOverlay?.sync();
1819
1867
  callback?.();
1820
1868
  probe?.onTerminalWriteProfile?.({
1821
1869
  totalMs: performance.now() - profileStartedAt,
@@ -1915,6 +1963,16 @@ export class TerminalCore {
1915
1963
  });
1916
1964
  }
1917
1965
  getResourceEstimate() {
1966
+ const wasmMemoryBytes = this.ownedRuntimeMemory?.buffer.byteLength ?? 0;
1967
+ if (wasmMemoryBytes <= 0) {
1968
+ return {
1969
+ bufferBytes: 0,
1970
+ cellCount: 0,
1971
+ wasmMemoryBytes: 0,
1972
+ estimatedBytes: 0,
1973
+ rendererType: this.config.rendererType ?? 'canvas',
1974
+ };
1975
+ }
1918
1976
  const info = this.getTerminalInfo();
1919
1977
  const cellCount = info ? Math.max(0, info.cols * info.bufferLength) : 0;
1920
1978
  let bufferBytes = 0;
@@ -1926,7 +1984,8 @@ export class TerminalCore {
1926
1984
  return {
1927
1985
  bufferBytes,
1928
1986
  cellCount,
1929
- estimatedBytes: ESTIMATED_RENDERER_BYTES + bufferBytes + cellCount * ESTIMATED_CELL_BYTES,
1987
+ wasmMemoryBytes,
1988
+ estimatedBytes: ESTIMATED_RENDERER_BYTES + wasmMemoryBytes,
1930
1989
  rendererType: this.config.rendererType ?? 'canvas',
1931
1990
  };
1932
1991
  }
@@ -2742,11 +2801,19 @@ export class TerminalCore {
2742
2801
  this.setPresentationScale(appearance.presentationScale);
2743
2802
  }
2744
2803
  }
2804
+ setScrollbarOptions(options) {
2805
+ normalizeTerminalScrollbarOptions(options);
2806
+ const next = normalizeTerminalScrollbarOptions({ ...this.scrollbarOptions, ...options });
2807
+ this.scrollbarOptions = next;
2808
+ this.config = { ...this.config, scrollbar: next };
2809
+ this.scrollbarOverlay?.setOptions(next);
2810
+ }
2745
2811
  setTheme(theme) {
2746
2812
  const mapped = mapThemeToGhostty(theme);
2747
2813
  // Persist latest theme so a future re-initialization can reuse it.
2748
2814
  this.config = { ...this.config, theme: mapped };
2749
2815
  this.themeColorTranslator = buildThemeColorTranslator(this.terminalThemeSource, mapped);
2816
+ this.scrollbarOverlay?.setBackgroundColor(mapped.background);
2750
2817
  if (!this.terminal) {
2751
2818
  return;
2752
2819
  }
@@ -2886,6 +2953,8 @@ export class TerminalCore {
2886
2953
  this.disposeInputBridge();
2887
2954
  this.disposeTerminalEventListeners();
2888
2955
  this.disposeSearchOverlay();
2956
+ this.scrollbarOverlay?.dispose();
2957
+ this.scrollbarOverlay = null;
2889
2958
  this.fabricAttachSeq += 1;
2890
2959
  this.cancelFabricAttachSchedule?.();
2891
2960
  this.cancelFabricAttachSchedule = null;
@@ -2895,10 +2964,14 @@ export class TerminalCore {
2895
2964
  this.fabricView = null;
2896
2965
  this.terminal?.dispose();
2897
2966
  this.terminal = null;
2967
+ this.ownedRuntimeMemory = null;
2968
+ this.ownedRuntime = null;
2898
2969
  this.inputElement?.remove();
2899
2970
  this.inputElement = null;
2971
+ this.viewportHost?.remove();
2900
2972
  this.viewportHost = null;
2901
2973
  this.renderHost = null;
2974
+ this.fitAddon = null;
2902
2975
  this.registeredLinkProviders.clear();
2903
2976
  this.appliedLinkProviders.clear();
2904
2977
  this.setState(TerminalState.DISPOSED);
@@ -3151,6 +3224,7 @@ export class TerminalCore {
3151
3224
  terminalAny.cursorMoveEmitter?.fire?.();
3152
3225
  }
3153
3226
  this.syncImeInputAnchor();
3227
+ this.scrollbarOverlay?.sync();
3154
3228
  const durationMs = performance.now() - startedAt;
3155
3229
  getPerfProbe()?.onTerminalRender?.(durationMs);
3156
3230
  if (this.config.rendererType !== 'webgl'
@@ -3183,12 +3257,10 @@ export class TerminalCore {
3183
3257
  presentationRequest.frameHandle = requestAnimationFrame(() => {
3184
3258
  if (!this.presentationRequests.has(presentationRequest))
3185
3259
  return;
3186
- presentationRequest.frameHandle = requestAnimationFrame(() => {
3187
- if (!this.presentationRequests.delete(presentationRequest))
3188
- return;
3189
- presentationRequest.frameHandle = null;
3190
- presentationRequest.resolve();
3191
- });
3260
+ if (!this.presentationRequests.delete(presentationRequest))
3261
+ return;
3262
+ presentationRequest.frameHandle = null;
3263
+ presentationRequest.resolve();
3192
3264
  });
3193
3265
  }
3194
3266
  }