@xterm/xterm 6.1.0-beta.18 → 6.1.0-beta.180

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 (156) hide show
  1. package/README.md +60 -38
  2. package/css/xterm.css +29 -22
  3. package/lib/xterm.js +1 -1
  4. package/lib/xterm.js.map +1 -1
  5. package/lib/xterm.mjs +8 -34
  6. package/lib/xterm.mjs.map +4 -4
  7. package/package.json +25 -14
  8. package/src/browser/AccessibilityManager.ts +6 -3
  9. package/src/browser/Clipboard.ts +6 -3
  10. package/src/browser/CoreBrowserTerminal.ts +142 -62
  11. package/src/browser/Dom.ts +178 -0
  12. package/src/browser/Linkifier.ts +3 -3
  13. package/src/browser/OscLinkProvider.ts +3 -1
  14. package/src/browser/RenderDebouncer.ts +2 -2
  15. package/src/browser/TimeBasedDebouncer.ts +2 -2
  16. package/src/browser/Types.ts +12 -11
  17. package/src/browser/Viewport.ts +40 -17
  18. package/src/browser/decorations/BufferDecorationRenderer.ts +1 -1
  19. package/src/browser/decorations/OverviewRulerRenderer.ts +15 -16
  20. package/src/browser/input/CompositionHelper.ts +16 -1
  21. package/src/browser/public/Terminal.ts +24 -27
  22. package/src/browser/renderer/dom/DomRenderer.ts +128 -8
  23. package/src/browser/renderer/dom/DomRendererRowFactory.ts +19 -13
  24. package/src/browser/renderer/dom/WidthCache.ts +54 -52
  25. package/src/browser/renderer/shared/Constants.ts +7 -0
  26. package/src/browser/renderer/shared/TextBlinkStateManager.ts +97 -0
  27. package/src/browser/renderer/shared/Types.ts +8 -2
  28. package/src/browser/scrollable/abstractScrollbar.ts +300 -0
  29. package/src/browser/scrollable/fastDomNode.ts +126 -0
  30. package/src/browser/scrollable/globalPointerMoveMonitor.ts +90 -0
  31. package/src/browser/scrollable/horizontalScrollbar.ts +85 -0
  32. package/src/browser/scrollable/mouseEvent.ts +292 -0
  33. package/src/browser/scrollable/scrollable.ts +486 -0
  34. package/src/browser/scrollable/scrollableElement.ts +579 -0
  35. package/src/browser/scrollable/scrollableElementOptions.ts +161 -0
  36. package/src/browser/scrollable/scrollbarArrow.ts +110 -0
  37. package/src/browser/scrollable/scrollbarState.ts +246 -0
  38. package/src/browser/scrollable/scrollbarVisibilityController.ts +113 -0
  39. package/src/browser/scrollable/touch.ts +481 -0
  40. package/src/browser/scrollable/verticalScrollbar.ts +143 -0
  41. package/src/browser/scrollable/widget.ts +23 -0
  42. package/src/browser/services/CharSizeService.ts +2 -2
  43. package/src/browser/services/CoreBrowserService.ts +7 -5
  44. package/src/browser/services/KeyboardService.ts +67 -0
  45. package/src/browser/services/LinkProviderService.ts +1 -1
  46. package/src/browser/services/MouseService.ts +2 -1
  47. package/src/browser/services/RenderService.ts +22 -15
  48. package/src/browser/services/SelectionService.ts +12 -4
  49. package/src/browser/services/Services.ts +24 -15
  50. package/src/browser/services/ThemeService.ts +2 -2
  51. package/src/common/Async.ts +105 -0
  52. package/src/common/CircularList.ts +2 -2
  53. package/src/common/Color.ts +8 -0
  54. package/src/common/CoreTerminal.ts +21 -11
  55. package/src/common/Event.ts +118 -0
  56. package/src/common/InputHandler.ts +244 -24
  57. package/src/common/Lifecycle.ts +113 -0
  58. package/src/common/Platform.ts +13 -3
  59. package/src/common/SortedList.ts +7 -3
  60. package/src/common/TaskQueue.ts +9 -3
  61. package/src/common/Types.ts +29 -9
  62. package/src/common/Version.ts +9 -0
  63. package/src/common/buffer/Buffer.ts +20 -14
  64. package/src/common/buffer/BufferLine.ts +4 -5
  65. package/src/common/buffer/BufferSet.ts +7 -6
  66. package/src/common/buffer/CellData.ts +57 -0
  67. package/src/common/buffer/Marker.ts +2 -2
  68. package/src/common/buffer/Types.ts +6 -2
  69. package/src/common/data/EscapeSequences.ts +71 -70
  70. package/src/common/input/Keyboard.ts +14 -7
  71. package/src/common/input/KittyKeyboard.ts +491 -0
  72. package/src/common/input/Win32InputMode.ts +297 -0
  73. package/src/common/input/WriteBuffer.ts +34 -2
  74. package/src/common/input/XParseColor.ts +2 -2
  75. package/src/common/parser/ApcParser.ts +245 -0
  76. package/src/common/parser/Constants.ts +22 -4
  77. package/src/common/parser/DcsParser.ts +5 -5
  78. package/src/common/parser/EscapeSequenceParser.ts +75 -22
  79. package/src/common/parser/OscParser.ts +5 -5
  80. package/src/common/parser/Types.ts +34 -1
  81. package/src/common/public/BufferLineApiView.ts +2 -2
  82. package/src/common/public/BufferNamespaceApi.ts +2 -2
  83. package/src/common/public/ParserApi.ts +3 -0
  84. package/src/common/services/BufferService.ts +8 -5
  85. package/src/common/services/CharsetService.ts +4 -0
  86. package/src/common/services/CoreMouseService.ts +2 -2
  87. package/src/common/services/CoreService.ts +18 -4
  88. package/src/common/services/DecorationService.ts +24 -8
  89. package/src/common/services/LogService.ts +1 -31
  90. package/src/common/services/OptionsService.ts +13 -4
  91. package/src/common/services/Services.ts +39 -16
  92. package/src/common/services/UnicodeService.ts +1 -1
  93. package/typings/xterm.d.ts +319 -35
  94. package/src/common/TypedArrayUtils.ts +0 -17
  95. package/src/vs/base/browser/browser.ts +0 -141
  96. package/src/vs/base/browser/canIUse.ts +0 -49
  97. package/src/vs/base/browser/dom.ts +0 -2369
  98. package/src/vs/base/browser/fastDomNode.ts +0 -316
  99. package/src/vs/base/browser/globalPointerMoveMonitor.ts +0 -112
  100. package/src/vs/base/browser/iframe.ts +0 -135
  101. package/src/vs/base/browser/keyboardEvent.ts +0 -213
  102. package/src/vs/base/browser/mouseEvent.ts +0 -229
  103. package/src/vs/base/browser/touch.ts +0 -372
  104. package/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts +0 -303
  105. package/src/vs/base/browser/ui/scrollbar/horizontalScrollbar.ts +0 -114
  106. package/src/vs/base/browser/ui/scrollbar/scrollableElement.ts +0 -720
  107. package/src/vs/base/browser/ui/scrollbar/scrollableElementOptions.ts +0 -165
  108. package/src/vs/base/browser/ui/scrollbar/scrollbarArrow.ts +0 -114
  109. package/src/vs/base/browser/ui/scrollbar/scrollbarState.ts +0 -243
  110. package/src/vs/base/browser/ui/scrollbar/scrollbarVisibilityController.ts +0 -118
  111. package/src/vs/base/browser/ui/scrollbar/verticalScrollbar.ts +0 -116
  112. package/src/vs/base/browser/ui/widget.ts +0 -57
  113. package/src/vs/base/browser/window.ts +0 -14
  114. package/src/vs/base/common/arrays.ts +0 -887
  115. package/src/vs/base/common/arraysFind.ts +0 -202
  116. package/src/vs/base/common/assert.ts +0 -71
  117. package/src/vs/base/common/async.ts +0 -1992
  118. package/src/vs/base/common/cancellation.ts +0 -148
  119. package/src/vs/base/common/charCode.ts +0 -450
  120. package/src/vs/base/common/collections.ts +0 -140
  121. package/src/vs/base/common/decorators.ts +0 -130
  122. package/src/vs/base/common/equals.ts +0 -146
  123. package/src/vs/base/common/errors.ts +0 -303
  124. package/src/vs/base/common/event.ts +0 -1778
  125. package/src/vs/base/common/functional.ts +0 -32
  126. package/src/vs/base/common/hash.ts +0 -316
  127. package/src/vs/base/common/iterator.ts +0 -159
  128. package/src/vs/base/common/keyCodes.ts +0 -526
  129. package/src/vs/base/common/keybindings.ts +0 -284
  130. package/src/vs/base/common/lazy.ts +0 -47
  131. package/src/vs/base/common/lifecycle.ts +0 -801
  132. package/src/vs/base/common/linkedList.ts +0 -142
  133. package/src/vs/base/common/map.ts +0 -202
  134. package/src/vs/base/common/numbers.ts +0 -98
  135. package/src/vs/base/common/observable.ts +0 -76
  136. package/src/vs/base/common/observableInternal/api.ts +0 -31
  137. package/src/vs/base/common/observableInternal/autorun.ts +0 -281
  138. package/src/vs/base/common/observableInternal/base.ts +0 -489
  139. package/src/vs/base/common/observableInternal/debugName.ts +0 -145
  140. package/src/vs/base/common/observableInternal/derived.ts +0 -428
  141. package/src/vs/base/common/observableInternal/lazyObservableValue.ts +0 -146
  142. package/src/vs/base/common/observableInternal/logging.ts +0 -328
  143. package/src/vs/base/common/observableInternal/promise.ts +0 -209
  144. package/src/vs/base/common/observableInternal/utils.ts +0 -610
  145. package/src/vs/base/common/platform.ts +0 -281
  146. package/src/vs/base/common/scrollable.ts +0 -522
  147. package/src/vs/base/common/sequence.ts +0 -34
  148. package/src/vs/base/common/stopwatch.ts +0 -43
  149. package/src/vs/base/common/strings.ts +0 -557
  150. package/src/vs/base/common/symbols.ts +0 -9
  151. package/src/vs/base/common/uint.ts +0 -59
  152. package/src/vs/patches/nls.ts +0 -90
  153. package/src/vs/typings/base-common.d.ts +0 -20
  154. package/src/vs/typings/require.d.ts +0 -42
  155. package/src/vs/typings/vscode-globals-nls.d.ts +0 -36
  156. package/src/vs/typings/vscode-globals-product.d.ts +0 -33
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xterm/xterm",
3
3
  "description": "Full xterm terminal, in your browser",
