@wendongfly/zihi 1.0.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 (145) hide show
  1. package/bin/daemon.js +23 -0
  2. package/bin/zihi.js +603 -0
  3. package/dist/admin.html +297 -0
  4. package/dist/attach.js +2 -0
  5. package/dist/chat.html +2254 -0
  6. package/dist/client-dist/socket.io.esm.min.js +7 -0
  7. package/dist/client-dist/socket.io.js +4955 -0
  8. package/dist/client-dist/socket.io.min.js +7 -0
  9. package/dist/client-dist/socket.io.msgpack.min.js +7 -0
  10. package/dist/files.html +722 -0
  11. package/dist/icon.png +0 -0
  12. package/dist/icon.svg +4 -0
  13. package/dist/index.html +976 -0
  14. package/dist/index.js +485 -0
  15. package/dist/lib/ansi_up.js +431 -0
  16. package/dist/lib/xterm/LICENSE +21 -0
  17. package/dist/lib/xterm/README.md +230 -0
  18. package/dist/lib/xterm/css/xterm.css +209 -0
  19. package/dist/lib/xterm/lib/xterm.js +2 -0
  20. package/dist/lib/xterm/lib/xterm.js.map +1 -0
  21. package/dist/lib/xterm/package.json +100 -0
  22. package/dist/lib/xterm/src/browser/AccessibilityManager.ts +300 -0
  23. package/dist/lib/xterm/src/browser/Clipboard.ts +93 -0
  24. package/dist/lib/xterm/src/browser/ColorContrastCache.ts +34 -0
  25. package/dist/lib/xterm/src/browser/Lifecycle.ts +33 -0
  26. package/dist/lib/xterm/src/browser/Linkifier2.ts +416 -0
  27. package/dist/lib/xterm/src/browser/LocalizableStrings.ts +12 -0
  28. package/dist/lib/xterm/src/browser/OscLinkProvider.ts +128 -0
  29. package/dist/lib/xterm/src/browser/RenderDebouncer.ts +83 -0
  30. package/dist/lib/xterm/src/browser/ScreenDprMonitor.ts +72 -0
  31. package/dist/lib/xterm/src/browser/Terminal.ts +1305 -0
  32. package/dist/lib/xterm/src/browser/TimeBasedDebouncer.ts +86 -0
  33. package/dist/lib/xterm/src/browser/Types.d.ts +181 -0
  34. package/dist/lib/xterm/src/browser/Viewport.ts +401 -0
  35. package/dist/lib/xterm/src/browser/decorations/BufferDecorationRenderer.ts +134 -0
  36. package/dist/lib/xterm/src/browser/decorations/ColorZoneStore.ts +117 -0
  37. package/dist/lib/xterm/src/browser/decorations/OverviewRulerRenderer.ts +219 -0
  38. package/dist/lib/xterm/src/browser/input/CompositionHelper.ts +246 -0
  39. package/dist/lib/xterm/src/browser/input/Mouse.ts +54 -0
  40. package/dist/lib/xterm/src/browser/input/MoveToCell.ts +249 -0
  41. package/dist/lib/xterm/src/browser/public/Terminal.ts +260 -0
  42. package/dist/lib/xterm/src/browser/renderer/dom/DomRenderer.ts +506 -0
  43. package/dist/lib/xterm/src/browser/renderer/dom/DomRendererRowFactory.ts +522 -0
  44. package/dist/lib/xterm/src/browser/renderer/dom/WidthCache.ts +157 -0
  45. package/dist/lib/xterm/src/browser/renderer/shared/CellColorResolver.ts +137 -0
  46. package/dist/lib/xterm/src/browser/renderer/shared/CharAtlasCache.ts +96 -0
  47. package/dist/lib/xterm/src/browser/renderer/shared/CharAtlasUtils.ts +75 -0
  48. package/dist/lib/xterm/src/browser/renderer/shared/Constants.ts +14 -0
  49. package/dist/lib/xterm/src/browser/renderer/shared/CursorBlinkStateManager.ts +146 -0
  50. package/dist/lib/xterm/src/browser/renderer/shared/CustomGlyphs.ts +687 -0
  51. package/dist/lib/xterm/src/browser/renderer/shared/DevicePixelObserver.ts +41 -0
  52. package/dist/lib/xterm/src/browser/renderer/shared/README.md +1 -0
  53. package/dist/lib/xterm/src/browser/renderer/shared/RendererUtils.ts +58 -0
  54. package/dist/lib/xterm/src/browser/renderer/shared/SelectionRenderModel.ts +91 -0
  55. package/dist/lib/xterm/src/browser/renderer/shared/TextureAtlas.ts +1082 -0
  56. package/dist/lib/xterm/src/browser/renderer/shared/Types.d.ts +173 -0
  57. package/dist/lib/xterm/src/browser/selection/SelectionModel.ts +144 -0
  58. package/dist/lib/xterm/src/browser/selection/Types.d.ts +15 -0
  59. package/dist/lib/xterm/src/browser/services/CharSizeService.ts +102 -0
  60. package/dist/lib/xterm/src/browser/services/CharacterJoinerService.ts +339 -0
  61. package/dist/lib/xterm/src/browser/services/CoreBrowserService.ts +33 -0
  62. package/dist/lib/xterm/src/browser/services/MouseService.ts +46 -0
  63. package/dist/lib/xterm/src/browser/services/RenderService.ts +284 -0
  64. package/dist/lib/xterm/src/browser/services/SelectionService.ts +1029 -0
  65. package/dist/lib/xterm/src/browser/services/Services.ts +138 -0
  66. package/dist/lib/xterm/src/browser/services/ThemeService.ts +237 -0
  67. package/dist/lib/xterm/src/common/CircularList.ts +241 -0
  68. package/dist/lib/xterm/src/common/Clone.ts +23 -0
  69. package/dist/lib/xterm/src/common/Color.ts +356 -0
  70. package/dist/lib/xterm/src/common/CoreTerminal.ts +284 -0
  71. package/dist/lib/xterm/src/common/EventEmitter.ts +73 -0
  72. package/dist/lib/xterm/src/common/InputHandler.ts +3443 -0
  73. package/dist/lib/xterm/src/common/Lifecycle.ts +108 -0
  74. package/dist/lib/xterm/src/common/MultiKeyMap.ts +42 -0
  75. package/dist/lib/xterm/src/common/Platform.ts +43 -0
  76. package/dist/lib/xterm/src/common/SortedList.ts +118 -0
  77. package/dist/lib/xterm/src/common/TaskQueue.ts +166 -0
  78. package/dist/lib/xterm/src/common/TypedArrayUtils.ts +17 -0
  79. package/dist/lib/xterm/src/common/Types.d.ts +553 -0
  80. package/dist/lib/xterm/src/common/WindowsMode.ts +27 -0
  81. package/dist/lib/xterm/src/common/buffer/AttributeData.ts +196 -0
  82. package/dist/lib/xterm/src/common/buffer/Buffer.ts +654 -0
  83. package/dist/lib/xterm/src/common/buffer/BufferLine.ts +520 -0
  84. package/dist/lib/xterm/src/common/buffer/BufferRange.ts +13 -0
  85. package/dist/lib/xterm/src/common/buffer/BufferReflow.ts +223 -0
  86. package/dist/lib/xterm/src/common/buffer/BufferSet.ts +134 -0
  87. package/dist/lib/xterm/src/common/buffer/CellData.ts +94 -0
  88. package/dist/lib/xterm/src/common/buffer/Constants.ts +149 -0
  89. package/dist/lib/xterm/src/common/buffer/Marker.ts +43 -0
  90. package/dist/lib/xterm/src/common/buffer/Types.d.ts +52 -0
  91. package/dist/lib/xterm/src/common/data/Charsets.ts +256 -0
  92. package/dist/lib/xterm/src/common/data/EscapeSequences.ts +153 -0
  93. package/dist/lib/xterm/src/common/input/Keyboard.ts +398 -0
  94. package/dist/lib/xterm/src/common/input/TextDecoder.ts +346 -0
  95. package/dist/lib/xterm/src/common/input/UnicodeV6.ts +132 -0
  96. package/dist/lib/xterm/src/common/input/WriteBuffer.ts +246 -0
  97. package/dist/lib/xterm/src/common/input/XParseColor.ts +80 -0
  98. package/dist/lib/xterm/src/common/parser/Constants.ts +58 -0
  99. package/dist/lib/xterm/src/common/parser/DcsParser.ts +192 -0
  100. package/dist/lib/xterm/src/common/parser/EscapeSequenceParser.ts +792 -0
  101. package/dist/lib/xterm/src/common/parser/OscParser.ts +238 -0
  102. package/dist/lib/xterm/src/common/parser/Params.ts +229 -0
  103. package/dist/lib/xterm/src/common/parser/Types.d.ts +274 -0
  104. package/dist/lib/xterm/src/common/public/AddonManager.ts +53 -0
  105. package/dist/lib/xterm/src/common/public/BufferApiView.ts +35 -0
  106. package/dist/lib/xterm/src/common/public/BufferLineApiView.ts +29 -0
  107. package/dist/lib/xterm/src/common/public/BufferNamespaceApi.ts +36 -0
  108. package/dist/lib/xterm/src/common/public/ParserApi.ts +37 -0
  109. package/dist/lib/xterm/src/common/public/UnicodeApi.ts +27 -0
  110. package/dist/lib/xterm/src/common/services/BufferService.ts +151 -0
  111. package/dist/lib/xterm/src/common/services/CharsetService.ts +34 -0
  112. package/dist/lib/xterm/src/common/services/CoreMouseService.ts +318 -0
  113. package/dist/lib/xterm/src/common/services/CoreService.ts +87 -0
  114. package/dist/lib/xterm/src/common/services/DecorationService.ts +140 -0
  115. package/dist/lib/xterm/src/common/services/InstantiationService.ts +85 -0
  116. package/dist/lib/xterm/src/common/services/LogService.ts +124 -0
  117. package/dist/lib/xterm/src/common/services/OptionsService.ts +201 -0
  118. package/dist/lib/xterm/src/common/services/OscLinkService.ts +115 -0
  119. package/dist/lib/xterm/src/common/services/ServiceRegistry.ts +49 -0
  120. package/dist/lib/xterm/src/common/services/Services.ts +342 -0
  121. package/dist/lib/xterm/src/common/services/UnicodeService.ts +86 -0
  122. package/dist/lib/xterm/src/headless/Terminal.ts +136 -0
  123. package/dist/lib/xterm/src/headless/public/Terminal.ts +195 -0
  124. package/dist/lib/xterm/typings/xterm.d.ts +1844 -0
  125. package/dist/lib/xterm-fit/LICENSE +19 -0
  126. package/dist/lib/xterm-fit/README.md +24 -0
  127. package/dist/lib/xterm-fit/lib/xterm-addon-fit.js +2 -0
  128. package/dist/lib/xterm-fit/lib/xterm-addon-fit.js.map +1 -0
  129. package/dist/lib/xterm-fit/package.json +26 -0
  130. package/dist/lib/xterm-fit/src/FitAddon.ts +89 -0
  131. package/dist/lib/xterm-fit/typings/xterm-addon-fit.d.ts +55 -0
  132. package/dist/lib/xterm-links/LICENSE +19 -0
  133. package/dist/lib/xterm-links/README.md +21 -0
  134. package/dist/lib/xterm-links/lib/xterm-addon-web-links.js +2 -0
  135. package/dist/lib/xterm-links/lib/xterm-addon-web-links.js.map +1 -0
  136. package/dist/lib/xterm-links/package.json +26 -0
  137. package/dist/lib/xterm-links/src/WebLinkProvider.ts +198 -0
  138. package/dist/lib/xterm-links/src/WebLinksAddon.ts +57 -0
  139. package/dist/lib/xterm-links/typings/xterm-addon-web-links.d.ts +53 -0
  140. package/dist/login.html +163 -0
  141. package/dist/manifest.json +12 -0
  142. package/dist/package.json +1 -0
  143. package/dist/sw.js +127 -0
  144. package/dist/sync.html +816 -0
  145. package/package.json +47 -0
