chrome-devtools-frontend 1.0.940714 → 1.0.942529
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.
- package/config/gni/all_devtools_files.gni +0 -57
- package/config/gni/devtools_grd_files.gni +55 -15
- package/config/gni/devtools_image_files.gni +2 -3
- package/front_end/.eslintrc.js +12 -1
- package/front_end/Images/src/feedback_button_icon.svg +3 -0
- package/front_end/Images/src/{feedback_thin_16x16_icon.svg → survey_feedback_icon.svg} +1 -1
- package/front_end/Tests.js +15 -0
- package/front_end/core/common/Color.ts +5 -0
- package/front_end/core/i18n/locales/en-US.json +31 -28
- package/front_end/core/i18n/locales/en-XL.json +31 -28
- package/front_end/core/sdk/DebuggerModel.ts +4 -14
- package/front_end/core/sdk/sdk-meta.ts +17 -3
- package/front_end/emulated_devices/module.json +1 -3
- package/front_end/entrypoints/devtools_app/devtools_app.json +1 -9
- package/front_end/entrypoints/main/MainImpl.ts +26 -0
- package/front_end/entrypoints/shell/shell.js +0 -11
- package/front_end/entrypoints/shell/shell.json +0 -2
- package/front_end/entrypoints/worker_app/worker_app.json +0 -4
- package/front_end/generated/InspectorBackendCommands.js +1 -0
- package/front_end/generated/protocol.d.ts +2 -0
- package/front_end/global_typings/global_defs.d.ts +5 -0
- package/front_end/legacy_test_runner/bindings_test_runner/IsolatedFilesystemTestRunner.js +2 -2
- package/front_end/legacy_test_runner/console_test_runner/console_test_runner.js +14 -2
- package/front_end/legacy_test_runner/legacy_test_runner.ts +10 -1
- package/front_end/legacy_test_runner/test_runner/TestRunner.js +11 -0
- package/front_end/models/formatter/SourceFormatter.ts +0 -10
- package/front_end/models/workspace/UISourceCode.ts +9 -42
- package/front_end/panels/animation/AnimationTimeline.ts +3 -3
- package/front_end/panels/application/ApplicationPanelSidebar.ts +3 -3
- package/front_end/panels/application/application-meta.ts +0 -3
- package/front_end/panels/application/components/EndpointsGrid.ts +1 -1
- package/front_end/panels/application/components/ReportsGrid.ts +1 -1
- package/front_end/panels/console/ConsolePinPane.ts +21 -26
- package/front_end/panels/coverage/CoverageDecorationManager.ts +4 -5
- package/front_end/panels/coverage/CoverageView.ts +2 -105
- package/front_end/panels/css_overview/components/CSSOverviewStartView.ts +11 -56
- package/front_end/panels/css_overview/components/cssOverviewStartView.css +1 -8
- package/front_end/panels/elements/ElementsTreeElement.ts +4 -9
- package/front_end/panels/elements/components/StylePropertyEditor.ts +2 -0
- package/front_end/panels/elements/components/adornerSettingsPane.css +0 -4
- package/front_end/panels/emulation/DeviceModeToolbar.ts +3 -1
- package/front_end/panels/emulation/DeviceModeView.ts +2 -1
- package/front_end/panels/emulation/InspectedPagePlaceholder.ts +3 -1
- package/front_end/panels/emulation/MediaQueryInspector.ts +3 -1
- package/front_end/panels/emulation/emulation-meta.ts +2 -4
- package/front_end/panels/issues/issues-meta.ts +0 -2
- package/front_end/panels/layers/module.json +0 -1
- package/front_end/panels/lighthouse/LighthousePanel.ts +2 -4
- package/front_end/panels/lighthouse/LighthouseReportRenderer.ts +1 -4
- package/front_end/panels/lighthouse/lighthouseStartView.css +4 -0
- package/front_end/panels/lighthouse/module.json +1 -4
- package/front_end/panels/media/media-meta.ts +0 -3
- package/front_end/panels/network/ResourceWebSocketFrameView.ts +2 -1
- package/front_end/panels/network/network-meta.ts +0 -3
- package/front_end/panels/profiler/module.json +1 -4
- package/front_end/panels/screencast/module.json +1 -4
- package/front_end/panels/security/security-meta.ts +0 -3
- package/front_end/panels/sources/BreakpointEditDialog.ts +16 -30
- package/front_end/panels/sources/CSSPlugin.ts +310 -331
- package/front_end/panels/sources/CallStackSidebarPane.ts +28 -34
- package/front_end/panels/sources/CoveragePlugin.ts +121 -6
- package/front_end/panels/sources/DebuggerPlugin.ts +1166 -1243
- package/front_end/panels/sources/EditingLocationHistoryManager.ts +71 -101
- package/front_end/panels/sources/GoToLineQuickOpen.ts +4 -3
- package/front_end/panels/sources/InplaceFormatterEditorAction.ts +3 -3
- package/front_end/panels/sources/JavaScriptCompilerPlugin.ts +26 -23
- package/front_end/panels/sources/Plugin.ts +20 -4
- package/front_end/panels/sources/ProfilePlugin.ts +185 -0
- package/front_end/panels/sources/ScriptFormatterEditorAction.ts +3 -3
- package/front_end/panels/sources/ScriptOriginPlugin.ts +0 -10
- package/front_end/panels/sources/SnippetsPlugin.ts +1 -10
- package/front_end/panels/sources/SourcesPanel.ts +15 -10
- package/front_end/panels/sources/SourcesView.ts +10 -8
- package/front_end/panels/sources/TabbedEditorContainer.ts +31 -27
- package/front_end/panels/sources/UISourceCodeFrame.ts +335 -470
- package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +3 -2
- package/front_end/panels/sources/sources-legacy.ts +0 -6
- package/front_end/panels/sources/sources.ts +0 -2
- package/front_end/panels/timeline/module.json +0 -3
- package/front_end/third_party/codemirror.next/bundle.ts +9 -13
- package/front_end/third_party/codemirror.next/chunk/codemirror.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/javascript.js +2 -2
- package/front_end/third_party/codemirror.next/chunk/markdown.js +2 -6
- package/front_end/third_party/codemirror.next/chunk/php.js +2 -6
- package/front_end/third_party/codemirror.next/chunk/python.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/wast.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/xml.js +2 -2
- package/front_end/third_party/codemirror.next/codemirror.next.d.ts +279 -198
- package/front_end/third_party/codemirror.next/codemirror.next.js +1 -1
- package/front_end/third_party/codemirror.next/package.json +13 -11
- package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +1128 -1158
- package/front_end/third_party/lighthouse/locales/ar-XB.json +211 -79
- package/front_end/third_party/lighthouse/locales/ar.json +213 -81
- package/front_end/third_party/lighthouse/locales/bg.json +211 -79
- package/front_end/third_party/lighthouse/locales/ca.json +212 -80
- package/front_end/third_party/lighthouse/locales/cs.json +211 -79
- package/front_end/third_party/lighthouse/locales/da.json +211 -79
- package/front_end/third_party/lighthouse/locales/de.json +211 -79
- package/front_end/third_party/lighthouse/locales/el.json +213 -81
- package/front_end/third_party/lighthouse/locales/en-GB.json +211 -79
- package/front_end/third_party/lighthouse/locales/en-US.json +186 -75
- package/front_end/third_party/lighthouse/locales/en-XA.json +211 -79
- package/front_end/third_party/lighthouse/locales/en-XL.json +186 -75
- package/front_end/third_party/lighthouse/locales/es-419.json +211 -79
- package/front_end/third_party/lighthouse/locales/es.json +212 -80
- package/front_end/third_party/lighthouse/locales/fi.json +211 -79
- package/front_end/third_party/lighthouse/locales/fil.json +211 -79
- package/front_end/third_party/lighthouse/locales/fr.json +211 -79
- package/front_end/third_party/lighthouse/locales/he.json +212 -80
- package/front_end/third_party/lighthouse/locales/hi.json +214 -82
- package/front_end/third_party/lighthouse/locales/hr.json +211 -79
- package/front_end/third_party/lighthouse/locales/hu.json +211 -79
- package/front_end/third_party/lighthouse/locales/id.json +211 -79
- package/front_end/third_party/lighthouse/locales/it.json +211 -79
- package/front_end/third_party/lighthouse/locales/ja.json +211 -79
- package/front_end/third_party/lighthouse/locales/ko.json +211 -79
- package/front_end/third_party/lighthouse/locales/lt.json +211 -79
- package/front_end/third_party/lighthouse/locales/lv.json +214 -82
- package/front_end/third_party/lighthouse/locales/nl.json +211 -79
- package/front_end/third_party/lighthouse/locales/no.json +211 -79
- package/front_end/third_party/lighthouse/locales/pl.json +211 -79
- package/front_end/third_party/lighthouse/locales/pt-PT.json +211 -79
- package/front_end/third_party/lighthouse/locales/pt.json +211 -79
- package/front_end/third_party/lighthouse/locales/ro.json +212 -80
- package/front_end/third_party/lighthouse/locales/ru.json +211 -79
- package/front_end/third_party/lighthouse/locales/sk.json +211 -79
- package/front_end/third_party/lighthouse/locales/sl.json +211 -79
- package/front_end/third_party/lighthouse/locales/sr-Latn.json +211 -79
- package/front_end/third_party/lighthouse/locales/sr.json +211 -79
- package/front_end/third_party/lighthouse/locales/sv.json +211 -79
- package/front_end/third_party/lighthouse/locales/ta.json +218 -86
- package/front_end/third_party/lighthouse/locales/te.json +251 -119
- package/front_end/third_party/lighthouse/locales/th.json +211 -79
- package/front_end/third_party/lighthouse/locales/tr.json +211 -79
- package/front_end/third_party/lighthouse/locales/uk.json +212 -80
- package/front_end/third_party/lighthouse/locales/vi.json +211 -79
- package/front_end/third_party/lighthouse/locales/zh-HK.json +211 -79
- package/front_end/third_party/lighthouse/locales/zh-TW.json +211 -79
- package/front_end/third_party/lighthouse/locales/zh.json +211 -79
- package/front_end/third_party/lighthouse/report/bundle.d.ts +72 -34
- package/front_end/third_party/lighthouse/report/bundle.js +698 -492
- package/front_end/third_party/lighthouse/report-assets/report-generator.js +1 -2
- package/front_end/third_party/lighthouse/report-assets/report.js +40 -35
- package/front_end/third_party/lighthouse/report-assets/standalone-template.html +2 -4
- package/front_end/ui/components/code_highlighter/CodeHighlighter.ts +60 -68
- package/front_end/ui/components/data_grid/dataGrid.css +12 -10
- package/front_end/ui/components/docs/css_overview/start_view.html +25 -0
- package/front_end/ui/components/docs/css_overview/start_view.ts +14 -0
- package/front_end/ui/components/docs/icon_button/basic.ts +3 -3
- package/front_end/ui/components/docs/panel_feedback/basic.html +25 -0
- package/front_end/ui/components/docs/panel_feedback/basic.ts +20 -0
- package/front_end/ui/components/docs/panel_feedback/button.html +25 -0
- package/front_end/ui/components/docs/panel_feedback/button.ts +18 -0
- package/front_end/ui/components/helpers/get-stylesheet.ts +0 -13
- package/front_end/ui/components/markdown_view/MarkdownImagesMap.ts +1 -1
- package/front_end/ui/components/panel_feedback/FeedbackButton.ts +67 -0
- package/front_end/ui/components/panel_feedback/PanelFeedback.ts +100 -0
- package/front_end/ui/components/panel_feedback/panelFeedback.css +76 -0
- package/front_end/ui/components/panel_feedback/panel_feedback.ts +6 -0
- package/front_end/ui/components/report_view/reportValue.css +1 -0
- package/front_end/ui/components/survey_link/SurveyLink.ts +1 -1
- package/front_end/ui/components/text_editor/TextEditor.ts +79 -36
- package/front_end/ui/components/text_editor/config.ts +42 -26
- package/front_end/ui/components/text_editor/javascript.ts +2 -3
- package/front_end/ui/components/text_editor/position.ts +17 -0
- package/front_end/ui/components/text_editor/text_editor.ts +1 -0
- package/front_end/ui/components/text_editor/theme.ts +5 -1
- package/front_end/ui/legacy/Dialog.ts +3 -1
- package/front_end/ui/legacy/DropTarget.ts +2 -1
- package/front_end/ui/legacy/EmptyWidget.ts +2 -1
- package/front_end/ui/legacy/FilterBar.ts +2 -1
- package/front_end/ui/legacy/GlassPane.ts +4 -2
- package/front_end/ui/legacy/Infobar.ts +5 -8
- package/front_end/ui/legacy/InspectorView.ts +6 -1
- package/front_end/ui/legacy/ListWidget.ts +2 -1
- package/front_end/ui/legacy/PopoverHelper.ts +2 -1
- package/front_end/ui/legacy/ProgressIndicator.ts +2 -1
- package/front_end/ui/legacy/RemoteDebuggingTerminatedScreen.ts +2 -1
- package/front_end/ui/legacy/ReportView.ts +2 -1
- package/front_end/ui/legacy/RootView.ts +2 -1
- package/front_end/ui/legacy/SearchableView.ts +2 -1
- package/front_end/ui/legacy/ShortcutRegistry.ts +11 -7
- package/front_end/ui/legacy/SoftContextMenu.ts +2 -1
- package/front_end/ui/legacy/SoftDropDown.ts +4 -2
- package/front_end/ui/legacy/SplitWidget.ts +2 -1
- package/front_end/ui/legacy/SuggestBox.ts +2 -1
- package/front_end/ui/legacy/TabbedPane.ts +2 -1
- package/front_end/ui/legacy/TargetCrashedScreen.ts +2 -1
- package/front_end/ui/legacy/TextPrompt.ts +2 -1
- package/front_end/ui/legacy/Toolbar.ts +3 -2
- package/front_end/ui/legacy/Treeoutline.ts +3 -2
- package/front_end/ui/legacy/UIUtils.ts +16 -13
- package/front_end/ui/legacy/ViewManager.ts +2 -1
- package/front_end/ui/legacy/Widget.ts +1 -1
- package/front_end/ui/legacy/components/perf_ui/ChartViewport.ts +2 -1
- package/front_end/ui/legacy/components/perf_ui/FilmStripView.ts +3 -1
- package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +2 -1
- package/front_end/ui/legacy/components/perf_ui/LineLevelProfile.ts +35 -131
- package/front_end/ui/legacy/components/perf_ui/OverviewGrid.ts +2 -1
- package/front_end/ui/legacy/components/perf_ui/TimelineGrid.ts +3 -1
- package/front_end/ui/legacy/components/perf_ui/TimelineOverviewPane.ts +2 -1
- package/front_end/ui/legacy/components/quick_open/filteredListWidget.css +2 -2
- package/front_end/ui/legacy/components/source_frame/BinaryResourceViewFactory.ts +3 -6
- package/front_end/ui/legacy/components/source_frame/FontView.ts +1 -0
- package/front_end/ui/legacy/components/source_frame/ImageView.ts +1 -0
- package/front_end/ui/legacy/components/source_frame/JSONView.ts +1 -0
- package/front_end/ui/legacy/components/source_frame/ResourceSourceFrame.ts +19 -14
- package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +502 -252
- package/front_end/ui/legacy/components/source_frame/XMLView.ts +2 -0
- package/front_end/ui/legacy/components/source_frame/module.json +0 -3
- package/front_end/ui/legacy/components/source_frame/source_frame-legacy.ts +0 -11
- package/front_end/ui/legacy/components/source_frame/source_frame.ts +0 -2
- package/front_end/ui/legacy/components/text_editor/CodeMirrorTextEditor.ts +2 -0
- package/front_end/ui/legacy/components/text_editor/cmdevtools.css +3 -1
- package/front_end/ui/legacy/components/text_editor/module.json +0 -3
- package/front_end/ui/legacy/components/utils/Linkifier.ts +7 -15
- package/front_end/ui/legacy/radioButton.css +1 -13
- package/front_end/ui/legacy/softContextMenu.css +1 -0
- package/front_end/ui/legacy/themeColors.css +36 -0
- package/front_end/ui/legacy/theme_support/theme_support_impl.ts +7 -9
- package/front_end/ui/legacy/utils/append-style.ts +9 -4
- package/front_end/ui/legacy/utils/create-shadow-root-with-core-styles.ts +2 -2
- package/front_end/ui/legacy/utils/inject-core-styles.ts +7 -4
- package/package.json +1 -1
- package/scripts/build/generate_css_js_files.js +23 -9
- package/scripts/build/ninja/generate_css.gni +10 -1
- package/scripts/eslint_rules/lib/check_css_import.js +2 -2
- package/scripts/eslint_rules/tests/check_css_import_test.js +12 -0
- package/front_end/Images/radioDot-dark-theme.png +0 -0
- package/front_end/Images/radioDot.png +0 -0
- package/front_end/panels/application/module.json +0 -7
- package/front_end/panels/emulation/module.json +0 -11
- package/front_end/panels/issues/module.json +0 -6
- package/front_end/panels/layer_viewer/module.json +0 -6
- package/front_end/panels/media/module.json +0 -6
- package/front_end/panels/network/module.json +0 -6
- package/front_end/panels/security/module.json +0 -5
- package/front_end/third_party/lighthouse/report-assets/report.css +0 -1774
- package/front_end/ui/legacy/components/perf_ui/module.json +0 -13
- package/front_end/ui/legacy/components/source_frame/SourcesTextEditor.ts +0 -1030
- package/front_end/ui/legacy/module.json +0 -41
|
@@ -33,12 +33,11 @@ import * as i18n from '../../../../core/i18n/i18n.js';
|
|
|
33
33
|
import * as Platform from '../../../../core/platform/platform.js';
|
|
34
34
|
import * as Formatter from '../../../../models/formatter/formatter.js';
|
|
35
35
|
import * as TextUtils from '../../../../models/text_utils/text_utils.js';
|
|
36
|
-
import
|
|
36
|
+
import * as CodeMirror from '../../../../third_party/codemirror.next/codemirror.next.js';
|
|
37
|
+
import * as CodeHighlighter from '../../../components/code_highlighter/code_highlighter.js';
|
|
38
|
+
import * as TextEditor from '../../../components/text_editor/text_editor.js';
|
|
37
39
|
import * as UI from '../../legacy.js';
|
|
38
40
|
|
|
39
|
-
import type {SourcesTextEditorDelegate} from './SourcesTextEditor.js';
|
|
40
|
-
import {Events, SourcesTextEditor} from './SourcesTextEditor.js';
|
|
41
|
-
|
|
42
41
|
const UIStrings = {
|
|
43
42
|
/**
|
|
44
43
|
*@description Text for the source of something
|
|
@@ -85,9 +84,25 @@ const UIStrings = {
|
|
|
85
84
|
const str_ = i18n.i18n.registerUIStrings('ui/legacy/components/source_frame/SourceFrame.ts', UIStrings);
|
|
86
85
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
87
86
|
|
|
88
|
-
export
|
|
89
|
-
|
|
90
|
-
|
|
87
|
+
export interface SourceFrameOptions {
|
|
88
|
+
// Whether to show line numbers. Defaults to true.
|
|
89
|
+
lineNumbers?: boolean;
|
|
90
|
+
// Whether to wrap lines. Defaults to false.
|
|
91
|
+
lineWrapping?: boolean;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export const enum Events {
|
|
95
|
+
EditorUpdate = 'EditorUpdate',
|
|
96
|
+
EditorScroll = 'EditorScroll',
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export type EventTypes = {
|
|
100
|
+
[Events.EditorUpdate]: CodeMirror.ViewUpdate,
|
|
101
|
+
[Events.EditorScroll]: void,
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
export class SourceFrameImpl extends Common.ObjectWrapper.eventMixin<EventTypes, typeof UI.View.SimpleView>(
|
|
105
|
+
UI.View.SimpleView) implements UI.SearchableView.Searchable, UI.SearchableView.Replaceable, Transformer {
|
|
91
106
|
private readonly lazyContent: () => Promise<TextUtils.ContentProvider.DeferredContent>;
|
|
92
107
|
private prettyInternal: boolean;
|
|
93
108
|
private rawContent: string|null;
|
|
@@ -96,13 +111,14 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
|
|
|
96
111
|
private readonly prettyToggle: UI.Toolbar.ToolbarToggle;
|
|
97
112
|
private shouldAutoPrettyPrint: boolean;
|
|
98
113
|
private readonly progressToolbarItem: UI.Toolbar.ToolbarItem;
|
|
99
|
-
private textEditorInternal:
|
|
100
|
-
private
|
|
101
|
-
private
|
|
114
|
+
private textEditorInternal: TextEditor.TextEditor.TextEditor;
|
|
115
|
+
private prettyBaseDoc: CodeMirror.Text|null = null;
|
|
116
|
+
private baseDoc: CodeMirror.Text;
|
|
117
|
+
private displayedSelection: CodeMirror.EditorSelection|null = null;
|
|
102
118
|
private searchConfig: UI.SearchableView.SearchConfig|null;
|
|
103
119
|
private delayedFindSearchMatches: (() => void)|null;
|
|
104
120
|
private currentSearchResultIndex: number;
|
|
105
|
-
private searchResults:
|
|
121
|
+
private searchResults: SearchMatch[];
|
|
106
122
|
private searchRegex: RegExp|null;
|
|
107
123
|
private loadError: boolean;
|
|
108
124
|
private muteChangeEventsForSetContent: boolean;
|
|
@@ -118,12 +134,11 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
|
|
|
118
134
|
private selectionToSet: TextUtils.TextRange.TextRange|null;
|
|
119
135
|
private loadedInternal: boolean;
|
|
120
136
|
private contentRequested: boolean;
|
|
121
|
-
private highlighterTypeInternal: string;
|
|
122
137
|
private wasmDisassemblyInternal: Common.WasmDisassembly.WasmDisassembly|null;
|
|
123
138
|
contentSet: boolean;
|
|
124
139
|
constructor(
|
|
125
140
|
lazyContent: () => Promise<TextUtils.ContentProvider.DeferredContent>,
|
|
126
|
-
|
|
141
|
+
private readonly options: SourceFrameOptions = {}) {
|
|
127
142
|
super(i18nString(UIStrings.source));
|
|
128
143
|
|
|
129
144
|
this.lazyContent = lazyContent;
|
|
@@ -141,11 +156,11 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
|
|
|
141
156
|
|
|
142
157
|
this.progressToolbarItem = new UI.Toolbar.ToolbarItem(document.createElement('div'));
|
|
143
158
|
|
|
144
|
-
this.textEditorInternal = new
|
|
145
|
-
this.textEditorInternal.
|
|
159
|
+
this.textEditorInternal = new TextEditor.TextEditor.TextEditor(this.placeholderEditorState(''));
|
|
160
|
+
this.textEditorInternal.style.flexGrow = '1';
|
|
161
|
+
this.element.appendChild(this.textEditorInternal);
|
|
146
162
|
|
|
147
|
-
this.
|
|
148
|
-
this.cleanGeneration = 0;
|
|
163
|
+
this.baseDoc = this.textEditorInternal.state.doc;
|
|
149
164
|
|
|
150
165
|
this.searchConfig = null;
|
|
151
166
|
this.delayedFindSearchMatches = null;
|
|
@@ -154,36 +169,110 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
|
|
|
154
169
|
this.searchRegex = null;
|
|
155
170
|
this.loadError = false;
|
|
156
171
|
|
|
157
|
-
this.textEditorInternal.addEventListener(Events.EditorFocused, this.resetCurrentSearchResultIndex, this);
|
|
158
|
-
this.textEditorInternal.addEventListener(Events.SelectionChanged, this.updateSourcePosition, this);
|
|
159
|
-
this.textEditorInternal.addEventListener(UI.TextEditor.Events.TextChanged, event => {
|
|
160
|
-
if (!this.muteChangeEventsForSetContent) {
|
|
161
|
-
this.onTextChanged(event.data.oldRange, event.data.newRange);
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
172
|
this.muteChangeEventsForSetContent = false;
|
|
165
173
|
|
|
166
174
|
this.sourcePosition = new UI.Toolbar.ToolbarText();
|
|
167
175
|
|
|
168
176
|
this.searchableView = null;
|
|
169
177
|
this.editable = false;
|
|
170
|
-
this.textEditorInternal.setReadOnly(true);
|
|
171
178
|
|
|
172
179
|
this.positionToReveal = null;
|
|
173
180
|
this.lineToScrollTo = null;
|
|
174
181
|
this.selectionToSet = null;
|
|
175
182
|
this.loadedInternal = false;
|
|
176
183
|
this.contentRequested = false;
|
|
177
|
-
this.highlighterTypeInternal = '';
|
|
178
184
|
|
|
179
185
|
this.wasmDisassemblyInternal = null;
|
|
180
186
|
this.contentSet = false;
|
|
181
187
|
}
|
|
182
188
|
|
|
189
|
+
private placeholderEditorState(content: string): CodeMirror.EditorState {
|
|
190
|
+
return CodeMirror.EditorState.create({
|
|
191
|
+
doc: content,
|
|
192
|
+
extensions: [
|
|
193
|
+
CodeMirror.EditorState.readOnly.of(true),
|
|
194
|
+
this.options.lineNumbers !== false ? CodeMirror.lineNumbers() : [],
|
|
195
|
+
TextEditor.Config.theme(),
|
|
196
|
+
],
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
protected editorConfiguration(doc: string): CodeMirror.Extension {
|
|
201
|
+
return [
|
|
202
|
+
CodeMirror.EditorView.updateListener.of(update => this.dispatchEventToListeners(Events.EditorUpdate, update)),
|
|
203
|
+
TextEditor.Config.baseConfiguration(doc),
|
|
204
|
+
TextEditor.Config.sourcesAutocompletion.instance(),
|
|
205
|
+
TextEditor.Config.showWhitespace.instance(),
|
|
206
|
+
TextEditor.Config.allowScrollPastEof.instance(),
|
|
207
|
+
TextEditor.Config.codeFolding.instance(),
|
|
208
|
+
TextEditor.Config.autoDetectIndent.instance(),
|
|
209
|
+
CodeMirror.EditorView.theme({
|
|
210
|
+
'&.cm-editor': {height: '100%'},
|
|
211
|
+
'.cm-scroller': {overflow: 'auto'},
|
|
212
|
+
'.cm-lineNumbers .cm-gutterElement.cm-nonBreakableLine': {color: 'var(--color-non-breakable-line)'},
|
|
213
|
+
'.cm-searchMatch': {
|
|
214
|
+
border: '1px solid var(--color-search-match-border)',
|
|
215
|
+
borderRadius: '3px',
|
|
216
|
+
margin: '0 -1px',
|
|
217
|
+
'&.cm-searchMatch-selected': {
|
|
218
|
+
borderRadius: '1px',
|
|
219
|
+
backgroundColor: 'var(--color-selected-search-match-background)',
|
|
220
|
+
borderColor: 'var(--color-selected-search-match-background)',
|
|
221
|
+
'&, & *': {
|
|
222
|
+
color: 'var(--color-selected-search-match) !important',
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
}),
|
|
227
|
+
CodeMirror.EditorView.domEventHandlers({
|
|
228
|
+
focus: () => this.onFocus(),
|
|
229
|
+
blur: () => this.onBlur(),
|
|
230
|
+
scroll: () => this.dispatchEventToListeners(Events.EditorScroll),
|
|
231
|
+
contextmenu: event => this.onContextMenu(event),
|
|
232
|
+
}),
|
|
233
|
+
CodeMirror.lineNumbers({
|
|
234
|
+
domEventHandlers:
|
|
235
|
+
{contextmenu: (_view, block, event) => this.onLineGutterContextMenu(block.from, event as MouseEvent)},
|
|
236
|
+
}),
|
|
237
|
+
CodeMirror.EditorView.updateListener.of(
|
|
238
|
+
(update):
|
|
239
|
+
void => {
|
|
240
|
+
if (update.selectionSet || update.docChanged) {
|
|
241
|
+
this.updateSourcePosition();
|
|
242
|
+
}
|
|
243
|
+
if (update.docChanged) {
|
|
244
|
+
this.onTextChanged();
|
|
245
|
+
}
|
|
246
|
+
}),
|
|
247
|
+
activeSearchState,
|
|
248
|
+
CodeMirror.Prec.lowest(searchHighlighter),
|
|
249
|
+
config.lineNumbers.of([]),
|
|
250
|
+
config.language.of([]),
|
|
251
|
+
this.wasmDisassemblyInternal ? markNonBreakableLines(this.wasmDisassemblyInternal) : nonBreakableLines,
|
|
252
|
+
this.options.lineWrapping ? CodeMirror.EditorView.lineWrapping : [],
|
|
253
|
+
this.options.lineNumbers !== false ? CodeMirror.lineNumbers() : [],
|
|
254
|
+
];
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
protected onBlur(): void {
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
protected onFocus(): void {
|
|
261
|
+
this.resetCurrentSearchResultIndex();
|
|
262
|
+
}
|
|
263
|
+
|
|
183
264
|
get wasmDisassembly(): Common.WasmDisassembly.WasmDisassembly|null {
|
|
184
265
|
return this.wasmDisassemblyInternal;
|
|
185
266
|
}
|
|
186
267
|
|
|
268
|
+
editorLocationToUILocation(lineNumber: number, columnNumber: number): {
|
|
269
|
+
lineNumber: number,
|
|
270
|
+
columnNumber: number,
|
|
271
|
+
};
|
|
272
|
+
editorLocationToUILocation(lineNumber: number): {
|
|
273
|
+
lineNumber: number,
|
|
274
|
+
columnNumber: number|undefined,
|
|
275
|
+
};
|
|
187
276
|
editorLocationToUILocation(lineNumber: number, columnNumber?: number): {
|
|
188
277
|
lineNumber: number,
|
|
189
278
|
columnNumber?: number|undefined,
|
|
@@ -215,47 +304,62 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
|
|
|
215
304
|
this.prettyToggle.setVisible(canPrettyPrint);
|
|
216
305
|
}
|
|
217
306
|
|
|
307
|
+
setEditable(editable: boolean): void {
|
|
308
|
+
this.editable = editable;
|
|
309
|
+
if (this.loaded && editable !== !this.textEditor.state.readOnly) {
|
|
310
|
+
this.textEditor.dispatch({effects: config.editable.reconfigure(CodeMirror.EditorState.readOnly.of(!editable))});
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
218
314
|
private async setPretty(value: boolean): Promise<void> {
|
|
219
315
|
this.prettyInternal = value;
|
|
220
316
|
this.prettyToggle.setEnabled(false);
|
|
221
317
|
|
|
222
318
|
const wasLoaded = this.loaded;
|
|
223
|
-
const
|
|
319
|
+
const {textEditor} = this;
|
|
320
|
+
const selection = textEditor.state.selection.main;
|
|
321
|
+
const startPos = textEditor.toLineColumn(selection.from), endPos = textEditor.toLineColumn(selection.to);
|
|
224
322
|
let newSelection;
|
|
225
323
|
if (this.prettyInternal) {
|
|
226
324
|
const formatInfo = await this.requestFormattedContent();
|
|
227
325
|
this.formattedMap = formatInfo.formattedMapping;
|
|
228
|
-
this.setContent(formatInfo.formattedContent
|
|
229
|
-
this.
|
|
230
|
-
const start = this.rawToPrettyLocation(
|
|
231
|
-
const end = this.rawToPrettyLocation(
|
|
232
|
-
newSelection =
|
|
326
|
+
await this.setContent(formatInfo.formattedContent);
|
|
327
|
+
this.prettyBaseDoc = textEditor.state.doc;
|
|
328
|
+
const start = this.rawToPrettyLocation(startPos.lineNumber, startPos.columnNumber);
|
|
329
|
+
const end = this.rawToPrettyLocation(endPos.lineNumber, endPos.columnNumber);
|
|
330
|
+
newSelection = textEditor.createSelection(
|
|
331
|
+
{lineNumber: start[0], columnNumber: start[1]}, {lineNumber: end[0], columnNumber: end[1]});
|
|
233
332
|
} else {
|
|
234
|
-
this.setContent(this.rawContent
|
|
235
|
-
this.
|
|
236
|
-
const start = this.prettyToRawLocation(
|
|
237
|
-
const end = this.prettyToRawLocation(
|
|
238
|
-
newSelection =
|
|
333
|
+
await this.setContent(this.rawContent || '');
|
|
334
|
+
this.baseDoc = textEditor.state.doc;
|
|
335
|
+
const start = this.prettyToRawLocation(startPos.lineNumber, startPos.columnNumber);
|
|
336
|
+
const end = this.prettyToRawLocation(endPos.lineNumber, endPos.columnNumber);
|
|
337
|
+
newSelection = textEditor.createSelection(
|
|
338
|
+
{lineNumber: start[0], columnNumber: start[1]}, {lineNumber: end[0], columnNumber: end[1]});
|
|
239
339
|
}
|
|
240
340
|
if (wasLoaded) {
|
|
241
|
-
|
|
242
|
-
this.textEditor.setSelection(newSelection);
|
|
341
|
+
textEditor.revealPosition(newSelection, false);
|
|
243
342
|
}
|
|
244
343
|
this.prettyToggle.setEnabled(true);
|
|
245
344
|
this.updatePrettyPrintState();
|
|
246
345
|
}
|
|
247
346
|
|
|
248
|
-
private
|
|
347
|
+
private getLineNumberFormatter(): CodeMirror.Extension {
|
|
348
|
+
if (this.options.lineNumbers === false) {
|
|
349
|
+
return [];
|
|
350
|
+
}
|
|
351
|
+
let formatNumber = null;
|
|
249
352
|
if (this.wasmDisassemblyInternal) {
|
|
250
353
|
const disassembly = this.wasmDisassemblyInternal;
|
|
251
354
|
const lastBytecodeOffset = disassembly.lineNumberToBytecodeOffset(disassembly.lineNumbers - 1);
|
|
252
355
|
const bytecodeOffsetDigits = lastBytecodeOffset.toString(16).length + 1;
|
|
253
|
-
|
|
254
|
-
const bytecodeOffset =
|
|
356
|
+
formatNumber = (lineNumber: number): string => {
|
|
357
|
+
const bytecodeOffset =
|
|
358
|
+
disassembly.lineNumberToBytecodeOffset(Math.min(disassembly.lineNumbers, lineNumber) - 1);
|
|
255
359
|
return `0x${bytecodeOffset.toString(16).padStart(bytecodeOffsetDigits, '0')}`;
|
|
256
|
-
}
|
|
360
|
+
};
|
|
257
361
|
} else if (this.prettyInternal) {
|
|
258
|
-
|
|
362
|
+
formatNumber = (lineNumber: number): string => {
|
|
259
363
|
const line = this.prettyToRawLocation(lineNumber - 1, 0)[0] + 1;
|
|
260
364
|
if (lineNumber === 1) {
|
|
261
365
|
return String(line);
|
|
@@ -264,17 +368,18 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
|
|
|
264
368
|
return String(line);
|
|
265
369
|
}
|
|
266
370
|
return '-';
|
|
267
|
-
}
|
|
268
|
-
} else {
|
|
269
|
-
this.textEditorInternal.setLineNumberFormatter(lineNumber => {
|
|
270
|
-
return String(lineNumber);
|
|
271
|
-
});
|
|
371
|
+
};
|
|
272
372
|
}
|
|
373
|
+
return formatNumber ? CodeMirror.lineNumbers({formatNumber}) : [];
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
private updateLineNumberFormatter(): void {
|
|
377
|
+
this.textEditor.dispatch({effects: config.lineNumbers.reconfigure(this.getLineNumberFormatter())});
|
|
273
378
|
}
|
|
274
379
|
|
|
275
380
|
private updatePrettyPrintState(): void {
|
|
276
381
|
this.prettyToggle.setToggled(this.prettyInternal);
|
|
277
|
-
this.textEditorInternal.
|
|
382
|
+
this.textEditorInternal.classList.toggle('pretty-printed', this.prettyInternal);
|
|
278
383
|
this.updateLineNumberFormatter();
|
|
279
384
|
}
|
|
280
385
|
|
|
@@ -292,13 +397,6 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
|
|
|
292
397
|
return this.formattedMap.originalToFormatted(line, column);
|
|
293
398
|
}
|
|
294
399
|
|
|
295
|
-
setEditable(editable: boolean): void {
|
|
296
|
-
this.editable = editable;
|
|
297
|
-
if (this.loadedInternal) {
|
|
298
|
-
this.textEditorInternal.setReadOnly(!editable);
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
400
|
hasLoadError(): boolean {
|
|
303
401
|
return this.loadError;
|
|
304
402
|
}
|
|
@@ -322,7 +420,7 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
|
|
|
322
420
|
return this.loadedInternal;
|
|
323
421
|
}
|
|
324
422
|
|
|
325
|
-
get textEditor():
|
|
423
|
+
get textEditor(): TextEditor.TextEditor.TextEditor {
|
|
326
424
|
return this.textEditorInternal;
|
|
327
425
|
}
|
|
328
426
|
|
|
@@ -330,6 +428,14 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
|
|
|
330
428
|
return this.prettyInternal;
|
|
331
429
|
}
|
|
332
430
|
|
|
431
|
+
get contentType(): string {
|
|
432
|
+
return this.loadError ? '' : this.getContentType();
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
protected getContentType(): string {
|
|
436
|
+
return '';
|
|
437
|
+
}
|
|
438
|
+
|
|
333
439
|
private async ensureContentLoaded(): Promise<void> {
|
|
334
440
|
if (!this.contentRequested) {
|
|
335
441
|
this.contentRequested = true;
|
|
@@ -351,7 +457,7 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
|
|
|
351
457
|
|
|
352
458
|
progressIndicator.setWorked(1);
|
|
353
459
|
|
|
354
|
-
if (!error && this.
|
|
460
|
+
if (!error && this.contentType === 'application/wasm') {
|
|
355
461
|
const worker = Common.Worker.WorkerWrapper.fromURL(
|
|
356
462
|
new URL('../../../../entrypoints/wasmparser_worker/wasmparser_worker-entrypoint.js', import.meta.url));
|
|
357
463
|
const promise = new Promise<{
|
|
@@ -407,24 +513,14 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
|
|
|
407
513
|
this.prettyToggle.setEnabled(true);
|
|
408
514
|
|
|
409
515
|
if (error) {
|
|
410
|
-
this.
|
|
516
|
+
this.loadError = true;
|
|
517
|
+
this.textEditor.editor.setState(this.placeholderEditorState(error));
|
|
411
518
|
this.prettyToggle.setEnabled(false);
|
|
412
|
-
|
|
413
|
-
// Occasionally on load, there can be a race in which it appears the CodeMirror plugin
|
|
414
|
-
// runs the highlighter type assignment out of order. In case of an error then, set
|
|
415
|
-
// the highlighter type after a short delay. This appears to only occur the first
|
|
416
|
-
// time that CodeMirror is initialized, likely because the highlighter type was first
|
|
417
|
-
// initialized based on the file type, and the syntax highlighting is in a race
|
|
418
|
-
// with the new highlighter assignment. As the option is just an option and is not
|
|
419
|
-
// observable, we can't handle waiting for it here.
|
|
420
|
-
// https://github.com/codemirror/CodeMirror/issues/6019
|
|
421
|
-
// CRBug 1011445
|
|
422
|
-
setTimeout(() => this.setHighlighterType('text/plain'), 50);
|
|
423
519
|
} else {
|
|
424
520
|
if (this.shouldAutoPrettyPrint && TextUtils.TextUtils.isMinified(content)) {
|
|
425
521
|
await this.setPretty(true);
|
|
426
522
|
} else {
|
|
427
|
-
this.setContent(this.rawContent
|
|
523
|
+
await this.setContent(this.rawContent || '');
|
|
428
524
|
}
|
|
429
525
|
}
|
|
430
526
|
this.contentSet = true;
|
|
@@ -436,14 +532,28 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
|
|
|
436
532
|
return this.formattedContentPromise;
|
|
437
533
|
}
|
|
438
534
|
this.formattedContentPromise =
|
|
439
|
-
Formatter.ScriptFormatter.formatScriptContent(this.
|
|
535
|
+
Formatter.ScriptFormatter.formatScriptContent(this.contentType, this.rawContent || '');
|
|
440
536
|
return this.formattedContentPromise;
|
|
441
537
|
}
|
|
442
538
|
|
|
443
|
-
revealPosition(
|
|
539
|
+
revealPosition(position: {lineNumber: number, columnNumber?: number}|number, shouldHighlight?: boolean): void {
|
|
444
540
|
this.lineToScrollTo = null;
|
|
445
541
|
this.selectionToSet = null;
|
|
446
|
-
|
|
542
|
+
let line = 0, column = 0;
|
|
543
|
+
if (typeof position === 'number') {
|
|
544
|
+
const {doc} = this.textEditor.state;
|
|
545
|
+
if (position > doc.length) {
|
|
546
|
+
line = doc.lines - 1;
|
|
547
|
+
} else if (position >= 0) {
|
|
548
|
+
const lineObj = doc.lineAt(position);
|
|
549
|
+
line = lineObj.number - 1;
|
|
550
|
+
column = position - lineObj.from;
|
|
551
|
+
}
|
|
552
|
+
} else {
|
|
553
|
+
line = position.lineNumber;
|
|
554
|
+
column = position.columnNumber ?? 0;
|
|
555
|
+
}
|
|
556
|
+
this.positionToReveal = {line, column, shouldHighlight: shouldHighlight};
|
|
447
557
|
this.innerRevealPositionIfNeeded();
|
|
448
558
|
}
|
|
449
559
|
|
|
@@ -456,15 +566,14 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
|
|
|
456
566
|
return;
|
|
457
567
|
}
|
|
458
568
|
|
|
459
|
-
const
|
|
460
|
-
this.uiLocationToEditorLocation(this.positionToReveal.line, this.positionToReveal.column);
|
|
569
|
+
const location = this.uiLocationToEditorLocation(this.positionToReveal.line, this.positionToReveal.column);
|
|
461
570
|
|
|
462
|
-
|
|
571
|
+
const {textEditor} = this;
|
|
572
|
+
textEditor.revealPosition(textEditor.createSelection(location), this.positionToReveal.shouldHighlight);
|
|
463
573
|
this.positionToReveal = null;
|
|
464
574
|
}
|
|
465
575
|
|
|
466
576
|
private clearPositionToReveal(): void {
|
|
467
|
-
this.textEditorInternal.clearPositionHighlight();
|
|
468
577
|
this.positionToReveal = null;
|
|
469
578
|
}
|
|
470
579
|
|
|
@@ -477,24 +586,28 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
|
|
|
477
586
|
private innerScrollToLineIfNeeded(): void {
|
|
478
587
|
if (this.lineToScrollTo !== null) {
|
|
479
588
|
if (this.loaded && this.isShowing()) {
|
|
480
|
-
this
|
|
589
|
+
const {textEditor} = this;
|
|
590
|
+
const position = textEditor.toOffset({lineNumber: this.lineToScrollTo, columnNumber: 0});
|
|
591
|
+
textEditor.dispatch({effects: CodeMirror.EditorView.scrollTo.of(CodeMirror.EditorSelection.cursor(position))});
|
|
481
592
|
this.lineToScrollTo = null;
|
|
482
593
|
}
|
|
483
594
|
}
|
|
484
595
|
}
|
|
485
596
|
|
|
486
|
-
selection(): TextUtils.TextRange.TextRange {
|
|
487
|
-
return this.textEditor.selection();
|
|
488
|
-
}
|
|
489
|
-
|
|
490
597
|
setSelection(textRange: TextUtils.TextRange.TextRange): void {
|
|
491
598
|
this.selectionToSet = textRange;
|
|
492
599
|
this.innerSetSelectionIfNeeded();
|
|
493
600
|
}
|
|
494
601
|
|
|
495
602
|
private innerSetSelectionIfNeeded(): void {
|
|
496
|
-
|
|
497
|
-
|
|
603
|
+
const sel = this.selectionToSet;
|
|
604
|
+
if (sel && this.loaded && this.isShowing()) {
|
|
605
|
+
const {textEditor} = this;
|
|
606
|
+
textEditor.dispatch({
|
|
607
|
+
selection: textEditor.createSelection(
|
|
608
|
+
{lineNumber: sel.startLine, columnNumber: sel.startColumn},
|
|
609
|
+
{lineNumber: sel.endLine, columnNumber: sel.endColumn}),
|
|
610
|
+
});
|
|
498
611
|
this.selectionToSet = null;
|
|
499
612
|
}
|
|
500
613
|
}
|
|
@@ -505,9 +618,9 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
|
|
|
505
618
|
this.innerScrollToLineIfNeeded();
|
|
506
619
|
}
|
|
507
620
|
|
|
508
|
-
onTextChanged(
|
|
621
|
+
onTextChanged(): void {
|
|
509
622
|
const wasPretty = this.pretty;
|
|
510
|
-
this.prettyInternal = this.
|
|
623
|
+
this.prettyInternal = Boolean(this.prettyBaseDoc && this.textEditor.state.doc.eq(this.prettyBaseDoc));
|
|
511
624
|
if (this.prettyInternal !== wasPretty) {
|
|
512
625
|
this.updatePrettyPrintState();
|
|
513
626
|
}
|
|
@@ -519,14 +632,14 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
|
|
|
519
632
|
}
|
|
520
633
|
|
|
521
634
|
isClean(): boolean {
|
|
522
|
-
return this.textEditor.
|
|
523
|
-
(this.
|
|
635
|
+
return this.textEditor.state.doc.eq(this.baseDoc) ||
|
|
636
|
+
(this.prettyBaseDoc !== null && this.textEditor.state.doc.eq(this.prettyBaseDoc));
|
|
524
637
|
}
|
|
525
638
|
|
|
526
639
|
contentCommitted(): void {
|
|
527
|
-
this.
|
|
528
|
-
this.
|
|
529
|
-
this.rawContent = this.textEditor.
|
|
640
|
+
this.baseDoc = this.textEditorInternal.state.doc;
|
|
641
|
+
this.prettyBaseDoc = null;
|
|
642
|
+
this.rawContent = this.textEditor.state.doc.toString();
|
|
530
643
|
this.formattedMap = null;
|
|
531
644
|
this.formattedContentPromise = null;
|
|
532
645
|
if (this.prettyInternal) {
|
|
@@ -562,52 +675,49 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
|
|
|
562
675
|
return mimeType;
|
|
563
676
|
}
|
|
564
677
|
|
|
565
|
-
|
|
566
|
-
this.
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
678
|
+
protected async getLanguageSupport(content: string): Promise<CodeMirror.Extension> {
|
|
679
|
+
const mimeType = this.simplifyMimeType(content, this.contentType) || '';
|
|
680
|
+
const languageDesc = await CodeHighlighter.CodeHighlighter.languageFromMIME(mimeType);
|
|
681
|
+
if (!languageDesc) {
|
|
682
|
+
return [];
|
|
683
|
+
}
|
|
684
|
+
if (mimeType === 'text/jsx') {
|
|
685
|
+
return [
|
|
686
|
+
languageDesc,
|
|
687
|
+
CodeMirror.javascript.javascriptLanguage.data.of({autocomplete: CodeMirror.completeAnyWord}),
|
|
688
|
+
];
|
|
689
|
+
}
|
|
690
|
+
return languageDesc;
|
|
572
691
|
}
|
|
573
692
|
|
|
574
|
-
|
|
575
|
-
this.
|
|
693
|
+
async updateLanguageMode(content: string): Promise<void> {
|
|
694
|
+
const langExtension = await this.getLanguageSupport(content);
|
|
695
|
+
this.textEditor.dispatch({effects: config.language.reconfigure(langExtension)});
|
|
576
696
|
}
|
|
577
697
|
|
|
578
|
-
setContent(content: string
|
|
698
|
+
async setContent(content: string): Promise<void> {
|
|
579
699
|
this.muteChangeEventsForSetContent = true;
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
this.
|
|
590
|
-
|
|
591
|
-
this.
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
// Mark non-breakable lines in the Wasm disassembly after setting
|
|
602
|
-
// up the content for the text editor (which creates the gutter).
|
|
603
|
-
if (this.wasmDisassemblyInternal) {
|
|
604
|
-
for (const lineNumber of this.wasmDisassemblyInternal.nonBreakableLineNumbers()) {
|
|
605
|
-
this.textEditorInternal.toggleLineClass(lineNumber, 'cm-non-breakable-line', true);
|
|
606
|
-
}
|
|
700
|
+
const {textEditor} = this;
|
|
701
|
+
const wasLoaded = this.loadedInternal;
|
|
702
|
+
const scrollTop = textEditor.editor.scrollDOM.scrollTop;
|
|
703
|
+
this.loadedInternal = true;
|
|
704
|
+
|
|
705
|
+
const languageSupport = await this.getLanguageSupport(content);
|
|
706
|
+
const editorState = CodeMirror.EditorState.create({
|
|
707
|
+
doc: content,
|
|
708
|
+
extensions: [
|
|
709
|
+
this.editorConfiguration(content),
|
|
710
|
+
languageSupport,
|
|
711
|
+
this.getLineNumberFormatter(),
|
|
712
|
+
config.editable.of(this.editable ? [] : CodeMirror.EditorState.readOnly.of(true)),
|
|
713
|
+
],
|
|
714
|
+
});
|
|
715
|
+
this.baseDoc = editorState.doc;
|
|
716
|
+
textEditor.editor.setState(editorState);
|
|
717
|
+
if (wasLoaded) {
|
|
718
|
+
textEditor.editor.scrollDOM.scrollTop = scrollTop;
|
|
607
719
|
}
|
|
608
|
-
|
|
609
|
-
this.updateLineNumberFormatter();
|
|
610
|
-
this.updateHighlighterType(content || '');
|
|
720
|
+
this.editorInitialized();
|
|
611
721
|
this.wasShownOrLoaded();
|
|
612
722
|
|
|
613
723
|
if (this.delayedFindSearchMatches) {
|
|
@@ -617,6 +727,9 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
|
|
|
617
727
|
this.muteChangeEventsForSetContent = false;
|
|
618
728
|
}
|
|
619
729
|
|
|
730
|
+
protected editorInitialized(): void {
|
|
731
|
+
}
|
|
732
|
+
|
|
620
733
|
setSearchableView(view: UI.SearchableView.SearchableView|null): void {
|
|
621
734
|
this.searchableView = view;
|
|
622
735
|
}
|
|
@@ -624,24 +737,25 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
|
|
|
624
737
|
private doFindSearchMatches(
|
|
625
738
|
searchConfig: UI.SearchableView.SearchConfig, shouldJump: boolean, jumpBackwards: boolean): void {
|
|
626
739
|
this.currentSearchResultIndex = -1;
|
|
627
|
-
this.searchResults = [];
|
|
628
740
|
|
|
629
|
-
|
|
630
|
-
this.
|
|
631
|
-
this.searchResults = this.collectRegexMatches(regex);
|
|
741
|
+
this.searchRegex = searchConfig.toSearchRegex(true);
|
|
742
|
+
this.searchResults = this.collectRegexMatches(this.searchRegex);
|
|
632
743
|
|
|
633
744
|
if (this.searchableView) {
|
|
634
745
|
this.searchableView.updateSearchMatchesCount(this.searchResults.length);
|
|
635
746
|
}
|
|
636
747
|
|
|
748
|
+
const editor = this.textEditor;
|
|
637
749
|
if (!this.searchResults.length) {
|
|
638
|
-
|
|
750
|
+
if (editor.state.field(activeSearchState)) {
|
|
751
|
+
editor.dispatch({effects: setActiveSearch.of(null)});
|
|
752
|
+
}
|
|
639
753
|
} else if (shouldJump && jumpBackwards) {
|
|
640
754
|
this.jumpToPreviousSearchResult();
|
|
641
755
|
} else if (shouldJump) {
|
|
642
756
|
this.jumpToNextSearchResult();
|
|
643
757
|
} else {
|
|
644
|
-
|
|
758
|
+
editor.dispatch({effects: setActiveSearch.of(new ActiveSearch(this.searchRegex, null))});
|
|
645
759
|
}
|
|
646
760
|
}
|
|
647
761
|
|
|
@@ -670,7 +784,11 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
|
|
|
670
784
|
if (this.searchableView) {
|
|
671
785
|
this.searchableView.updateCurrentMatchIndex(this.currentSearchResultIndex);
|
|
672
786
|
}
|
|
673
|
-
|
|
787
|
+
const editor = this.textEditor;
|
|
788
|
+
const currentActiveSearch = editor.state.field(activeSearchState);
|
|
789
|
+
if (currentActiveSearch && currentActiveSearch.currentRange) {
|
|
790
|
+
editor.dispatch({effects: setActiveSearch.of(new ActiveSearch(currentActiveSearch.regexp, null))});
|
|
791
|
+
}
|
|
674
792
|
}
|
|
675
793
|
|
|
676
794
|
private resetSearch(): void {
|
|
@@ -687,10 +805,13 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
|
|
|
687
805
|
if (!this.loaded) {
|
|
688
806
|
return;
|
|
689
807
|
}
|
|
690
|
-
this.
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
808
|
+
const editor = this.textEditor;
|
|
809
|
+
editor.dispatch({
|
|
810
|
+
effects: setActiveSearch.of(null),
|
|
811
|
+
selection: range ? {anchor: range.from, head: range.to} : undefined,
|
|
812
|
+
scrollIntoView: true,
|
|
813
|
+
userEvent: 'select.search.cancel',
|
|
814
|
+
});
|
|
694
815
|
}
|
|
695
816
|
|
|
696
817
|
jumpToLastSearchResult(): void {
|
|
@@ -699,8 +820,7 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
|
|
|
699
820
|
|
|
700
821
|
private searchResultIndexForCurrentSelection(): number {
|
|
701
822
|
return Platform.ArrayUtilities.lowerBound(
|
|
702
|
-
this.searchResults, this.
|
|
703
|
-
TextUtils.TextRange.TextRange.comparator);
|
|
823
|
+
this.searchResults, this.textEditor.state.selection.main, (a, b): number => a.to - b.to);
|
|
704
824
|
}
|
|
705
825
|
|
|
706
826
|
jumpToNextSearchResult(): void {
|
|
@@ -730,8 +850,14 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
|
|
|
730
850
|
if (this.searchableView) {
|
|
731
851
|
this.searchableView.updateCurrentMatchIndex(this.currentSearchResultIndex);
|
|
732
852
|
}
|
|
733
|
-
this.
|
|
734
|
-
|
|
853
|
+
const editor = this.textEditor;
|
|
854
|
+
const range = this.searchResults[this.currentSearchResultIndex];
|
|
855
|
+
editor.dispatch({
|
|
856
|
+
effects: setActiveSearch.of(new ActiveSearch(this.searchRegex as RegExp, range)),
|
|
857
|
+
selection: {anchor: range.from, head: range.to},
|
|
858
|
+
scrollIntoView: true,
|
|
859
|
+
userEvent: 'select.search',
|
|
860
|
+
});
|
|
735
861
|
}
|
|
736
862
|
|
|
737
863
|
replaceSelectionWith(searchConfig: UI.SearchableView.SearchConfig, replacement: string): void {
|
|
@@ -739,146 +865,153 @@ export class SourceFrameImpl extends UI.View.SimpleView implements UI.Searchable
|
|
|
739
865
|
if (!range) {
|
|
740
866
|
return;
|
|
741
867
|
}
|
|
742
|
-
this.textEditorInternal.highlightSearchResults((this.searchRegex as RegExp), null);
|
|
743
|
-
|
|
744
|
-
const oldText = this.textEditorInternal.text(range);
|
|
745
|
-
const regex = searchConfig.toSearchRegex();
|
|
746
|
-
let text;
|
|
747
|
-
if (regex.__fromRegExpQuery) {
|
|
748
|
-
text = oldText.replace(regex, replacement);
|
|
749
|
-
} else {
|
|
750
|
-
text = oldText.replace(regex, function() {
|
|
751
|
-
return replacement;
|
|
752
|
-
});
|
|
753
|
-
}
|
|
754
868
|
|
|
755
|
-
const
|
|
756
|
-
this.
|
|
869
|
+
const insert = (this.searchRegex as RegExp).__fromRegExpQuery ? range.insertPlaceholders(replacement) : replacement;
|
|
870
|
+
const editor = this.textEditor;
|
|
871
|
+
const changes = editor.state.changes({from: range.from, to: range.to, insert});
|
|
872
|
+
editor.dispatch(
|
|
873
|
+
{changes, selection: {anchor: changes.mapPos(editor.state.selection.main.to, 1)}, userEvent: 'input.replace'});
|
|
757
874
|
}
|
|
758
875
|
|
|
759
876
|
replaceAllWith(searchConfig: UI.SearchableView.SearchConfig, replacement: string): void {
|
|
760
877
|
this.resetCurrentSearchResultIndex();
|
|
761
878
|
|
|
762
|
-
let text = this.textEditorInternal.text();
|
|
763
|
-
const range = this.textEditorInternal.fullRange();
|
|
764
|
-
|
|
765
879
|
const regex = searchConfig.toSearchRegex(true);
|
|
766
|
-
if (regex.__fromRegExpQuery) {
|
|
767
|
-
text = text.replace(regex, replacement);
|
|
768
|
-
} else {
|
|
769
|
-
text = text.replace(regex, function() {
|
|
770
|
-
return replacement;
|
|
771
|
-
});
|
|
772
|
-
}
|
|
773
|
-
|
|
774
880
|
const ranges = this.collectRegexMatches(regex);
|
|
775
881
|
if (!ranges.length) {
|
|
776
882
|
return;
|
|
777
883
|
}
|
|
778
884
|
|
|
779
|
-
|
|
780
|
-
const
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
const lastRange = ranges[lastRangeIndex];
|
|
784
|
-
const replacementLineEndings = Platform.StringUtilities.findLineEndingIndexes(replacement);
|
|
785
|
-
const replacementLineCount = replacementLineEndings.length;
|
|
786
|
-
const lastLineNumber = lastRange.startLine + replacementLineEndings.length - 1;
|
|
787
|
-
let lastColumnNumber: number = lastRange.startColumn;
|
|
788
|
-
if (replacementLineEndings.length > 1) {
|
|
789
|
-
lastColumnNumber =
|
|
790
|
-
replacementLineEndings[replacementLineCount - 1] - replacementLineEndings[replacementLineCount - 2] - 1;
|
|
791
|
-
}
|
|
885
|
+
const isRegExp = regex.__fromRegExpQuery;
|
|
886
|
+
const changes = ranges.map(
|
|
887
|
+
match =>
|
|
888
|
+
({from: match.from, to: match.to, insert: isRegExp ? match.insertPlaceholders(replacement) : replacement}));
|
|
792
889
|
|
|
793
|
-
this.
|
|
794
|
-
this.textEditorInternal.revealPosition(lastLineNumber, lastColumnNumber);
|
|
795
|
-
this.textEditorInternal.setSelection(
|
|
796
|
-
TextUtils.TextRange.TextRange.createFromLocation(lastLineNumber, lastColumnNumber));
|
|
890
|
+
this.textEditor.dispatch({changes, scrollIntoView: true, userEvent: 'input.replace.all'});
|
|
797
891
|
}
|
|
798
892
|
|
|
799
|
-
private collectRegexMatches(regexObject: RegExp):
|
|
893
|
+
private collectRegexMatches(regexObject: RegExp): SearchMatch[] {
|
|
800
894
|
const ranges = [];
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
const matchEndIndex = match.index + Math.max(match[0].length, 1);
|
|
809
|
-
if (match[0].length) {
|
|
810
|
-
ranges.push(new TextUtils.TextRange.TextRange(i, offset + match.index, i, offset + matchEndIndex));
|
|
811
|
-
}
|
|
812
|
-
offset += matchEndIndex;
|
|
813
|
-
line = line.substring(matchEndIndex);
|
|
895
|
+
let pos = 0;
|
|
896
|
+
for (const line of this.textEditor.state.doc.iterLines()) {
|
|
897
|
+
regexObject.lastIndex = 0;
|
|
898
|
+
for (;;) {
|
|
899
|
+
const match = regexObject.exec(line);
|
|
900
|
+
if (!match) {
|
|
901
|
+
break;
|
|
814
902
|
}
|
|
815
|
-
|
|
903
|
+
if (match[0].length) {
|
|
904
|
+
const from = pos + match.index;
|
|
905
|
+
ranges.push(new SearchMatch(from, from + match[0].length, match));
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
pos += line.length + 1;
|
|
816
909
|
}
|
|
817
910
|
return ranges;
|
|
818
911
|
}
|
|
819
912
|
|
|
820
|
-
populateLineGutterContextMenu(_contextMenu: UI.ContextMenu.ContextMenu, _editorLineNumber: number): Promise<void> {
|
|
821
|
-
return Promise.resolve();
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
populateTextAreaContextMenu(
|
|
825
|
-
_contextMenu: UI.ContextMenu.ContextMenu, _editorLineNumber: number, _editorColumnNumber: number): Promise<void> {
|
|
826
|
-
return Promise.resolve();
|
|
827
|
-
}
|
|
828
|
-
|
|
829
913
|
canEditSource(): boolean {
|
|
830
914
|
return this.editable;
|
|
831
915
|
}
|
|
832
916
|
|
|
833
917
|
private updateSourcePosition(): void {
|
|
834
|
-
const
|
|
835
|
-
if (
|
|
918
|
+
const {textEditor} = this, {state} = textEditor, {selection} = state;
|
|
919
|
+
if (this.displayedSelection?.eq(selection)) {
|
|
836
920
|
return;
|
|
837
921
|
}
|
|
838
|
-
|
|
839
|
-
|
|
922
|
+
this.displayedSelection = selection;
|
|
923
|
+
|
|
924
|
+
if (selection.ranges.length > 1) {
|
|
925
|
+
this.sourcePosition.setText(i18nString(UIStrings.dSelectionRegions, {PH1: selection.ranges.length}));
|
|
840
926
|
return;
|
|
841
927
|
}
|
|
842
|
-
|
|
843
|
-
if (
|
|
844
|
-
const
|
|
928
|
+
const {main} = state.selection;
|
|
929
|
+
if (main.empty) {
|
|
930
|
+
const {lineNumber, columnNumber} = textEditor.toLineColumn(main.head);
|
|
931
|
+
const location = this.prettyToRawLocation(lineNumber, columnNumber);
|
|
845
932
|
if (this.wasmDisassemblyInternal) {
|
|
846
933
|
const disassembly = this.wasmDisassemblyInternal;
|
|
847
934
|
const lastBytecodeOffset = disassembly.lineNumberToBytecodeOffset(disassembly.lineNumbers - 1);
|
|
848
935
|
const bytecodeOffsetDigits = lastBytecodeOffset.toString(16).length;
|
|
849
936
|
const bytecodeOffset = disassembly.lineNumberToBytecodeOffset(location[0]);
|
|
850
|
-
|
|
851
937
|
this.sourcePosition.setText(i18nString(
|
|
852
938
|
UIStrings.bytecodePositionXs, {PH1: bytecodeOffset.toString(16).padStart(bytecodeOffsetDigits, '0')}));
|
|
853
939
|
} else {
|
|
854
|
-
if (!this.canEditSource()) {
|
|
855
|
-
this.textEditorInternal.revealPosition(textRange.endLine, textRange.endColumn, true);
|
|
856
|
-
}
|
|
857
940
|
this.sourcePosition.setText(i18nString(UIStrings.lineSColumnS, {PH1: location[0] + 1, PH2: location[1] + 1}));
|
|
858
941
|
}
|
|
859
|
-
return;
|
|
860
|
-
}
|
|
861
|
-
textRange = textRange.normalize();
|
|
862
|
-
|
|
863
|
-
const selectedText = this.textEditorInternal.text(textRange);
|
|
864
|
-
if (textRange.startLine === textRange.endLine) {
|
|
865
|
-
this.sourcePosition.setText(i18nString(UIStrings.dCharactersSelected, {PH1: selectedText.length}));
|
|
866
942
|
} else {
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
943
|
+
const startLine = state.doc.lineAt(main.from), endLine = state.doc.lineAt(main.to);
|
|
944
|
+
if (startLine.number === endLine.number) {
|
|
945
|
+
this.sourcePosition.setText(i18nString(UIStrings.dCharactersSelected, {PH1: main.to - main.from}));
|
|
946
|
+
} else {
|
|
947
|
+
this.sourcePosition.setText(i18nString(
|
|
948
|
+
UIStrings.dLinesDCharactersSelected,
|
|
949
|
+
{PH1: endLine.number - startLine.number + 1, PH2: main.to - main.from}));
|
|
950
|
+
}
|
|
870
951
|
}
|
|
871
952
|
}
|
|
953
|
+
|
|
954
|
+
onContextMenu(event: MouseEvent): boolean {
|
|
955
|
+
event.consume(true); // Consume event now to prevent document from handling the async menu
|
|
956
|
+
const contextMenu = new UI.ContextMenu.ContextMenu(event);
|
|
957
|
+
const {state} = this.textEditor;
|
|
958
|
+
const pos = state.selection.main.from, line = state.doc.lineAt(pos);
|
|
959
|
+
this.populateTextAreaContextMenu(contextMenu, line.number - 1, pos - line.from);
|
|
960
|
+
contextMenu.appendApplicableItems(this);
|
|
961
|
+
contextMenu.show();
|
|
962
|
+
return true;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
protected populateTextAreaContextMenu(_menu: UI.ContextMenu.ContextMenu, _lineNumber: number, _columnNumber: number):
|
|
966
|
+
void {
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
onLineGutterContextMenu(position: number, event: MouseEvent): boolean {
|
|
970
|
+
event.consume(true); // Consume event now to prevent document from handling the async menu
|
|
971
|
+
const contextMenu = new UI.ContextMenu.ContextMenu(event);
|
|
972
|
+
const lineNumber = this.textEditor.state.doc.lineAt(position).number - 1;
|
|
973
|
+
this.populateLineGutterContextMenu(contextMenu, lineNumber);
|
|
974
|
+
contextMenu.appendApplicableItems(this);
|
|
975
|
+
contextMenu.show();
|
|
976
|
+
return true;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
protected populateLineGutterContextMenu(_menu: UI.ContextMenu.ContextMenu, _lineNumber: number): void {
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
focus(): void {
|
|
983
|
+
this.textEditor.focus();
|
|
984
|
+
}
|
|
872
985
|
}
|
|
873
986
|
|
|
874
|
-
|
|
875
|
-
|
|
987
|
+
class SearchMatch {
|
|
988
|
+
constructor(readonly from: number, readonly to: number, readonly match: RegExpMatchArray) {
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
insertPlaceholders(replacement: string): string {
|
|
992
|
+
return replacement.replace(/\$(\$|&|\d+|<[^>]+>)/g, (_, selector): string => {
|
|
993
|
+
if (selector === '$') {
|
|
994
|
+
return '$';
|
|
995
|
+
}
|
|
996
|
+
if (selector === '&') {
|
|
997
|
+
return this.match[0];
|
|
998
|
+
}
|
|
999
|
+
if (selector[0] === '<') {
|
|
1000
|
+
return (this.match.groups && this.match.groups[selector.slice(1, selector.length - 1)]) || '';
|
|
1001
|
+
}
|
|
1002
|
+
return this.match[Number.parseInt(selector, 10)] || '';
|
|
1003
|
+
});
|
|
1004
|
+
}
|
|
876
1005
|
}
|
|
877
1006
|
|
|
878
1007
|
export interface Transformer {
|
|
879
|
-
editorLocationToUILocation(lineNumber: number, columnNumber
|
|
1008
|
+
editorLocationToUILocation(lineNumber: number, columnNumber: number): {
|
|
880
1009
|
lineNumber: number,
|
|
881
|
-
columnNumber
|
|
1010
|
+
columnNumber: number,
|
|
1011
|
+
};
|
|
1012
|
+
editorLocationToUILocation(lineNumber: number): {
|
|
1013
|
+
lineNumber: number,
|
|
1014
|
+
columnNumber: number|undefined,
|
|
882
1015
|
};
|
|
883
1016
|
|
|
884
1017
|
uiLocationToEditorLocation(lineNumber: number, columnNumber?: number): {
|
|
@@ -887,16 +1020,6 @@ export interface Transformer {
|
|
|
887
1020
|
};
|
|
888
1021
|
}
|
|
889
1022
|
|
|
890
|
-
const registeredLineDecorators: LineDecoratorRegistration[] = [];
|
|
891
|
-
|
|
892
|
-
export function registerLineDecorator(registration: LineDecoratorRegistration): void {
|
|
893
|
-
registeredLineDecorators.push(registration);
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
export function getRegisteredLineDecorators(): LineDecoratorRegistration[] {
|
|
897
|
-
return registeredLineDecorators;
|
|
898
|
-
}
|
|
899
|
-
|
|
900
1023
|
// TODO(crbug.com/1167717): Make this a const enum again
|
|
901
1024
|
// eslint-disable-next-line rulesdir/const_enum
|
|
902
1025
|
export enum DecoratorType {
|
|
@@ -905,7 +1028,134 @@ export enum DecoratorType {
|
|
|
905
1028
|
COVERAGE = 'coverage',
|
|
906
1029
|
}
|
|
907
1030
|
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
1031
|
+
const config = {
|
|
1032
|
+
editable: new CodeMirror.Compartment(),
|
|
1033
|
+
language: new CodeMirror.Compartment(),
|
|
1034
|
+
lineNumbers: new CodeMirror.Compartment(),
|
|
1035
|
+
};
|
|
1036
|
+
|
|
1037
|
+
class ActiveSearch {
|
|
1038
|
+
constructor(readonly regexp: RegExp, readonly currentRange: {from: number, to: number}|null) {
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
map(change: CodeMirror.ChangeDesc): ActiveSearch {
|
|
1042
|
+
return change.empty || !this.currentRange ?
|
|
1043
|
+
this :
|
|
1044
|
+
new ActiveSearch(
|
|
1045
|
+
this.regexp, {from: change.mapPos(this.currentRange.from), to: change.mapPos(this.currentRange.to)});
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
static eq(a: ActiveSearch|null, b: ActiveSearch|null): boolean {
|
|
1049
|
+
return Boolean(
|
|
1050
|
+
a === b ||
|
|
1051
|
+
a && b && a.currentRange?.from === b.currentRange?.from && a.currentRange?.to === b.currentRange?.to &&
|
|
1052
|
+
a.regexp.source === b.regexp.source && a.regexp.flags === b.regexp.flags);
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
const setActiveSearch = CodeMirror.StateEffect.define<ActiveSearch|null>(
|
|
1057
|
+
{map: (value, mapping): ActiveSearch | null => value && value.map(mapping)});
|
|
1058
|
+
|
|
1059
|
+
const activeSearchState = CodeMirror.StateField.define<ActiveSearch|null>({
|
|
1060
|
+
create(): null {
|
|
1061
|
+
return null;
|
|
1062
|
+
},
|
|
1063
|
+
update(state, tr): ActiveSearch |
|
|
1064
|
+
null {
|
|
1065
|
+
return tr.effects.reduce(
|
|
1066
|
+
(state, effect) => effect.is(setActiveSearch) ? effect.value : state, state && state.map(tr.changes));
|
|
1067
|
+
},
|
|
1068
|
+
});
|
|
1069
|
+
|
|
1070
|
+
const searchMatchDeco = CodeMirror.Decoration.mark({class: 'cm-searchMatch'});
|
|
1071
|
+
const currentSearchMatchDeco = CodeMirror.Decoration.mark({class: 'cm-searchMatch cm-searchMatch-selected'});
|
|
1072
|
+
|
|
1073
|
+
const searchHighlighter = CodeMirror.ViewPlugin.fromClass(class {
|
|
1074
|
+
decorations: CodeMirror.DecorationSet;
|
|
1075
|
+
|
|
1076
|
+
constructor(view: CodeMirror.EditorView) {
|
|
1077
|
+
this.decorations = this.computeDecorations(view);
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
update(update: CodeMirror.ViewUpdate): void {
|
|
1081
|
+
const active = update.state.field(activeSearchState);
|
|
1082
|
+
if (!ActiveSearch.eq(active, update.startState.field(activeSearchState)) ||
|
|
1083
|
+
(active && (update.viewportChanged || update.docChanged))) {
|
|
1084
|
+
this.decorations = this.computeDecorations(update.view);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
private computeDecorations(view: CodeMirror.EditorView): CodeMirror.DecorationSet {
|
|
1089
|
+
const active = view.state.field(activeSearchState);
|
|
1090
|
+
if (!active) {
|
|
1091
|
+
return CodeMirror.Decoration.none;
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
const builder = new CodeMirror.RangeSetBuilder<CodeMirror.Decoration>();
|
|
1095
|
+
const {doc} = view.state;
|
|
1096
|
+
for (const {from, to} of view.visibleRanges) {
|
|
1097
|
+
let pos = from;
|
|
1098
|
+
for (const line of doc.iterLines(doc.lineAt(from).number, doc.lineAt(to).number + 1)) {
|
|
1099
|
+
active.regexp.lastIndex = 0;
|
|
1100
|
+
for (;;) {
|
|
1101
|
+
const match = active.regexp.exec(line);
|
|
1102
|
+
if (!match) {
|
|
1103
|
+
break;
|
|
1104
|
+
}
|
|
1105
|
+
const start = pos + match.index, end = start + match[0].length;
|
|
1106
|
+
const current = active.currentRange && active.currentRange.from === start && active.currentRange.to === end;
|
|
1107
|
+
builder.add(start, end, current ? currentSearchMatchDeco : searchMatchDeco);
|
|
1108
|
+
}
|
|
1109
|
+
pos += line.length + 1;
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
return builder.finish();
|
|
1113
|
+
}
|
|
1114
|
+
}, {decorations: (value): CodeMirror.DecorationSet => value.decorations});
|
|
1115
|
+
|
|
1116
|
+
const nonBreakableLineMark = new (class extends CodeMirror.GutterMarker {
|
|
1117
|
+
elementClass = 'cm-nonBreakableLine';
|
|
1118
|
+
})();
|
|
1119
|
+
|
|
1120
|
+
// Effect to add lines (by position) to the set of non-breakable lines.
|
|
1121
|
+
export const addNonBreakableLines = CodeMirror.StateEffect.define<readonly number[]>();
|
|
1122
|
+
|
|
1123
|
+
const nonBreakableLines = CodeMirror.StateField.define<CodeMirror.RangeSet<CodeMirror.GutterMarker>>({
|
|
1124
|
+
create(): CodeMirror.RangeSet<CodeMirror.GutterMarker> {
|
|
1125
|
+
return CodeMirror.RangeSet.empty;
|
|
1126
|
+
},
|
|
1127
|
+
update(deco, tr): CodeMirror.RangeSet<CodeMirror.GutterMarker> {
|
|
1128
|
+
return tr.effects.reduce((deco, effect) => {
|
|
1129
|
+
return !effect.is(addNonBreakableLines) ?
|
|
1130
|
+
deco :
|
|
1131
|
+
deco.update({add: effect.value.map(pos => nonBreakableLineMark.range(pos))});
|
|
1132
|
+
}, deco.map(tr.changes));
|
|
1133
|
+
},
|
|
1134
|
+
provide: field => CodeMirror.lineNumberMarkers.from(field),
|
|
1135
|
+
});
|
|
1136
|
+
|
|
1137
|
+
export function isBreakableLine(state: CodeMirror.EditorState, line: CodeMirror.Line): boolean {
|
|
1138
|
+
const nonBreakable = state.field(nonBreakableLines);
|
|
1139
|
+
if (!nonBreakable.size) {
|
|
1140
|
+
return true;
|
|
1141
|
+
}
|
|
1142
|
+
let found = false;
|
|
1143
|
+
nonBreakable.between(line.from, line.from, () => {
|
|
1144
|
+
found = true;
|
|
1145
|
+
});
|
|
1146
|
+
return !found;
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
function markNonBreakableLines(disassembly: Common.WasmDisassembly.WasmDisassembly): CodeMirror.Extension {
|
|
1150
|
+
// Mark non-breakable lines in the Wasm disassembly after setting
|
|
1151
|
+
// up the content for the text editor (which creates the gutter).
|
|
1152
|
+
return nonBreakableLines.init(state => {
|
|
1153
|
+
const marks = [];
|
|
1154
|
+
for (const lineNumber of disassembly.nonBreakableLineNumbers()) {
|
|
1155
|
+
if (lineNumber < state.doc.lines) {
|
|
1156
|
+
marks.push(nonBreakableLineMark.range(state.doc.line(lineNumber + 1).from));
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
return CodeMirror.RangeSet.of(marks);
|
|
1160
|
+
});
|
|
911
1161
|
}
|