4
- "version": "6.1.0-beta.18",
4
+ "version": "6.1.0-beta.180",
5
5
  "main": "lib/xterm.js",
6
6
  "module": "lib/xterm.mjs",
7
7
  "style": "css/xterm.css",
@@ -27,29 +27,37 @@
27
27
  "xterm"
28
28
  ],
29
29
  "scripts": {
30
- "setup": "npm run build",
30
+ "presetup": "npm run build",
31
+ "setup": "npm run esbuild",
32
+ "postsetup": "npm run esbuild-demo-server",
31
33
  "start": "node demo/start",
34
+ "dev": "concurrently -k -p [{name}] -n tsc,esbuild,esbuild-demo-client,esbuild-demo-server,server -c blue,yellow,cyan,green,magenta \"npm:tsc-watch\" \"npm:esbuild-watch\" \"npm:esbuild-demo-client-watch\" \"npm:esbuild-demo-server-watch\" \"npm:start\"",
32
35
  "build": "npm run tsc",
33
36
  "watch": "npm run tsc-watch",
34
- "tsc": "tsc -b ./tsconfig.all.json",
35
- "tsc-watch": "tsc -b -w ./tsconfig.all.json --preserveWatchOutput",
37
+ "tsc": "tsgo -b ./tsconfig.all.json",
38
+ "tsc-watch": "tsgo -b -w ./tsconfig.all.json --preserveWatchOutput",
36
39
  "esbuild": "node bin/esbuild_all.mjs",
37
40
  "esbuild-watch": "node bin/esbuild_all.mjs --watch",
38
41
  "esbuild-package": "node bin/esbuild_all.mjs --prod",
39
42
  "esbuild-package-watch": "node bin/esbuild_all.mjs --prod --watch",
40
43
  "esbuild-package-headless-only": "node bin/esbuild.mjs --prod --headless",
41
- "esbuild-demo": "node bin/esbuild.mjs --demo-client",
42
- "esbuild-demo-watch": "node bin/esbuild.mjs --demo-client --watch",
44
+ "esbuild-demo-client": "node bin/esbuild.mjs --demo-client",
45
+ "esbuild-demo-client-watch": "node bin/esbuild.mjs --demo-client --watch",
46
+ "esbuild-demo-server": "node bin/esbuild.mjs --demo-server",
47
+ "esbuild-demo-server-watch": "node bin/esbuild.mjs --demo-server --watch",
43
48
  "test": "npm run test-unit",
44
49
  "posttest": "npm run lint",
45
- "lint": "eslint --max-warnings 0 src/ addons/",
46
- "lint-fix": "eslint --fix src/ addons/",
50
+ "lint": "eslint --max-warnings 0 src/ addons/ demo/ test/",
51
+ "lint-changes": "node ./bin/lint_changes.js",
52
+ "lint-changes-fix": "node ./bin/lint_changes.js --fix",
53
+ "lint-fix": "eslint --fix src/ addons/ demo/ test/",
47
54
  "lint-api": "eslint --config eslint.config.typings.mjs --max-warnings 0 typings/",
48
55
  "test-unit": "node ./bin/test_unit.js",
56
+ "test-unit-slow-tests": "npm run test-unit | grep \"ms)\"",
49
57
  "test-unit-coverage": "node ./bin/test_unit.js --coverage",
50
58
  "test-unit-dev": "cross-env NODE_PATH='./out' mocha",
51
59
  "test-integration": "node ./bin/test_integration.js --workers=75%",
52
- "test-integration-chromium": "node ./bin/test_integration.js --workers=75% \"--project=ChromeStable\"",
60
+ "test-integration-chromium": "node ./bin/test_integration.js --workers=75% \"--project=Chromium\"",
53
61
  "test-integration-firefox": "node ./bin/test_integration.js --workers=75% \"--project=FirefoxStable\"",
54
62
  "test-integration-webkit": "node ./bin/test_integration.js --workers=75% \"--project=WebKit\"",
55
63
  "test-integration-debug": "node ./bin/test_integration.js --workers=1 --headed --timeout=30000",
@@ -64,11 +72,12 @@
64
72
  "prepackage-headless": "npm run esbuild-package-headless-only",
65
73
  "package-headless": "webpack --config ./webpack.config.headless.js",
66
74
  "postpackage-headless": "node ./bin/package_headless.js",
67
- "prepublishOnly": "npm run package"
75
+ "prepublishOnly": "npm run package",
76
+ "agent:setup-repo": "node bin/agent/setup-repo.mjs"
68
77
  },
