chrome-devtools-frontend 1.0.941208 → 1.0.942095

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 (99) hide show
  1. package/config/gni/all_devtools_files.gni +0 -6
  2. package/config/gni/devtools_grd_files.gni +6 -12
  3. package/config/gni/devtools_image_files.gni +0 -2
  4. package/front_end/Tests.js +1 -0
  5. package/front_end/core/common/Color.ts +5 -0
  6. package/front_end/core/i18n/locales/en-US.json +16 -28
  7. package/front_end/core/i18n/locales/en-XL.json +16 -28
  8. package/front_end/core/sdk/sdk-meta.ts +17 -3
  9. package/front_end/entrypoints/devtools_app/devtools_app.json +1 -7
  10. package/front_end/entrypoints/main/MainImpl.ts +26 -0
  11. package/front_end/entrypoints/shell/shell.js +0 -11
  12. package/front_end/entrypoints/worker_app/worker_app.json +0 -4
  13. package/front_end/generated/InspectorBackendCommands.js +1 -0
  14. package/front_end/generated/protocol.d.ts +2 -0
  15. package/front_end/legacy_test_runner/legacy_test_runner.ts +10 -1
  16. package/front_end/models/formatter/SourceFormatter.ts +0 -10
  17. package/front_end/models/workspace/UISourceCode.ts +9 -42
  18. package/front_end/panels/animation/AnimationTimeline.ts +3 -3
  19. package/front_end/panels/application/ApplicationPanelSidebar.ts +3 -3
  20. package/front_end/panels/application/application-meta.ts +0 -3
  21. package/front_end/panels/console/ConsolePinPane.ts +21 -26
  22. package/front_end/panels/coverage/CoverageDecorationManager.ts +4 -5
  23. package/front_end/panels/coverage/CoverageView.ts +2 -105
  24. package/front_end/panels/css_overview/components/CSSOverviewStartView.ts +11 -56
  25. package/front_end/panels/css_overview/components/cssOverviewStartView.css +1 -8
  26. package/front_end/panels/elements/ElementsTreeElement.ts +4 -9
  27. package/front_end/panels/elements/components/adornerSettingsPane.css +0 -4
  28. package/front_end/panels/emulation/emulation-meta.ts +2 -2
  29. package/front_end/panels/issues/issues-meta.ts +0 -2
  30. package/front_end/panels/layers/module.json +0 -1
  31. package/front_end/panels/lighthouse/lighthouseStartView.css +4 -0
  32. package/front_end/panels/media/media-meta.ts +0 -3
  33. package/front_end/panels/network/ResourceWebSocketFrameView.ts +2 -1
  34. package/front_end/panels/network/network-meta.ts +0 -3
  35. package/front_end/panels/security/security-meta.ts +0 -3
  36. package/front_end/panels/sources/BreakpointEditDialog.ts +16 -30
  37. package/front_end/panels/sources/CSSPlugin.ts +310 -331
  38. package/front_end/panels/sources/CallStackSidebarPane.ts +28 -34
  39. package/front_end/panels/sources/CoveragePlugin.ts +121 -6
  40. package/front_end/panels/sources/DebuggerPlugin.ts +1166 -1243
  41. package/front_end/panels/sources/EditingLocationHistoryManager.ts +71 -101
  42. package/front_end/panels/sources/GoToLineQuickOpen.ts +4 -3
  43. package/front_end/panels/sources/InplaceFormatterEditorAction.ts +3 -3
  44. package/front_end/panels/sources/JavaScriptCompilerPlugin.ts +26 -23
  45. package/front_end/panels/sources/Plugin.ts +20 -4
  46. package/front_end/panels/sources/ProfilePlugin.ts +185 -0
  47. package/front_end/panels/sources/ScriptFormatterEditorAction.ts +3 -3
  48. package/front_end/panels/sources/ScriptOriginPlugin.ts +0 -10
  49. package/front_end/panels/sources/SnippetsPlugin.ts +1 -10
  50. package/front_end/panels/sources/SourcesPanel.ts +6 -5
  51. package/front_end/panels/sources/SourcesView.ts +10 -8
  52. package/front_end/panels/sources/TabbedEditorContainer.ts +31 -27
  53. package/front_end/panels/sources/UISourceCodeFrame.ts +335 -470
  54. package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +3 -2
  55. package/front_end/panels/sources/sources-legacy.ts +0 -6
  56. package/front_end/panels/sources/sources.ts +0 -2
  57. package/front_end/panels/timeline/module.json +0 -1
  58. package/front_end/third_party/codemirror.next/bundle.ts +9 -13
  59. package/front_end/third_party/codemirror.next/chunk/codemirror.js +1 -1
  60. package/front_end/third_party/codemirror.next/chunk/javascript.js +2 -2
  61. package/front_end/third_party/codemirror.next/chunk/markdown.js +2 -6
  62. package/front_end/third_party/codemirror.next/chunk/php.js +2 -6
  63. package/front_end/third_party/codemirror.next/chunk/python.js +1 -1
  64. package/front_end/third_party/codemirror.next/chunk/wast.js +1 -1
  65. package/front_end/third_party/codemirror.next/chunk/xml.js +2 -2
  66. package/front_end/third_party/codemirror.next/codemirror.next.d.ts +279 -198
  67. package/front_end/third_party/codemirror.next/codemirror.next.js +1 -1
  68. package/front_end/third_party/codemirror.next/package.json +13 -11
  69. package/front_end/ui/components/code_highlighter/CodeHighlighter.ts +60 -68
  70. package/front_end/ui/components/data_grid/dataGrid.css +12 -10
  71. package/front_end/ui/components/docs/css_overview/start_view.html +25 -0
  72. package/front_end/ui/components/docs/css_overview/start_view.ts +14 -0
  73. package/front_end/ui/components/text_editor/TextEditor.ts +79 -36
  74. package/front_end/ui/components/text_editor/config.ts +42 -26
  75. package/front_end/ui/components/text_editor/javascript.ts +2 -3
  76. package/front_end/ui/components/text_editor/position.ts +17 -0
  77. package/front_end/ui/components/text_editor/text_editor.ts +1 -0
  78. package/front_end/ui/components/text_editor/theme.ts +5 -1
  79. package/front_end/ui/legacy/Infobar.ts +2 -6
  80. package/front_end/ui/legacy/ShortcutRegistry.ts +11 -7
  81. package/front_end/ui/legacy/components/perf_ui/LineLevelProfile.ts +35 -131
  82. package/front_end/ui/legacy/components/source_frame/BinaryResourceViewFactory.ts +3 -6
  83. package/front_end/ui/legacy/components/source_frame/ResourceSourceFrame.ts +18 -14
  84. package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +502 -252
  85. package/front_end/ui/legacy/components/source_frame/source_frame-legacy.ts +0 -11
  86. package/front_end/ui/legacy/components/source_frame/source_frame.ts +0 -2
  87. package/front_end/ui/legacy/components/text_editor/cmdevtools.css +3 -1
  88. package/front_end/ui/legacy/radioButton.css +1 -13
  89. package/front_end/ui/legacy/themeColors.css +36 -0
  90. package/package.json +1 -1
  91. package/front_end/Images/radioDot-dark-theme.png +0 -0
  92. package/front_end/Images/radioDot.png +0 -0
  93. package/front_end/panels/application/module.json +0 -6
  94. package/front_end/panels/issues/module.json +0 -6
  95. package/front_end/panels/layer_viewer/module.json +0 -5
  96. package/front_end/panels/media/module.json +0 -5
  97. package/front_end/panels/network/module.json +0 -5
  98. package/front_end/panels/security/module.json +0 -5
  99. package/front_end/ui/legacy/components/source_frame/SourcesTextEditor.ts +0 -1030