@@ -0,0 +1,339 @@
1
+ /**
2
+ * Copyright (c) 2018 The xterm.js authors. All rights reserved.
3
+ * @license MIT
4
+ */
5
+
6
+ import { IBufferLine, ICellData, CharData } from 'common/Types';
7
+ import { ICharacterJoiner } from 'browser/Types';
8
+ import { AttributeData } from 'common/buffer/AttributeData';
9
+ import { WHITESPACE_CELL_CHAR, Content } from 'common/buffer/Constants';
10
+ import { CellData } from 'common/buffer/CellData';
11
+ import { IBufferService } from 'common/services/Services';
12
+ import { ICharacterJoinerService } from 'browser/services/Services';
13
+
14
+ export class JoinedCellData extends AttributeData implements ICellData {
15
+ private _width: number;
16
+ // .content carries no meaning for joined CellData, simply nullify it
17
+ // thus we have to overload all other .content accessors
18
+ public content: number = 0;
19
+ public fg: number;
20
+ public bg: number;
21
+ public combinedData: string = '';
22
+
23
+ constructor(firstCell: ICellData, chars: string, width: number) {
24
+ super();
25
+ this.fg = firstCell.fg;
26
+ this.bg = firstCell.bg;
27
+ this.combinedData = chars;
28
+ this._width = width;
29
+ }
30
+
31
+ public isCombined(): number {
32
+ // always mark joined cell data as combined
33
+ return Content.IS_COMBINED_MASK;
34
+ }
35
+
36
+ public getWidth(): number {
37
+ return this._width;
38
+ }
39
+
40
+ public getChars(): string {
41
+ return this.combinedData;
42
+ }
43
+
44
+ public getCode(): number {
45
+ // code always gets the highest possible fake codepoint (read as -1)
46
+ // this is needed as code is used by caches as identifier
47
+ return 0x1FFFFF;
48
+ }
49
+
50
+ public setFromCharData(value: CharData): void {
51
+ throw new Error('not implemented');
52
+ }
53
+
54
+ public getAsCharData(): CharData {
55
+ return [this.fg, this.getChars(), this.getWidth(), this.getCode()];
56
+ }
57
+ }
58
+
59
+ export class CharacterJoinerService implements ICharacterJoinerService {
60
+ public serviceBrand: undefined;
61
+
62
+ private _characterJoiners: ICharacterJoiner[] = [];
63
+ private _nextCharacterJoinerId: number = 0;
64
+ private _workCell: CellData = new CellData();
65
+
66
+ constructor(
67
+ @IBufferService private _bufferService: IBufferService
68
+ ) { }
69
+
70
+ public register(handler: (text: string) => [number, number][]): number {
71
+ const joiner: ICharacterJoiner = {
72
+ id: this._nextCharacterJoinerId++,
73
+ handler
74
+ };
75
+
76
+ this._characterJoiners.push(joiner);
77
+ return joiner.id;
78
+ }
79
+
80
+ public deregister(joinerId: number): boolean {
81
+ for (let i = 0; i < this._characterJoiners.length; i++) {
82
+ if (this._characterJoiners[i].id === joinerId) {
83
+ this._characterJoiners.splice(i, 1);
84
+ return true;
85
+ }
86
+ }
87
+
88
+ return false;
89
+ }
90
+
91
+ public getJoinedCharacters(row: number): [number, number][] {
92
+ if (this._characterJoiners.length === 0) {
93
+ return [];
94
+ }
95
+
96
+ const line = this._bufferService.buffer.lines.get(row);
97
+ if (!line || line.length === 0) {
98
+ return [];
99
+ }
100
+
101
+ const ranges: [number, number][] = [];
102
+ const lineStr = line.translateToString(true);
103
+
104
+ // Because some cells can be represented by multiple javascript characters,
105
+ // we track the cell and the string indexes separately. This allows us to
106
+ // translate the string ranges we get from the joiners back into cell ranges
107
+ // for use when rendering
108
+ let rangeStartColumn = 0;
109
+ let currentStringIndex = 0;
110
+ let rangeStartStringIndex = 0;
111
+ let rangeAttrFG = line.getFg(0);
112
+ let rangeAttrBG = line.getBg(0);
113
+
114
+ for (let x = 0; x < line.getTrimmedLength(); x++) {
115
+ line.loadCell(x, this._workCell);
116
+
117
+ if (this._workCell.getWidth() === 0) {
118
+ // If this character is of width 0, skip it.
119
+ continue;
120
+ }
121
+
122
+ // End of range
123
+ if (this._workCell.fg !== rangeAttrFG || this._workCell.bg !== rangeAttrBG) {
124
+ // If we ended up with a sequence of more than one character,
125
+ // look for ranges to join.
126
+ if (x - rangeStartColumn > 1) {
127
+ const joinedRanges = this._getJoinedRanges(
128
+ lineStr,
129
+ rangeStartStringIndex,
130
+ currentStringIndex,
131
+ line,
132
+ rangeStartColumn
133
+ );
134
+ for (let i = 0; i < joinedRanges.length; i++) {
135
+ ranges.push(joinedRanges[i]);
136
+ }
137
+ }
138
+
139
+ // Reset our markers for a new range.
140
+ rangeStartColumn = x;
141
+ rangeStartStringIndex = currentStringIndex;
142
+ rangeAttrFG = this._workCell.fg;
143
+ rangeAttrBG = this._workCell.bg;
144
+ }
145
+
146
+ currentStringIndex += this._workCell.getChars().length || WHITESPACE_CELL_CHAR.length;
147
+ }
148
+
149
+ // Process any trailing ranges.
150
+ if (this._bufferService.cols - rangeStartColumn > 1) {
151
+ const joinedRanges = this._getJoinedRanges(
152
+ lineStr,
153
+ rangeStartStringIndex,
154
+ currentStringIndex,
155
+ line,
156
+ rangeStartColumn
157
+ );
158
+ for (let i = 0; i < joinedRanges.length; i++) {
159
+ ranges.push(joinedRanges[i]);
160
+ }
161
+ }
162
+
163
+ return ranges;
164
+ }
165
+
166
+ /**
167
+ * Given a segment of a line of text, find all ranges of text that should be
168
+ * joined in a single rendering unit. Ranges are internally converted to
169
+ * column ranges, rather than string ranges.
170
+ * @param line String representation of the full line of text
171
+ * @param startIndex Start position of the range to search in the string (inclusive)
172
+ * @param endIndex End position of the range to search in the string (exclusive)
173
+ */
174
+ private _getJoinedRanges(line: string, startIndex: number, endIndex: number, lineData: IBufferLine, startCol: number): [number, number][] {
175
+ const text = line.substring(startIndex, endIndex);
176
+ // At this point we already know that there is at least one joiner so
177
+ // we can just pull its value and assign it directly rather than
178
+ // merging it into an empty array, which incurs unnecessary writes.
179
+ let allJoinedRanges: [number, number][] = [];
180
+ try {
181
+ allJoinedRanges = this._characterJoiners[0].handler(text);
182
+ } catch (error) {
183
+ console.error(error);
184
+ }
185
+ for (let i = 1; i < this._characterJoiners.length; i++) {
186
+ // We merge any overlapping ranges across the different joiners
187
+ try {
188
+ const joinerRanges = this._characterJoiners[i].handler(text);
189
+ for (let j = 0; j < joinerRanges.length; j++) {
190
+ CharacterJoinerService._mergeRanges(allJoinedRanges, joinerRanges[j]);
191
+ }
192
+ } catch (error) {
193
+ console.error(error);
194
+ }
195
+ }
196
+ this._stringRangesToCellRanges(allJoinedRanges, lineData, startCol);
197
+ return allJoinedRanges;
198
+ }
199
+
200
+ /**
201
+ * Modifies the provided ranges in-place to adjust for variations between
202
+ * string length and cell width so that the range represents a cell range,
203
+ * rather than the string range the joiner provides.
204
+ * @param ranges String ranges containing start (inclusive) and end (exclusive) index
205
+ * @param line Cell data for the relevant line in the terminal
206
+ * @param startCol Offset within the line to start from
207
+ */
208
+ private _stringRangesToCellRanges(ranges: [number, number][], line: IBufferLine, startCol: number): void {
209
+ let currentRangeIndex = 0;
210
+ let currentRangeStarted = false;
211
+ let currentStringIndex = 0;
212
+ let currentRange = ranges[currentRangeIndex];
213
+
214
+ // If we got through all of the ranges, stop searching
215
+ if (!currentRange) {
216
+ return;
217
+ }
218
+
219
+ for (let x = startCol; x < this._bufferService.cols; x++) {
220
+ const width = line.getWidth(x);
221
+ const length = line.getString(x).length || WHITESPACE_CELL_CHAR.length;
222
+
223
+ // We skip zero-width characters when creating the string to join the text
224
+ // so we do the same here
225
+ if (width === 0) {
226
+ continue;
227
+ }
228
+
229
+ // Adjust the start of the range
230
+ if (!currentRangeStarted && currentRange[0] <= currentStringIndex) {
231
+ currentRange[0] = x;
232
+ currentRangeStarted = true;
233
+ }
234
+
235
+ // Adjust the end of the range
236
+ if (currentRange[1] <= currentStringIndex) {
237
+ currentRange[1] = x;
238
+
239
+ // We're finished with this range, so we move to the next one
240
+ currentRange = ranges[++currentRangeIndex];
241
+
242
+ // If there are no more ranges left, stop searching
243
+ if (!currentRange) {
244
+ break;
245
+ }
246
+
247
+ // Ranges can be on adjacent characters. Because the end index of the
248
+ // ranges are exclusive, this means that the index for the start of a
249
+ // range can be the same as the end index of the previous range. To
250
+ // account for the start of the next range, we check here just in case.
251
+ if (currentRange[0] <= currentStringIndex) {
252
+ currentRange[0] = x;
253
+ currentRangeStarted = true;
254
+ } else {
255
+ currentRangeStarted = false;
256
+ }
257
+ }
258
+
259
+ // Adjust the string index based on the character length to line up with
260
+ // the column adjustment
261
+ currentStringIndex += length;
262
+ }
263
+
264
+ // If there is still a range left at the end, it must extend all the way to
265
+ // the end of the line.
266
+ if (currentRange) {
267
+ currentRange[1] = this._bufferService.cols;
268
+ }
269
+ }
270
+
271
+ /**
272
+ * Merges the range defined by the provided start and end into the list of
273
+ * existing ranges. The merge is done in place on the existing range for
274
+ * performance and is also returned.
275
+ * @param ranges Existing range list
276
+ * @param newRange Tuple of two numbers representing the new range to merge in.
277
+ * @returns The ranges input with the new range merged in place
278
+ */
279
+ private static _mergeRanges(ranges: [number, number][], newRange: [number, number]): [number, number][] {
280
+ let inRange = false;
281
+ for (let i = 0; i < ranges.length; i++) {
282
+ const range = ranges[i];
283
+ if (!inRange) {
284
+ if (newRange[1] <= range[0]) {
285
+ // Case 1: New range is before the search range
286
+ ranges.splice(i, 0, newRange);
287
+ return ranges;
288
+ }
289
+
290
+ if (newRange[1] <= range[1]) {
291
+ // Case 2: New range is either wholly contained within the
292
+ // search range or overlaps with the front of it
293
+ range[0] = Math.min(newRange[0], range[0]);
294
+ return ranges;
295
+ }
296
+
297
+ if (newRange[0] < range[1]) {
298
+ // Case 3: New range either wholly contains the search range
299
+ // or overlaps with the end of it
300
+ range[0] = Math.min(newRange[0], range[0]);
301
+ inRange = true;
302
+ }
303
+
304
+ // Case 4: New range starts after the search range
305
+ continue;
306
+ } else {
307
+ if (newRange[1] <= range[0]) {
308
+ // Case 5: New range extends from previous range but doesn't
309
+ // reach the current one
310
+ ranges[i - 1][1] = newRange[1];
311
+ return ranges;
312
+ }
313
+
314
+ if (newRange[1] <= range[1]) {
315
+ // Case 6: New range extends from prvious range into the
316
+ // current range
317
+ ranges[i - 1][1] = Math.max(newRange[1], range[1]);
318
+ ranges.splice(i, 1);
319
+ return ranges;
320
+ }
321
+
322
+ // Case 7: New range extends from previous range past the
323
+ // end of the current range
324
+ ranges.splice(i, 1);
325
+ i--;
326
+ }
327
+ }
328
+
329
+ if (inRange) {
330
+ // Case 8: New range extends past the last existing range
331
+ ranges[ranges.length - 1][1] = newRange[1];
332
+ } else {
333
+ // Case 9: New range starts after the last existing range
334
+ ranges.push(newRange);
335
+ }
336
+
337
+ return ranges;
338
+ }
339
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Copyright (c) 2019 The xterm.js authors. All rights reserved.
3
+ * @license MIT
4
+ */
5
+
6
+ import { ICoreBrowserService } from './Services';
7
+
8
+ export class CoreBrowserService implements ICoreBrowserService {
9
+ public serviceBrand: undefined;
10
+
11
+ private _isFocused = false;
12
+ private _cachedIsFocused: boolean | undefined = undefined;
13
+
14
+ constructor(
15
+ private _textarea: HTMLTextAreaElement,
16
+ public readonly window: Window & typeof globalThis
17
+ ) {
18
+ this._textarea.addEventListener('focus', () => this._isFocused = true);
19
+ this._textarea.addEventListener('blur', () => this._isFocused = false);
20
+ }
21
+
22
+ public get dpr(): number {
23
+ return this.window.devicePixelRatio;
24
+ }
25
+
26
+ public get isFocused(): boolean {
27
+ if (this._cachedIsFocused === undefined) {
28
+ this._cachedIsFocused = this._isFocused && this._textarea.ownerDocument.hasFocus();
29
+ queueMicrotask(() => this._cachedIsFocused = undefined);
30
+ }
31
+ return this._cachedIsFocused;
32
+ }
33
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Copyright (c) 2017 The xterm.js authors. All rights reserved.
3
+ * @license MIT
4
+ */
5
+
6
+ import { ICharSizeService, IRenderService, IMouseService } from './Services';
7
+ import { getCoords, getCoordsRelativeToElement } from 'browser/input/Mouse';
8
+
9
+ export class MouseService implements IMouseService {
10
+ public serviceBrand: undefined;
11
+
12
+ constructor(
13
+ @IRenderService private readonly _renderService: IRenderService,
14
+ @ICharSizeService private readonly _charSizeService: ICharSizeService
15
+ ) {
16
+ }
17
+
18
+ public getCoords(event: {clientX: number, clientY: number}, element: HTMLElement, colCount: number, rowCount: number, isSelection?: boolean): [number, number] | undefined {
19
+ return getCoords(
20
+ window,
21
+ event,
22
+ element,
23
+ colCount,
24
+ rowCount,
25
+ this._charSizeService.hasValidSize,
26
+ this._renderService.dimensions.css.cell.width,
27
+ this._renderService.dimensions.css.cell.height,
28
+ isSelection
29
+ );
30
+ }
31
+
32
+ public getMouseReportCoords(event: MouseEvent, element: HTMLElement): { col: number, row: number, x: number, y: number } | undefined {
33
+ const coords = getCoordsRelativeToElement(window, event, element);
34
+ if (!this._charSizeService.hasValidSize) {
35
+ return undefined;
36
+ }
37
+ coords[0] = Math.min(Math.max(coords[0], 0), this._renderService.dimensions.css.canvas.width - 1);
38
+ coords[1] = Math.min(Math.max(coords[1], 0), this._renderService.dimensions.css.canvas.height - 1);
39
+ return {
40
+ col: Math.floor(coords[0] / this._renderService.dimensions.css.cell.width),
41
+ row: Math.floor(coords[1] / this._renderService.dimensions.css.cell.height),
42
+ x: Math.floor(coords[0]),
43
+ y: Math.floor(coords[1])
44
+ };
45
+ }
46
+ }
@@ -0,0 +1,284 @@
1
+ /**
2
+ * Copyright (c) 2019 The xterm.js authors. All rights reserved.
3
+ * @license MIT
4
+ */
5
+
6
+ import { addDisposableDomListener } from 'browser/Lifecycle';
7
+ import { RenderDebouncer } from 'browser/RenderDebouncer';
8
+ import { ScreenDprMonitor } from 'browser/ScreenDprMonitor';
9
+ import { IRenderDebouncerWithCallback } from 'browser/Types';
10
+ import { IRenderDimensions, IRenderer } from 'browser/renderer/shared/Types';
11
+ import { ICharSizeService, ICoreBrowserService, IRenderService, IThemeService } from 'browser/services/Services';
12
+ import { EventEmitter } from 'common/EventEmitter';
13
+ import { Disposable, MutableDisposable } from 'common/Lifecycle';
14
+ import { DebouncedIdleTask } from 'common/TaskQueue';
15
+ import { IBufferService, IDecorationService, IOptionsService } from 'common/services/Services';
16
+
17
+ interface ISelectionState {
18
+ start: [number, number] | undefined;
19
+ end: [number, number] | undefined;
20
+ columnSelectMode: boolean;
21
+ }
22
+
23
+ export class RenderService extends Disposable implements IRenderService {
24
+ public serviceBrand: undefined;
25
+
26
+ private _renderer: MutableDisposable<IRenderer> = this.register(new MutableDisposable());
27
+ private _renderDebouncer: IRenderDebouncerWithCallback;
28
+ private _screenDprMonitor: ScreenDprMonitor;
29
+ private _pausedResizeTask = new DebouncedIdleTask();
30
+
31
+ private _isPaused: boolean = false;
32
+ private _needsFullRefresh: boolean = false;
33
+ private _isNextRenderRedrawOnly: boolean = true;
34
+ private _needsSelectionRefresh: boolean = false;
35
+ private _canvasWidth: number = 0;
36
+ private _canvasHeight: number = 0;
37
+ private _selectionState: ISelectionState = {
38
+ start: undefined,
39
+ end: undefined,
40
+ columnSelectMode: false
41
+ };
42
+
43
+ private readonly _onDimensionsChange = this.register(new EventEmitter<IRenderDimensions>());
44
+ public readonly onDimensionsChange = this._onDimensionsChange.event;
45
+ private readonly _onRenderedViewportChange = this.register(new EventEmitter<{ start: number, end: number }>());
46
+ public readonly onRenderedViewportChange = this._onRenderedViewportChange.event;
47
+ private readonly _onRender = this.register(new EventEmitter<{ start: number, end: number }>());
48
+ public readonly onRender = this._onRender.event;
49
+ private readonly _onRefreshRequest = this.register(new EventEmitter<{ start: number, end: number }>());
50
+ public readonly onRefreshRequest = this._onRefreshRequest.event;
51
+
52
+ public get dimensions(): IRenderDimensions { return this._renderer.value!.dimensions; }
53
+
54
+ constructor(
55
+ private _rowCount: number,
56
+ screenElement: HTMLElement,
57
+ @IOptionsService optionsService: IOptionsService,
58
+ @ICharSizeService private readonly _charSizeService: ICharSizeService,
59
+ @IDecorationService decorationService: IDecorationService,
60
+ @IBufferService bufferService: IBufferService,
61
+ @ICoreBrowserService coreBrowserService: ICoreBrowserService,
62
+ @IThemeService themeService: IThemeService
63
+ ) {
64
+ super();
65
+
66
+ this._renderDebouncer = new RenderDebouncer(coreBrowserService.window, (start, end) => this._renderRows(start, end));
67
+ this.register(this._renderDebouncer);
68
+
69
+ this._screenDprMonitor = new ScreenDprMonitor(coreBrowserService.window);
70
+ this._screenDprMonitor.setListener(() => this.handleDevicePixelRatioChange());
71
+ this.register(this._screenDprMonitor);
72
+
73
+ this.register(bufferService.onResize(() => this._fullRefresh()));
74
+ this.register(bufferService.buffers.onBufferActivate(() => this._renderer.value?.clear()));
75
+ this.register(optionsService.onOptionChange(() => this._handleOptionsChanged()));
76
+ this.register(this._charSizeService.onCharSizeChange(() => this.handleCharSizeChanged()));
77
+
78
+ // Do a full refresh whenever any decoration is added or removed. This may not actually result
79
+ // in changes but since decorations should be used sparingly or added/removed all in the same
80
+ // frame this should have minimal performance impact.
81
+ this.register(decorationService.onDecorationRegistered(() => this._fullRefresh()));
82
+ this.register(decorationService.onDecorationRemoved(() => this._fullRefresh()));
83
+
84
+ // Clear the renderer when the a change that could affect glyphs occurs
85
+ this.register(optionsService.onMultipleOptionChange([
86
+ 'customGlyphs',
87
+ 'drawBoldTextInBrightColors',
88
+ 'letterSpacing',
89
+ 'lineHeight',
90
+ 'fontFamily',
91
+ 'fontSize',
92
+ 'fontWeight',
93
+ 'fontWeightBold',
94
+ 'minimumContrastRatio'
95
+ ], () => {
96
+ this.clear();
97
+ this.handleResize(bufferService.cols, bufferService.rows);
98
+ this._fullRefresh();
99
+ }));
100
+
101
+ // Refresh the cursor line when the cursor changes
102
+ this.register(optionsService.onMultipleOptionChange([
103
+ 'cursorBlink',
104
+ 'cursorStyle'
105
+ ], () => this.refreshRows(bufferService.buffer.y, bufferService.buffer.y, true)));
106
+
107
+ // dprchange should handle this case, we need this as well for browsers that don't support the
108
+ // matchMedia query.
109
+ this.register(addDisposableDomListener(coreBrowserService.window, 'resize', () => this.handleDevicePixelRatioChange()));
110
+
111
+ this.register(themeService.onChangeColors(() => this._fullRefresh()));
112
+
113
+ // Detect whether IntersectionObserver is detected and enable renderer pause
114
+ // and resume based on terminal visibility if so
115
+ if ('IntersectionObserver' in coreBrowserService.window) {
116
+ const observer = new coreBrowserService.window.IntersectionObserver(e => this._handleIntersectionChange(e[e.length - 1]), { threshold: 0 });
117
+ observer.observe(screenElement);
118
+ this.register({ dispose: () => observer.disconnect() });
119
+ }
120
+ }
121
+
122
+ private _handleIntersectionChange(entry: IntersectionObserverEntry): void {
123
+ this._isPaused = entry.isIntersecting === undefined ? (entry.intersectionRatio === 0) : !entry.isIntersecting;
124
+
125
+ // Terminal was hidden on open
126
+ if (!this._isPaused && !this._charSizeService.hasValidSize) {
127
+ this._charSizeService.measure();
128
+ }
129
+
130
+ if (!this._isPaused && this._needsFullRefresh) {
131
+ this._pausedResizeTask.flush();
132
+ this.refreshRows(0, this._rowCount - 1);
133
+ this._needsFullRefresh = false;
134
+ }
135
+ }
136
+
137
+ public refreshRows(start: number, end: number, isRedrawOnly: boolean = false): void {
138
+ if (this._isPaused) {
139
+ this._needsFullRefresh = true;
140
+ return;
141
+ }
142
+ if (!isRedrawOnly) {
143
+ this._isNextRenderRedrawOnly = false;
144
+ }
145
+ this._renderDebouncer.refresh(start, end, this._rowCount);
146
+ }
147
+
148
+ private _renderRows(start: number, end: number): void {
149
+ if (!this._renderer.value) {
150
+ return;
151
+ }
152
+
153
+ // Since this is debounced, a resize event could have happened between the time a refresh was
154
+ // requested and when this triggers. Clamp the values of start and end to ensure they're valid
155
+ // given the current viewport state.
156
+ start = Math.min(start, this._rowCount - 1);
157
+ end = Math.min(end, this._rowCount - 1);
158
+
159
+ // Render
160
+ this._renderer.value.renderRows(start, end);
161
+
162
+ // Update selection if needed
163
+ if (this._needsSelectionRefresh) {
164
+ this._renderer.value.handleSelectionChanged(this._selectionState.start, this._selectionState.end, this._selectionState.columnSelectMode);
165
+ this._needsSelectionRefresh = false;
166
+ }
167
+
168
+ // Fire render event only if it was not a redraw
169
+ if (!this._isNextRenderRedrawOnly) {
170
+ this._onRenderedViewportChange.fire({ start, end });
171
+ }
172
+ this._onRender.fire({ start, end });
173
+ this._isNextRenderRedrawOnly = true;
174
+ }
175
+
176
+ public resize(cols: number, rows: number): void {
177
+ this._rowCount = rows;
178
+ this._fireOnCanvasResize();
179
+ }
180
+
181
+ private _handleOptionsChanged(): void {
182
+ if (!this._renderer.value) {
183
+ return;
184
+ }
185
+ this.refreshRows(0, this._rowCount - 1);
186
+ this._fireOnCanvasResize();
187
+ }
188
+
189
+ private _fireOnCanvasResize(): void {
190
+ if (!this._renderer.value) {
191
+ return;
192
+ }
193
+ // Don't fire the event if the dimensions haven't changed
194
+ if (this._renderer.value.dimensions.css.canvas.width === this._canvasWidth && this._renderer.value.dimensions.css.canvas.height === this._canvasHeight) {
195
+ return;
196
+ }
197
+ this._onDimensionsChange.fire(this._renderer.value.dimensions);
198
+ }
199
+
200
+ public hasRenderer(): boolean {
201
+ return !!this._renderer.value;
202
+ }
203
+
204
+ public setRenderer(renderer: IRenderer): void {
205
+ this._renderer.value = renderer;
206
+ this._renderer.value.onRequestRedraw(e => this.refreshRows(e.start, e.end, true));
207
+
208
+ // Force a refresh
209
+ this._needsSelectionRefresh = true;
210
+ this._fullRefresh();
211
+ }
212
+
213
+ public addRefreshCallback(callback: FrameRequestCallback): number {
214
+ return this._renderDebouncer.addRefreshCallback(callback);
215
+ }
216
+
217
+ private _fullRefresh(): void {
218
+ if (this._isPaused) {
219
+ this._needsFullRefresh = true;
220
+ } else {
221
+ this.refreshRows(0, this._rowCount - 1);
222
+ }
223
+ }
224
+
225
+ public clearTextureAtlas(): void {
226
+ if (!this._renderer.value) {
227
+ return;
228
+ }
229
+ this._renderer.value.clearTextureAtlas?.();
230
+ this._fullRefresh();
231
+ }
232
+
233
+ public handleDevicePixelRatioChange(): void {
234
+ // Force char size measurement as DomMeasureStrategy(getBoundingClientRect) is not stable
235
+ // when devicePixelRatio changes
236
+ this._charSizeService.measure();
237
+
238
+ if (!this._renderer.value) {
239
+ return;
240
+ }
241
+ this._renderer.value.handleDevicePixelRatioChange();
242
+ this.refreshRows(0, this._rowCount - 1);
243
+ }
244
+
245
+ public handleResize(cols: number, rows: number): void {
246
+ if (!this._renderer.value) {
247
+ return;
248
+ }
249
+ if (this._isPaused) {
250
+ this._pausedResizeTask.set(() => this._renderer.value!.handleResize(cols, rows));
251
+ } else {
252
+ this._renderer.value.handleResize(cols, rows);
253
+ }
254
+ this._fullRefresh();
255
+ }
256
+
257
+ // TODO: Is this useful when we have onResize?
258
+ public handleCharSizeChanged(): void {
259
+ this._renderer.value?.handleCharSizeChanged();
260
+ }
261
+
262
+ public handleBlur(): void {
263
+ this._renderer.value?.handleBlur();
264
+ }
265
+
266
+ public handleFocus(): void {
267
+ this._renderer.value?.handleFocus();
268
+ }
269
+
270
+ public handleSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void {
271
+ this._selectionState.start = start;
272
+ this._selectionState.end = end;
273
+ this._selectionState.columnSelectMode = columnSelectMode;
274
+ this._renderer.value?.handleSelectionChanged(start, end, columnSelectMode);
275
+ }
276
+
277
+ public handleCursorMove(): void {
278
+ this._renderer.value?.handleCursorMove();
279
+ }
280
+
281
+ public clear(): void {
282
+ this._renderer.value?.clear();
283
+ }
284
+ }