69
78
  "devDependencies": {
70
79
  "@lunapaint/png-codec": "^0.2.0",
71
- "@playwright/test": "^1.37.1",
80
+ "@playwright/test": "^1.57.0",
72
81
  "@stylistic/eslint-plugin": "^4.4.1",
73
82
  "@types/chai": "^4.2.22",
74
83
  "@types/debug": "^4.1.7",
@@ -84,7 +93,9 @@
84
93
  "@types/ws": "^8.2.0",
85
94
  "@typescript-eslint/eslint-plugin": "^8.50.1",
86
95
  "@typescript-eslint/parser": "^8.50.1",
96
+ "@typescript/native-preview": "^7.0.0-dev.20260213.1",
87
97
  "chai": "^4.3.4",
98
+ "concurrently": "^9.1.2",
88
99
  "cross-env": "^7.0.3",
89
100
  "deep-equal": "^2.0.5",
90
101
  "esbuild": "~0.25.2",
@@ -95,12 +106,12 @@
95
106
  "jsdom": "^27.3.0",
96
107
  "mocha": "^10.1.0",
97
108
  "mustache": "^4.2.0",
98
- "node-pty": "1.1.0-beta19",
109
+ "node-pty": "^1.2.0-beta.9",
99
110
  "nyc": "^17.1.0",
100
111
  "source-map-loader": "^3.0.0",
101
112
  "source-map-support": "^0.5.20",
102
113
  "ts-loader": "^9.3.1",
103
- "typescript": "5.5",
114
+ "typescript": "^5.9.3",
104
115
  "typescript-eslint": "^8.50.1",
105
116
  "utf8": "^3.0.0",
106
117
  "webpack": "^5.61.0",
@@ -108,5 +119,5 @@
108
119
  "ws": "^8.2.3",
109
120
  "xterm-benchmark": "^0.3.1"
110
121
  },