@@ -1,1030 +0,0 @@
1
- // Copyright (c) 2016 The Chromium Authors. All rights reserved.
2
- // Use of this source code is governed by a BSD-style license that can be
3
- // found in the LICENSE file.
4
-
5
- import * as Common from '../../../../core/common/common.js';
6
- import * as TextUtils from '../../../../models/text_utils/text_utils.js';
7
- import * as UI from '../../legacy.js';
8
- import * as TextEditor from '../text_editor/text_editor.js';
9
-
10
- const whitespaceStyleInjectedSet = new WeakSet<Document>();
11
-
12
- export class SourcesTextEditor extends
13
- Common.ObjectWrapper.eventMixin<EventTypes, typeof TextEditor.CodeMirrorTextEditor.CodeMirrorTextEditor>(
14
- TextEditor.CodeMirrorTextEditor.CodeMirrorTextEditor) {
15
- private readonly delegate: SourcesTextEditorDelegate;
16
- private readonly gutterMouseMove: (event: Event) => void;
17
- private readonly gutterMouseOut: () => void;
18
- private readonly tokenHighlighter: TokenHighlighter;
19
- private readonly gutters: string[];
20
- private isHandlingMouseDownEvent: boolean;
21
- private autocompleteConfig: UI.TextEditor.AutocompleteConfig|null;
22
- private infoBarDiv: Element|null;
23
- private selectionBeforeSearch?: TextUtils.TextRange.TextRange;
24
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
25
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
- private executionLine?: any;
27
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
28
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
29
- private executionLineTailMarker?: any;
30
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
31
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
32
- private indentationLevel?: any;
33
- private autoAppendedSpaces?: TextEditor.CodeMirrorTextEditor.TextEditorPositionHandle[];
34
-
35
- constructor(delegate: SourcesTextEditorDelegate, codeMirrorOptions?: UI.TextEditor.Options) {
36
- const defaultCodeMirrorOptions: UI.TextEditor.Options = {
37
- lineNumbers: true,
38
- lineWrapping: false,
39
- bracketMatchingSetting: Common.Settings.Settings.instance().moduleSetting('textEditorBracketMatching'),
40
- padBottom: Common.Settings.Settings.instance().moduleSetting('allowScrollPastEof').get(),
41
- lineWiseCopyCut: true,
42
- devtoolsAccessibleName: undefined,
43
- mimeType: undefined,
44
- autoHeight: undefined,
45
- maxHighlightLength: undefined,
46
- placeholder: undefined,
47
- inputStyle: undefined,
48
- };
49
- if (codeMirrorOptions) {
50
- Object.assign(defaultCodeMirrorOptions, codeMirrorOptions);
51
- }
52
-
53
- super(defaultCodeMirrorOptions);
54
-
55
- this.codeMirror().addKeyMap({'Enter': 'smartNewlineAndIndent', 'Esc': 'sourcesDismiss'});
56
-
57
- this.delegate = delegate;
58
-
59
- this.codeMirror().on('cursorActivity', this.cursorActivity.bind(this));
60
- this.codeMirror().on('gutterClick', this.gutterClick.bind(this));
61
- this.codeMirror().on('scroll', this.scroll.bind(this));
62
- this.codeMirror().on('focus', this.focusInternal.bind(this));
63
- this.codeMirror().on('blur', this.blurInternal.bind(this));
64
- this.codeMirror().on('beforeSelectionChange', this.fireBeforeSelectionChanged.bind(this));
65
- this.codeMirror().on('gutterContextMenu', this.gutterContextMenu.bind(this));
66
- this.element.addEventListener('contextmenu', this.textAreaContextMenu.bind(this), false);
67
- this.gutterMouseMove = (event: Event): void => {
68
- const mouseEvent = (event as MouseEvent);
69
- this.element.classList.toggle(
70
- 'CodeMirror-gutter-hovered',
71
- mouseEvent.clientX < this.codeMirror().getGutterElement().getBoundingClientRect().right);
72
- };
73
- this.gutterMouseOut = (): void => {
74
- this.element.classList.toggle('CodeMirror-gutter-hovered', false);
75
- };
76
-
77
- this.codeMirror().addKeyMap(_BlockIndentController);
78
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
79
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
80
- this.tokenHighlighter = new TokenHighlighter(this, (this.codeMirror() as any));
81
-
82
- this.gutters = [lineNumbersGutterType];
83
- this.codeMirror().setOption('gutters', this.gutters.slice());
84
-
85
- this.codeMirror().setOption('electricChars', false);
86
- this.codeMirror().setOption('smartIndent', false);
87
-
88
- this.isHandlingMouseDownEvent = false;
89
- function updateAnticipateJumpFlag(this: SourcesTextEditor, value: boolean): void {
90
- this.isHandlingMouseDownEvent = value;
91
- }
92
-
93
- this.element.addEventListener('mousedown', updateAnticipateJumpFlag.bind(this, true), true);
94
- this.element.addEventListener('mousedown', updateAnticipateJumpFlag.bind(this, false), false);
95
- Common.Settings.Settings.instance()
96
- .moduleSetting('textEditorIndent')
97
- .addChangeListener(this.onUpdateEditorIndentation, this);
98
- Common.Settings.Settings.instance()
99
- .moduleSetting('textEditorAutoDetectIndent')
100
- .addChangeListener(this.onUpdateEditorIndentation, this);
101
- Common.Settings.Settings.instance()
102
- .moduleSetting('showWhitespacesInEditor')
103
- .addChangeListener(this.updateWhitespace, this);
104
- Common.Settings.Settings.instance()
105
- .moduleSetting('textEditorCodeFolding')
106
- .addChangeListener(this.updateCodeFolding, this);
107
- Common.Settings.Settings.instance()
108
- .moduleSetting('allowScrollPastEof')
109
- .addChangeListener(this.updateScrollPastEof, this);
110
- this.updateCodeFolding();
111
-
112
- this.autocompleteConfig = {
113
- isWordChar: TextUtils.TextUtils.Utils.isWordChar,
114
- substituteRangeCallback: undefined,
115
- tooltipCallback: undefined,
116
- suggestionsCallback: undefined,
117
- anchorBehavior: undefined,
118
- };
119
- Common.Settings.Settings.instance()
120
- .moduleSetting('textEditorAutocompletion')
121
- .addChangeListener(this.updateAutocomplete, this);
122
- this.updateAutocomplete();
123
-
124
- this.onUpdateEditorIndentation();
125
- this.setupWhitespaceHighlight();
126
-
127
- this.infoBarDiv = null;
128
- }
129
-
130
- // https://crbug.com/1151919 * = CodeMirror.Editor
131
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
132
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
133
- static getForCodeMirror(codeMirrorEditor: any): SourcesTextEditor {
134
- return TextEditor.CodeMirrorTextEditor.CodeMirrorTextEditor.getForCodeMirror(codeMirrorEditor) as SourcesTextEditor;
135
- }
136
-
137
- attachInfobar(infobar: UI.Infobar.Infobar): void {
138
- if (!this.infoBarDiv) {
139
- this.infoBarDiv = document.createElement('div');
140
- this.infoBarDiv.classList.add('flex-none');
141
- this.element.insertBefore(this.infoBarDiv, this.element.firstChild);
142
- }
143
- this.infoBarDiv.appendChild(infobar.element);
144
- infobar.setParentView(this);
145
- this.doResize();
146
- }
147
-
148
- private static guessIndentationLevel(lines: string[]): string {
149
- const tabRegex = /^\t+/;
150
- let tabLines = 0;
151
- /**
152
- * Maps the indentation level to its frequency in |lines|.
153
- */
154
- const indents = new Map<number, number>();
155
- for (let lineNumber = 0; lineNumber < lines.length; ++lineNumber) {
156
- const text = lines[lineNumber];
157
- if (text.length === 0 || !TextUtils.TextUtils.Utils.isSpaceChar(text[0])) {
158
- continue;
159
- }
160
- if (tabRegex.test(text)) {
161
- ++tabLines;
162
- continue;
163
- }
164
- let i = 0;
165
- while (i < text.length && TextUtils.TextUtils.Utils.isSpaceChar(text[i])) {
166
- ++i;
167
- }
168
- if (i % 2 !== 0) {
169
- continue;
170
- }
171
- indents.set(i, 1 + (indents.get(i) || 0));
172
- }
173
- const linesCountPerIndentThreshold = 3 * lines.length / 100;
174
- if (tabLines && tabLines > linesCountPerIndentThreshold) {
175
- return '\t';
176
- }
177
- let minimumIndent: number = Infinity;
178
- for (const [indent, frequency] of indents) {
179
- if (frequency < linesCountPerIndentThreshold) {
180
- continue;
181
- }
182
- if (minimumIndent > indent) {
183
- minimumIndent = indent;
184
- }
185
- }
186
- if (minimumIndent === Infinity) {
187
- return Common.Settings.Settings.instance().moduleSetting('textEditorIndent').get();
188
- }
189
- return ' '.repeat(minimumIndent);
190
- }
191
-
192
- isSearchActive(): boolean {
193
- return Boolean(this.tokenHighlighter.highlightedRegex());
194
- }
195
-
196
- scrollToLine(lineNumber: number): void {
197
- super.scrollToLine(lineNumber);
198
- this.scroll();
199
- }
200
-
201
- highlightSearchResults(regex: RegExp, range: TextUtils.TextRange.TextRange|null): void {
202
- function innerHighlightRegex(this: SourcesTextEditor): void {
203
- if (range) {
204
- this.scrollLineIntoView(range.startLine);
205
- if (range.endColumn > TextEditor.CodeMirrorTextEditor.CodeMirrorTextEditor.maxHighlightLength) {
206
- this.setSelection(range);
207
- } else {
208
- this.setSelection(TextUtils.TextRange.TextRange.createFromLocation(range.startLine, range.startColumn));
209
- }
210
- }
211
- this.tokenHighlighter.highlightSearchResults(regex, range);
212
- }
213
-
214
- if (!this.selectionBeforeSearch) {
215
- this.selectionBeforeSearch = this.selection();
216
- }
217
-
218
- this.codeMirror().operation(innerHighlightRegex.bind(this));
219
- }
220
-
221
- cancelSearchResultsHighlight(): void {
222
- this.codeMirror().operation(this.tokenHighlighter.highlightSelectedTokens.bind(this.tokenHighlighter));
223
-
224
- if (this.selectionBeforeSearch) {
225
- this.reportJump(this.selectionBeforeSearch, this.selection());
226
- delete this.selectionBeforeSearch;
227
- }
228
- }
229
-
230
- // https://crbug.com/1151919 * = CodeMirror.TextMarker
231
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
232
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
233
- removeHighlight(highlightDescriptor: any): void {
234
- highlightDescriptor.clear();
235
- }
236
-
237
- // https://crbug.com/1151919 * = CodeMirror.TextMarker<CodeMirror.MarkerRange>
238
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
239
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
240
- highlightRange(range: TextUtils.TextRange.TextRange, cssClass: string): any {
241
- cssClass = 'CodeMirror-persist-highlight ' + cssClass;
242
- const pos = TextUtils.CodeMirrorUtils.toPos(range);
243
- ++pos.end.ch;
244
- return this.codeMirror().markText(
245
- pos.start, pos.end, {className: cssClass, startStyle: cssClass + '-start', endStyle: cssClass + '-end'});
246
- }
247
-
248
- installGutter(type: string, leftToNumbers: boolean): void {
249
- if (this.gutters.indexOf(type) !== -1) {
250
- return;
251
- }
252
-
253
- if (leftToNumbers) {
254
- this.gutters.unshift(type);
255
- } else {
256
- this.gutters.push(type);
257
- }
258
-
259
- this.codeMirror().setOption('gutters', this.gutters.slice());
260
- this.refresh();
261
- }
262
-
263
- uninstallGutter(type: string): void {
264
- const index = this.gutters.indexOf(type);
265
- if (index === -1) {
266
- return;
267
- }
268
- this.codeMirror().clearGutter(type);
269
- this.gutters.splice(index, 1);
270
- this.codeMirror().setOption('gutters', this.gutters.slice());
271
- this.refresh();
272
- }
273
-
274
- setGutterDecoration(lineNumber: number, type: string, element: Element|null): void {
275
- console.assert(this.gutters.indexOf(type) !== -1, 'Cannot decorate unexisting gutter.');
276
- this.codeMirror().setGutterMarker(lineNumber, type, element);
277
- }
278
-
279
- setExecutionLocation(lineNumber: number, columnNumber: number): void {
280
- this.clearPositionHighlight();
281
-
282
- this.executionLine = this.codeMirror().getLineHandle(lineNumber);
283
- if (!this.executionLine) {
284
- return;
285
- }
286
-
287
- this.showExecutionLineBackground();
288
- this.codeMirror().addLineClass(this.executionLine, 'wrap', 'cm-execution-line-outline');
289
- let token = this.tokenAtTextPosition(lineNumber, columnNumber);
290
-
291
- if (token && !token.type && token.startColumn + 1 === token.endColumn) {
292
- const tokenContent = this.codeMirror().getLine(lineNumber)[token.startColumn];
293
- if (tokenContent === '.' || tokenContent === '(') {
294
- token = this.tokenAtTextPosition(lineNumber, token.endColumn + 1);
295
- }
296
- }
297
-
298
- let endColumn;
299
- if (token && token.type) {
300
- endColumn = token.endColumn;
301
- } else {
302
- endColumn = this.codeMirror().getLine(lineNumber).length;
303
- }
304
-
305
- this.executionLineTailMarker = this.codeMirror().markText(
306
- {line: lineNumber, ch: columnNumber}, {line: lineNumber, ch: endColumn}, {className: 'cm-execution-line-tail'});
307
- }
308
-
309
- showExecutionLineBackground(): void {
310
- if (this.executionLine) {
311
- this.codeMirror().addLineClass(this.executionLine, 'wrap', 'cm-execution-line');
312
- }
313
- }
314
-
315
- hideExecutionLineBackground(): void {
316
- if (this.executionLine) {
317
- this.codeMirror().removeLineClass(this.executionLine, 'wrap', 'cm-execution-line');
318
- }
319
- }
320
-
321
- clearExecutionLine(): void {
322
- this.clearPositionHighlight();
323
-
324
- if (this.executionLine) {
325
- this.hideExecutionLineBackground();
326
- this.codeMirror().removeLineClass(this.executionLine, 'wrap', 'cm-execution-line-outline');
327
- }
328
- delete this.executionLine;
329
-
330
- if (this.executionLineTailMarker) {
331
- this.executionLineTailMarker.clear();
332
- }
333
- delete this.executionLineTailMarker;
334
- }
335
-
336
- toggleLineClass(lineNumber: number, className: string, toggled: boolean): void {
337
- if (this.hasLineClass(lineNumber, className) === toggled) {
338
- return;
339
- }
340
-
341
- const lineHandle = this.codeMirror().getLineHandle(lineNumber);
342
- if (!lineHandle) {
343
- return;
344
- }
345
-
346
- if (toggled) {
347
- this.codeMirror().addLineClass(lineHandle, 'gutter', className);
348
- this.codeMirror().addLineClass(lineHandle, 'wrap', className);
349
- } else {
350
- this.codeMirror().removeLineClass(lineHandle, 'gutter', className);
351
- this.codeMirror().removeLineClass(lineHandle, 'wrap', className);
352
- }
353
- }
354
-
355
- hasLineClass(lineNumber: number, className: string): boolean {
356
- const lineInfo = this.codeMirror().lineInfo(lineNumber);
357
- if (!lineInfo) {
358
- return false;
359
- }
360
- const wrapClass = lineInfo.wrapClass;
361
- if (!wrapClass) {
362
- return false;
363
- }
364
- const classNames = wrapClass.split(' ');
365
- return classNames.indexOf(className) !== -1;
366
- }
367
-
368
- /**
369
- * |instance| is actually a CodeMirror.Editor
370
- */
371
- private gutterClick(_instance: Object, lineNumber: number, gutterType: string, event: MouseEvent): void {
372
- this.dispatchEventToListeners(Events.GutterClick, {gutterType, lineNumber, event});
373
- }
374
-
375
- private textAreaContextMenu(event: MouseEvent): void {
376
- const contextMenu = new UI.ContextMenu.ContextMenu(event);
377
- event.consume(true); // Consume event now to prevent document from handling the async menu
378
-
379
- const textSelection = this.selection();
380
- this.delegate.populateTextAreaContextMenu(contextMenu, textSelection.startLine, textSelection.startColumn)
381
- .then(() => {
382
- contextMenu.appendApplicableItems(this);
383
- contextMenu.show();
384
- });
385
- }
386
-
387
- /**
388
- * |instance| is actually a CodeMirror.Editor
389
- */
390
- private gutterContextMenu(_instance: Object, lineNumber: number, _gutterType: string, event: MouseEvent): void {
391
- const contextMenu = new UI.ContextMenu.ContextMenu(event);
392
- event.consume(true); // Consume event now to prevent document from handling the async menu
393
-
394
- this.delegate.populateLineGutterContextMenu(contextMenu, lineNumber).then(() => {
395
- contextMenu.appendApplicableItems(this);
396
- contextMenu.show();
397
- });
398
- }
399
-
400
- editRange(range: TextUtils.TextRange.TextRange, text: string, origin?: string): TextUtils.TextRange.TextRange {
401
- const newRange = super.editRange(range, text, origin);
402
- if (Common.Settings.Settings.instance().moduleSetting('textEditorAutoDetectIndent').get()) {
403
- this.onUpdateEditorIndentation();
404
- }
405
-
406
- return newRange;
407
- }
408
-
409
- private onUpdateEditorIndentation(): void {
410
- this.setEditorIndentation(
411
- TextUtils.CodeMirrorUtils.pullLines(this.codeMirror(), LinesToScanForIndentationGuessing));
412
- }
413
-
414
- private setEditorIndentation(lines: string[]): void {
415
- const extraKeys = {};
416
- let indent = Common.Settings.Settings.instance().moduleSetting('textEditorIndent').get();
417
- if (Common.Settings.Settings.instance().moduleSetting('textEditorAutoDetectIndent').get()) {
418
- indent = SourcesTextEditor.guessIndentationLevel(lines);
419
- }
420
-
421
- if (indent === '\t') {
422
- this.codeMirror().setOption('indentWithTabs', true);
423
- this.codeMirror().setOption('indentUnit', 4);
424
- } else {
425
- this.codeMirror().setOption('indentWithTabs', false);
426
- this.codeMirror().setOption('indentUnit', indent.length);
427
- /**
428
- * TODO: |codeMirror| is really a CodeMirror.Editor
429
- */
430
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
431
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
432
- function tab(codeMirror: any): any {
433
- if (codeMirror.somethingSelected()) {
434
- return CodeMirror.Pass;
435
- }
436
- const pos = codeMirror.getCursor('head');
437
- codeMirror.replaceRange(indent.substring(pos.ch % indent.length), codeMirror.getCursor());
438
- }
439
-
440
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
441
- // @ts-expect-error
442
- extraKeys.Tab = tab;
443
- }
444
-
445
- this.codeMirror().setOption('extraKeys', extraKeys);
446
- this.indentationLevel = indent;
447
- }
448
-
449
- indent(): string {
450
- return this.indentationLevel;
451
- }
452
-
453
- onAutoAppendedSpaces(): void {
454
- this.autoAppendedSpaces = this.autoAppendedSpaces || [];
455
-
456
- for (let i = 0; i < this.autoAppendedSpaces.length; ++i) {
457
- const position = this.autoAppendedSpaces[i].resolve();
458
- if (!position) {
459
- continue;
460
- }
461
- const line = this.line(position.lineNumber);
462
- if (line.length === position.columnNumber && TextUtils.TextUtils.Utils.lineIndent(line).length === line.length) {
463
- this.codeMirror().replaceRange(
464
- '', new CodeMirror.Pos(position.lineNumber, 0),
465
- new CodeMirror.Pos(position.lineNumber, position.columnNumber));
466
- }
467
- }
468
-
469
- this.autoAppendedSpaces = [];
470
- const selections = this.selections();
471
- for (let i = 0; i < selections.length; ++i) {
472
- const selection = selections[i];
473
- this.autoAppendedSpaces.push(this.textEditorPositionHandle(selection.startLine, selection.startColumn));
474
- }
475
- }
476
-
477
- private cursorActivity(): void {
478
- if (!this.isSearchActive()) {
479
- this.codeMirror().operation(this.tokenHighlighter.highlightSelectedTokens.bind(this.tokenHighlighter));
480
- }
481
-
482
- const start = this.codeMirror().getCursor('anchor');
483
- const end = this.codeMirror().getCursor('head');
484
- this.dispatchEventToListeners(Events.SelectionChanged, TextUtils.CodeMirrorUtils.toRange(start, end));
485
- }
486
-
487
- private reportJump(from: TextUtils.TextRange.TextRange|null, to: TextUtils.TextRange.TextRange|null): void {
488
- if (from && to && from.equal(to)) {
489
- return;
490
- }
491
- this.dispatchEventToListeners(Events.JumpHappened, {from, to});
492
- }
493
-
494
- private scroll(): void {
495
- const topmostLineNumber = this.codeMirror().lineAtHeight(this.codeMirror().getScrollInfo().top, 'local');
496
- this.dispatchEventToListeners(Events.ScrollChanged, topmostLineNumber);
497
- }
498
-
499
- focusInternal(): void {
500
- this.dispatchEventToListeners(Events.EditorFocused);
501
- }
502
-
503
- private blurInternal(): void {
504
- this.dispatchEventToListeners(Events.EditorBlurred);
505
- }
506
-
507
- // https://crbug.com/1151919 * = {ranges: !Array.<{head: !CodeMirror.Pos, anchor: !CodeMirror.Pos}>}
508
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
509
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
510
- private fireBeforeSelectionChanged(_codeMirror: typeof CodeMirror, selection: any): void {
511
- if (!this.isHandlingMouseDownEvent) {
512
- return;
513
- }
514
- if (!selection.ranges.length) {
515
- return;
516
- }
517
-
518
- const primarySelection = selection.ranges[0];
519
- this.reportJump(
520
- this.selection(), TextUtils.CodeMirrorUtils.toRange(primarySelection.anchor, primarySelection.head));
521
- }
522
-
523
- dispose(): void {
524
- super.dispose();
525
- Common.Settings.Settings.instance()
526
- .moduleSetting('textEditorIndent')
527
- .removeChangeListener(this.onUpdateEditorIndentation, this);
528
- Common.Settings.Settings.instance()
529
- .moduleSetting('textEditorAutoDetectIndent')
530
- .removeChangeListener(this.onUpdateEditorIndentation, this);
531
- Common.Settings.Settings.instance()
532
- .moduleSetting('showWhitespacesInEditor')
533
- .removeChangeListener(this.updateWhitespace, this);
534
- Common.Settings.Settings.instance()
535
- .moduleSetting('textEditorCodeFolding')
536
- .removeChangeListener(this.updateCodeFolding, this);
537
- Common.Settings.Settings.instance()
538
- .moduleSetting('allowScrollPastEof')
539
- .removeChangeListener(this.updateScrollPastEof, this);
540
- }
541
-
542
- setText(text: string): void {
543
- this.setEditorIndentation(text.split('\n').slice(0, LinesToScanForIndentationGuessing));
544
- super.setText(text);
545
- }
546
-
547
- private updateWhitespace(): void {
548
- this.setMimeType(this.mimeType());
549
- }
550
-
551
- private updateCodeFolding(): void {
552
- if (Common.Settings.Settings.instance().moduleSetting('textEditorCodeFolding').get()) {
553
- this.installGutter('CodeMirror-foldgutter', false);
554
- this.element.addEventListener('mousemove', this.gutterMouseMove);
555
- this.element.addEventListener('mouseout', this.gutterMouseOut);
556
- this.codeMirror().setOption('foldGutter', true);
557
- this.codeMirror().setOption('foldOptions', {minFoldSize: 1});
558
- } else {
559
- this.codeMirror().execCommand('unfoldAll');
560
- this.element.removeEventListener('mousemove', this.gutterMouseMove);
561
- this.element.removeEventListener('mouseout', this.gutterMouseOut);
562
- this.uninstallGutter('CodeMirror-foldgutter');
563
- this.codeMirror().setOption('foldGutter', false);
564
- }
565
- }
566
-
567
- private updateScrollPastEof(): void {
568
- this.toggleScrollPastEof(Common.Settings.Settings.instance().moduleSetting('allowScrollPastEof').get());
569
- }
570
-
571
- rewriteMimeType(mimeType: string): string {
572
- this.setupWhitespaceHighlight();
573
- const whitespaceMode = Common.Settings.Settings.instance().moduleSetting('showWhitespacesInEditor').get();
574
- this.element.classList.toggle('show-whitespaces', whitespaceMode === 'all');
575
-
576
- if (whitespaceMode === 'all') {
577
- return this.allWhitespaceOverlayMode(mimeType);
578
- }
579
- if (whitespaceMode === 'trailing') {
580
- return this.trailingWhitespaceOverlayMode(mimeType);
581
- }
582
-
583
- return mimeType;
584
- }
585
-
586
- private allWhitespaceOverlayMode(mimeType: string): string {
587
- let modeName = CodeMirror.mimeModes[mimeType] ?
588
- (CodeMirror.mimeModes[mimeType].name || CodeMirror.mimeModes[mimeType]) :
589
- CodeMirror.mimeModes['text/plain'];
590
- modeName += '+all-whitespaces';
591
- if (CodeMirror.modes[modeName]) {
592
- return modeName;
593
- }
594
-
595
- /**
596
- * TODO: |config| is really a CodeMirror.EditorConfiguration
597
- */
598
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
599
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
600
- function modeConstructor(config: Object, _parserConfig: any): CodeMirror.Mode<any> {
601
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
602
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
603
- function nextToken(stream: any): string|null {
604
- if (stream.peek() === ' ') {
605
- let spaces = 0;
606
- while (spaces < MaximumNumberOfWhitespacesPerSingleSpan && stream.peek() === ' ') {
607
- ++spaces;
608
- stream.next();
609
- }
610
- return 'whitespace whitespace-' + spaces;
611
- }
612
- while (!stream.eol() && stream.peek() !== ' ') {
613
- stream.next();
614
- }
615
- return null;
616
- }
617
- const whitespaceMode = {token: nextToken};
618
- return CodeMirror.overlayMode(CodeMirror.getMode(config, mimeType), whitespaceMode, false);
619
- }
620
- CodeMirror.defineMode(modeName, modeConstructor);
621
- return modeName;
622
- }
623
-
624
- private trailingWhitespaceOverlayMode(mimeType: string): string {
625
- let modeName = CodeMirror.mimeModes[mimeType] ?
626
- (CodeMirror.mimeModes[mimeType].name || CodeMirror.mimeModes[mimeType]) :
627
- CodeMirror.mimeModes['text/plain'];
628
- modeName += '+trailing-whitespaces';
629
- if (CodeMirror.modes[modeName]) {
630
- return modeName;
631
- }
632
-
633
- /**
634
- * TODO: |config| is really a CodeMirror.EditorConfiguration
635
- */
636
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
637
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
638
- function modeConstructor(config: Object, _parserConfig: any): CodeMirror.Mode<any> {
639
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
640
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
641
- function nextToken(stream: any): 'trailing-whitespace'|null {
642
- if (stream.match(/^\s+$/, true)) {
643
- return true ? 'trailing-whitespace' : null;
644
- }
645
- do {
646
- stream.next();
647
- } while (!stream.eol() && stream.peek() !== ' ');
648
- return null;
649
- }
650
- const whitespaceMode = {token: nextToken};
651
- return CodeMirror.overlayMode(CodeMirror.getMode(config, mimeType), whitespaceMode, false);
652
- }
653
- CodeMirror.defineMode(modeName, modeConstructor);
654
- return modeName;
655
- }
656
-
657
- private setupWhitespaceHighlight(): void {
658
- const doc = (this.element.ownerDocument as Document);
659
- if (whitespaceStyleInjectedSet.has(doc) ||
660
- !Common.Settings.Settings.instance().moduleSetting('showWhitespacesInEditor').get()) {
661
- return;
662
- }
663
- whitespaceStyleInjectedSet.add(doc);
664
- const classBase = '.show-whitespaces .CodeMirror .cm-whitespace-';
665
- const spaceChar = '·';
666
- let spaceChars = '';
667
- let rules = '';
668
- for (let i = 1; i <= MaximumNumberOfWhitespacesPerSingleSpan; ++i) {
669
- spaceChars += spaceChar;
670
- const rule = classBase + i + '::before { content: \'' + spaceChars + '\';}\n';
671
- rules += rule;
672
- }
673
- const style = doc.createElement('style');
674
- style.textContent = rules;
675
- doc.head.appendChild(style);
676
- }
677
-
678
- configureAutocomplete(config: UI.TextEditor.AutocompleteConfig|null): void {
679
- this.autocompleteConfig = config;
680
- this.updateAutocomplete();
681
- }
682
-
683
- private updateAutocomplete(): void {
684
- super.configureAutocomplete(
685
- Common.Settings.Settings.instance().moduleSetting('textEditorAutocompletion').get() ? this.autocompleteConfig :
686
- null);
687
- }
688
- }
689
-
690
- // TODO(crbug.com/1167717): Make this a const enum again
691
- // eslint-disable-next-line rulesdir/const_enum
692
- export enum Events {
693
- GutterClick = 'GutterClick',
694
- SelectionChanged = 'SelectionChanged',
695
- ScrollChanged = 'ScrollChanged',
696
- EditorFocused = 'EditorFocused',
697
- EditorBlurred = 'EditorBlurred',
698
- JumpHappened = 'JumpHappened',
699
- }
700
-
701
- export interface JumpHappenedEvent {
702
- from: TextUtils.TextRange.TextRange|null;
703
- to: TextUtils.TextRange.TextRange|null;
704
- }
705
-
706
- export type EventTypes = {
707
- [Events.GutterClick]: GutterClickEventData,
708
- [Events.SelectionChanged]: TextUtils.TextRange.TextRange,
709
- [Events.ScrollChanged]: number,
710
- [Events.EditorFocused]: void,
711
- [Events.EditorBlurred]: void,
712
- [Events.JumpHappened]: JumpHappenedEvent,
713
- };
714
-
715
- export class SourcesTextEditorDelegate {
716
- populateLineGutterContextMenu(_contextMenu: UI.ContextMenu.ContextMenu, _lineNumber: number): Promise<void> {
717
- throw new Error('Not implemented');
718
- }
719
- populateTextAreaContextMenu(_contextMenu: UI.ContextMenu.ContextMenu, _lineNumber: number, _columnNumber: number):
720
- Promise<void> {
721
- throw new Error('Not implemented');
722
- }
723
- }
724
-
725
- // https://crbug.com/1151919 * = !CodeMirror.Editor
726
- // @ts-ignore https://crbug.com/1151919 CodeMirror types are incorrect
727
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
728
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
729
- CodeMirror.commands.smartNewlineAndIndent = function(codeMirror: any): void {
730
- codeMirror.operation(innerSmartNewlineAndIndent.bind(null, codeMirror));
731
- // https://crbug.com/1151919 * = !CodeMirror.Editor
732
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
733
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
734
- function innerSmartNewlineAndIndent(codeMirror: any): void {
735
- const selections = codeMirror.listSelections();
736
- const replacements = [];
737
- for (let i = 0; i < selections.length; ++i) {
738
- const selection = selections[i];
739
- const cur = CodeMirror.cmpPos(selection.head, selection.anchor) < 0 ? selection.head : selection.anchor;
740
- const line = codeMirror.getLine(cur.line);
741
- const indent = TextUtils.TextUtils.Utils.lineIndent(line);
742
- replacements.push('\n' + indent.substring(0, Math.min(cur.ch, indent.length)));
743
- }
744
- // @ts-ignore replaceSelection has not been added to the types yet.
745
- codeMirror.replaceSelections(replacements);
746
- SourcesTextEditor.getForCodeMirror(codeMirror).onAutoAppendedSpaces();
747
- }
748
- };
749
-
750
- // https://crbug.com/1151919 * = !CodeMirror.Editor
751
- // @ts-ignore https://crbug.com/1151919 CodeMirror types are incorrect
752
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
753
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
754
- CodeMirror.commands.sourcesDismiss = function(codeMirror: any): Object|undefined {
755
- if (codeMirror.listSelections().length === 1 && SourcesTextEditor.getForCodeMirror(codeMirror).isSearchActive()) {
756
- return CodeMirror.Pass;
757
- }
758
- // @ts-ignore https://crbug.com/1151919 CodeMirror types are incorrect
759
- return CodeMirror.commands.dismiss(codeMirror);
760
- };
761
-
762
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
763
- // eslint-disable-next-line @typescript-eslint/naming-convention
764
- export const _BlockIndentController = {
765
- name: 'blockIndentKeymap',
766
-
767
- // https://crbug.com/1151919 * = !CodeMirror.Editor
768
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
769
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
770
- Enter: function(codeMirror: any): any {
771
- let selections = codeMirror.listSelections();
772
- const replacements = [];
773
- let allSelectionsAreCollapsedBlocks = false;
774
- for (let i = 0; i < selections.length; ++i) {
775
- const selection = selections[i];
776
- const start = CodeMirror.cmpPos(selection.head, selection.anchor) < 0 ? selection.head : selection.anchor;
777
- const line = codeMirror.getLine(start.line);
778
- const indent = TextUtils.TextUtils.Utils.lineIndent(line);
779
- let indentToInsert = '\n' + indent + SourcesTextEditor.getForCodeMirror(codeMirror).indent();
780
- let isCollapsedBlock = false;
781
- if (selection.head.ch === 0) {
782
- return CodeMirror.Pass;
783
- }
784
- if (line.substr(selection.head.ch - 1, 2) === '{}') {
785
- indentToInsert += '\n' + indent;
786
- isCollapsedBlock = true;
787
- } else if (line.substr(selection.head.ch - 1, 1) !== '{') {
788
- return CodeMirror.Pass;
789
- }
790
- if (i > 0 && allSelectionsAreCollapsedBlocks !== isCollapsedBlock) {
791
- return CodeMirror.Pass;
792
- }
793
- replacements.push(indentToInsert);
794
- allSelectionsAreCollapsedBlocks = isCollapsedBlock;
795
- }
796
- codeMirror.replaceSelections(replacements);
797
- if (!allSelectionsAreCollapsedBlocks) {
798
- SourcesTextEditor.getForCodeMirror(codeMirror).onAutoAppendedSpaces();
799
- return;
800
- }
801
- selections = codeMirror.listSelections();
802
- const updatedSelections = [];
803
- for (let i = 0; i < selections.length; ++i) {
804
- const selection = selections[i];
805
- const line = codeMirror.getLine(selection.head.line - 1);
806
- const position = new CodeMirror.Pos(selection.head.line - 1, line.length);
807
- updatedSelections.push({head: position, anchor: position});
808
- }
809
- codeMirror.setSelections(updatedSelections);
810
- SourcesTextEditor.getForCodeMirror(codeMirror).onAutoAppendedSpaces();
811
- },
812
-
813
- // https://crbug.com/1151919 * = !CodeMirror.Editor
814
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
815
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
816
- '\'}\'': function(codeMirror: any): any {
817
- if (codeMirror.somethingSelected()) {
818
- return CodeMirror.Pass;
819
- }
820
- let selections = codeMirror.listSelections();
821
- let replacements: string[] = [];
822
- for (let i = 0; i < selections.length; ++i) {
823
- const selection = selections[i];
824
- const line = codeMirror.getLine(selection.head.line);
825
- if (line !== TextUtils.TextUtils.Utils.lineIndent(line)) {
826
- return CodeMirror.Pass;
827
- }
828
- replacements.push('}');
829
- }
830
- codeMirror.replaceSelections(replacements);
831
- selections = codeMirror.listSelections();
832
- replacements = [];
833
- const updatedSelections = [];
834
- for (let i = 0; i < selections.length; ++i) {
835
- const selection = selections[i];
836
- const matchingBracket = codeMirror.findMatchingBracket(selection.head);
837
- if (!matchingBracket || !matchingBracket.match) {
838
- return;
839
- }
840
- updatedSelections.push({head: selection.head, anchor: new CodeMirror.Pos(selection.head.line, 0)});
841
- const line = codeMirror.getLine(matchingBracket.to.line);
842
- const indent = TextUtils.TextUtils.Utils.lineIndent(line);
843
- replacements.push(indent + '}');
844
- }
845
- codeMirror.setSelections(updatedSelections);
846
- codeMirror.replaceSelections(replacements);
847
- },
848
- };
849
-
850
- export class TokenHighlighter {
851
- private readonly textEditor: SourcesTextEditor;
852
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
853
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
854
- private codeMirror: any;
855
- private highlightDescriptor!: {
856
- overlay: {
857
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
858
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
859
- token: (arg0: any) => string | null,
860
- },
861
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
862
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
863
- selectionStart: any,
864
- }|undefined;
865
- private highlightRegex?: RegExp;
866
- private highlightRange?: TextUtils.TextRange.TextRange|null;
867
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
868
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
869
- private searchResultMarker?: any;
870
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
871
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
872
- private searchMatchLength?: any;
873
- // https://crbug.com/1151919 * = !CodeMirror.Editor
874
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
875
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
876
- constructor(textEditor: SourcesTextEditor, codeMirror: any) {
877
- this.textEditor = textEditor;
878
- this.codeMirror = codeMirror;
879
- }
880
-
881
- highlightSearchResults(regex: RegExp, range: TextUtils.TextRange.TextRange|null): void {
882
- const oldRegex = this.highlightRegex;
883
- this.highlightRegex = regex;
884
- this.highlightRange = range;
885
- if (this.searchResultMarker) {
886
- this.searchResultMarker.clear();
887
- delete this.searchResultMarker;
888
- }
889
- if (this.highlightDescriptor && this.highlightDescriptor.selectionStart) {
890
- this.codeMirror.removeLineClass(this.highlightDescriptor.selectionStart.line, 'wrap', 'cm-line-with-selection');
891
- }
892
- const selectionStart =
893
- this.highlightRange ? new CodeMirror.Pos(this.highlightRange.startLine, this.highlightRange.startColumn) : null;
894
- if (selectionStart) {
895
- this.codeMirror.addLineClass(selectionStart.line, 'wrap', 'cm-line-with-selection');
896
- }
897
- if (oldRegex && this.highlightRegex.toString() === oldRegex.toString()) {
898
- // Do not re-add overlay mode if regex did not change for better performance.
899
- if (this.highlightDescriptor) {
900
- this.highlightDescriptor.selectionStart = selectionStart;
901
- }
902
- } else {
903
- this.removeHighlight();
904
- this.setHighlighter(this.searchHighlighter.bind(this, this.highlightRegex), selectionStart);
905
- }
906
- if (this.highlightRange) {
907
- const pos = TextUtils.CodeMirrorUtils.toPos(this.highlightRange);
908
- this.searchResultMarker = this.codeMirror.markText(pos.start, pos.end, {className: 'cm-column-with-selection'});
909
- }
910
- }
911
-
912
- highlightedRegex(): RegExp|undefined {
913
- return this.highlightRegex;
914
- }
915
-
916
- highlightSelectedTokens(): void {
917
- delete this.highlightRegex;
918
- delete this.highlightRange;
919
- if (this.highlightDescriptor && this.highlightDescriptor.selectionStart) {
920
- this.codeMirror.removeLineClass(this.highlightDescriptor.selectionStart.line, 'wrap', 'cm-line-with-selection');
921
- }
922
- this.removeHighlight();
923
- const selectionStart = this.codeMirror.getCursor('start');
924
- const selectionEnd = this.codeMirror.getCursor('end');
925
- if (selectionStart.line !== selectionEnd.line) {
926
- return;
927
- }
928
- if (selectionStart.ch === selectionEnd.ch) {
929
- return;
930
- }
931
- const selections = this.codeMirror.getSelections();
932
- if (selections.length > 1) {
933
- return;
934
- }
935
- const selectedText = selections[0];
936
- if (this.isWord(selectedText, selectionStart.line, selectionStart.ch, selectionEnd.ch)) {
937
- if (selectionStart) {
938
- this.codeMirror.addLineClass(selectionStart.line, 'wrap', 'cm-line-with-selection');
939
- }
940
- this.setHighlighter(this.tokenHighlighter.bind(this, selectedText, selectionStart), selectionStart);
941
- }
942
- }
943
-
944
- private isWord(selectedText: string, lineNumber: number, startColumn: number, endColumn: number): boolean {
945
- const line = this.codeMirror.getLine(lineNumber);
946
- const leftBound = startColumn === 0 || !TextUtils.TextUtils.Utils.isWordChar(line.charAt(startColumn - 1));
947
- const rightBound = endColumn === line.length || !TextUtils.TextUtils.Utils.isWordChar(line.charAt(endColumn));
948
- return leftBound && rightBound && TextUtils.TextUtils.Utils.isWord(selectedText);
949
- }
950
-
951
- private removeHighlight(): void {
952
- if (this.highlightDescriptor) {
953
- this.codeMirror.removeOverlay(this.highlightDescriptor.overlay);
954
- delete this.highlightDescriptor;
955
- }
956
- }
957
-
958
- // https://crbug.com/1151919 * = !CodeMirror.StringStream
959
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
960
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
961
- private searchHighlighter(regex: RegExp, stream: any): string|null {
962
- if (stream.column() === 0) {
963
- delete this.searchMatchLength;
964
- }
965
- if (this.searchMatchLength) {
966
- if (this.searchMatchLength > 2) {
967
- for (let i = 0; i < this.searchMatchLength - 2; ++i) {
968
- stream.next();
969
- }
970
- this.searchMatchLength = 1;
971
- return 'search-highlight';
972
- }
973
- stream.next();
974
- delete this.searchMatchLength;
975
- return 'search-highlight search-highlight-end';
976
- }
977
- const match = stream.string.slice(stream.pos).match(regex);
978
- if (match) {
979
- if (match.index === 0) {
980
- stream.next();
981
- const matchLength = match[0].length;
982
- if (matchLength === 1) {
983
- return 'search-highlight search-highlight-full';
984
- }
985
- this.searchMatchLength = matchLength;
986
- return 'search-highlight search-highlight-start';
987
- }
988
- stream.pos += (match.index as number);
989
- } else {
990
- stream.skipToEnd();
991
- }
992
- return null;
993
- }
994
-
995
- // https://crbug.com/1151919 * = !CodeMirror.Position selectionStart
996
- // https://crbug.com/1151919 * = !CodeMirror.StringStream stream
997
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
998
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
999
- private tokenHighlighter(token: string, selectionStart: any, stream: any): string|null {
1000
- const tokenFirstChar = token.charAt(0);
1001
- if (stream.match(token) && (stream.eol() || !TextUtils.TextUtils.Utils.isWordChar((stream.peek() as string)))) {
1002
- return stream.column() === selectionStart.ch ? 'token-highlight column-with-selection' : 'token-highlight';
1003
- }
1004
- let eatenChar;
1005
- do {
1006
- eatenChar = stream.next();
1007
- } while (eatenChar && (TextUtils.TextUtils.Utils.isWordChar(eatenChar) || stream.peek() !== tokenFirstChar));
1008
- return null;
1009
- }
1010
-
1011
- // https://crbug.com/1151919 * = !CodeMirror.StringStream
1012
- // https://crbug.com/1151919 * = ?CodeMirror.Position
1013
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
1014
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1015
- private setHighlighter(highlighter: (arg0: any) => string | null, selectionStart: any): void {
1016
- const overlayMode = {token: highlighter};
1017
- this.codeMirror.addOverlay(overlayMode);
1018
- this.highlightDescriptor = {overlay: overlayMode, selectionStart: selectionStart};
1019
- }
1020
- }
1021
-
1022
- const LinesToScanForIndentationGuessing = 1000;
1023
- const MaximumNumberOfWhitespacesPerSingleSpan = 16;
1024
- export const lineNumbersGutterType = 'CodeMirror-linenumbers';
1025
-
1026
- export interface GutterClickEventData {
1027
- gutterType: string;
1028
- lineNumber: number;
1029
- event: MouseEvent;
1030
- }