111
- "commit": "a3d6bf671084b659d92502421d7fe1a45c563f15"
122
+ "commit": "783c4a34d296480f29ecddfb8743e4e542e29cf5"
112
123
  }
@@ -6,11 +6,11 @@
6
6
  import * as Strings from 'browser/LocalizableStrings';
7
7
  import { ITerminal, IRenderDebouncer } from 'browser/Types';
8
8
  import { TimeBasedDebouncer } from 'browser/TimeBasedDebouncer';
9
- import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
9
+ import { Disposable, toDisposable } from 'common/Lifecycle';
10
10
  import { ICoreBrowserService, IRenderService } from 'browser/services/Services';
11
11
  import { IBuffer } from 'common/buffer/Types';
12
12
  import { IInstantiationService } from 'common/services/Services';
13
- import { addDisposableListener } from 'vs/base/browser/dom';
13
+ import { addDisposableListener } from 'browser/Dom';
14
14
 
15
15
  const MAX_ROWS_TO_READ = 20;
16
16
 
@@ -151,7 +151,7 @@ export class AccessibilityManager extends Disposable {
151
151
  if (char === '\n') {
152
152
  this._liveRegionLineCount++;
153
153
  if (this._liveRegionLineCount === MAX_ROWS_TO_READ + 1) {
154
- this._liveRegion.textContent += Strings.tooMuchOutput.get();
154
+ this._liveRegion.textContent = Strings.tooMuchOutput.get();
155
155
  }
156
156
  }
157
157
  }
@@ -203,6 +203,9 @@ export class AccessibilityManager extends Disposable {
203
203
  if (this._charsToAnnounce.length === 0) {
204
204
  return;
205
205
  }
206
+ if (this._liveRegion.textContent === Strings.tooMuchOutput.get()) {
207
+ this._clearLiveRegion();
208
+ }
206
209
  this._liveRegion.textContent += this._charsToAnnounce;
207
210
  this._charsToAnnounce = '';
208
211
  }
@@ -19,10 +19,13 @@ export function prepareTextForTerminal(text: string): string {
19
19
  * @param text The pasted text to bracket
20
20
  */
21
21
  export function bracketTextForPaste(text: string, bracketedPasteMode: boolean): string {
22
- if (bracketedPasteMode) {
23
- return '\x1b[200~' + text + '\x1b[201~';
22
+ if (!bracketedPasteMode) {
23
+ return text;
24
24
  }
25
- return text;
25
+ // Sanitize pasted text to prevent injected escape sequences (e.g. exiting bracketed paste)
26
+ // by replacing ESC (\x1b) with its visible representation U+241B (␛).
27
+ const sanitizedText = text.replace(/\x1b/g, '\u241b');
28
+ return `\x1b[200~${sanitizedText}\x1b[201~`;
26
29
  }
27
30
 
28
31
  /**
@@ -21,7 +21,7 @@
21
21
  * http://linux.die.net/man/7/urxvt
22
22
  */
23
23
 
24
- import { IDecoration, IDecorationOptions, IDisposable, ILinkProvider, IMarker } from '@xterm/xterm';
24
+ import { IDecoration, IDecorationOptions, IDisposable, ILinkProvider, IMarker, IRenderDimensions as IRenderDimensionsApi } from '@xterm/xterm';
25
25
  import { copyHandler, handlePasteEvent, moveTextAreaUnderMouseCursor, paste, rightClickHandler } from 'browser/Clipboard';
26
26
  import * as Strings from 'browser/LocalizableStrings';
27
27
  import { OscLinkProvider } from 'browser/OscLinkProvider';
@@ -39,25 +39,25 @@ import { LinkProviderService } from 'browser/services/LinkProviderService';
39
39
  import { MouseService } from 'browser/services/MouseService';
40
40
  import { RenderService } from 'browser/services/RenderService';
41
41
  import { SelectionService } from 'browser/services/SelectionService';
42
- import { ICharSizeService, ICharacterJoinerService, ICoreBrowserService, ILinkProviderService, IMouseService, IRenderService, ISelectionService, IThemeService } from 'browser/services/Services';
42
+ import { ICharSizeService, ICharacterJoinerService, ICoreBrowserService, IKeyboardService, ILinkProviderService, IMouseService, IRenderService, ISelectionService, IThemeService } from 'browser/services/Services';
43
43
  import { ThemeService } from 'browser/services/ThemeService';
44
- import { channels, color } from 'common/Color';
44
+ import { KeyboardService } from 'browser/services/KeyboardService';
45
+ import { channels, color, rgb } from 'common/Color';
45
46
  import { CoreTerminal } from 'common/CoreTerminal';
46
47
  import * as Browser from 'common/Platform';
47
48
  import { ColorRequestType, CoreMouseAction, CoreMouseButton, CoreMouseEventType, IColorEvent, ITerminalOptions, KeyboardResultType, SpecialColorIndex } from 'common/Types';
48
49
  import { DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine';
49
50
  import { IBuffer } from 'common/buffer/Types';
50
- import { C0, C1_ESCAPED } from 'common/data/EscapeSequences';
51
- import { evaluateKeyboardEvent } from 'common/input/Keyboard';
51
+ import { C0, C1ESCAPED } from 'common/data/EscapeSequences';
52
52
  import { toRgbString } from 'common/input/XParseColor';
53
53
  import { DecorationService } from 'common/services/DecorationService';
54
54
  import { IDecorationService } from 'common/services/Services';
55
55
  import { WindowsOptionsReportType } from '../common/InputHandler';
56
56
  import { AccessibilityManager } from './AccessibilityManager';
57
57
  import { Linkifier } from './Linkifier';
58
- import { Emitter, Event } from 'vs/base/common/event';
59
- import { addDisposableListener } from 'vs/base/browser/dom';
60
- import { MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
58
+ import { Emitter, EventUtils, type IEvent } from 'common/Event';
59
+ import { addDisposableListener } from 'browser/Dom';
60
+ import { MutableDisposable, toDisposable } from 'common/Lifecycle';
61
61
 
62
62
  export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
63
63
  public textarea: HTMLTextAreaElement | undefined;
@@ -80,8 +80,9 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
80
80
  private _customWheelEventHandler: CustomWheelEventHandler | undefined;
81
81
 
82
82
  // Browser services
83
- private _decorationService: DecorationService;
84
- private _linkProviderService: ILinkProviderService;
83
+ private readonly _decorationService: DecorationService;
84
+ private readonly _keyboardService: IKeyboardService;
85
+ private readonly _linkProviderService: ILinkProviderService;
85
86
 
86
87
  // Optional browser services
87
88
  private _charSizeService: ICharSizeService | undefined;
@@ -126,8 +127,6 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
126
127
  public readonly onCursorMove = this._onCursorMove.event;
127
128
  private readonly _onKey = this._register(new Emitter<{ key: string, domEvent: KeyboardEvent }>());
128
129
  public readonly onKey = this._onKey.event;
129
- private readonly _onRender = this._register(new Emitter<{ start: number, end: number }>());
130
- public readonly onRender = this._onRender.event;
131
130
  private readonly _onSelectionChange = this._register(new Emitter<void>());
132
131
  public readonly onSelectionChange = this._onSelectionChange.event;
133
132
  private readonly _onTitleChange = this._register(new Emitter<string>());
@@ -136,15 +135,35 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
136
135
  public readonly onBell = this._onBell.event;
137
136
 
138
137
  private _onFocus = this._register(new Emitter<void>());
139
- public get onFocus(): Event<void> { return this._onFocus.event; }
138
+ public get onFocus(): IEvent<void> { return this._onFocus.event; }
140
139
  private _onBlur = this._register(new Emitter<void>());
141
- public get onBlur(): Event<void> { return this._onBlur.event; }
140
+ public get onBlur(): IEvent<void> { return this._onBlur.event; }
142
141
  private _onA11yCharEmitter = this._register(new Emitter<string>());
143
- public get onA11yChar(): Event<string> { return this._onA11yCharEmitter.event; }
142
+ public get onA11yChar(): IEvent<string> { return this._onA11yCharEmitter.event; }
144
143
  private _onA11yTabEmitter = this._register(new Emitter<number>());
145
- public get onA11yTab(): Event<number> { return this._onA11yTabEmitter.event; }
144
+ public get onA11yTab(): IEvent<number> { return this._onA11yTabEmitter.event; }
146
145
  private _onWillOpen = this._register(new Emitter<HTMLElement>());
147
- public get onWillOpen(): Event<HTMLElement> { return this._onWillOpen.event; }
146
+ public get onWillOpen(): IEvent<HTMLElement> { return this._onWillOpen.event; }
147
+ private readonly _onDimensionsChange = this._register(new Emitter<IRenderDimensionsApi>());
148
+ public readonly onDimensionsChange = this._onDimensionsChange.event;
149
+
150
+ public get dimensions(): IRenderDimensionsApi | undefined {
151
+ if (!this._renderService) {
152
+ return undefined;
153
+ }
154
+ const dimensions = this._renderService.dimensions;
155
+ return {
156
+ css: {
157
+ canvas: { ...dimensions.css.canvas },
158
+ cell: { ...dimensions.css.cell }
159
+ },
160
+ device: {
161
+ canvas: { ...dimensions.device.canvas },
162
+ cell: { ...dimensions.device.cell },
163
+ char: { ...dimensions.device.char }
164
+ }
165
+ };
166
+ }
148
167
 
149
168
  constructor(
150
169
  options: Partial<ITerminalOptions> = {}
@@ -155,6 +174,8 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
155
174
 
156
175
  this._decorationService = this._instantiationService.createInstance(DecorationService);
157
176
  this._instantiationService.setService(IDecorationService, this._decorationService);
177
+ this._keyboardService = this._instantiationService.createInstance(KeyboardService);
178
+ this._instantiationService.setService(IKeyboardService, this._keyboardService);
158
179
  this._linkProviderService = this._instantiationService.createInstance(LinkProviderService);
159
180
  this._instantiationService.setService(ILinkProviderService, this._linkProviderService);
160
181
  this._linkProviderService.registerLinkProvider(this._instantiationService.createInstance(OscLinkProvider));
@@ -166,10 +187,10 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
166
187
  this._register(this._inputHandler.onRequestReset(() => this.reset()));
167
188
  this._register(this._inputHandler.onRequestWindowsOptionsReport(type => this._reportWindowsOptions(type)));
168
189
  this._register(this._inputHandler.onColor((event) => this._handleColorEvent(event)));
169
- this._register(Event.forward(this._inputHandler.onCursorMove, this._onCursorMove));
170
- this._register(Event.forward(this._inputHandler.onTitleChange, this._onTitleChange));
171
- this._register(Event.forward(this._inputHandler.onA11yChar, this._onA11yCharEmitter));
172
- this._register(Event.forward(this._inputHandler.onA11yTab, this._onA11yTabEmitter));
190
+ this._register(EventUtils.forward(this._inputHandler.onCursorMove, this._onCursorMove));
191
+ this._register(EventUtils.forward(this._inputHandler.onTitleChange, this._onTitleChange));
192
+ this._register(EventUtils.forward(this._inputHandler.onA11yChar, this._onA11yCharEmitter));
193
+ this._register(EventUtils.forward(this._inputHandler.onA11yTab, this._onA11yTabEmitter));
173
194
 
174
195
  // Setup listeners
175
196
  this._register(this._bufferService.onResize(e => this._afterResize(e.cols, e.rows)));
@@ -214,7 +235,7 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
214
235
  const colorRgb = color.toColorRGB(acc === 'ansi'
215
236
  ? this._themeService.colors.ansi[req.index]
216
237
  : this._themeService.colors[acc]);
217
- this.coreService.triggerDataEvent(`${C0.ESC}]${ident};${toRgbString(colorRgb)}${C1_ESCAPED.ST}`);
238
+ this.coreService.triggerDataEvent(`${C0.ESC}]${ident};${toRgbString(colorRgb)}${C1ESCAPED.ST}`);
218
239
  break;
219
240
  case ColorRequestType.SET:
220
241
  if (acc === 'ansi') {
@@ -231,6 +252,20 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
231
252
  }
232
253
  }
233
254
 
255
+ /**
256
+ * Reports the current color scheme (dark or light) based on the relative luminance
257
+ * of the background and foreground theme colors.
258
+ * Sends CSI ? 997 ; 1 n for dark mode or CSI ? 997 ; 2 n for light mode.
259
+ */
260
+ private _reportColorScheme(): void {
261
+ if (!this._themeService) return;
262
+ const bgLuminance = rgb.relativeLuminance(this._themeService.colors.background.rgba >> 8);
263
+ const fgLuminance = rgb.relativeLuminance(this._themeService.colors.foreground.rgba >> 8);
264
+ // Dark mode = background is darker than foreground (lower luminance)
265
+ const colorSchemeMode = bgLuminance < fgLuminance ? 1 : 2;
266
+ this.coreService.triggerDataEvent(`${C0.ESC}[?997;${colorSchemeMode}n`);
267
+ }
268
+
234
269
  protected _setup(): void {
235
270
  super._setup();
236
271
 
@@ -418,6 +453,8 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
418
453
  this.element.dir = 'ltr'; // xterm.css assumes LTR
419
454
  this.element.classList.add('terminal');
420
455
  this.element.classList.add('xterm');
456
+ this.element.classList.toggle('allow-transparency', this.options.allowTransparency);
457
+ this._register(this.optionsService.onSpecificOptionChange('allowTransparency', value => this.element!.classList.toggle('allow-transparency', value)));
421
458
  parent.appendChild(this.element);
422
459
 
423
460
  // Performance: Use a document fragment to build the terminal
@@ -472,12 +509,33 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
472
509
  this._themeService = this._instantiationService.createInstance(ThemeService);
473
510
  this._instantiationService.setService(IThemeService, this._themeService);
474
511
 
512
+ // CSI ? 996 n - color scheme query (https://contour-terminal.org/vt-extensions/color-palette-update-notifications/)
513
+ this._register(this._inputHandler.onRequestColorSchemeQuery(() => this._reportColorScheme()));
514
+
515
+ // Emit unsolicited color scheme notification on theme change when DECSET 2031 is enabled
516
+ this._register(this._themeService.onChangeColors(() => {
517
+ if (this.coreService.decPrivateModes.colorSchemeUpdates) {
518
+ this._reportColorScheme();
519
+ }
520
+ }));
521
+
475
522
  this._characterJoinerService = this._instantiationService.createInstance(CharacterJoinerService);
476
523
  this._instantiationService.setService(ICharacterJoinerService, this._characterJoinerService);
477
524
 
478
525
  this._renderService = this._register(this._instantiationService.createInstance(RenderService, this.rows, this.screenElement));
479
526
  this._instantiationService.setService(IRenderService, this._renderService);
480
527
  this._register(this._renderService.onRenderedViewportChange(e => this._onRender.fire(e)));
528
+ this._register(this._renderService.onDimensionsChange(e => this._onDimensionsChange.fire({
529
+ css: {
530
+ canvas: { ...e.css.canvas },
531
+ cell: { ...e.css.cell }
532
+ },
533
+ device: {
534
+ canvas: { ...e.device.canvas },
535
+ cell: { ...e.device.cell },
536
+ char: { ...e.device.char }
537
+ }
538
+ })));
481
539
  this.onResize(e => this._renderService!.resize(e.cols, e.rows));
482
540
 
483
541
  this._compositionView = this._document.createElement('div');
@@ -532,7 +590,7 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
532
590
  this.textarea!.focus();
533
591
  this.textarea!.select();
534
592
  }));
535
- this._register(Event.any(
593
+ this._register(EventUtils.any(
536
594
  this._onScroll.event,
537
595
  this._inputHandler.onScroll
538
596
  )(() => {
@@ -558,11 +616,14 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
558
616
  }
559
617
  this._register(this.optionsService.onSpecificOptionChange('screenReaderMode', e => this._handleScreenReaderModeOptionChange(e)));
560
618
 
561
- if (this.options.overviewRuler.width) {
619
+ const showScrollbar = this.options.scrollbar?.showScrollbar ?? true;
620
+ const overviewRulerWidth = this.options.scrollbar?.width;
621
+ if (showScrollbar && overviewRulerWidth) {
562
622
  this._overviewRulerRenderer = this._register(this._instantiationService.createInstance(OverviewRulerRenderer, this._viewportElement, this.screenElement));
563
623
  }
564
- this.optionsService.onSpecificOptionChange('overviewRuler', value => {
565
- if (!this._overviewRulerRenderer && value && this._viewportElement && this.screenElement) {
624
+ this.optionsService.onSpecificOptionChange('scrollbar', value => {
625
+ const shouldShow = (value?.showScrollbar ?? true) && !!value?.width;
626
+ if (!this._overviewRulerRenderer && shouldShow && this._viewportElement && this.screenElement) {
566
627
  this._overviewRulerRenderer = this._register(this._instantiationService.createInstance(OverviewRulerRenderer, this._viewportElement, this.screenElement));
567
628
  }
568
629
  });
@@ -605,8 +666,8 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
605
666
 
606
667
  // send event to CoreMouseService
607
668
  function sendEvent(ev: MouseEvent | WheelEvent): boolean {
608
- // get mouse coordinates
609
- const pos = self._mouseService!.getMouseReportCoords(ev, self.screenElement!);
669
+ // Get mouse coordinates
670
+ const pos = self._mouseService?.getMouseReportCoords(ev, self.screenElement!);
610
671
  if (!pos) {
611
672
  return false;
612
673
  }
@@ -705,11 +766,12 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
705
766
  this._document!.removeEventListener('mousemove', requestedEvents.mousedrag);
706
767
  }
707
768
  }
708
- return this.cancel(ev);
709
769
  },
710
770
  wheel: (ev: WheelEvent) => {
711
771
  sendEvent(ev);
712
- return this.cancel(ev, true);
772
+ ev.preventDefault();
773
+ ev.stopPropagation();
774
+ return false;
713
775
  },
714
776
  mousedrag: (ev: MouseEvent) => {
715
777
  // deal only with move while a button is held
@@ -759,20 +821,30 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
759
821
  if (!(events & CoreMouseEventType.UP)) {
760
822
  this._document!.removeEventListener('mouseup', requestedEvents.mouseup!);
761
823
  requestedEvents.mouseup = null;
762
- } else if (!requestedEvents.mouseup) {
763
- requestedEvents.mouseup = eventListeners.mouseup;
824
+ } else {
825
+ requestedEvents.mouseup ??= eventListeners.mouseup;
764
826
  }
765
827
 
766
828
  if (!(events & CoreMouseEventType.DRAG)) {
767
829
  this._document!.removeEventListener('mousemove', requestedEvents.mousedrag!);
768
830
  requestedEvents.mousedrag = null;
769
- } else if (!requestedEvents.mousedrag) {
770
- requestedEvents.mousedrag = eventListeners.mousedrag;
831
+ } else {
832
+ requestedEvents.mousedrag ??= eventListeners.mousedrag;
771
833
  }
772
834
  }));
773
835
  // force initial onProtocolChange so we dont miss early mouse requests
774
836
  this.coreMouseService.activeProtocol = this.coreMouseService.activeProtocol;
775
837
 
838
+ // Ensure document-level listeners are removed on dispose
839
+ this._register(toDisposable(() => {
840
+ if (requestedEvents.mouseup) {
841
+ this._document!.removeEventListener('mouseup', requestedEvents.mouseup);
842
+ }
843
+ if (requestedEvents.mousedrag) {
844
+ this._document!.removeEventListener('mousemove', requestedEvents.mousedrag);
845
+ }
846
+ }));
847
+
776
848
  /**
777
849
  * "Always on" event listeners.
778
850
  */
@@ -799,8 +871,6 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
799
871
  if (requestedEvents.mousedrag) {
800
872
  this._document!.addEventListener('mousemove', requestedEvents.mousedrag);
801
873
  }
802
-
803
- return this.cancel(ev);
804
874
  }));
805
875
 
806
876
  this._register(addDisposableListener(el, 'wheel', (ev: WheelEvent) => {
@@ -831,13 +901,17 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
831
901
  self._coreBrowserService?.dpr
832
902
  );
833
903
  if (lines === 0) {
834
- return this.cancel(ev, true);
904
+ ev.preventDefault();
905
+ ev.stopPropagation();
906
+ return false;
835
907
  }
836
908
 
837
909
  // Construct and send sequences
838
910
  const sequence = C0.ESC + (this.coreService.decPrivateModes.applicationCursorKeys ? 'O' : '[') + (ev.deltaY < 0 ? 'A' : 'B');
839
911
  this.coreService.triggerDataEvent(sequence, true);
840
- return this.cancel(ev, true);
912
+ ev.preventDefault();
913
+ ev.stopPropagation();
914
+ return false;
841
915
  }
842
916
  }, { passive: false }));
843
917
  }
@@ -849,8 +923,8 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
849
923
  * @param start The row to start from (between 0 and this.rows - 1).
850
924
  * @param end The row to end at (between start and this.rows - 1).
851
925
  */
852
- public refresh(start: number, end: number): void {
853
- this._renderService?.refreshRows(start, end);
926
+ public refresh(start: number, end: number, sync: boolean = false): void {
927
+ this._renderService?.refreshRows(start, end, sync);
854
928
  }
855
929
 
856
930
  /**
@@ -1040,14 +1114,16 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
1040
1114
  this._unprocessedDeadKey = true;
1041
1115
  }
1042
1116
 
1043
- const result = evaluateKeyboardEvent(event, this.coreService.decPrivateModes.applicationCursorKeys, this.browser.isMac, this.options.macOptionIsMeta);
1117
+ const result = this._keyboardService.evaluateKeyDown(event);
1044
1118
 
1045
1119
  this.updateCursorStyle(event);
1046
1120
 
1047
1121
  if (result.type === KeyboardResultType.PAGE_DOWN || result.type === KeyboardResultType.PAGE_UP) {
1048
1122
  const scrollCount = this.rows - 1;
1049
1123
  this.scrollLines(result.type === KeyboardResultType.PAGE_UP ? -scrollCount : scrollCount);
1050
- return this.cancel(event, true);
1124
+ event.preventDefault();
1125
+ event.stopPropagation();
1126
+ return false;
1051
1127
  }
1052
1128
 
1053
1129
  if (result.type === KeyboardResultType.SELECT_ALL) {
@@ -1060,7 +1136,8 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
1060
1136
 
1061
1137
  if (result.cancel) {
1062
1138
  // The event is canceled at the end already, is this necessary?
1063
- this.cancel(event, true);
1139
+ event.preventDefault();
1140
+ event.stopPropagation();
1064
1141
  }
1065
1142
 
1066
1143
  if (!result.key) {
@@ -1068,8 +1145,9 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
1068
1145
  }
1069
1146
 
1070
1147
  // HACK: Process A-Z in the keypress event to fix an issue with macOS IMEs where lower case
1071
- // letters cannot be input while caps lock is on.
1072
- if (event.key && !event.ctrlKey && !event.altKey && !event.metaKey && event.key.length === 1) {
1148
+ // letters cannot be input while caps lock is on. Skip this hack when using kitty protocol
1149
+ // or Win32 input mode as they need to send proper sequences for all key events.
1150
+ if (!this._keyboardService.useKitty && !this._keyboardService.useWin32InputMode && event.key && !event.ctrlKey && !event.altKey && !event.metaKey && event.key.length === 1) {
1073
1151
  if (event.key.charCodeAt(0) >= 65 && event.key.charCodeAt(0) <= 90) {
1074
1152
  return true;
1075
1153
  }
@@ -1087,16 +1165,19 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
1087
1165
  this.textarea!.value = '';
1088
1166
  }
1089
1167
 
1168
+ const wasModifierOnly = this._keyboardService.useWin32InputMode && wasModifierKeyOnlyEvent(event);
1090
1169
  this._onKey.fire({ key: result.key, domEvent: event });
1091
1170
  this._showCursor();
1092
- this.coreService.triggerDataEvent(result.key, true);
1171
+ this.coreService.triggerDataEvent(result.key, !wasModifierOnly);
1093
1172
 
1094
1173
  // Cancel events when not in screen reader mode so events don't get bubbled up and handled by
1095
1174
  // other listeners. When screen reader mode is enabled, we don't cancel them (unless ctrl or alt
1096
1175
  // is also depressed) so that the cursor textarea can be updated, which triggers the screen
1097
1176
  // reader to read it.
1098
1177
  if (!this.optionsService.rawOptions.screenReaderMode || event.altKey || event.ctrlKey) {
1099
- return this.cancel(event, true);
1178
+ event.preventDefault();
1179
+ event.stopPropagation();
1180
+ return false;
1100
1181
  }
1101
1182
 
1102
1183
  this._keyDownHandled = true;
@@ -1127,6 +1208,13 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
1127
1208
  this.focus();
1128
1209
  }
1129
1210
 
1211
+ // Handle key release for Kitty keyboard protocol
1212
+ const result = this._keyboardService.evaluateKeyUp(ev);
1213
+ if (result?.key) {
1214
+ const wasModifierOnly = this._keyboardService.useWin32InputMode && wasModifierKeyOnlyEvent(ev);
1215
+ this.coreService.triggerDataEvent(result.key, !wasModifierOnly);
1216
+ }
1217
+
1130
1218
  this.updateCursorStyle(ev);
1131
1219
  this._keyPressHandled = false;
1132
1220
  }
@@ -1150,8 +1238,6 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
1150
1238
  return false;
1151
1239
  }
1152
1240
 
1153
- this.cancel(ev);
1154
-
1155
1241
  if (ev.charCode) {
1156
1242
  key = ev.charCode;
1157
1243
  } else if (ev.which === null || ev.which === undefined) {
@@ -1204,8 +1290,6 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
1204
1290
 
1205
1291
  const text = ev.data;
1206
1292
  this.coreService.triggerDataEvent(text, true);
1207
-
1208
- this.cancel(ev);
1209
1293
  return true;
1210
1294
  }
1211
1295
 
@@ -1283,7 +1367,7 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
1283
1367
  this._customKeyEventHandler = customKeyEventHandler;
1284
1368
 
1285
1369
  // do a full screen refresh
1286
- this.refresh(0, this.rows - 1);
1370
+ this.refresh(0, this.rows - 1, true);
1287
1371
  }
1288
1372
 
1289
1373
  public clearTextureAtlas(): void {
@@ -1317,15 +1401,6 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
1317
1401
  }
1318
1402
  }
1319
1403
 
1320
- // TODO: Remove cancel function and cancelEvents option
1321
- public cancel(ev: MouseEvent | WheelEvent | KeyboardEvent | InputEvent, force?: boolean): boolean | undefined {
1322
- if (!this.options.cancelEvents && !force) {
1323
- return;
1324
- }
1325
- ev.preventDefault();
1326
- ev.stopPropagation();
1327
- return false;
1328
- }
1329
1404
  }
1330
1405
 
1331
1406
  /**
@@ -1335,5 +1410,10 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal {
1335
1410
  function wasModifierKeyOnlyEvent(ev: KeyboardEvent): boolean {
1336
1411
  return ev.keyCode === 16 || // Shift
1337
1412
  ev.keyCode === 17 || // Ctrl
1338
- ev.keyCode === 18; // Alt
1413
+ ev.keyCode === 18 || // Alt
1414
+ ev.keyCode === 91 || // Meta (Left)
1415
+ ev.keyCode === 92 || // Meta (Right)
1416
+ ev.keyCode === 93 || // Meta (Menu)
1417
+ ev.keyCode === 224 || // Meta (Firefox)
1418
+ ev.key === 'Meta';
1339
1419
  }