chrome-devtools-frontend 1.0.941208 → 1.0.943182
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/WATCHLISTS +1 -1
- package/config/gni/all_devtools_files.gni +0 -64
- package/config/gni/devtools_grd_files.gni +54 -19
- package/config/gni/devtools_image_files.gni +1 -3
- package/front_end/.eslintrc.js +11 -1
- package/front_end/Images/src/{feedback_thin_16x16_icon.svg → survey_feedback_icon.svg} +1 -1
- package/front_end/Tests.js +1 -32
- package/front_end/core/common/Color.ts +5 -0
- package/front_end/core/i18n/locales/en-US.json +17 -29
- package/front_end/core/i18n/locales/en-XL.json +17 -29
- package/front_end/core/sdk/CPUProfilerModel.ts +7 -9
- package/front_end/core/sdk/ConsoleModel.ts +27 -33
- package/front_end/core/sdk/DebuggerModel.ts +4 -14
- package/front_end/core/sdk/sdk-meta.ts +17 -3
- package/front_end/entrypoints/device_mode_emulation_frame/device_mode_emulation_frame.ts +1 -1
- package/front_end/entrypoints/devtools_app/devtools_app.js +1 -1
- package/front_end/entrypoints/devtools_app/devtools_app.json +1 -12
- package/front_end/entrypoints/formatter_worker/formatter_worker-entrypoint.ts +1 -1
- package/front_end/entrypoints/heap_snapshot_worker/heap_snapshot_worker-entrypoint.ts +1 -1
- package/front_end/entrypoints/inspector/inspector.js +1 -1
- package/front_end/entrypoints/inspector/inspector.json +1 -3
- package/front_end/entrypoints/inspector_main/inspector_main-meta.ts +2 -3
- package/front_end/entrypoints/js_app/js_app.js +1 -1
- package/front_end/entrypoints/js_app/js_app.json +1 -3
- package/front_end/entrypoints/main/MainImpl.ts +26 -0
- package/front_end/entrypoints/main/main-meta.ts +1 -2
- package/front_end/entrypoints/ndb_app/ndb_app.js +1 -1
- package/front_end/entrypoints/node_app/node_app-meta.ts +0 -2
- package/front_end/entrypoints/node_app/node_app.js +1 -1
- package/front_end/entrypoints/node_app/node_app.json +1 -3
- package/front_end/entrypoints/node_main/node_main-meta.ts +0 -1
- package/front_end/entrypoints/shell/shell.js +0 -11
- package/front_end/entrypoints/shell/shell.json +1 -5
- package/front_end/entrypoints/wasmparser_worker/wasmparser_worker-entrypoint.ts +1 -1
- package/front_end/entrypoints/worker_app/worker_app.js +1 -1
- package/front_end/entrypoints/worker_app/worker_app.json +1 -7
- package/front_end/generated/InspectorBackendCommands.js +19 -0
- package/front_end/generated/protocol-mapping.d.ts +31 -1
- package/front_end/generated/protocol-proxy-api.d.ts +34 -2
- package/front_end/generated/protocol.d.ts +81 -6
- 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 +5 -1
- package/front_end/legacy_test_runner/legacy_test_runner.ts +10 -1
- package/front_end/legacy_test_runner/test_runner/TestRunner.js +3 -1
- package/front_end/models/formatter/SourceFormatter.ts +0 -10
- package/front_end/models/persistence/persistence-meta.ts +0 -1
- package/front_end/models/workspace/UISourceCode.ts +9 -42
- package/front_end/panels/accessibility/accessibility-meta.ts +0 -1
- package/front_end/panels/animation/AnimationTimeline.ts +3 -3
- package/front_end/panels/animation/animation-meta.ts +0 -1
- package/front_end/panels/application/ApplicationPanelSidebar.ts +3 -3
- package/front_end/panels/application/BackForwardCacheStrings.ts +3 -1
- package/front_end/panels/application/application-meta.ts +0 -4
- package/front_end/panels/application/components/EndpointsGrid.ts +1 -1
- package/front_end/panels/application/components/ReportsGrid.ts +1 -1
- package/front_end/panels/application/components/stackTraceRow.css +8 -0
- package/front_end/panels/browser_debugger/browser_debugger-meta.ts +1 -2
- package/front_end/panels/changes/changes-meta.ts +0 -1
- package/front_end/panels/console/ConsolePinPane.ts +23 -32
- package/front_end/panels/console/ConsoleViewMessage.ts +8 -1
- package/front_end/panels/console/console-meta.ts +0 -1
- package/front_end/panels/console_counters/console_counters-meta.ts +0 -1
- package/front_end/panels/coverage/CoverageDecorationManager.ts +4 -5
- package/front_end/panels/coverage/CoverageView.ts +2 -105
- package/front_end/panels/coverage/coverage-meta.ts +0 -1
- 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/css_overview/css_overview-meta.ts +0 -1
- package/front_end/panels/developer_resources/developer_resources-meta.ts +0 -1
- 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/elements/elements-meta.ts +0 -1
- 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 -5
- package/front_end/panels/help/help-meta.ts +0 -1
- package/front_end/panels/input/input-meta.ts +0 -1
- package/front_end/panels/issues/issues-meta.ts +0 -3
- package/front_end/panels/js_profiler/js_profiler-meta.ts +0 -4
- package/front_end/panels/layers/layers-meta.ts +0 -4
- package/front_end/panels/lighthouse/LighthousePanel.ts +2 -4
- package/front_end/panels/lighthouse/LighthouseReportRenderer.ts +1 -4
- package/front_end/panels/lighthouse/lighthouse-meta.ts +0 -1
- package/front_end/panels/lighthouse/lighthouseStartView.css +4 -0
- package/front_end/panels/lighthouse/module.json +0 -6
- package/front_end/panels/media/media-meta.ts +0 -4
- package/front_end/panels/mobile_throttling/mobile_throttling-meta.ts +0 -1
- package/front_end/panels/network/ResourceWebSocketFrameView.ts +2 -1
- package/front_end/panels/network/network-meta.ts +1 -5
- package/front_end/panels/performance_monitor/performance_monitor-meta.ts +0 -1
- package/front_end/panels/profiler/CPUProfileView.ts +10 -3
- package/front_end/panels/profiler/profiler-meta.ts +0 -3
- package/front_end/panels/protocol_monitor/protocol_monitor-meta.ts +0 -1
- package/front_end/panels/screencast/screencast-meta.ts +0 -4
- package/front_end/panels/security/security-meta.ts +0 -4
- package/front_end/panels/sensors/sensors-meta.ts +0 -1
- package/front_end/panels/settings/emulation/emulation-meta.ts +0 -1
- package/front_end/panels/settings/settings-meta.ts +0 -1
- 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 +6 -5
- 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-meta.ts +2 -6
- package/front_end/panels/sources/sources.ts +0 -2
- package/front_end/panels/timeline/timeline-meta.ts +2 -9
- package/front_end/panels/web_audio/web_audio-meta.ts +0 -1
- package/front_end/panels/webauthn/webauthn-meta.ts +0 -1
- 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/component_docs.ts +14 -0
- package/front_end/ui/components/docs/create_breadcrumbs.ts +1 -1
- 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/toggle_dark_mode.ts +1 -0
- package/front_end/ui/components/docs/toggle_fonts.ts +2 -0
- package/front_end/ui/components/helpers/get-stylesheet.ts +0 -15
- package/front_end/ui/components/linear_memory_inspector/linear_memory_inspector-meta.ts +1 -2
- package/front_end/ui/components/markdown_view/MarkdownImagesMap.ts +1 -1
- 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/components/tree_outline/TreeOutline.ts +63 -8
- package/front_end/ui/components/tree_outline/TreeOutlineUtils.ts +8 -6
- 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 +3 -2
- 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 +4 -3
- package/front_end/ui/legacy/UIUtils.ts +17 -14
- package/front_end/ui/legacy/ViewManager.ts +2 -1
- package/front_end/ui/legacy/components/inline_editor/CSSAngle.ts +1 -2
- package/front_end/ui/legacy/components/inline_editor/cssAngle.css +4 -0
- package/front_end/ui/legacy/components/object_ui/JavaScriptREPL.ts +2 -2
- package/front_end/ui/legacy/components/object_ui/object_ui-meta.ts +0 -4
- package/front_end/ui/legacy/components/perf_ui/LineLevelProfile.ts +35 -131
- package/front_end/ui/legacy/components/perf_ui/perf_ui-meta.ts +0 -3
- package/front_end/ui/legacy/components/quick_open/filteredListWidget.css +2 -2
- package/front_end/ui/legacy/components/quick_open/quick_open-meta.ts +2 -3
- package/front_end/ui/legacy/components/source_frame/BinaryResourceViewFactory.ts +3 -6
- package/front_end/ui/legacy/components/source_frame/FontView.ts +4 -1
- package/front_end/ui/legacy/components/source_frame/ImageView.ts +4 -1
- package/front_end/ui/legacy/components/source_frame/JSONView.ts +4 -1
- package/front_end/ui/legacy/components/source_frame/ResourceSourceFrame.ts +21 -15
- package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +501 -252
- package/front_end/ui/legacy/components/source_frame/XMLView.ts +7 -2
- 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/textButton.css +5 -4
- 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/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/check_gn.js +0 -35
- package/scripts/eslint_rules/lib/es_modules_import.js +15 -8
- package/scripts/eslint_rules/tests/es_modules_import_test.js +8 -0
- package/front_end/Images/radioDot-dark-theme.png +0 -0
- package/front_end/Images/radioDot.png +0 -0
- package/front_end/emulated_devices/module.json +0 -6
- package/front_end/panels/application/module.json +0 -6
- package/front_end/panels/emulation/module.json +0 -11
- package/front_end/panels/issues/module.json +0 -6
- package/front_end/panels/js_profiler/module.json +0 -5
- package/front_end/panels/layer_viewer/module.json +0 -5
- package/front_end/panels/layers/module.json +0 -5
- package/front_end/panels/media/module.json +0 -5
- package/front_end/panels/network/module.json +0 -5
- package/front_end/panels/profiler/module.json +0 -5
- package/front_end/panels/screencast/module.json +0 -6
- package/front_end/panels/security/module.json +0 -5
- package/front_end/panels/timeline/module.json +0 -7
- package/front_end/third_party/lighthouse/report-assets/report.css +0 -1774
- package/front_end/ui/legacy/components/source_frame/SourcesTextEditor.ts +0 -1030
- package/front_end/ui/legacy/components/source_frame/messagesPopover.css +0 -32
- package/front_end/ui/legacy/components/source_frame/module.json +0 -14
- package/front_end/ui/legacy/module.json +0 -41
|
@@ -34,15 +34,15 @@ import * as i18n from '../../core/i18n/i18n.js';
|
|
|
34
34
|
import * as Platform from '../../core/platform/platform.js';
|
|
35
35
|
import * as Root from '../../core/root/root.js';
|
|
36
36
|
import * as SDK from '../../core/sdk/sdk.js';
|
|
37
|
+
import * as Protocol from '../../generated/protocol.js';
|
|
37
38
|
import * as Bindings from '../../models/bindings/bindings.js';
|
|
38
39
|
import * as TextUtils from '../../models/text_utils/text_utils.js';
|
|
39
40
|
import * as Workspace from '../../models/workspace/workspace.js';
|
|
41
|
+
import * as CodeMirror from '../../third_party/codemirror.next/codemirror.next.js';
|
|
40
42
|
import * as ObjectUI from '../../ui/legacy/components/object_ui/object_ui.js';
|
|
41
43
|
import * as SourceFrame from '../../ui/legacy/components/source_frame/source_frame.js';
|
|
42
|
-
|
|
43
|
-
import type * as TextEditor from '../../ui/legacy/components/text_editor/text_editor.js';
|
|
44
44
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
45
|
-
import * as
|
|
45
|
+
import type * as TextEditor from '../../ui/components/text_editor/text_editor.js';
|
|
46
46
|
|
|
47
47
|
import {AddSourceMapURLDialog} from './AddSourceMapURLDialog.js';
|
|
48
48
|
import {BreakpointEditDialog, LogpointPrefix} from './BreakpointEditDialog.js';
|
|
@@ -144,154 +144,67 @@ const UIStrings = {
|
|
|
144
144
|
};
|
|
145
145
|
const str_ = i18n.i18n.registerUIStrings('panels/sources/DebuggerPlugin.ts', UIStrings);
|
|
146
146
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
147
|
+
|
|
148
|
+
// Note: Line numbers are passed around as zero-based numbers (though
|
|
149
|
+
// CodeMirror numbers them from 1).
|
|
150
|
+
|
|
151
|
+
// Don't scan for possible breakpoints on a line beyond this position;
|
|
152
|
+
const MAX_POSSIBLE_BREAKPOINT_LINE = 2500;
|
|
153
|
+
|
|
154
|
+
type BreakpointDescription = {
|
|
155
|
+
position: number,
|
|
156
|
+
breakpoint: Bindings.BreakpointManager.Breakpoint,
|
|
157
|
+
};
|
|
156
158
|
|
|
157
159
|
export class DebuggerPlugin extends Plugin {
|
|
158
|
-
private
|
|
159
|
-
private
|
|
160
|
-
private
|
|
161
|
-
private
|
|
162
|
-
private
|
|
163
|
-
private asyncStepInHoveredLine: number|null;
|
|
164
|
-
private asyncStepInHovered: boolean;
|
|
165
|
-
private clearValueWidgetsTimer: number|null;
|
|
166
|
-
private sourceMapInfobar: UI.Infobar.Infobar|null;
|
|
167
|
-
private controlTimeout: number|null;
|
|
160
|
+
private editor: TextEditor.TextEditor.TextEditor|undefined = undefined;
|
|
161
|
+
private executionLocation: Workspace.UISourceCode.UILocation|null = null;
|
|
162
|
+
private controlDown: boolean = false;
|
|
163
|
+
private sourceMapInfobar: UI.Infobar.Infobar|null = null;
|
|
164
|
+
private controlTimeout: number|undefined = undefined;
|
|
168
165
|
private readonly scriptsPanel: SourcesPanel;
|
|
169
166
|
private readonly breakpointManager: Bindings.BreakpointManager.BreakpointManager;
|
|
170
167
|
private readonly popoverHelper: UI.PopoverHelper.PopoverHelper;
|
|
171
|
-
private readonly boundPopoverHelperHide: () => void;
|
|
172
|
-
private readonly boundKeyDown: (arg0: Event) => void;
|
|
173
|
-
private readonly boundKeyUp: (arg0: Event) => void;
|
|
174
|
-
private readonly boundMouseMove: (arg0: Event) => void;
|
|
175
|
-
private readonly boundMouseDown: (arg0: Event) => void;
|
|
176
|
-
private readonly boundBlur: (arg0: Event) => void;
|
|
177
|
-
private readonly boundWheel: (arg0: Event) => void;
|
|
178
|
-
private readonly boundGutterClick:
|
|
179
|
-
(arg0: Common.EventTarget.EventTargetEvent<SourceFrame.SourcesTextEditor.GutterClickEventData>) => void;
|
|
180
|
-
private readonly breakpointDecorations: Set<BreakpointDecoration>;
|
|
181
|
-
private readonly decorationByBreakpoint:
|
|
182
|
-
Map<Bindings.BreakpointManager.Breakpoint, Map<string, BreakpointDecoration>>;
|
|
183
|
-
private readonly possibleBreakpointsRequested: Set<number>;
|
|
184
168
|
private scriptFileForDebuggerModel:
|
|
185
169
|
Map<SDK.DebuggerModel.DebuggerModel, Bindings.ResourceScriptMapping.ResourceScriptFile>;
|
|
186
|
-
|
|
170
|
+
// The current set of breakpoints for this file. The locations in
|
|
171
|
+
// here are only in sync with editor positions when `this.muted` is
|
|
172
|
+
// false.
|
|
173
|
+
private breakpoints: BreakpointDescription[] = [];
|
|
187
174
|
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
|
|
188
175
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
189
|
-
private
|
|
176
|
+
private continueToLocations: {from: number, to: number, async: boolean, click: () => void}[]|null = null;
|
|
190
177
|
private readonly liveLocationPool: Bindings.LiveLocation.LiveLocationPool;
|
|
191
178
|
private muted: boolean;
|
|
192
|
-
private
|
|
179
|
+
private initializedMuted: boolean;
|
|
193
180
|
private ignoreListInfobar: UI.Infobar.Infobar|null;
|
|
194
|
-
private hasLineWithoutMapping: boolean;
|
|
195
181
|
private prettyPrintInfobar!: UI.Infobar.Infobar|null;
|
|
196
182
|
private scheduledBreakpointDecorationUpdates?: Set<BreakpointDecoration>|null;
|
|
183
|
+
private refreshBreakpointsTimeout: undefined|number = undefined;
|
|
197
184
|
|
|
198
185
|
constructor(
|
|
199
|
-
|
|
200
|
-
transformer: SourceFrame.SourceFrame.Transformer) {
|
|
201
|
-
super();
|
|
202
|
-
this.textEditor = textEditor;
|
|
203
|
-
this.uiSourceCode = uiSourceCode;
|
|
204
|
-
this.transformer = transformer;
|
|
205
|
-
|
|
206
|
-
this.executionLocation = null;
|
|
207
|
-
this.controlDown = false;
|
|
208
|
-
this.asyncStepInHoveredLine = 0;
|
|
209
|
-
this.asyncStepInHovered = false;
|
|
210
|
-
this.clearValueWidgetsTimer = null;
|
|
211
|
-
this.sourceMapInfobar = null;
|
|
212
|
-
this.controlTimeout = null;
|
|
186
|
+
uiSourceCode: Workspace.UISourceCode.UISourceCode,
|
|
187
|
+
private readonly transformer: SourceFrame.SourceFrame.Transformer) {
|
|
188
|
+
super(uiSourceCode);
|
|
213
189
|
|
|
214
190
|
this.scriptsPanel = SourcesPanel.instance();
|
|
215
191
|
this.breakpointManager = Bindings.BreakpointManager.BreakpointManager.instance();
|
|
216
|
-
if (uiSourceCode.project().type() === Workspace.Workspace.projectTypes.Debugger) {
|
|
217
|
-
this.textEditor.element.classList.add('source-frame-debugger-script');
|
|
218
|
-
}
|
|
219
192
|
|
|
220
193
|
this.popoverHelper =
|
|
221
194
|
new UI.PopoverHelper.PopoverHelper(this.scriptsPanel.element, this.getPopoverRequest.bind(this));
|
|
222
195
|
this.popoverHelper.setDisableOnClick(true);
|
|
223
196
|
this.popoverHelper.setTimeout(250, 250);
|
|
224
197
|
this.popoverHelper.setHasPadding(true);
|
|
225
|
-
this.boundPopoverHelperHide = this.popoverHelper.hidePopover.bind(this.popoverHelper);
|
|
226
|
-
this.scriptsPanel.element.addEventListener('scroll', this.boundPopoverHelperHide, true);
|
|
227
|
-
|
|
228
|
-
const shortcutHandlers = {
|
|
229
|
-
'debugger.toggle-breakpoint': async(): Promise<boolean> => {
|
|
230
|
-
const selection = this.textEditor.selection();
|
|
231
|
-
if (!selection) {
|
|
232
|
-
return false;
|
|
233
|
-
}
|
|
234
|
-
await this.toggleBreakpoint(selection.startLine, false);
|
|
235
|
-
return true;
|
|
236
|
-
},
|
|
237
|
-
'debugger.toggle-breakpoint-enabled': async(): Promise<boolean> => {
|
|
238
|
-
const selection = this.textEditor.selection();
|
|
239
|
-
if (!selection) {
|
|
240
|
-
return false;
|
|
241
|
-
}
|
|
242
|
-
await this.toggleBreakpoint(selection.startLine, true);
|
|
243
|
-
return true;
|
|
244
|
-
},
|
|
245
|
-
'debugger.breakpoint-input-window': async(): Promise<boolean> => {
|
|
246
|
-
const selection = this.textEditor.selection();
|
|
247
|
-
if (!selection) {
|
|
248
|
-
return false;
|
|
249
|
-
}
|
|
250
|
-
const breakpoints = this.lineBreakpointDecorations(selection.startLine)
|
|
251
|
-
.map(decoration => decoration.breakpoint)
|
|
252
|
-
.filter(breakpoint => Boolean(breakpoint));
|
|
253
|
-
let breakpoint: (Bindings.BreakpointManager.Breakpoint|null)|null = null;
|
|
254
|
-
if (breakpoints.length) {
|
|
255
|
-
breakpoint = breakpoints[0];
|
|
256
|
-
}
|
|
257
|
-
const isLogpoint = breakpoint ? breakpoint.condition().includes(LogpointPrefix) : false;
|
|
258
|
-
this.editBreakpointCondition(selection.startLine, breakpoint, null, isLogpoint);
|
|
259
|
-
return true;
|
|
260
|
-
},
|
|
261
|
-
};
|
|
262
|
-
UI.ShortcutRegistry.ShortcutRegistry.instance().addShortcutListener(this.textEditor.element, shortcutHandlers);
|
|
263
|
-
this.boundKeyDown = (this.onKeyDown.bind(this) as (arg0: Event) => void);
|
|
264
|
-
this.textEditor.element.addEventListener('keydown', this.boundKeyDown, true);
|
|
265
|
-
this.boundKeyUp = (this.onKeyUp.bind(this) as (arg0: Event) => void);
|
|
266
|
-
this.textEditor.element.addEventListener('keyup', this.boundKeyUp, true);
|
|
267
|
-
this.boundMouseMove = (this.onMouseMove.bind(this) as (arg0: Event) => void);
|
|
268
|
-
this.textEditor.element.addEventListener('mousemove', this.boundMouseMove, false);
|
|
269
|
-
this.boundMouseDown = (this.onMouseDown.bind(this) as (arg0: Event) => void);
|
|
270
|
-
this.textEditor.element.addEventListener('mousedown', this.boundMouseDown, true);
|
|
271
|
-
this.boundBlur = (this.onBlur.bind(this) as (arg0: Event) => void);
|
|
272
|
-
this.textEditor.element.addEventListener('focusout', this.boundBlur, false);
|
|
273
|
-
this.boundWheel = (this.onWheel.bind(this) as (arg0: Event) => void);
|
|
274
|
-
this.textEditor.element.addEventListener('wheel', this.boundWheel, true);
|
|
275
|
-
this.boundGutterClick =
|
|
276
|
-
(e: Common.EventTarget.EventTargetEvent<SourceFrame.SourcesTextEditor.GutterClickEventData>): void => {
|
|
277
|
-
this.handleGutterClick(e);
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
this.textEditor.addEventListener(SourceFrame.SourcesTextEditor.Events.GutterClick, this.boundGutterClick, this);
|
|
281
198
|
|
|
282
199
|
this.breakpointManager.addEventListener(
|
|
283
|
-
Bindings.BreakpointManager.Events.BreakpointAdded, this.
|
|
200
|
+
Bindings.BreakpointManager.Events.BreakpointAdded, this.breakpointChange, this);
|
|
284
201
|
this.breakpointManager.addEventListener(
|
|
285
|
-
Bindings.BreakpointManager.Events.BreakpointRemoved, this.
|
|
202
|
+
Bindings.BreakpointManager.Events.BreakpointRemoved, this.breakpointChange, this);
|
|
286
203
|
|
|
287
204
|
this.uiSourceCode.addEventListener(Workspace.UISourceCode.Events.WorkingCopyChanged, this.workingCopyChanged, this);
|
|
288
205
|
this.uiSourceCode.addEventListener(
|
|
289
206
|
Workspace.UISourceCode.Events.WorkingCopyCommitted, this.workingCopyCommitted, this);
|
|
290
207
|
|
|
291
|
-
this.breakpointDecorations = new Set();
|
|
292
|
-
this.decorationByBreakpoint = new Map();
|
|
293
|
-
this.possibleBreakpointsRequested = new Set();
|
|
294
|
-
|
|
295
208
|
this.scriptFileForDebuggerModel = new Map();
|
|
296
209
|
|
|
297
210
|
Common.Settings.Settings.instance()
|
|
@@ -301,23 +214,13 @@ export class DebuggerPlugin extends Plugin {
|
|
|
301
214
|
.moduleSetting('skipContentScripts')
|
|
302
215
|
.addChangeListener(this.showIgnoreListInfobarIfNeeded, this);
|
|
303
216
|
|
|
304
|
-
this.valueWidgets = new Map();
|
|
305
|
-
this.continueToLocationDecorations = null;
|
|
306
|
-
|
|
307
217
|
UI.Context.Context.instance().addFlavorChangeListener(SDK.DebuggerModel.CallFrame, this.callFrameChanged, this);
|
|
308
218
|
this.liveLocationPool = new Bindings.LiveLocation.LiveLocationPool();
|
|
309
|
-
this.callFrameChanged();
|
|
310
219
|
|
|
311
220
|
this.updateScriptFiles();
|
|
312
221
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
this.mutedFromStart = true;
|
|
316
|
-
} else {
|
|
317
|
-
this.muted = false;
|
|
318
|
-
this.mutedFromStart = false;
|
|
319
|
-
this.initializeBreakpoints();
|
|
320
|
-
}
|
|
222
|
+
this.muted = this.uiSourceCode.isDirty();
|
|
223
|
+
this.initializedMuted = this.muted;
|
|
321
224
|
|
|
322
225
|
this.ignoreListInfobar = null;
|
|
323
226
|
this.showIgnoreListInfobarIfNeeded();
|
|
@@ -326,14 +229,98 @@ export class DebuggerPlugin extends Plugin {
|
|
|
326
229
|
scriptFile.checkMapping();
|
|
327
230
|
}
|
|
328
231
|
|
|
329
|
-
this.hasLineWithoutMapping = false;
|
|
330
|
-
this.updateLinesWithoutMappingHighlight();
|
|
331
232
|
if (!Root.Runtime.experiments.isEnabled('sourcesPrettyPrint')) {
|
|
332
233
|
this.prettyPrintInfobar = null;
|
|
333
234
|
this.detectMinified();
|
|
334
235
|
}
|
|
335
236
|
}
|
|
336
237
|
|
|
238
|
+
editorExtension(): CodeMirror.Extension {
|
|
239
|
+
const handlers = this.shortcutHandlers();
|
|
240
|
+
|
|
241
|
+
return [
|
|
242
|
+
CodeMirror.EditorView.updateListener.of(update => this.onEditorUpdate(update)),
|
|
243
|
+
CodeMirror.EditorView.domEventHandlers({
|
|
244
|
+
keydown: (event): boolean => {
|
|
245
|
+
if (this.onKeyDown(event)) {
|
|
246
|
+
return true;
|
|
247
|
+
}
|
|
248
|
+
handlers(event);
|
|
249
|
+
return event.defaultPrevented;
|
|
250
|
+
},
|
|
251
|
+
keyup: event => this.onKeyUp(event),
|
|
252
|
+
mousemove: event => this.onMouseMove(event),
|
|
253
|
+
mousedown: event => this.onMouseDown(event),
|
|
254
|
+
focusout: event => this.onBlur(event),
|
|
255
|
+
wheel: event => this.onWheel(event),
|
|
256
|
+
}),
|
|
257
|
+
CodeMirror.lineNumbers({
|
|
258
|
+
domEventHandlers: {
|
|
259
|
+
mousedown: (view, block, event) =>
|
|
260
|
+
this.handleGutterClick(view.state.doc.lineAt(block.from), event as MouseEvent),
|
|
261
|
+
},
|
|
262
|
+
}),
|
|
263
|
+
infobarState,
|
|
264
|
+
breakpointMarkers,
|
|
265
|
+
CodeMirror.Prec.highest(executionLine.field),
|
|
266
|
+
CodeMirror.Prec.lowest(continueToMarkers.field),
|
|
267
|
+
markIfContinueTo,
|
|
268
|
+
valueDecorations.field,
|
|
269
|
+
CodeMirror.Prec.lowest(evalExpression.field),
|
|
270
|
+
theme,
|
|
271
|
+
this.uiSourceCode.project().type() === Workspace.Workspace.projectTypes.Debugger ?
|
|
272
|
+
CodeMirror.EditorView.editorAttributes.of({class: 'source-frame-debugger-script'}) :
|
|
273
|
+
[],
|
|
274
|
+
];
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
private shortcutHandlers(): (event: KeyboardEvent) => void {
|
|
278
|
+
const selectionLine = (editor: TextEditor.TextEditor.TextEditor): CodeMirror.Line => {
|
|
279
|
+
return editor.state.doc.lineAt(editor.state.selection.main.head);
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
return UI.ShortcutRegistry.ShortcutRegistry.instance().getShortcutListener({
|
|
283
|
+
'debugger.toggle-breakpoint': async(): Promise<boolean> => {
|
|
284
|
+
if (this.muted || !this.editor) {
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
await this.toggleBreakpoint(selectionLine(this.editor), false);
|
|
288
|
+
return true;
|
|
289
|
+
},
|
|
290
|
+
'debugger.toggle-breakpoint-enabled': async(): Promise<boolean> => {
|
|
291
|
+
if (this.muted || !this.editor) {
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
await this.toggleBreakpoint(selectionLine(this.editor), true);
|
|
295
|
+
return true;
|
|
296
|
+
},
|
|
297
|
+
'debugger.breakpoint-input-window': async(): Promise<boolean> => {
|
|
298
|
+
if (this.muted || !this.editor) {
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
const line = selectionLine(this.editor);
|
|
302
|
+
const breakpoint =
|
|
303
|
+
this.breakpoints.find(b => b.position >= line.from && b.position <= line.to)?.breakpoint || null;
|
|
304
|
+
const isLogpoint = breakpoint ? breakpoint.condition().includes(LogpointPrefix) : false;
|
|
305
|
+
this.editBreakpointCondition(line, breakpoint, null, isLogpoint);
|
|
306
|
+
return true;
|
|
307
|
+
},
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
editorInitialized(editor: TextEditor.TextEditor.TextEditor): void {
|
|
312
|
+
this.editor = editor;
|
|
313
|
+
computeNonBreakableLines(editor.state, this.uiSourceCode).then(linePositions => {
|
|
314
|
+
if (linePositions.length) {
|
|
315
|
+
editor.dispatch({effects: SourceFrame.SourceFrame.addNonBreakableLines.of(linePositions)});
|
|
316
|
+
}
|
|
317
|
+
}, console.error);
|
|
318
|
+
if (!this.muted) {
|
|
319
|
+
this.refreshBreakpoints();
|
|
320
|
+
}
|
|
321
|
+
this.callFrameChanged();
|
|
322
|
+
}
|
|
323
|
+
|
|
337
324
|
static accepts(uiSourceCode: Workspace.UISourceCode.UISourceCode): boolean {
|
|
338
325
|
return uiSourceCode.contentType().hasScripts();
|
|
339
326
|
}
|
|
@@ -372,6 +359,7 @@ export class DebuggerPlugin extends Plugin {
|
|
|
372
359
|
},
|
|
373
360
|
]);
|
|
374
361
|
this.ignoreListInfobar = infobar;
|
|
362
|
+
infobar.setCloseCallback(() => this.removeInfobar(this.ignoreListInfobar));
|
|
375
363
|
|
|
376
364
|
infobar.createDetailsRowMessage(i18nString(UIStrings.theDebuggerWillSkipStepping));
|
|
377
365
|
|
|
@@ -380,7 +368,19 @@ export class DebuggerPlugin extends Plugin {
|
|
|
380
368
|
if (scriptFile && scriptFile.hasSourceMapURL()) {
|
|
381
369
|
infobar.createDetailsRowMessage(i18nString(UIStrings.sourceMapFoundButIgnoredForFile));
|
|
382
370
|
}
|
|
383
|
-
this.
|
|
371
|
+
this.attachInfobar(this.ignoreListInfobar);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
attachInfobar(bar: UI.Infobar.Infobar): void {
|
|
375
|
+
if (this.editor) {
|
|
376
|
+
this.editor.dispatch({effects: addInfobar.of(bar)});
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
removeInfobar(bar: UI.Infobar.Infobar|null): void {
|
|
381
|
+
if (this.editor && bar) {
|
|
382
|
+
this.editor.dispatch({effects: removeInfobar.of(bar)});
|
|
383
|
+
}
|
|
384
384
|
}
|
|
385
385
|
|
|
386
386
|
private hideIgnoreListInfobar(): void {
|
|
@@ -391,73 +391,64 @@ export class DebuggerPlugin extends Plugin {
|
|
|
391
391
|
this.ignoreListInfobar = null;
|
|
392
392
|
}
|
|
393
393
|
|
|
394
|
-
wasShown(): void {
|
|
395
|
-
if (this.executionLocation) {
|
|
396
|
-
// We need SourcesTextEditor to be initialized prior to this call. @see crbug.com/499889
|
|
397
|
-
queueMicrotask(() => {
|
|
398
|
-
this.generateValuesInSource();
|
|
399
|
-
});
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
|
|
403
394
|
willHide(): void {
|
|
404
395
|
this.popoverHelper.hidePopover();
|
|
405
396
|
}
|
|
406
397
|
|
|
407
|
-
|
|
408
|
-
Promise<void> {
|
|
398
|
+
populateLineGutterContextMenu(contextMenu: UI.ContextMenu.ContextMenu, editorLineNumber: number): void {
|
|
409
399
|
const uiLocation = new Workspace.UISourceCode.UILocation(this.uiSourceCode, editorLineNumber, 0);
|
|
410
400
|
this.scriptsPanel.appendUILocationItems(contextMenu, uiLocation);
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
401
|
+
if (this.muted || !this.editor) {
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
const line = this.editor.state.doc.line(editorLineNumber + 1);
|
|
405
|
+
const breakpoints = this.lineBreakpoints(line);
|
|
415
406
|
const supportsConditionalBreakpoints =
|
|
416
407
|
Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().supportsConditionalBreakpoints(
|
|
417
408
|
this.uiSourceCode);
|
|
418
409
|
if (!breakpoints.length) {
|
|
419
|
-
if (
|
|
410
|
+
if (this.editor && SourceFrame.SourceFrame.isBreakableLine(this.editor.state, line)) {
|
|
420
411
|
contextMenu.debugSection().appendItem(
|
|
421
|
-
i18nString(UIStrings.addBreakpoint), this.createNewBreakpoint.bind(this,
|
|
412
|
+
i18nString(UIStrings.addBreakpoint), this.createNewBreakpoint.bind(this, line, '', true));
|
|
422
413
|
if (supportsConditionalBreakpoints) {
|
|
423
414
|
contextMenu.debugSection().appendItem(
|
|
424
415
|
i18nString(UIStrings.addConditionalBreakpoint),
|
|
425
|
-
this.editBreakpointCondition.bind(this,
|
|
416
|
+
this.editBreakpointCondition.bind(this, line, null, null, false /* preferLogpoint */));
|
|
426
417
|
contextMenu.debugSection().appendItem(
|
|
427
418
|
i18nString(UIStrings.addLogpoint),
|
|
428
|
-
this.editBreakpointCondition.bind(this,
|
|
419
|
+
this.editBreakpointCondition.bind(this, line, null, null, true /* preferLogpoint */));
|
|
429
420
|
contextMenu.debugSection().appendItem(
|
|
430
|
-
i18nString(UIStrings.neverPauseHere),
|
|
431
|
-
this.createNewBreakpoint.bind(this, editorLineNumber, 'false', true));
|
|
421
|
+
i18nString(UIStrings.neverPauseHere), this.createNewBreakpoint.bind(this, line, 'false', true));
|
|
432
422
|
}
|
|
433
423
|
}
|
|
434
424
|
} else {
|
|
435
425
|
const removeTitle = i18nString(UIStrings.removeBreakpoint, {n: breakpoints.length});
|
|
436
|
-
contextMenu.debugSection().appendItem(
|
|
426
|
+
contextMenu.debugSection().appendItem(
|
|
427
|
+
removeTitle, () => breakpoints.forEach(breakpoint => breakpoint.remove(false)));
|
|
437
428
|
if (breakpoints.length === 1 && supportsConditionalBreakpoints) {
|
|
438
429
|
// Editing breakpoints only make sense for conditional breakpoints
|
|
439
430
|
// and logpoints and both are currently only available for JavaScript
|
|
440
431
|
// debugging.
|
|
441
432
|
contextMenu.debugSection().appendItem(
|
|
442
433
|
i18nString(UIStrings.editBreakpoint),
|
|
443
|
-
this.editBreakpointCondition.bind(
|
|
444
|
-
this, editorLineNumber, breakpoints[0], null, false /* preferLogpoint */));
|
|
434
|
+
this.editBreakpointCondition.bind(this, line, breakpoints[0], null, false /* preferLogpoint */));
|
|
445
435
|
}
|
|
446
436
|
const hasEnabled = breakpoints.some(breakpoint => breakpoint.enabled());
|
|
447
437
|
if (hasEnabled) {
|
|
448
438
|
const title = i18nString(UIStrings.disableBreakpoint, {n: breakpoints.length});
|
|
449
|
-
contextMenu.debugSection().appendItem(
|
|
439
|
+
contextMenu.debugSection().appendItem(
|
|
440
|
+
title, () => breakpoints.forEach(breakpoint => breakpoint.setEnabled(false)));
|
|
450
441
|
}
|
|
451
442
|
const hasDisabled = breakpoints.some(breakpoint => !breakpoint.enabled());
|
|
452
443
|
if (hasDisabled) {
|
|
453
444
|
const title = i18nString(UIStrings.enableBreakpoint, {n: breakpoints.length});
|
|
454
|
-
contextMenu.debugSection().appendItem(
|
|
445
|
+
contextMenu.debugSection().appendItem(
|
|
446
|
+
title, () => breakpoints.forEach(breakpoint => breakpoint.setEnabled(true)));
|
|
455
447
|
}
|
|
456
448
|
}
|
|
457
449
|
}
|
|
458
450
|
|
|
459
|
-
populateTextAreaContextMenu(
|
|
460
|
-
contextMenu: UI.ContextMenu.ContextMenu, editorLineNumber: number, editorColumnNumber: number): Promise<void> {
|
|
451
|
+
populateTextAreaContextMenu(contextMenu: UI.ContextMenu.ContextMenu): void {
|
|
461
452
|
function addSourceMapURL(scriptFile: Bindings.ResourceScriptMapping.ResourceScriptFile): void {
|
|
462
453
|
const dialog = new AddSourceMapURLDialog(addSourceMapURLDialogCallback.bind(null, scriptFile));
|
|
463
454
|
dialog.show();
|
|
@@ -471,95 +462,66 @@ export class DebuggerPlugin extends Plugin {
|
|
|
471
462
|
scriptFile.addSourceMapURL(url);
|
|
472
463
|
}
|
|
473
464
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
contextMenu.debugSection().appendItem(addSourceMapURLLabel, addSourceMapURL.bind(null, scriptFile));
|
|
482
|
-
}
|
|
465
|
+
if (this.uiSourceCode.project().type() === Workspace.Workspace.projectTypes.Network &&
|
|
466
|
+
Common.Settings.Settings.instance().moduleSetting('jsSourceMapsEnabled').get() &&
|
|
467
|
+
!Bindings.IgnoreListManager.IgnoreListManager.instance().isIgnoreListedUISourceCode(this.uiSourceCode)) {
|
|
468
|
+
if (this.scriptFileForDebuggerModel.size) {
|
|
469
|
+
const scriptFile = this.scriptFileForDebuggerModel.values().next().value;
|
|
470
|
+
const addSourceMapURLLabel = i18nString(UIStrings.addSourceMap);
|
|
471
|
+
contextMenu.debugSection().appendItem(addSourceMapURLLabel, addSourceMapURL.bind(null, scriptFile));
|
|
483
472
|
}
|
|
484
473
|
}
|
|
485
|
-
|
|
486
|
-
return super.populateTextAreaContextMenu(contextMenu, editorLineNumber, editorColumnNumber)
|
|
487
|
-
.then(populateSourceMapMembers.bind(this));
|
|
488
474
|
}
|
|
489
475
|
|
|
490
476
|
private workingCopyChanged(): void {
|
|
491
|
-
if (this.scriptFileForDebuggerModel.size) {
|
|
492
|
-
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
if (this.uiSourceCode.isDirty()) {
|
|
496
|
-
this.muteBreakpointsWhileEditing();
|
|
497
|
-
} else {
|
|
498
|
-
this.restoreBreakpointsAfterEditing();
|
|
477
|
+
if (!this.scriptFileForDebuggerModel.size) {
|
|
478
|
+
this.setMuted(this.uiSourceCode.isDirty());
|
|
499
479
|
}
|
|
500
480
|
}
|
|
501
481
|
|
|
502
482
|
private workingCopyCommitted(): void {
|
|
503
483
|
this.scriptsPanel.updateLastModificationTime();
|
|
504
484
|
if (!this.scriptFileForDebuggerModel.size) {
|
|
505
|
-
this.
|
|
485
|
+
this.setMuted(false);
|
|
506
486
|
}
|
|
507
487
|
}
|
|
508
488
|
|
|
509
489
|
private didMergeToVM(): void {
|
|
510
|
-
this.
|
|
490
|
+
if (this.consistentScripts()) {
|
|
491
|
+
this.setMuted(false);
|
|
492
|
+
}
|
|
511
493
|
}
|
|
512
494
|
|
|
513
495
|
private didDivergeFromVM(): void {
|
|
514
|
-
this.
|
|
496
|
+
this.setMuted(true);
|
|
515
497
|
}
|
|
516
498
|
|
|
517
|
-
private
|
|
518
|
-
if (this.
|
|
499
|
+
private setMuted(value: boolean): void {
|
|
500
|
+
if (this.initializedMuted) {
|
|
519
501
|
return;
|
|
520
502
|
}
|
|
521
|
-
|
|
522
|
-
this.
|
|
503
|
+
if (value !== this.muted) {
|
|
504
|
+
this.muted = value;
|
|
505
|
+
if (!value) {
|
|
506
|
+
this.restoreBreakpointsAfterEditing();
|
|
507
|
+
} else if (this.editor) {
|
|
508
|
+
this.editor.dispatch({effects: muteBreakpoints.of(null)});
|
|
509
|
+
}
|
|
523
510
|
}
|
|
524
|
-
this.muted = true;
|
|
525
511
|
}
|
|
526
512
|
|
|
527
|
-
private
|
|
513
|
+
private consistentScripts(): boolean {
|
|
528
514
|
for (const scriptFile of this.scriptFileForDebuggerModel.values()) {
|
|
529
515
|
if (scriptFile.hasDivergedFromVM() || scriptFile.isMergingToVM()) {
|
|
530
|
-
return;
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
await this.restoreBreakpointsAfterEditing();
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
private async restoreBreakpointsAfterEditing(): Promise<void> {
|
|
538
|
-
this.muted = false;
|
|
539
|
-
if (this.mutedFromStart) {
|
|
540
|
-
this.mutedFromStart = false;
|
|
541
|
-
this.initializeBreakpoints();
|
|
542
|
-
return;
|
|
543
|
-
}
|
|
544
|
-
const decorations = Array.from(this.breakpointDecorations);
|
|
545
|
-
this.breakpointDecorations.clear();
|
|
546
|
-
this.textEditor.operation(() => decorations.map(decoration => decoration.hide()));
|
|
547
|
-
for (const decoration of decorations) {
|
|
548
|
-
if (!decoration.breakpoint) {
|
|
549
|
-
continue;
|
|
550
|
-
}
|
|
551
|
-
const enabled = decoration.enabled;
|
|
552
|
-
decoration.breakpoint.remove(false);
|
|
553
|
-
const location = decoration.handle.resolve();
|
|
554
|
-
if (location) {
|
|
555
|
-
await this.setBreakpoint(location.lineNumber, location.columnNumber, decoration.condition, enabled);
|
|
516
|
+
return false;
|
|
556
517
|
}
|
|
557
518
|
}
|
|
519
|
+
return true;
|
|
558
520
|
}
|
|
559
521
|
|
|
560
522
|
private isIdentifier(tokenType: string): boolean {
|
|
561
|
-
return tokenType
|
|
562
|
-
tokenType === '
|
|
523
|
+
return tokenType === 'VariableName' || tokenType === 'VariableDefinition' || tokenType === 'PropertyName' ||
|
|
524
|
+
tokenType === 'PropertyDefinition';
|
|
563
525
|
}
|
|
564
526
|
|
|
565
527
|
private getPopoverRequest(event: MouseEvent): UI.PopoverHelper.PopoverRequest|null {
|
|
@@ -568,161 +530,98 @@ export class DebuggerPlugin extends Plugin {
|
|
|
568
530
|
}
|
|
569
531
|
const target = UI.Context.Context.instance().flavor(SDK.Target.Target);
|
|
570
532
|
const debuggerModel = target ? target.model(SDK.DebuggerModel.DebuggerModel) : null;
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
const textPosition = this.textEditor.coordinatesToCursorPosition(event.x, event.y);
|
|
576
|
-
if (!textPosition) {
|
|
533
|
+
const {editor} = this;
|
|
534
|
+
if (!debuggerModel || !debuggerModel.isPaused() || !editor) {
|
|
577
535
|
return null;
|
|
578
536
|
}
|
|
579
537
|
|
|
580
|
-
const mouseLine = textPosition.startLine;
|
|
581
|
-
const mouseColumn = textPosition.startColumn;
|
|
582
|
-
const textSelection = this.textEditor.selection().normalize();
|
|
583
|
-
let editorLineNumber = -1;
|
|
584
|
-
let startHighlight = -1;
|
|
585
|
-
let endHighlight = -1;
|
|
586
|
-
|
|
587
538
|
const selectedCallFrame =
|
|
588
539
|
(UI.Context.Context.instance().flavor(SDK.DebuggerModel.CallFrame) as SDK.DebuggerModel.CallFrame);
|
|
589
540
|
if (!selectedCallFrame) {
|
|
590
541
|
return null;
|
|
591
542
|
}
|
|
592
543
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
544
|
+
let textPosition = editor.editor.posAtCoords(event);
|
|
545
|
+
if (!textPosition) {
|
|
546
|
+
return null;
|
|
547
|
+
}
|
|
548
|
+
const positionCoords = editor.editor.coordsAtPos(textPosition);
|
|
549
|
+
if (!positionCoords || event.clientY < positionCoords.top || event.clientY > positionCoords.bottom ||
|
|
550
|
+
event.clientX < positionCoords.left - 30 || event.clientX > positionCoords.right + 30) {
|
|
551
|
+
return null;
|
|
552
|
+
}
|
|
553
|
+
if (event.clientX < positionCoords.left && textPosition > editor.state.doc.lineAt(textPosition).from) {
|
|
554
|
+
textPosition -= 1;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
const textSelection = editor.state.selection.main;
|
|
558
|
+
let highlightRange: {from: number, to: number};
|
|
559
|
+
|
|
560
|
+
if (!textSelection.empty) {
|
|
561
|
+
if (textPosition < textSelection.from || textPosition > textSelection.to) {
|
|
596
562
|
return null;
|
|
597
563
|
}
|
|
598
|
-
|
|
599
|
-
startHighlight = textSelection.startColumn;
|
|
600
|
-
endHighlight = textSelection.endColumn - 1;
|
|
564
|
+
highlightRange = textSelection;
|
|
601
565
|
} else if (this.uiSourceCode.mimeType() === 'application/wasm') {
|
|
602
|
-
const
|
|
603
|
-
if (
|
|
566
|
+
const node = CodeMirror.syntaxTree(editor.state).resolveInner(textPosition, 1);
|
|
567
|
+
if (node.name !== 'Identifier') {
|
|
604
568
|
return null;
|
|
605
569
|
}
|
|
606
|
-
editorLineNumber = textPosition.startLine;
|
|
607
|
-
startHighlight = token.startColumn;
|
|
608
|
-
endHighlight = token.endColumn - 1;
|
|
609
|
-
|
|
610
570
|
// For $label identifiers we can't show a meaningful preview (https://crbug.com/1155548),
|
|
611
571
|
// so we suppress them for now. Label identifiers can only appear as operands to control
|
|
612
|
-
// instructions[1]
|
|
572
|
+
// instructions[1].
|
|
613
573
|
//
|
|
614
574
|
// [1]: https://webassembly.github.io/spec/core/text/instructions.html#control-instructions
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
if (
|
|
618
|
-
const
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
case 'if':
|
|
623
|
-
case 'else':
|
|
624
|
-
case 'end':
|
|
625
|
-
case 'br':
|
|
626
|
-
case 'br_if':
|
|
627
|
-
case 'br_table':
|
|
628
|
-
return null;
|
|
629
|
-
default:
|
|
630
|
-
break;
|
|
575
|
+
const controlInstructions = ['block', 'loop', 'if', 'else', 'end', 'br', 'br_if', 'br_table'];
|
|
576
|
+
for (let parent: CodeMirror.SyntaxNode|null = node.parent; parent; parent = parent.parent) {
|
|
577
|
+
if (parent.name === 'App') {
|
|
578
|
+
const firstChild = parent.firstChild;
|
|
579
|
+
const opName = firstChild?.name === 'Keyword' && editor.state.sliceDoc(firstChild.from, firstChild.to);
|
|
580
|
+
if (opName && controlInstructions.includes(opName)) {
|
|
581
|
+
return null;
|
|
631
582
|
}
|
|
632
|
-
break;
|
|
633
583
|
}
|
|
634
584
|
}
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
585
|
+
highlightRange = node;
|
|
586
|
+
} else if (/^text\/(javascript|typescript|jsx)/.test(this.uiSourceCode.mimeType())) {
|
|
587
|
+
let node: CodeMirror.SyntaxNode|null = CodeMirror.syntaxTree(editor.state).resolveInner(textPosition, 1);
|
|
588
|
+
// Only do something if the cursor is over a leaf node.
|
|
589
|
+
if (node.firstChild) {
|
|
638
590
|
return null;
|
|
639
591
|
}
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
// When the user hovers an opening bracket, we look for the closing bracket
|
|
645
|
-
// and kick off the matching from that below.
|
|
646
|
-
if (tokenContent === '[') {
|
|
647
|
-
const closingColumn = line.indexOf(']', token.startColumn);
|
|
648
|
-
if (closingColumn < 0) {
|
|
649
|
-
return null;
|
|
650
|
-
}
|
|
651
|
-
token = this.textEditor.tokenAtTextPosition(editorLineNumber, closingColumn);
|
|
652
|
-
if (!token) {
|
|
653
|
-
return null;
|
|
654
|
-
}
|
|
655
|
-
tokenContent = line.substring(token.startColumn, token.endColumn);
|
|
656
|
-
}
|
|
657
|
-
startHighlight = token.startColumn;
|
|
658
|
-
endHighlight = token.endColumn - 1;
|
|
659
|
-
|
|
660
|
-
// Consume multiple `[index][0]...[f(1)]` at the end of the expression.
|
|
661
|
-
while (tokenContent === ']') {
|
|
662
|
-
startHighlight = line.lastIndexOf('[', startHighlight) - 1;
|
|
663
|
-
if (startHighlight < 0) {
|
|
664
|
-
return null;
|
|
665
|
-
}
|
|
666
|
-
token = this.textEditor.tokenAtTextPosition(editorLineNumber, startHighlight);
|
|
667
|
-
if (!token) {
|
|
668
|
-
return null;
|
|
669
|
-
}
|
|
670
|
-
tokenContent = line.substring(token.startColumn, token.endColumn);
|
|
671
|
-
startHighlight = token.startColumn;
|
|
592
|
+
while (node && node.name !== 'VariableDefinition' && node.name !== 'VariableName' &&
|
|
593
|
+
node.name !== 'MemberExpression') {
|
|
594
|
+
node = node.parent;
|
|
672
595
|
}
|
|
673
|
-
|
|
674
|
-
if (!token.type) {
|
|
596
|
+
if (!node) {
|
|
675
597
|
return null;
|
|
676
598
|
}
|
|
677
|
-
|
|
678
|
-
|
|
599
|
+
highlightRange = node;
|
|
600
|
+
} else {
|
|
601
|
+
// In other languages, just assume a token consisting entirely
|
|
602
|
+
// of identifier-like characters is an identifier.
|
|
603
|
+
const node: CodeMirror.SyntaxNode = CodeMirror.syntaxTree(editor.state).resolveInner(textPosition, 1);
|
|
604
|
+
if (node.to - node.from > 50 || /[^\w_\-$]/.test(editor.state.sliceDoc(node.from, node.to))) {
|
|
679
605
|
return null;
|
|
680
606
|
}
|
|
607
|
+
highlightRange = node;
|
|
608
|
+
}
|
|
681
609
|
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
startHighlight = line.lastIndexOf('[', startHighlight - 2) - 1;
|
|
686
|
-
if (startHighlight < 0) {
|
|
687
|
-
return null;
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
const tokenBefore = this.textEditor.tokenAtTextPosition(editorLineNumber, startHighlight - 2);
|
|
691
|
-
if (!tokenBefore || !tokenBefore.type) {
|
|
692
|
-
return null;
|
|
693
|
-
}
|
|
694
|
-
if (tokenBefore.type === 'js-meta') {
|
|
695
|
-
break;
|
|
696
|
-
}
|
|
697
|
-
if (tokenBefore.type === 'js-string-2') {
|
|
698
|
-
// If we hit a template literal, find the opening ` in this line.
|
|
699
|
-
// TODO(bmeurer): We should eventually replace this tokenization
|
|
700
|
-
// approach with a proper soluation based on parsing, maybe reusing
|
|
701
|
-
// the Parser and AST inside V8 for this (or potentially relying on
|
|
702
|
-
// acorn to do the job).
|
|
703
|
-
if (tokenBefore.endColumn < 2) {
|
|
704
|
-
return null;
|
|
705
|
-
}
|
|
706
|
-
startHighlight = line.lastIndexOf('`', tokenBefore.endColumn - 2);
|
|
707
|
-
if (startHighlight < 0) {
|
|
708
|
-
return null;
|
|
709
|
-
}
|
|
710
|
-
break;
|
|
711
|
-
}
|
|
712
|
-
startHighlight = tokenBefore.startColumn;
|
|
713
|
-
}
|
|
610
|
+
const highlightLine = editor.state.doc.lineAt(highlightRange.from);
|
|
611
|
+
if (highlightRange.to > highlightLine.to) {
|
|
612
|
+
return null;
|
|
714
613
|
}
|
|
715
614
|
|
|
716
|
-
const leftCorner =
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
615
|
+
const leftCorner = editor.editor.coordsAtPos(highlightRange.from);
|
|
616
|
+
const rightCorner = editor.editor.coordsAtPos(highlightRange.to);
|
|
617
|
+
if (!leftCorner || !rightCorner) {
|
|
618
|
+
return null;
|
|
619
|
+
}
|
|
620
|
+
const box = new AnchorBox(
|
|
621
|
+
leftCorner.left, leftCorner.top - 2, rightCorner.right - leftCorner.left, rightCorner.bottom - leftCorner.top);
|
|
622
|
+
const evaluationText = editor.state.sliceDoc(highlightRange.from, highlightRange.to);
|
|
723
623
|
|
|
724
624
|
let objectPopoverHelper: ObjectUI.ObjectPopoverHelper.ObjectPopoverHelper|null = null;
|
|
725
|
-
let highlightDescriptor: CodeMirror.TextMarker|null = null;
|
|
726
625
|
|
|
727
626
|
async function evaluate(uiSourceCode: Workspace.UISourceCode.UISourceCode, evaluationText: string): Promise<{
|
|
728
627
|
object: SDK.RemoteObject.RemoteObject,
|
|
@@ -731,7 +630,8 @@ export class DebuggerPlugin extends Plugin {
|
|
|
731
630
|
error: string,
|
|
732
631
|
}|null> {
|
|
733
632
|
const resolvedText = await resolveExpression(
|
|
734
|
-
selectedCallFrame, evaluationText, uiSourceCode,
|
|
633
|
+
selectedCallFrame, evaluationText, uiSourceCode, highlightLine.number - 1,
|
|
634
|
+
highlightRange.from - highlightLine.from, highlightRange.to - highlightLine.from);
|
|
735
635
|
return await selectedCallFrame.evaluate({
|
|
736
636
|
expression: resolvedText || evaluationText,
|
|
737
637
|
objectGroup: 'popover',
|
|
@@ -750,9 +650,7 @@ export class DebuggerPlugin extends Plugin {
|
|
|
750
650
|
return {
|
|
751
651
|
box,
|
|
752
652
|
show: async(popover: UI.GlassPane.GlassPane): Promise<boolean> => {
|
|
753
|
-
const evaluationText = this.textEditor.line(editorLineNumber).substring(startHighlight, endHighlight + 1);
|
|
754
653
|
const result = await evaluate(this.uiSourceCode, evaluationText);
|
|
755
|
-
|
|
756
654
|
if (!result || 'error' in result || !result.object ||
|
|
757
655
|
(result.object.type === 'object' && result.object.subtype === 'error')) {
|
|
758
656
|
return false;
|
|
@@ -767,9 +665,8 @@ export class DebuggerPlugin extends Plugin {
|
|
|
767
665
|
}
|
|
768
666
|
return false;
|
|
769
667
|
}
|
|
770
|
-
const highlightRange
|
|
771
|
-
|
|
772
|
-
highlightDescriptor = this.textEditor.highlightRange(highlightRange, 'source-frame-eval-expression');
|
|
668
|
+
const decoration = CodeMirror.Decoration.set(evalExpressionMark.range(highlightRange.from, highlightRange.to));
|
|
669
|
+
editor.dispatch({effects: evalExpression.update.of(decoration)});
|
|
773
670
|
return true;
|
|
774
671
|
},
|
|
775
672
|
hide: (): void => {
|
|
@@ -777,379 +674,389 @@ export class DebuggerPlugin extends Plugin {
|
|
|
777
674
|
objectPopoverHelper.dispose();
|
|
778
675
|
}
|
|
779
676
|
debuggerModel.runtimeModel().releaseObjectGroup('popover');
|
|
780
|
-
|
|
781
|
-
this.textEditor.removeHighlight(highlightDescriptor);
|
|
782
|
-
}
|
|
677
|
+
editor.dispatch({effects: evalExpression.update.of(CodeMirror.Decoration.none)});
|
|
783
678
|
},
|
|
784
679
|
};
|
|
785
680
|
}
|
|
786
681
|
|
|
682
|
+
private onEditorUpdate(update: CodeMirror.ViewUpdate): void {
|
|
683
|
+
if (!update.changes.empty) {
|
|
684
|
+
for (const breakpointDesc of this.breakpoints) {
|
|
685
|
+
breakpointDesc.position = update.changes.mapPos(breakpointDesc.position);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
|
|
787
690
|
private onWheel(event: WheelEvent): void {
|
|
788
691
|
if (this.executionLocation && UI.KeyboardShortcut.KeyboardShortcut.eventHasCtrlEquivalentKey(event)) {
|
|
789
692
|
event.preventDefault();
|
|
790
693
|
}
|
|
791
694
|
}
|
|
792
695
|
|
|
793
|
-
private onKeyDown(event: KeyboardEvent):
|
|
794
|
-
|
|
795
|
-
|
|
696
|
+
private onKeyDown(event: KeyboardEvent): boolean {
|
|
697
|
+
const ctrlDown = UI.KeyboardShortcut.KeyboardShortcut.eventHasCtrlEquivalentKey(event);
|
|
698
|
+
if (!ctrlDown) {
|
|
699
|
+
this.setControlDown(false);
|
|
796
700
|
}
|
|
797
|
-
|
|
798
701
|
if (event.key === Platform.KeyboardUtilities.ESCAPE_KEY) {
|
|
799
702
|
if (this.popoverHelper.isPopoverVisible()) {
|
|
800
703
|
this.popoverHelper.hidePopover();
|
|
801
704
|
event.consume();
|
|
802
705
|
}
|
|
803
|
-
return;
|
|
706
|
+
return true;
|
|
804
707
|
}
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
this.controlDown = true;
|
|
808
|
-
if (event.key === (Host.Platform.isMac() ? 'Meta' : 'Control')) {
|
|
809
|
-
this.controlTimeout = window.setTimeout(() => {
|
|
810
|
-
if (this.executionLocation && this.controlDown) {
|
|
811
|
-
this.showContinueToLocations();
|
|
812
|
-
}
|
|
813
|
-
}, 150);
|
|
814
|
-
}
|
|
708
|
+
if (ctrlDown && this.executionLocation) {
|
|
709
|
+
this.setControlDown(true);
|
|
815
710
|
}
|
|
711
|
+
return false;
|
|
816
712
|
}
|
|
817
713
|
|
|
818
714
|
private onMouseMove(event: MouseEvent): void {
|
|
819
715
|
if (this.executionLocation && this.controlDown &&
|
|
820
716
|
UI.KeyboardShortcut.KeyboardShortcut.eventHasCtrlEquivalentKey(event)) {
|
|
821
|
-
if (!this.
|
|
717
|
+
if (!this.continueToLocations) {
|
|
822
718
|
this.showContinueToLocations();
|
|
823
719
|
}
|
|
824
720
|
}
|
|
825
|
-
if (this.continueToLocationDecorations) {
|
|
826
|
-
const target = (event.target as Element);
|
|
827
|
-
const textPosition = this.textEditor.coordinatesToCursorPosition(event.x, event.y);
|
|
828
|
-
const hovering = Boolean(target.enclosingNodeOrSelfWithClass('source-frame-async-step-in'));
|
|
829
|
-
this.setAsyncStepInHoveredLine(textPosition ? textPosition.startLine : null, hovering);
|
|
830
|
-
}
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
private setAsyncStepInHoveredLine(editorLineNumber: number|null, hovered: boolean): void {
|
|
834
|
-
if (this.asyncStepInHoveredLine === editorLineNumber && this.asyncStepInHovered === hovered) {
|
|
835
|
-
return;
|
|
836
|
-
}
|
|
837
|
-
if (this.asyncStepInHovered && this.asyncStepInHoveredLine) {
|
|
838
|
-
this.textEditor.toggleLineClass(this.asyncStepInHoveredLine, 'source-frame-async-step-in-hovered', false);
|
|
839
|
-
}
|
|
840
|
-
this.asyncStepInHoveredLine = editorLineNumber;
|
|
841
|
-
this.asyncStepInHovered = hovered;
|
|
842
|
-
if (this.asyncStepInHovered && this.asyncStepInHoveredLine) {
|
|
843
|
-
this.textEditor.toggleLineClass(this.asyncStepInHoveredLine, 'source-frame-async-step-in-hovered', true);
|
|
844
|
-
}
|
|
845
721
|
}
|
|
846
722
|
|
|
847
723
|
private onMouseDown(event: MouseEvent): void {
|
|
848
724
|
if (!this.executionLocation || !UI.KeyboardShortcut.KeyboardShortcut.eventHasCtrlEquivalentKey(event)) {
|
|
849
725
|
return;
|
|
850
726
|
}
|
|
851
|
-
if (!this.
|
|
727
|
+
if (!this.continueToLocations || !this.editor) {
|
|
852
728
|
return;
|
|
853
729
|
}
|
|
854
730
|
event.consume();
|
|
855
|
-
const textPosition = this.
|
|
856
|
-
if (
|
|
731
|
+
const textPosition = this.editor.editor.posAtCoords(event);
|
|
732
|
+
if (textPosition === null) {
|
|
857
733
|
return;
|
|
858
734
|
}
|
|
859
|
-
for (const
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
continue;
|
|
863
|
-
}
|
|
864
|
-
if (range.from.line !== textPosition.startLine || range.to.line !== textPosition.startLine) {
|
|
865
|
-
continue;
|
|
866
|
-
}
|
|
867
|
-
if (range.from.ch <= textPosition.startColumn && textPosition.startColumn <= range.to.ch) {
|
|
868
|
-
const callback = this.continueToLocationDecorations.get(decoration);
|
|
869
|
-
if (!callback) {
|
|
870
|
-
throw new Error('Expected a function');
|
|
871
|
-
}
|
|
872
|
-
callback();
|
|
735
|
+
for (const {from, to, click} of this.continueToLocations) {
|
|
736
|
+
if (from <= textPosition && to >= textPosition) {
|
|
737
|
+
click();
|
|
873
738
|
break;
|
|
874
739
|
}
|
|
875
740
|
}
|
|
876
741
|
}
|
|
877
742
|
|
|
878
743
|
private onBlur(_event: Event): void {
|
|
879
|
-
this.
|
|
744
|
+
this.setControlDown(false);
|
|
880
745
|
}
|
|
881
746
|
|
|
882
747
|
private onKeyUp(_event: KeyboardEvent): void {
|
|
883
|
-
this.
|
|
748
|
+
this.setControlDown(false);
|
|
884
749
|
}
|
|
885
750
|
|
|
886
|
-
private
|
|
887
|
-
this.controlDown
|
|
888
|
-
|
|
889
|
-
if (this.controlTimeout) {
|
|
751
|
+
private setControlDown(state: boolean): void {
|
|
752
|
+
if (state !== this.controlDown) {
|
|
753
|
+
this.controlDown = state;
|
|
890
754
|
clearTimeout(this.controlTimeout);
|
|
755
|
+
this.controlTimeout = undefined;
|
|
756
|
+
if (state && this.executionLocation) {
|
|
757
|
+
this.controlTimeout = window.setTimeout(() => {
|
|
758
|
+
if (this.executionLocation && this.controlDown) {
|
|
759
|
+
this.showContinueToLocations();
|
|
760
|
+
}
|
|
761
|
+
}, 150);
|
|
762
|
+
} else {
|
|
763
|
+
this.clearContinueToLocations();
|
|
764
|
+
}
|
|
891
765
|
}
|
|
892
766
|
}
|
|
893
767
|
|
|
894
|
-
private
|
|
895
|
-
|
|
768
|
+
private editBreakpointCondition(
|
|
769
|
+
line: CodeMirror.Line, breakpoint: Bindings.BreakpointManager.Breakpoint|null, location: {
|
|
896
770
|
lineNumber: number,
|
|
897
771
|
columnNumber: number,
|
|
898
772
|
}|null,
|
|
899
|
-
preferLogpoint?: boolean):
|
|
773
|
+
preferLogpoint?: boolean): void {
|
|
774
|
+
const editor = this.editor as TextEditor.TextEditor.TextEditor;
|
|
900
775
|
const oldCondition = breakpoint ? breakpoint.condition() : '';
|
|
901
776
|
const decorationElement = document.createElement('div');
|
|
902
|
-
const
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
777
|
+
const compartment = new CodeMirror.Compartment();
|
|
778
|
+
const dialog = new BreakpointEditDialog(line.number - 1, oldCondition, Boolean(preferLogpoint), async result => {
|
|
779
|
+
dialog.detach();
|
|
780
|
+
editor.dispatch({effects: compartment.reconfigure([])});
|
|
781
|
+
if (!result.committed) {
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
784
|
+
if (breakpoint) {
|
|
785
|
+
breakpoint.setCondition(result.condition);
|
|
786
|
+
} else if (location) {
|
|
787
|
+
await this.setBreakpoint(location.lineNumber, location.columnNumber, result.condition, true);
|
|
788
|
+
} else {
|
|
789
|
+
await this.createNewBreakpoint(line, result.condition, true);
|
|
790
|
+
}
|
|
791
|
+
});
|
|
792
|
+
editor.dispatch({
|
|
793
|
+
effects: CodeMirror.StateEffect.appendConfig.of(compartment.of(CodeMirror.EditorView.decorations.of(
|
|
794
|
+
CodeMirror.Decoration.set([CodeMirror.Decoration
|
|
795
|
+
.widget({
|
|
796
|
+
block: true, widget: new class extends CodeMirror.WidgetType {
|
|
797
|
+
toDOM(): HTMLElement {
|
|
798
|
+
return decorationElement;
|
|
799
|
+
}
|
|
800
|
+
}(),
|
|
801
|
+
side: 1,
|
|
802
|
+
})
|
|
803
|
+
.range(line.from)])))),
|
|
804
|
+
});
|
|
918
805
|
dialog.markAsExternallyManaged();
|
|
919
806
|
dialog.show(decorationElement);
|
|
920
807
|
dialog.focusEditor();
|
|
921
808
|
}
|
|
922
809
|
|
|
923
|
-
private
|
|
924
|
-
|
|
925
|
-
const
|
|
926
|
-
if (
|
|
927
|
-
|
|
928
|
-
return;
|
|
810
|
+
private computeExecutionDecorations(editorState: CodeMirror.EditorState, lineNumber: number, columnNumber: number):
|
|
811
|
+
CodeMirror.DecorationSet {
|
|
812
|
+
const {doc} = editorState;
|
|
813
|
+
if (lineNumber >= doc.lines) {
|
|
814
|
+
return CodeMirror.Decoration.none;
|
|
929
815
|
}
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
const
|
|
933
|
-
|
|
934
|
-
if (
|
|
935
|
-
|
|
936
|
-
queueMicrotask(() => {
|
|
937
|
-
if (this.controlDown) {
|
|
938
|
-
this.showContinueToLocations();
|
|
939
|
-
} else {
|
|
940
|
-
this.generateValuesInSource();
|
|
941
|
-
}
|
|
942
|
-
});
|
|
816
|
+
const line = doc.line(lineNumber + 1);
|
|
817
|
+
const decorations: CodeMirror.Range<CodeMirror.Decoration>[] = [executionLineDeco.range(line.from)];
|
|
818
|
+
const position = Math.min(line.to, line.from + columnNumber);
|
|
819
|
+
let syntaxNode = CodeMirror.syntaxTree(editorState).resolveInner(position, 1);
|
|
820
|
+
if (syntaxNode.to === syntaxNode.from - 1 && /[(.]/.test(doc.sliceString(syntaxNode.from, syntaxNode.to))) {
|
|
821
|
+
syntaxNode = syntaxNode.resolve(syntaxNode.to, 1);
|
|
943
822
|
}
|
|
823
|
+
const tokenEnd = Math.min(line.to, syntaxNode.to);
|
|
824
|
+
if (tokenEnd > position) {
|
|
825
|
+
decorations.push(executionTokenDeco.range(position, tokenEnd));
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
return CodeMirror.Decoration.set(decorations);
|
|
944
829
|
}
|
|
945
830
|
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
const executionContext = UI.Context.Context.instance().flavor(SDK.RuntimeModel.ExecutionContext);
|
|
951
|
-
if (!executionContext) {
|
|
952
|
-
return;
|
|
953
|
-
}
|
|
954
|
-
const callFrame = UI.Context.Context.instance().flavor(SDK.DebuggerModel.CallFrame);
|
|
955
|
-
if (!callFrame) {
|
|
831
|
+
// Show widgets with variable's values after lines that mention the
|
|
832
|
+
// variables, if the debugger is paused in this file.
|
|
833
|
+
private async updateValueDecorations(): Promise<void> {
|
|
834
|
+
if (!this.editor) {
|
|
956
835
|
return;
|
|
957
836
|
}
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
if (localScope && functionLocation) {
|
|
962
|
-
resolveScopeInObject(localScope)
|
|
963
|
-
.getAllProperties(false, false)
|
|
964
|
-
.then(this.prepareScopeVariables.bind(this, callFrame));
|
|
837
|
+
const decorations = this.executionLocation ? await this.computeValueDecorations() : null;
|
|
838
|
+
if (decorations || this.editor.state.field(valueDecorations.field).size) {
|
|
839
|
+
this.editor.dispatch({effects: valueDecorations.update.of(decorations || CodeMirror.Decoration.none)});
|
|
965
840
|
}
|
|
966
841
|
}
|
|
967
842
|
|
|
968
|
-
private
|
|
969
|
-
this.
|
|
843
|
+
private async computeValueDecorations(): Promise<CodeMirror.DecorationSet|null> {
|
|
844
|
+
if (!this.editor) {
|
|
845
|
+
return null;
|
|
846
|
+
}
|
|
847
|
+
if (!Common.Settings.Settings.instance().moduleSetting('inlineVariableValues').get()) {
|
|
848
|
+
return null;
|
|
849
|
+
}
|
|
970
850
|
const executionContext = UI.Context.Context.instance().flavor(SDK.RuntimeModel.ExecutionContext);
|
|
971
851
|
if (!executionContext) {
|
|
972
|
-
return;
|
|
852
|
+
return null;
|
|
973
853
|
}
|
|
974
854
|
const callFrame = UI.Context.Context.instance().flavor(SDK.DebuggerModel.CallFrame);
|
|
975
855
|
if (!callFrame) {
|
|
976
|
-
return;
|
|
856
|
+
return null;
|
|
977
857
|
}
|
|
978
|
-
const start = callFrame.functionLocation() || callFrame.location();
|
|
979
|
-
const debuggerModel = callFrame.debuggerModel;
|
|
980
|
-
debuggerModel.getPossibleBreakpoints(start, null, true)
|
|
981
|
-
.then(locations => this.textEditor.operation(renderLocations.bind(this, locations)));
|
|
982
|
-
|
|
983
|
-
function renderLocations(this: DebuggerPlugin, locations: SDK.DebuggerModel.BreakLocation[]): void {
|
|
984
|
-
this.clearContinueToLocationsNoRestore();
|
|
985
|
-
this.textEditor.hideExecutionLineBackground();
|
|
986
|
-
this.continueToLocationDecorations = new Map();
|
|
987
|
-
locations = locations.reverse();
|
|
988
|
-
let previousCallLine = -1;
|
|
989
|
-
for (const location of locations) {
|
|
990
|
-
const editorLocation = this.transformer.uiLocationToEditorLocation(location.lineNumber, location.columnNumber);
|
|
991
|
-
const tokenThatIsPossiblyNull =
|
|
992
|
-
this.textEditor.tokenAtTextPosition(editorLocation.lineNumber, editorLocation.columnNumber);
|
|
993
|
-
if (!tokenThatIsPossiblyNull) {
|
|
994
|
-
continue;
|
|
995
|
-
}
|
|
996
|
-
let token: TextEditor.CodeMirrorTextEditor.Token =
|
|
997
|
-
(tokenThatIsPossiblyNull as TextEditor.CodeMirrorTextEditor.Token);
|
|
998
|
-
|
|
999
|
-
const line = this.textEditor.line(editorLocation.lineNumber);
|
|
1000
|
-
let tokenContent = line.substring(token.startColumn, token.endColumn);
|
|
1001
|
-
if (!token.type && tokenContent === '.') {
|
|
1002
|
-
const nextToken = this.textEditor.tokenAtTextPosition(editorLocation.lineNumber, token.endColumn + 1);
|
|
1003
|
-
if (!nextToken) {
|
|
1004
|
-
throw new Error('nextToken should not be null.');
|
|
1005
|
-
}
|
|
1006
|
-
token = nextToken;
|
|
1007
|
-
tokenContent = line.substring(token.startColumn, token.endColumn);
|
|
1008
|
-
}
|
|
1009
|
-
if (!token.type) {
|
|
1010
|
-
continue;
|
|
1011
|
-
}
|
|
1012
|
-
const validKeyword = token.type === 'js-keyword' &&
|
|
1013
|
-
(tokenContent === 'this' || tokenContent === 'return' || tokenContent === 'new' ||
|
|
1014
|
-
tokenContent === 'continue' || tokenContent === 'break');
|
|
1015
|
-
if (!validKeyword && !this.isIdentifier(token.type)) {
|
|
1016
|
-
continue;
|
|
1017
|
-
}
|
|
1018
|
-
if (previousCallLine === editorLocation.lineNumber &&
|
|
1019
|
-
location.type !== Protocol.Debugger.BreakLocationType.Call) {
|
|
1020
|
-
continue;
|
|
1021
|
-
}
|
|
1022
|
-
|
|
1023
|
-
let highlightRange: TextUtils.TextRange.TextRange = new TextUtils.TextRange.TextRange(
|
|
1024
|
-
editorLocation.lineNumber, token.startColumn, editorLocation.lineNumber, token.endColumn - 1);
|
|
1025
|
-
let decoration = this.textEditor.highlightRange(highlightRange, 'source-frame-continue-to-location');
|
|
1026
|
-
this.continueToLocationDecorations.set(decoration, location.continueToLocation.bind(location));
|
|
1027
|
-
if (location.type === Protocol.Debugger.BreakLocationType.Call) {
|
|
1028
|
-
previousCallLine = editorLocation.lineNumber;
|
|
1029
|
-
}
|
|
1030
|
-
|
|
1031
|
-
let isAsyncCall: boolean = (line[token.startColumn - 1] === '.' && tokenContent === 'then') ||
|
|
1032
|
-
tokenContent === 'setTimeout' || tokenContent === 'setInterval' || tokenContent === 'postMessage';
|
|
1033
|
-
if (tokenContent === 'new') {
|
|
1034
|
-
const nextToken = this.textEditor.tokenAtTextPosition(editorLocation.lineNumber, token.endColumn + 1);
|
|
1035
|
-
if (!nextToken) {
|
|
1036
|
-
throw new Error('nextToken should not be null.');
|
|
1037
|
-
}
|
|
1038
|
-
token = nextToken;
|
|
1039
|
-
tokenContent = line.substring(token.startColumn, token.endColumn);
|
|
1040
|
-
isAsyncCall = tokenContent === 'Worker';
|
|
1041
|
-
}
|
|
1042
|
-
const isCurrentPosition = this.executionLocation && location.lineNumber === this.executionLocation.lineNumber &&
|
|
1043
|
-
location.columnNumber === this.executionLocation.columnNumber;
|
|
1044
|
-
if (location.type === Protocol.Debugger.BreakLocationType.Call && isAsyncCall) {
|
|
1045
|
-
const asyncStepInRange =
|
|
1046
|
-
this.findAsyncStepInRange(this.textEditor, editorLocation.lineNumber, line, token.endColumn);
|
|
1047
|
-
if (asyncStepInRange) {
|
|
1048
|
-
highlightRange = new TextUtils.TextRange.TextRange(
|
|
1049
|
-
editorLocation.lineNumber, asyncStepInRange.from, editorLocation.lineNumber, asyncStepInRange.to - 1);
|
|
1050
|
-
decoration = this.textEditor.highlightRange(highlightRange, 'source-frame-async-step-in');
|
|
1051
|
-
this.continueToLocationDecorations.set(
|
|
1052
|
-
decoration, this.asyncStepIn.bind(this, location, Boolean(isCurrentPosition)));
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
|
-
}
|
|
1056
858
|
|
|
1057
|
-
|
|
859
|
+
const localScope = callFrame.localScope();
|
|
860
|
+
if (!localScope || !callFrame.functionLocation()) {
|
|
861
|
+
return null;
|
|
1058
862
|
}
|
|
1059
|
-
}
|
|
1060
|
-
|
|
1061
|
-
private continueToLocationRenderedForTest(): void {
|
|
1062
|
-
}
|
|
1063
863
|
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
to: number,
|
|
1069
|
-
}|null {
|
|
1070
|
-
let token: (TextEditor.CodeMirrorTextEditor.Token|null)|null = null;
|
|
1071
|
-
let tokenText;
|
|
1072
|
-
let from: number = column;
|
|
1073
|
-
let to: number = line.length;
|
|
864
|
+
const {properties} = await resolveScopeInObject(localScope).getAllProperties(false, false);
|
|
865
|
+
if (!properties || !properties.length || properties.length > 500) {
|
|
866
|
+
return null;
|
|
867
|
+
}
|
|
1074
868
|
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
869
|
+
const functionUILocationPromise =
|
|
870
|
+
Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().rawLocationToUILocation(
|
|
871
|
+
(callFrame.functionLocation() as SDK.DebuggerModel.Location));
|
|
872
|
+
const executionUILocationPromise =
|
|
873
|
+
Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().rawLocationToUILocation(
|
|
874
|
+
callFrame.location());
|
|
875
|
+
const [functionUILocation, executionUILocation] =
|
|
876
|
+
await Promise.all([functionUILocationPromise, executionUILocationPromise]);
|
|
877
|
+
if (!functionUILocation || !executionUILocation ||
|
|
878
|
+
functionUILocation.uiSourceCode.url() !== this.uiSourceCode.url() ||
|
|
879
|
+
executionUILocation.uiSourceCode.url() !== this.uiSourceCode.url()) {
|
|
1078
880
|
return null;
|
|
1079
881
|
}
|
|
1080
|
-
position++;
|
|
1081
882
|
|
|
1082
|
-
|
|
1083
|
-
|
|
883
|
+
const functionLocation =
|
|
884
|
+
this.transformer.uiLocationToEditorLocation(functionUILocation.lineNumber, functionUILocation.columnNumber);
|
|
885
|
+
const executionLocation =
|
|
886
|
+
this.transformer.uiLocationToEditorLocation(executionUILocation.lineNumber, executionUILocation.columnNumber);
|
|
887
|
+
if (functionLocation.lineNumber >= executionLocation.lineNumber ||
|
|
888
|
+
executionLocation.lineNumber - functionLocation.lineNumber > 500 || functionLocation.lineNumber < 0 ||
|
|
889
|
+
executionLocation.lineNumber >= this.editor.state.doc.lines) {
|
|
1084
890
|
return null;
|
|
1085
891
|
}
|
|
1086
892
|
|
|
1087
|
-
|
|
1088
|
-
|
|
893
|
+
const variableMap = new Map<string, SDK.RemoteObject.RemoteObject>(
|
|
894
|
+
properties.map(p => [p.name, p.value] as [string, SDK.RemoteObject.RemoteObject]));
|
|
895
|
+
|
|
896
|
+
const variablesByLine =
|
|
897
|
+
this.getVariablesByLine(this.editor.state, variableMap, functionLocation, executionLocation);
|
|
898
|
+
if (!variablesByLine) {
|
|
1089
899
|
return null;
|
|
1090
900
|
}
|
|
1091
|
-
from = token.startColumn;
|
|
1092
901
|
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
902
|
+
const decorations: CodeMirror.Range<CodeMirror.Decoration>[] = [];
|
|
903
|
+
|
|
904
|
+
for (const [line, names] of variablesByLine) {
|
|
905
|
+
const prevLine = variablesByLine.get(line - 1);
|
|
906
|
+
let newNames = prevLine ? Array.from(names).filter(n => !prevLine.has(n)) : Array.from(names);
|
|
907
|
+
if (!newNames.length) {
|
|
908
|
+
continue;
|
|
1097
909
|
}
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
return {from: from, to: to};
|
|
910
|
+
if (newNames.length > 10) {
|
|
911
|
+
newNames = newNames.slice(0, 10);
|
|
1101
912
|
}
|
|
913
|
+
const pairs = newNames.map(name => [name, variableMap.get(name)] as [string, SDK.RemoteObject.RemoteObject]);
|
|
914
|
+
decorations.push(CodeMirror.Decoration.widget({widget: new ValueDecoration(pairs), side: 1})
|
|
915
|
+
.range(this.editor.state.doc.line(line + 1).to));
|
|
1102
916
|
}
|
|
917
|
+
return CodeMirror.Decoration.set(decorations, true);
|
|
918
|
+
}
|
|
1103
919
|
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
920
|
+
getVariablesByLine(
|
|
921
|
+
editorState: CodeMirror.EditorState, variableMap: Map<string, unknown>,
|
|
922
|
+
fromLoc: {lineNumber: number, columnNumber: number},
|
|
923
|
+
toLoc: {lineNumber: number, columnNumber: number}): Map<number, Set<string>>|null {
|
|
924
|
+
const fromLine = editorState.doc.line(fromLoc.lineNumber + 1);
|
|
925
|
+
const fromPos = Math.min(fromLine.to, fromLine.from + fromLoc.columnNumber);
|
|
926
|
+
const toPos = editorState.doc.line(toLoc.lineNumber + 1).from;
|
|
1107
927
|
|
|
1108
|
-
|
|
1109
|
-
|
|
928
|
+
const tree = CodeMirror.ensureSyntaxTree(editorState, toPos, 100);
|
|
929
|
+
if (!tree) {
|
|
930
|
+
return null;
|
|
1110
931
|
}
|
|
1111
932
|
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
933
|
+
const namesPerLine = new Map<number, Set<string>>();
|
|
934
|
+
let curLine = fromLine;
|
|
935
|
+
tree.iterate({
|
|
936
|
+
from: fromPos,
|
|
937
|
+
to: toPos,
|
|
938
|
+
enter(type, from, to): void {
|
|
939
|
+
const varName = type.name === 'VariableName' && editorState.sliceDoc(from, to);
|
|
940
|
+
if (varName && variableMap.has(varName)) {
|
|
941
|
+
if (from > curLine.to) {
|
|
942
|
+
curLine = editorState.doc.lineAt(from);
|
|
943
|
+
}
|
|
944
|
+
let names = namesPerLine.get(curLine.number - 1);
|
|
945
|
+
if (!names) {
|
|
946
|
+
names = new Set();
|
|
947
|
+
namesPerLine.set(curLine.number - 1, names);
|
|
948
|
+
}
|
|
949
|
+
names.add(varName);
|
|
950
|
+
}
|
|
951
|
+
},
|
|
952
|
+
});
|
|
953
|
+
return namesPerLine;
|
|
954
|
+
}
|
|
1115
955
|
|
|
1116
|
-
|
|
1117
|
-
|
|
956
|
+
private async showContinueToLocations(): Promise<void> {
|
|
957
|
+
this.popoverHelper.hidePopover();
|
|
958
|
+
const executionContext = UI.Context.Context.instance().flavor(SDK.RuntimeModel.ExecutionContext);
|
|
959
|
+
if (!executionContext || !this.editor) {
|
|
960
|
+
return;
|
|
1118
961
|
}
|
|
1119
|
-
const
|
|
1120
|
-
if (
|
|
1121
|
-
return
|
|
962
|
+
const callFrame = UI.Context.Context.instance().flavor(SDK.DebuggerModel.CallFrame);
|
|
963
|
+
if (!callFrame) {
|
|
964
|
+
return;
|
|
1122
965
|
}
|
|
1123
|
-
|
|
966
|
+
const start = callFrame.functionLocation() || callFrame.location();
|
|
967
|
+
const debuggerModel = callFrame.debuggerModel;
|
|
968
|
+
|
|
969
|
+
const {state} = this.editor;
|
|
970
|
+
const locations = await debuggerModel.getPossibleBreakpoints(start, null, true);
|
|
1124
971
|
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
972
|
+
this.continueToLocations = [];
|
|
973
|
+
let previousCallLine = -1;
|
|
974
|
+
for (const location of locations.reverse()) {
|
|
975
|
+
const editorLocation = this.transformer.uiLocationToEditorLocation(location.lineNumber, location.columnNumber);
|
|
976
|
+
if (previousCallLine === editorLocation.lineNumber &&
|
|
977
|
+
location.type !== Protocol.Debugger.BreakLocationType.Call ||
|
|
978
|
+
editorLocation.lineNumber >= state.doc.lines) {
|
|
979
|
+
continue;
|
|
980
|
+
}
|
|
981
|
+
const line = state.doc.line(editorLocation.lineNumber + 1);
|
|
982
|
+
const position = Math.min(line.to, line.from + editorLocation.columnNumber);
|
|
983
|
+
let syntaxNode = CodeMirror.syntaxTree(state).resolveInner(position, 1);
|
|
984
|
+
if (syntaxNode.firstChild || syntaxNode.from < line.from ||
|
|
985
|
+
syntaxNode.to > line.to) { // Only use leaf nodes within the line
|
|
986
|
+
continue;
|
|
987
|
+
}
|
|
988
|
+
if (syntaxNode.name === '.') {
|
|
989
|
+
const nextNode = syntaxNode.resolve(syntaxNode.to, 1);
|
|
990
|
+
if (nextNode.firstChild || nextNode.from < line.from || nextNode.to > line.to) {
|
|
991
|
+
continue;
|
|
992
|
+
}
|
|
993
|
+
syntaxNode = nextNode;
|
|
994
|
+
}
|
|
995
|
+
const syntaxType = syntaxNode.name;
|
|
996
|
+
const validKeyword = syntaxType === 'this' || syntaxType === 'return' || syntaxType === 'new' ||
|
|
997
|
+
syntaxType === 'break' || syntaxType === 'continue';
|
|
998
|
+
if (!validKeyword && !this.isIdentifier(syntaxType)) {
|
|
999
|
+
continue;
|
|
1131
1000
|
}
|
|
1132
1001
|
|
|
1133
|
-
|
|
1134
|
-
|
|
1002
|
+
this.continueToLocations.push(
|
|
1003
|
+
{from: syntaxNode.from, to: syntaxNode.to, async: false, click: () => location.continueToLocation()});
|
|
1004
|
+
if (location.type === Protocol.Debugger.BreakLocationType.Call) {
|
|
1005
|
+
previousCallLine = editorLocation.lineNumber;
|
|
1006
|
+
}
|
|
1135
1007
|
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1008
|
+
const identifierName =
|
|
1009
|
+
validKeyword ? '' : line.text.slice(syntaxNode.from - line.from, syntaxNode.to - line.from);
|
|
1010
|
+
let asyncCall: CodeMirror.SyntaxNode|null = null;
|
|
1011
|
+
if (identifierName === 'then' && syntaxNode.parent?.name === 'MemberExpression') {
|
|
1012
|
+
asyncCall = syntaxNode.parent.parent;
|
|
1013
|
+
} else if (
|
|
1014
|
+
identifierName === 'setTimeout' || identifierName === 'setInterval' || identifierName === 'postMessage') {
|
|
1015
|
+
asyncCall = syntaxNode.parent;
|
|
1016
|
+
}
|
|
1017
|
+
if (syntaxType === 'new') {
|
|
1018
|
+
const callee = syntaxNode.parent?.getChild('Expression');
|
|
1019
|
+
if (callee && callee.name === 'VariableName' && state.sliceDoc(callee.from, callee.to) === 'Worker') {
|
|
1020
|
+
asyncCall = syntaxNode.parent;
|
|
1141
1021
|
}
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1022
|
+
}
|
|
1023
|
+
if (asyncCall && (asyncCall.name === 'CallExpression' || asyncCall.name === 'NewExpression') &&
|
|
1024
|
+
location.type === Protocol.Debugger.BreakLocationType.Call) {
|
|
1025
|
+
const firstArg = asyncCall.getChild('ArgList')?.firstChild?.nextSibling;
|
|
1026
|
+
let highlightNode;
|
|
1027
|
+
if (firstArg?.name === 'VariableName') {
|
|
1028
|
+
highlightNode = firstArg;
|
|
1029
|
+
} else if (firstArg?.name === 'ArrowFunction' || firstArg?.name === 'FunctionExpression') {
|
|
1030
|
+
highlightNode = firstArg.firstChild;
|
|
1031
|
+
if (highlightNode?.name === 'async') {
|
|
1032
|
+
highlightNode = highlightNode.nextSibling;
|
|
1033
|
+
}
|
|
1145
1034
|
}
|
|
1146
|
-
if (
|
|
1147
|
-
|
|
1148
|
-
|
|
1035
|
+
if (highlightNode) {
|
|
1036
|
+
const isCurrentPosition = this.executionLocation &&
|
|
1037
|
+
location.lineNumber === this.executionLocation.lineNumber &&
|
|
1038
|
+
location.columnNumber === this.executionLocation.columnNumber;
|
|
1039
|
+
this.continueToLocations.push({
|
|
1040
|
+
from: highlightNode.from,
|
|
1041
|
+
to: highlightNode.to,
|
|
1042
|
+
async: true,
|
|
1043
|
+
click: () => this.asyncStepIn(location, Boolean(isCurrentPosition)),
|
|
1044
|
+
});
|
|
1149
1045
|
}
|
|
1150
|
-
break;
|
|
1151
1046
|
}
|
|
1152
1047
|
}
|
|
1048
|
+
const decorations = CodeMirror.Decoration.set(
|
|
1049
|
+
this.continueToLocations.map(loc => {
|
|
1050
|
+
return (loc.async ? asyncContinueToMark : continueToMark).range(loc.from, loc.to);
|
|
1051
|
+
}),
|
|
1052
|
+
true);
|
|
1053
|
+
this.editor.dispatch({effects: continueToMarkers.update.of(decorations)});
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
private clearContinueToLocations(): void {
|
|
1057
|
+
if (this.editor && this.editor.state.field(continueToMarkers.field).size) {
|
|
1058
|
+
this.editor.dispatch({effects: continueToMarkers.update.of(CodeMirror.Decoration.none)});
|
|
1059
|
+
}
|
|
1153
1060
|
}
|
|
1154
1061
|
|
|
1155
1062
|
private asyncStepIn(location: SDK.DebuggerModel.BreakLocation, isCurrentPosition: boolean): void {
|
|
@@ -1164,573 +1071,213 @@ export class DebuggerPlugin extends Plugin {
|
|
|
1164
1071
|
}
|
|
1165
1072
|
}
|
|
1166
1073
|
|
|
1167
|
-
private
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
if (!
|
|
1172
|
-
return;
|
|
1074
|
+
private fetchBreakpoints(): {
|
|
1075
|
+
position: number,
|
|
1076
|
+
breakpoint: Bindings.BreakpointManager.Breakpoint,
|
|
1077
|
+
}[] {
|
|
1078
|
+
if (!this.editor) {
|
|
1079
|
+
return [];
|
|
1173
1080
|
}
|
|
1081
|
+
const {editor} = this;
|
|
1082
|
+
const breakpointLocations = this.breakpointManager.breakpointLocationsForUISourceCode(this.uiSourceCode);
|
|
1083
|
+
return breakpointLocations.map(({uiLocation, breakpoint}) => {
|
|
1084
|
+
const editorLocation =
|
|
1085
|
+
this.transformer.uiLocationToEditorLocation(uiLocation.lineNumber, uiLocation.columnNumber);
|
|
1086
|
+
return {
|
|
1087
|
+
position: editor.toOffset(editorLocation),
|
|
1088
|
+
breakpoint,
|
|
1089
|
+
};
|
|
1090
|
+
});
|
|
1091
|
+
}
|
|
1174
1092
|
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
const executionUILocationPromise =
|
|
1179
|
-
Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().rawLocationToUILocation(
|
|
1180
|
-
callFrame.location());
|
|
1181
|
-
const [functionUILocation, executionUILocation] =
|
|
1182
|
-
await Promise.all([functionUILocationPromise, executionUILocationPromise]);
|
|
1183
|
-
if (!functionUILocation || !executionUILocation ||
|
|
1184
|
-
functionUILocation.uiSourceCode.url() !== this.uiSourceCode.url() ||
|
|
1185
|
-
executionUILocation.uiSourceCode.url() !== this.uiSourceCode.url()) {
|
|
1186
|
-
return;
|
|
1187
|
-
}
|
|
1093
|
+
private lineBreakpoints(line: CodeMirror.Line): readonly Bindings.BreakpointManager.Breakpoint[] {
|
|
1094
|
+
return this.breakpoints.filter(b => b.position >= line.from && b.position <= line.to).map(b => b.breakpoint);
|
|
1095
|
+
}
|
|
1188
1096
|
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
const
|
|
1192
|
-
|
|
1193
|
-
const
|
|
1194
|
-
const
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
}
|
|
1097
|
+
private async computeBreakpointDecoration(state: CodeMirror.EditorState, breakpoints: BreakpointDescription[]):
|
|
1098
|
+
Promise<BreakpointDecoration> {
|
|
1099
|
+
const decorations: CodeMirror.Range<CodeMirror.Decoration>[] = [];
|
|
1100
|
+
const gutterMarkers: CodeMirror.Range<CodeMirror.GutterMarker>[] = [];
|
|
1101
|
+
const breakpointsByLine = new Map<number, Bindings.BreakpointManager.Breakpoint[]>();
|
|
1102
|
+
const inlineMarkersByLine =
|
|
1103
|
+
new Map<number, {breakpoint: Bindings.BreakpointManager.Breakpoint | null, column: number}[]>();
|
|
1104
|
+
const possibleBreakpointRequests: Promise<void>[] = [];
|
|
1105
|
+
const inlineMarkerPositions = new Set<number>();
|
|
1199
1106
|
|
|
1200
|
-
const
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1107
|
+
const addInlineMarker =
|
|
1108
|
+
(linePos: number, columnNumber: number, breakpoint: Bindings.BreakpointManager.Breakpoint|null): void => {
|
|
1109
|
+
let inlineMarkers = inlineMarkersByLine.get(linePos);
|
|
1110
|
+
if (!inlineMarkers) {
|
|
1111
|
+
inlineMarkers = [];
|
|
1112
|
+
inlineMarkersByLine.set(linePos, inlineMarkers);
|
|
1113
|
+
}
|
|
1114
|
+
inlineMarkers.push({breakpoint, column: columnNumber});
|
|
1115
|
+
};
|
|
1204
1116
|
|
|
1205
|
-
const
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1117
|
+
for (const {position, breakpoint} of breakpoints) {
|
|
1118
|
+
const line = state.doc.lineAt(position);
|
|
1119
|
+
let forThisLine = breakpointsByLine.get(line.from);
|
|
1120
|
+
if (!forThisLine) {
|
|
1121
|
+
forThisLine = [];
|
|
1122
|
+
breakpointsByLine.set(line.from, forThisLine);
|
|
1123
|
+
}
|
|
1124
|
+
if (breakpoint.enabled() && forThisLine.every(b => !b.enabled())) {
|
|
1125
|
+
// Start a request for possible breakpoint positions on this line
|
|
1126
|
+
const start = this.transformer.editorLocationToUILocation(line.number - 1, 0);
|
|
1127
|
+
const end = this.transformer.editorLocationToUILocation(
|
|
1128
|
+
line.number - 1, Math.min(line.length, MAX_POSSIBLE_BREAKPOINT_LINE));
|
|
1129
|
+
const range = new TextUtils.TextRange.TextRange(
|
|
1130
|
+
start.lineNumber, start.columnNumber || 0, end.lineNumber, end.columnNumber || 0);
|
|
1131
|
+
possibleBreakpointRequests.push(this.breakpointManager.possibleBreakpoints(this.uiSourceCode, range)
|
|
1132
|
+
.then(locations => addPossibleBreakpoints(line, locations)));
|
|
1133
|
+
}
|
|
1134
|
+
forThisLine.push(breakpoint);
|
|
1135
|
+
if (breakpoint.enabled()) {
|
|
1136
|
+
inlineMarkerPositions.add(position);
|
|
1137
|
+
addInlineMarker(line.from, position - line.from, breakpoint);
|
|
1223
1138
|
}
|
|
1224
|
-
skipObjectProperty = tokenValue === '.';
|
|
1225
1139
|
}
|
|
1226
|
-
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
|
|
1227
|
-
// @ts-expect-error
|
|
1228
|
-
this.textEditor.operation(this.renderDecorations.bind(this, valuesMap, namesPerLine, fromLine, toLine));
|
|
1229
|
-
}
|
|
1230
1140
|
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
const names = namesPerLine.get(i);
|
|
1237
|
-
const oldWidget = this.valueWidgets.get(i);
|
|
1238
|
-
if (!names) {
|
|
1239
|
-
if (oldWidget) {
|
|
1240
|
-
this.valueWidgets.delete(i);
|
|
1241
|
-
this.textEditor.removeDecoration(oldWidget, i);
|
|
1242
|
-
}
|
|
1243
|
-
continue;
|
|
1141
|
+
for (const [lineStart, lineBreakpoints] of breakpointsByLine) {
|
|
1142
|
+
const main = lineBreakpoints.sort(mostSpecificBreakpoint)[0];
|
|
1143
|
+
let gutterClass = 'cm-breakpoint';
|
|
1144
|
+
if (!main.enabled()) {
|
|
1145
|
+
gutterClass += ' cm-breakpoint-disabled';
|
|
1244
1146
|
}
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
widget.classList.add('text-editor-value-decoration');
|
|
1248
|
-
const base = this.textEditor.cursorPositionToCoordinates(i, 0);
|
|
1249
|
-
if (!base) {
|
|
1250
|
-
throw new Error('base is expected to not be null');
|
|
1147
|
+
if (!main.bound()) {
|
|
1148
|
+
gutterClass += ' cm-breakpoint-unbound';
|
|
1251
1149
|
}
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1150
|
+
if (main.condition().includes(LogpointPrefix)) {
|
|
1151
|
+
gutterClass += ' cm-breakpoint-logpoint';
|
|
1152
|
+
} else if (main.condition()) {
|
|
1153
|
+
gutterClass += ' cm-breakpoint-conditional';
|
|
1255
1154
|
}
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
if (renderedNameCount > 10) {
|
|
1264
|
-
break;
|
|
1265
|
-
}
|
|
1266
|
-
const names = namesPerLine.get(i - 1);
|
|
1267
|
-
if (names && names.has(name)) {
|
|
1155
|
+
gutterMarkers.push((new BreakpointGutterMarker(gutterClass)).range(lineStart));
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
const addPossibleBreakpoints = (line: CodeMirror.Line, locations: Workspace.UISourceCode.UILocation[]): void => {
|
|
1159
|
+
for (const location of locations) {
|
|
1160
|
+
const editorLocation = this.transformer.uiLocationToEditorLocation(location.lineNumber, location.columnNumber);
|
|
1161
|
+
if (editorLocation.lineNumber !== line.number - 1) {
|
|
1268
1162
|
continue;
|
|
1269
|
-
} // Only render name once in the given continuous block.
|
|
1270
|
-
if (renderedNameCount) {
|
|
1271
|
-
UI.UIUtils.createTextChild(widget, ', ');
|
|
1272
1163
|
}
|
|
1273
|
-
const
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
const value = valuesMap.get(name);
|
|
1277
|
-
if (!value) {
|
|
1278
|
-
throw new Error('value is expected to be null');
|
|
1164
|
+
const position = Math.min(line.to, line.from + editorLocation.columnNumber);
|
|
1165
|
+
if (!inlineMarkerPositions.has(position)) {
|
|
1166
|
+
addInlineMarker(line.from, editorLocation.columnNumber, null);
|
|
1279
1167
|
}
|
|
1280
|
-
const propertyCount = value.preview ? value.preview.properties.length : 0;
|
|
1281
|
-
const entryCount = value.preview && value.preview.entries ? value.preview.entries.length : 0;
|
|
1282
|
-
if (value.preview && propertyCount + entryCount < 10) {
|
|
1283
|
-
formatter.appendObjectPreview(nameValuePair, value.preview, false /* isEntry */);
|
|
1284
|
-
} else {
|
|
1285
|
-
const propertyValue = ObjectUI.ObjectPropertiesSection.ObjectPropertiesSection.createPropertyValue(
|
|
1286
|
-
value, /* wasThrown */ false, /* showPreview */ false);
|
|
1287
|
-
nameValuePair.appendChild(propertyValue.element);
|
|
1288
|
-
}
|
|
1289
|
-
++renderedNameCount;
|
|
1290
1168
|
}
|
|
1169
|
+
};
|
|
1291
1170
|
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
for (const
|
|
1296
|
-
const
|
|
1297
|
-
|
|
1298
|
-
const oldText = oldTextElement ? oldTextElement.textContent : '';
|
|
1299
|
-
const newText = newTextElement ? newTextElement.textContent : '';
|
|
1300
|
-
if (newText !== oldText) {
|
|
1301
|
-
widgetChanged = true;
|
|
1302
|
-
UI.UIUtils.runCSSAnimationOnce(
|
|
1303
|
-
(widget.nameToToken.get(name) as Element), 'source-frame-value-update-highlight');
|
|
1304
|
-
}
|
|
1305
|
-
}
|
|
1306
|
-
if (widgetChanged) {
|
|
1307
|
-
this.valueWidgets.delete(i);
|
|
1308
|
-
this.textEditor.removeDecoration(oldWidget, i);
|
|
1171
|
+
await Promise.all(possibleBreakpointRequests);
|
|
1172
|
+
for (const [linePos, inlineMarkers] of inlineMarkersByLine) {
|
|
1173
|
+
if (inlineMarkers.length > 1) {
|
|
1174
|
+
for (const {column, breakpoint} of inlineMarkers) {
|
|
1175
|
+
const marker = new BreakpointInlineMarker(breakpoint, this);
|
|
1176
|
+
decorations.push(CodeMirror.Decoration.widget({widget: marker, side: -1}).range(linePos + column));
|
|
1309
1177
|
}
|
|
1310
1178
|
}
|
|
1311
|
-
if (widgetChanged) {
|
|
1312
|
-
this.valueWidgets.set(i, widget);
|
|
1313
|
-
this.textEditor.addDecoration(widget, i);
|
|
1314
|
-
}
|
|
1315
|
-
}
|
|
1316
|
-
}
|
|
1317
|
-
|
|
1318
|
-
private clearExecutionLine(): void {
|
|
1319
|
-
this.textEditor.operation(() => {
|
|
1320
|
-
if (this.executionLocation) {
|
|
1321
|
-
this.textEditor.clearExecutionLine();
|
|
1322
|
-
}
|
|
1323
|
-
this.executionLocation = null;
|
|
1324
|
-
if (this.clearValueWidgetsTimer) {
|
|
1325
|
-
clearTimeout(this.clearValueWidgetsTimer);
|
|
1326
|
-
this.clearValueWidgetsTimer = null;
|
|
1327
|
-
}
|
|
1328
|
-
this.clearValueWidgetsTimer = window.setTimeout(this.clearValueWidgets.bind(this), 1000);
|
|
1329
|
-
this.clearContinueToLocationsNoRestore();
|
|
1330
|
-
});
|
|
1331
|
-
}
|
|
1332
|
-
|
|
1333
|
-
private clearValueWidgets(): void {
|
|
1334
|
-
if (this.clearValueWidgetsTimer) {
|
|
1335
|
-
clearTimeout(this.clearValueWidgetsTimer);
|
|
1336
1179
|
}
|
|
1337
|
-
this.clearValueWidgetsTimer = null;
|
|
1338
|
-
this.textEditor.operation(() => {
|
|
1339
|
-
for (const line of this.valueWidgets.keys()) {
|
|
1340
|
-
const valueWidget = this.valueWidgets.get(line);
|
|
1341
|
-
if (valueWidget) {
|
|
1342
|
-
this.textEditor.removeDecoration(valueWidget, line);
|
|
1343
|
-
}
|
|
1344
|
-
}
|
|
1345
|
-
this.valueWidgets.clear();
|
|
1346
|
-
});
|
|
1347
|
-
}
|
|
1348
1180
|
|
|
1349
|
-
|
|
1350
|
-
const continueToLocationDecorations = this.continueToLocationDecorations;
|
|
1351
|
-
if (!continueToLocationDecorations) {
|
|
1352
|
-
return;
|
|
1353
|
-
}
|
|
1354
|
-
this.textEditor.operation(() => {
|
|
1355
|
-
for (const decoration of continueToLocationDecorations.keys()) {
|
|
1356
|
-
this.textEditor.removeHighlight(decoration);
|
|
1357
|
-
}
|
|
1358
|
-
this.continueToLocationDecorations = null;
|
|
1359
|
-
this.setAsyncStepInHoveredLine(null, false);
|
|
1360
|
-
});
|
|
1181
|
+
return {content: CodeMirror.Decoration.set(decorations, true), gutter: CodeMirror.RangeSet.of(gutterMarkers, true)};
|
|
1361
1182
|
}
|
|
1362
1183
|
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1184
|
+
// If, after editing, the editor is synced again (either by going
|
|
1185
|
+
// back to the original document or by saving), we replace any
|
|
1186
|
+
// breakpoints the breakpoint manager might have (which point into
|
|
1187
|
+
// the old file) with the breakpoints we have, which had their
|
|
1188
|
+
// positions tracked through the changes.
|
|
1189
|
+
private restoreBreakpointsAfterEditing(): void {
|
|
1190
|
+
const {breakpoints} = this;
|
|
1191
|
+
const editor = this.editor as TextEditor.TextEditor.TextEditor;
|
|
1192
|
+
this.breakpoints = [];
|
|
1193
|
+
for (const {breakpoint, position} of breakpoints) {
|
|
1194
|
+
const condition = breakpoint.condition(), enabled = breakpoint.enabled();
|
|
1195
|
+
breakpoint.remove(false);
|
|
1196
|
+
const editorLocation = editor.toLineColumn(position);
|
|
1197
|
+
const uiLocation =
|
|
1198
|
+
this.transformer.editorLocationToUILocation(editorLocation.lineNumber, editorLocation.columnNumber);
|
|
1199
|
+
this.setBreakpoint(uiLocation.lineNumber, uiLocation.columnNumber, condition, enabled);
|
|
1366
1200
|
}
|
|
1367
|
-
this.textEditor.operation(() => {
|
|
1368
|
-
this.textEditor.showExecutionLineBackground();
|
|
1369
|
-
this.generateValuesInSource();
|
|
1370
|
-
this.clearContinueToLocationsNoRestore();
|
|
1371
|
-
});
|
|
1372
|
-
}
|
|
1373
|
-
|
|
1374
|
-
private lineBreakpointDecorations(lineNumber: number): BreakpointDecoration[] {
|
|
1375
|
-
return Array.from(this.breakpointDecorations)
|
|
1376
|
-
.filter(decoration => (decoration.handle.resolve() || {}).lineNumber === lineNumber);
|
|
1377
1201
|
}
|
|
1378
1202
|
|
|
1379
|
-
private
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1203
|
+
private async refreshBreakpoints(): Promise<void> {
|
|
1204
|
+
if (this.editor) {
|
|
1205
|
+
this.breakpoints = this.fetchBreakpoints();
|
|
1206
|
+
const forBreakpoints = this.breakpoints;
|
|
1207
|
+
const decorations = await this.computeBreakpointDecoration(this.editor.state, forBreakpoints);
|
|
1208
|
+
if (this.breakpoints === forBreakpoints &&
|
|
1209
|
+
(decorations.gutter.size || this.editor.state.field(breakpointMarkers).gutter.size)) {
|
|
1210
|
+
this.editor.dispatch({effects: setBreakpointDeco.of(decorations)});
|
|
1387
1211
|
}
|
|
1388
1212
|
}
|
|
1389
|
-
return null;
|
|
1390
1213
|
}
|
|
1391
1214
|
|
|
1392
|
-
private
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
});
|
|
1398
|
-
}
|
|
1399
|
-
this.scheduledBreakpointDecorationUpdates.add(decoration);
|
|
1400
|
-
|
|
1401
|
-
function update(this: DebuggerPlugin): void {
|
|
1402
|
-
if (!this.scheduledBreakpointDecorationUpdates) {
|
|
1403
|
-
return;
|
|
1404
|
-
}
|
|
1405
|
-
const editorLineNumbers = new Set<number>();
|
|
1406
|
-
for (const decoration of this.scheduledBreakpointDecorationUpdates) {
|
|
1407
|
-
const location = decoration.handle.resolve();
|
|
1408
|
-
if (!location) {
|
|
1409
|
-
continue;
|
|
1410
|
-
}
|
|
1411
|
-
editorLineNumbers.add(location.lineNumber);
|
|
1412
|
-
}
|
|
1413
|
-
this.scheduledBreakpointDecorationUpdates = null;
|
|
1414
|
-
let waitingForInlineDecorations = false;
|
|
1415
|
-
for (const lineNumber of editorLineNumbers) {
|
|
1416
|
-
const decorations = this.lineBreakpointDecorations(lineNumber);
|
|
1417
|
-
updateGutter.call(this, lineNumber, decorations);
|
|
1418
|
-
if (this.possibleBreakpointsRequested.has(lineNumber)) {
|
|
1419
|
-
waitingForInlineDecorations = true;
|
|
1420
|
-
continue;
|
|
1421
|
-
}
|
|
1422
|
-
updateInlineDecorations.call(this, lineNumber, decorations);
|
|
1423
|
-
}
|
|
1424
|
-
if (!waitingForInlineDecorations) {
|
|
1425
|
-
this.breakpointDecorationsUpdatedForTest();
|
|
1426
|
-
}
|
|
1427
|
-
}
|
|
1428
|
-
|
|
1429
|
-
function updateGutter(this: DebuggerPlugin, editorLineNumber: number, decorations: BreakpointDecoration[]): void {
|
|
1430
|
-
this.textEditor.toggleLineClass(editorLineNumber, 'cm-breakpoint', false);
|
|
1431
|
-
this.textEditor.toggleLineClass(editorLineNumber, 'cm-breakpoint-disabled', false);
|
|
1432
|
-
this.textEditor.toggleLineClass(editorLineNumber, 'cm-breakpoint-unbound', false);
|
|
1433
|
-
this.textEditor.toggleLineClass(editorLineNumber, 'cm-breakpoint-conditional', false);
|
|
1434
|
-
this.textEditor.toggleLineClass(editorLineNumber, 'cm-breakpoint-logpoint', false);
|
|
1435
|
-
|
|
1436
|
-
if (decorations.length) {
|
|
1437
|
-
decorations.sort(BreakpointDecoration.mostSpecificFirst);
|
|
1438
|
-
const isDisabled = !decorations[0].enabled || this.muted;
|
|
1439
|
-
const isLogpoint = decorations[0].condition.includes(LogpointPrefix);
|
|
1440
|
-
const isUnbound = !decorations[0].bound;
|
|
1441
|
-
const isConditionalBreakpoint = Boolean(decorations[0].condition) && !isLogpoint;
|
|
1442
|
-
|
|
1443
|
-
this.textEditor.toggleLineClass(editorLineNumber, 'cm-breakpoint', true);
|
|
1444
|
-
this.textEditor.toggleLineClass(editorLineNumber, 'cm-breakpoint-disabled', isDisabled);
|
|
1445
|
-
this.textEditor.toggleLineClass(editorLineNumber, 'cm-breakpoint-unbound', isUnbound && !isDisabled);
|
|
1446
|
-
this.textEditor.toggleLineClass(editorLineNumber, 'cm-breakpoint-logpoint', isLogpoint);
|
|
1447
|
-
this.textEditor.toggleLineClass(editorLineNumber, 'cm-breakpoint-conditional', isConditionalBreakpoint);
|
|
1448
|
-
}
|
|
1215
|
+
private breakpointChange(event: Common.EventTarget.EventTargetEvent<Bindings.BreakpointManager.BreakpointLocation>):
|
|
1216
|
+
void {
|
|
1217
|
+
const {uiLocation} = event.data;
|
|
1218
|
+
if (uiLocation.uiSourceCode !== this.uiSourceCode || this.muted) {
|
|
1219
|
+
return;
|
|
1449
1220
|
}
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
this: DebuggerPlugin, editorLineNumber: number, decorations: BreakpointDecoration[]): void {
|
|
1453
|
-
const actualBookmarks = new Set<TextEditor.CodeMirrorTextEditor.TextEditorBookMark>(
|
|
1454
|
-
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
|
|
1455
|
-
// @ts-expect-error
|
|
1456
|
-
decorations.map(decoration => decoration.bookmark).filter(bookmark => Boolean(bookmark)));
|
|
1457
|
-
const lineEnd = this.textEditor.line(editorLineNumber).length;
|
|
1458
|
-
const bookmarks = this.textEditor.bookmarks(
|
|
1459
|
-
new TextUtils.TextRange.TextRange(editorLineNumber, 0, editorLineNumber, lineEnd),
|
|
1460
|
-
BreakpointDecoration.bookmarkSymbol);
|
|
1461
|
-
for (const bookmark of bookmarks) {
|
|
1462
|
-
if (!actualBookmarks.has(bookmark)) {
|
|
1463
|
-
bookmark.clear();
|
|
1464
|
-
}
|
|
1465
|
-
}
|
|
1466
|
-
if (!decorations.length) {
|
|
1221
|
+
for (const scriptFile of this.scriptFileForDebuggerModel.values()) {
|
|
1222
|
+
if (scriptFile.isDivergingFromVM() || scriptFile.isMergingToVM()) {
|
|
1467
1223
|
return;
|
|
1468
1224
|
}
|
|
1469
|
-
if (decorations.length > 1) {
|
|
1470
|
-
for (const decoration of decorations) {
|
|
1471
|
-
decoration.update();
|
|
1472
|
-
if (!this.muted) {
|
|
1473
|
-
decoration.show();
|
|
1474
|
-
} else {
|
|
1475
|
-
decoration.hide();
|
|
1476
|
-
}
|
|
1477
|
-
}
|
|
1478
|
-
} else {
|
|
1479
|
-
decorations[0].update();
|
|
1480
|
-
decorations[0].hide();
|
|
1481
|
-
}
|
|
1482
1225
|
}
|
|
1226
|
+
// These tend to arrive in bursts, so debounce them
|
|
1227
|
+
window.clearTimeout(this.refreshBreakpointsTimeout);
|
|
1228
|
+
this.refreshBreakpointsTimeout = window.setTimeout(() => this.refreshBreakpoints(), 50);
|
|
1483
1229
|
}
|
|
1484
1230
|
|
|
1485
|
-
|
|
1486
|
-
}
|
|
1487
|
-
|
|
1488
|
-
private async inlineBreakpointClick(decoration: BreakpointDecoration, event: MouseEvent): Promise<void> {
|
|
1231
|
+
onInlineBreakpointMarkerClick(event: MouseEvent, breakpoint: Bindings.BreakpointManager.Breakpoint|null): void {
|
|
1489
1232
|
event.consume(true);
|
|
1490
|
-
if (
|
|
1233
|
+
if (breakpoint) {
|
|
1491
1234
|
if (event.shiftKey) {
|
|
1492
|
-
|
|
1235
|
+
breakpoint.setEnabled(!breakpoint.enabled());
|
|
1493
1236
|
} else {
|
|
1494
|
-
|
|
1495
|
-
}
|
|
1496
|
-
} else {
|
|
1497
|
-
const editorLocation = decoration.handle.resolve();
|
|
1498
|
-
if (!editorLocation) {
|
|
1499
|
-
return;
|
|
1237
|
+
breakpoint.remove(false);
|
|
1500
1238
|
}
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1239
|
+
} else if (this.editor) {
|
|
1240
|
+
const editorLocation = this.editor.editor.posAtDOM(event.target as unknown as HTMLElement);
|
|
1241
|
+
const line = this.editor.state.doc.lineAt(editorLocation);
|
|
1242
|
+
const uiLocation = this.transformer.editorLocationToUILocation(line.number - 1, editorLocation - line.from);
|
|
1243
|
+
this.setBreakpoint(uiLocation.lineNumber, uiLocation.columnNumber, '', true);
|
|
1504
1244
|
}
|
|
1505
1245
|
}
|
|
1506
1246
|
|
|
1507
|
-
|
|
1247
|
+
onInlineBreakpointMarkerContextMenu(event: MouseEvent, breakpoint: Bindings.BreakpointManager.Breakpoint|null): void {
|
|
1508
1248
|
event.consume(true);
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
if (
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1249
|
+
// If there's events coming from the editor, there must be an editor.
|
|
1250
|
+
const editor = this.editor as TextEditor.TextEditor.TextEditor;
|
|
1251
|
+
const position = editor.editor.posAtDOM(event.target as unknown as HTMLElement);
|
|
1252
|
+
const line = editor.state.doc.lineAt(position);
|
|
1253
|
+
if (!SourceFrame.SourceFrame.isBreakableLine(editor.state, line) ||
|
|
1254
|
+
// Editing breakpoints only make sense for conditional breakpoints
|
|
1255
|
+
// and logpoints.
|
|
1256
|
+
!Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().supportsConditionalBreakpoints(
|
|
1517
1257
|
this.uiSourceCode)) {
|
|
1518
|
-
// Editing breakpoints only make sense for conditional breakpoints
|
|
1519
|
-
// and logpoints.
|
|
1520
1258
|
return;
|
|
1521
1259
|
}
|
|
1522
|
-
const location =
|
|
1523
|
-
this.transformer.editorLocationToUILocation(editorLocation.lineNumber, editorLocation.columnNumber);
|
|
1524
1260
|
const contextMenu = new UI.ContextMenu.ContextMenu(event);
|
|
1525
|
-
if (
|
|
1261
|
+
if (breakpoint) {
|
|
1526
1262
|
contextMenu.debugSection().appendItem(
|
|
1527
1263
|
i18nString(UIStrings.editBreakpoint),
|
|
1528
|
-
this.editBreakpointCondition.bind(
|
|
1529
|
-
this, editorLocation.lineNumber, decoration.breakpoint, null, false /* preferLogpoint */));
|
|
1264
|
+
this.editBreakpointCondition.bind(this, line, breakpoint, null, false /* preferLogpoint */));
|
|
1530
1265
|
} else {
|
|
1266
|
+
const uiLocation = this.transformer.editorLocationToUILocation(line.number - 1, position - line.from);
|
|
1531
1267
|
contextMenu.debugSection().appendItem(
|
|
1532
1268
|
i18nString(UIStrings.addConditionalBreakpoint),
|
|
1533
|
-
this.editBreakpointCondition.bind(
|
|
1534
|
-
this, editorLocation.lineNumber, null, editorLocation, false /* preferLogpoint */));
|
|
1269
|
+
this.editBreakpointCondition.bind(this, line, null, uiLocation, false /* preferLogpoint */));
|
|
1535
1270
|
contextMenu.debugSection().appendItem(
|
|
1536
1271
|
i18nString(UIStrings.addLogpoint),
|
|
1537
|
-
this.editBreakpointCondition.bind(
|
|
1538
|
-
|
|
1272
|
+
this.editBreakpointCondition.bind(this, line, null, uiLocation, true /* preferLogpoint */));
|
|
1273
|
+
|
|
1539
1274
|
contextMenu.debugSection().appendItem(
|
|
1540
1275
|
i18nString(UIStrings.neverPauseHere),
|
|
1541
|
-
this.setBreakpoint.bind(this,
|
|
1276
|
+
this.setBreakpoint.bind(this, uiLocation.lineNumber, uiLocation.columnNumber, 'false', true));
|
|
1542
1277
|
}
|
|
1543
1278
|
contextMenu.show();
|
|
1544
1279
|
}
|
|
1545
1280
|
|
|
1546
|
-
private shouldIgnoreExternalBreakpointEvents(
|
|
1547
|
-
event: Common.EventTarget.EventTargetEvent<Bindings.BreakpointManager.BreakpointLocation>): boolean {
|
|
1548
|
-
const {uiLocation} = event.data;
|
|
1549
|
-
if (uiLocation.uiSourceCode !== this.uiSourceCode) {
|
|
1550
|
-
return true;
|
|
1551
|
-
}
|
|
1552
|
-
if (this.muted) {
|
|
1553
|
-
return true;
|
|
1554
|
-
}
|
|
1555
|
-
for (const scriptFile of this.scriptFileForDebuggerModel.values()) {
|
|
1556
|
-
if (scriptFile.isDivergingFromVM() || scriptFile.isMergingToVM()) {
|
|
1557
|
-
return true;
|
|
1558
|
-
}
|
|
1559
|
-
}
|
|
1560
|
-
return false;
|
|
1561
|
-
}
|
|
1562
|
-
|
|
1563
|
-
private breakpointAdded(event: Common.EventTarget.EventTargetEvent<Bindings.BreakpointManager.BreakpointLocation>):
|
|
1564
|
-
void {
|
|
1565
|
-
if (this.shouldIgnoreExternalBreakpointEvents(event)) {
|
|
1566
|
-
return;
|
|
1567
|
-
}
|
|
1568
|
-
const {breakpoint, uiLocation} = event.data;
|
|
1569
|
-
this.addBreakpoint(uiLocation, breakpoint);
|
|
1570
|
-
}
|
|
1571
|
-
|
|
1572
|
-
private addBreakpoint(
|
|
1573
|
-
uiLocation: Workspace.UISourceCode.UILocation, breakpoint: Bindings.BreakpointManager.Breakpoint): void {
|
|
1574
|
-
const editorLocation = this.transformer.uiLocationToEditorLocation(uiLocation.lineNumber, uiLocation.columnNumber);
|
|
1575
|
-
const lineDecorations = this.lineBreakpointDecorations(uiLocation.lineNumber);
|
|
1576
|
-
let decoration = this.breakpointDecoration(editorLocation.lineNumber, editorLocation.columnNumber);
|
|
1577
|
-
if (decoration) {
|
|
1578
|
-
decoration.breakpoint = breakpoint;
|
|
1579
|
-
decoration.condition = breakpoint.condition();
|
|
1580
|
-
decoration.enabled = breakpoint.enabled();
|
|
1581
|
-
} else {
|
|
1582
|
-
const handle = this.textEditor.textEditorPositionHandle(editorLocation.lineNumber, editorLocation.columnNumber);
|
|
1583
|
-
decoration = new BreakpointDecoration(
|
|
1584
|
-
this.textEditor, handle, breakpoint.condition(), breakpoint.enabled(),
|
|
1585
|
-
breakpoint.bound() || !breakpoint.hasBoundScript(), breakpoint);
|
|
1586
|
-
decoration.element.addEventListener('click', this.inlineBreakpointClick.bind(this, decoration), true);
|
|
1587
|
-
decoration.element.addEventListener('contextmenu', this.inlineBreakpointContextMenu.bind(this, decoration), true);
|
|
1588
|
-
this.breakpointDecorations.add(decoration);
|
|
1589
|
-
}
|
|
1590
|
-
|
|
1591
|
-
let uiLocationsForBreakpoint = this.decorationByBreakpoint.get(breakpoint);
|
|
1592
|
-
if (!uiLocationsForBreakpoint) {
|
|
1593
|
-
uiLocationsForBreakpoint = new Map();
|
|
1594
|
-
this.decorationByBreakpoint.set(breakpoint, uiLocationsForBreakpoint);
|
|
1595
|
-
}
|
|
1596
|
-
uiLocationsForBreakpoint.set(uiLocation.id(), decoration);
|
|
1597
|
-
|
|
1598
|
-
this.updateBreakpointDecoration(decoration);
|
|
1599
|
-
if (breakpoint.enabled() && !lineDecorations.length) {
|
|
1600
|
-
this.possibleBreakpointsRequested.add(editorLocation.lineNumber);
|
|
1601
|
-
const start = this.transformer.editorLocationToUILocation(editorLocation.lineNumber, 0);
|
|
1602
|
-
const end = this.transformer.editorLocationToUILocation(editorLocation.lineNumber + 1, 0);
|
|
1603
|
-
this.breakpointManager
|
|
1604
|
-
.possibleBreakpoints(
|
|
1605
|
-
this.uiSourceCode,
|
|
1606
|
-
new TextUtils.TextRange.TextRange(
|
|
1607
|
-
start.lineNumber, start.columnNumber || 0, end.lineNumber, end.columnNumber || 0))
|
|
1608
|
-
.then(addInlineDecorations.bind(this, editorLocation.lineNumber));
|
|
1609
|
-
}
|
|
1610
|
-
|
|
1611
|
-
function addInlineDecorations(
|
|
1612
|
-
this: DebuggerPlugin, editorLineNumber: number, possibleLocations: Workspace.UISourceCode.UILocation[]): void {
|
|
1613
|
-
this.possibleBreakpointsRequested.delete(editorLineNumber);
|
|
1614
|
-
const decorations = this.lineBreakpointDecorations(editorLineNumber);
|
|
1615
|
-
for (const decoration of decorations) {
|
|
1616
|
-
this.updateBreakpointDecoration(decoration);
|
|
1617
|
-
}
|
|
1618
|
-
if (!decorations.some(decoration => Boolean(decoration.breakpoint))) {
|
|
1619
|
-
return;
|
|
1620
|
-
}
|
|
1621
|
-
const columns = new Set<number>();
|
|
1622
|
-
for (const decoration of decorations) {
|
|
1623
|
-
const editorLocation = decoration.handle.resolve();
|
|
1624
|
-
if (!editorLocation) {
|
|
1625
|
-
continue;
|
|
1626
|
-
}
|
|
1627
|
-
columns.add(editorLocation.columnNumber);
|
|
1628
|
-
}
|
|
1629
|
-
// Only consider the first 100 inline breakpoints, as DevTools might appear to hang while CodeMirror is updating
|
|
1630
|
-
// the inline breakpoints. See crbug.com/1060105.
|
|
1631
|
-
for (const location of possibleLocations.slice(0, 100)) {
|
|
1632
|
-
const editorLocation = this.transformer.uiLocationToEditorLocation(location.lineNumber, location.columnNumber);
|
|
1633
|
-
if (editorLocation.lineNumber !== editorLineNumber) {
|
|
1634
|
-
continue;
|
|
1635
|
-
}
|
|
1636
|
-
if (columns.has(editorLocation.columnNumber)) {
|
|
1637
|
-
continue;
|
|
1638
|
-
}
|
|
1639
|
-
const handle = this.textEditor.textEditorPositionHandle(editorLocation.lineNumber, editorLocation.columnNumber);
|
|
1640
|
-
const decoration = new BreakpointDecoration(
|
|
1641
|
-
this.textEditor, handle, '', /** enabled */ false, /** bound */ false, /** breakpoint */ null);
|
|
1642
|
-
decoration.element.addEventListener('click', this.inlineBreakpointClick.bind(this, decoration), true);
|
|
1643
|
-
decoration.element.addEventListener(
|
|
1644
|
-
'contextmenu', this.inlineBreakpointContextMenu.bind(this, decoration), true);
|
|
1645
|
-
this.breakpointDecorations.add(decoration);
|
|
1646
|
-
this.updateBreakpointDecoration(decoration);
|
|
1647
|
-
}
|
|
1648
|
-
}
|
|
1649
|
-
}
|
|
1650
|
-
|
|
1651
|
-
private breakpointRemoved(event: Common.EventTarget.EventTargetEvent<Bindings.BreakpointManager.BreakpointLocation>):
|
|
1652
|
-
void {
|
|
1653
|
-
if (this.shouldIgnoreExternalBreakpointEvents(event)) {
|
|
1654
|
-
return;
|
|
1655
|
-
}
|
|
1656
|
-
const {breakpoint, uiLocation} = event.data;
|
|
1657
|
-
|
|
1658
|
-
const uiLocationsForBreakpoint = this.decorationByBreakpoint.get(breakpoint);
|
|
1659
|
-
if (!uiLocationsForBreakpoint) {
|
|
1660
|
-
return;
|
|
1661
|
-
}
|
|
1662
|
-
|
|
1663
|
-
const decoration = uiLocationsForBreakpoint.get(uiLocation.id());
|
|
1664
|
-
uiLocationsForBreakpoint.delete(uiLocation.id());
|
|
1665
|
-
|
|
1666
|
-
if (uiLocationsForBreakpoint.size === 0) {
|
|
1667
|
-
this.decorationByBreakpoint.delete(breakpoint);
|
|
1668
|
-
}
|
|
1669
|
-
|
|
1670
|
-
if (!decoration) {
|
|
1671
|
-
return;
|
|
1672
|
-
}
|
|
1673
|
-
|
|
1674
|
-
const editorLocation = this.transformer.uiLocationToEditorLocation(uiLocation.lineNumber, uiLocation.columnNumber);
|
|
1675
|
-
decoration.breakpoint = null;
|
|
1676
|
-
decoration.enabled = false;
|
|
1677
|
-
|
|
1678
|
-
const lineDecorations = this.lineBreakpointDecorations(editorLocation.lineNumber);
|
|
1679
|
-
if (!lineDecorations.some(decoration => Boolean(decoration.breakpoint))) {
|
|
1680
|
-
for (const lineDecoration of lineDecorations) {
|
|
1681
|
-
this.breakpointDecorations.delete(lineDecoration);
|
|
1682
|
-
this.updateBreakpointDecoration(lineDecoration);
|
|
1683
|
-
}
|
|
1684
|
-
} else {
|
|
1685
|
-
this.updateBreakpointDecoration(decoration);
|
|
1686
|
-
}
|
|
1687
|
-
}
|
|
1688
|
-
|
|
1689
|
-
private initializeBreakpoints(): void {
|
|
1690
|
-
const breakpointLocations = this.breakpointManager.breakpointLocationsForUISourceCode(this.uiSourceCode);
|
|
1691
|
-
for (const breakpointLocation of breakpointLocations) {
|
|
1692
|
-
this.addBreakpoint(breakpointLocation.uiLocation, breakpointLocation.breakpoint);
|
|
1693
|
-
}
|
|
1694
|
-
}
|
|
1695
|
-
|
|
1696
|
-
private updateLinesWithoutMappingHighlight(): void {
|
|
1697
|
-
if (Bindings.CompilerScriptMapping.CompilerScriptMapping.uiSourceCodeOrigin(this.uiSourceCode).length) {
|
|
1698
|
-
const linesCount = this.textEditor.linesCount;
|
|
1699
|
-
for (let i = 0; i < linesCount; ++i) {
|
|
1700
|
-
const lineHasMapping =
|
|
1701
|
-
Bindings.CompilerScriptMapping.CompilerScriptMapping.uiLineHasMapping(this.uiSourceCode, i);
|
|
1702
|
-
if (!lineHasMapping) {
|
|
1703
|
-
this.hasLineWithoutMapping = true;
|
|
1704
|
-
}
|
|
1705
|
-
if (this.hasLineWithoutMapping) {
|
|
1706
|
-
this.textEditor.toggleLineClass(i, 'cm-non-breakable-line', !lineHasMapping);
|
|
1707
|
-
}
|
|
1708
|
-
}
|
|
1709
|
-
return;
|
|
1710
|
-
}
|
|
1711
|
-
|
|
1712
|
-
const {pluginManager} = Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance();
|
|
1713
|
-
if (pluginManager) {
|
|
1714
|
-
pluginManager.getMappedLines(this.uiSourceCode)
|
|
1715
|
-
.then(mappedLines => {
|
|
1716
|
-
if (mappedLines === undefined) {
|
|
1717
|
-
return;
|
|
1718
|
-
}
|
|
1719
|
-
const linesCount = this.textEditor.linesCount;
|
|
1720
|
-
for (let i = 0; i < linesCount; ++i) {
|
|
1721
|
-
const lineHasMapping = mappedLines.has(i);
|
|
1722
|
-
if (!lineHasMapping) {
|
|
1723
|
-
this.hasLineWithoutMapping = true;
|
|
1724
|
-
}
|
|
1725
|
-
if (this.hasLineWithoutMapping) {
|
|
1726
|
-
this.textEditor.toggleLineClass(i, 'cm-non-breakable-line', !lineHasMapping);
|
|
1727
|
-
}
|
|
1728
|
-
}
|
|
1729
|
-
})
|
|
1730
|
-
.catch(console.error);
|
|
1731
|
-
}
|
|
1732
|
-
}
|
|
1733
|
-
|
|
1734
1281
|
private updateScriptFiles(): void {
|
|
1735
1282
|
for (const debuggerModel of SDK.TargetManager.TargetManager.instance().models(SDK.DebuggerModel.DebuggerModel)) {
|
|
1736
1283
|
const scriptFile = Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().scriptFile(
|
|
@@ -1751,8 +1298,8 @@ export class DebuggerPlugin extends Plugin {
|
|
|
1751
1298
|
Bindings.ResourceScriptMapping.ResourceScriptFile.Events.DidMergeToVM, this.didMergeToVM, this);
|
|
1752
1299
|
oldScriptFile.removeEventListener(
|
|
1753
1300
|
Bindings.ResourceScriptMapping.ResourceScriptFile.Events.DidDivergeFromVM, this.didDivergeFromVM, this);
|
|
1754
|
-
if (this.muted && !this.uiSourceCode.isDirty()) {
|
|
1755
|
-
this.
|
|
1301
|
+
if (this.muted && !this.uiSourceCode.isDirty() && this.consistentScripts) {
|
|
1302
|
+
this.setMuted(false);
|
|
1756
1303
|
}
|
|
1757
1304
|
}
|
|
1758
1305
|
if (!newScriptFile) {
|
|
@@ -1784,9 +1331,10 @@ export class DebuggerPlugin extends Plugin {
|
|
|
1784
1331
|
PH1: String(UI.ShortcutRegistry.ShortcutRegistry.instance().shortcutTitleForAction('quickOpen.show')),
|
|
1785
1332
|
}));
|
|
1786
1333
|
this.sourceMapInfobar.setCloseCallback(() => {
|
|
1334
|
+
this.removeInfobar(this.sourceMapInfobar);
|
|
1787
1335
|
this.sourceMapInfobar = null;
|
|
1788
1336
|
});
|
|
1789
|
-
this.
|
|
1337
|
+
this.attachInfobar(this.sourceMapInfobar);
|
|
1790
1338
|
}
|
|
1791
1339
|
|
|
1792
1340
|
private async detectMinified(): Promise<void> {
|
|
@@ -1817,12 +1365,13 @@ export class DebuggerPlugin extends Plugin {
|
|
|
1817
1365
|
}
|
|
1818
1366
|
|
|
1819
1367
|
this.prettyPrintInfobar.setCloseCallback(() => {
|
|
1368
|
+
this.removeInfobar(this.prettyPrintInfobar);
|
|
1820
1369
|
this.prettyPrintInfobar = null;
|
|
1821
1370
|
});
|
|
1822
1371
|
const toolbar = new UI.Toolbar.Toolbar('');
|
|
1823
1372
|
const button = new UI.Toolbar.ToolbarButton('', 'largeicon-pretty-print');
|
|
1824
1373
|
toolbar.appendToolbarItem(button);
|
|
1825
|
-
toolbar.element.style.display = 'inline
|
|
1374
|
+
toolbar.element.style.display = 'inline';
|
|
1826
1375
|
toolbar.element.style.verticalAlign = 'middle';
|
|
1827
1376
|
toolbar.element.style.marginBottom = '3px';
|
|
1828
1377
|
toolbar.element.style.pointerEvents = 'none';
|
|
@@ -1831,38 +1380,27 @@ export class DebuggerPlugin extends Plugin {
|
|
|
1831
1380
|
element.appendChild(
|
|
1832
1381
|
i18n.i18n.getFormatLocalizedString(str_, UIStrings.prettyprintingWillFormatThisFile, {PH1: toolbar.element}));
|
|
1833
1382
|
UI.ARIAUtils.markAsAlert(element);
|
|
1834
|
-
this.
|
|
1383
|
+
this.attachInfobar(this.prettyPrintInfobar);
|
|
1835
1384
|
}
|
|
1836
1385
|
|
|
1837
|
-
private
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
return;
|
|
1841
|
-
}
|
|
1842
|
-
|
|
1843
|
-
const {gutterType, lineNumber: editorLineNumber, event: eventObject} = event.data;
|
|
1844
|
-
if (gutterType !== SourceFrame.SourcesTextEditor.lineNumbersGutterType) {
|
|
1845
|
-
return;
|
|
1386
|
+
private handleGutterClick(line: CodeMirror.Line, event: MouseEvent): boolean {
|
|
1387
|
+
if (this.muted || event.button !== 0 || event.altKey || event.ctrlKey || event.metaKey) {
|
|
1388
|
+
return false;
|
|
1846
1389
|
}
|
|
1390
|
+
this.toggleBreakpoint(line, event.shiftKey);
|
|
1391
|
+
return true;
|
|
1392
|
+
}
|
|
1847
1393
|
|
|
1848
|
-
|
|
1394
|
+
private async toggleBreakpoint(line: CodeMirror.Line, onlyDisable: boolean): Promise<void> {
|
|
1395
|
+
if (this.muted) {
|
|
1849
1396
|
return;
|
|
1850
1397
|
}
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
}
|
|
1855
|
-
|
|
1856
|
-
private async toggleBreakpoint(editorLineNumber: number, onlyDisable: boolean): Promise<void> {
|
|
1857
|
-
const decorations = this.lineBreakpointDecorations(editorLineNumber);
|
|
1858
|
-
if (!decorations.length) {
|
|
1859
|
-
await this.createNewBreakpoint(editorLineNumber, '', true);
|
|
1398
|
+
const breakpoints = this.lineBreakpoints(line);
|
|
1399
|
+
if (!breakpoints.length) {
|
|
1400
|
+
await this.createNewBreakpoint(line, '', true);
|
|
1860
1401
|
return;
|
|
1861
1402
|
}
|
|
1862
|
-
const hasDisabled =
|
|
1863
|
-
const breakpoints =
|
|
1864
|
-
(decorations.map(decoration => decoration.breakpoint).filter(breakpoint => Boolean(breakpoint)) as
|
|
1865
|
-
Bindings.BreakpointManager.Breakpoint[]);
|
|
1403
|
+
const hasDisabled = breakpoints.some(b => !b.enabled());
|
|
1866
1404
|
for (const breakpoint of breakpoints) {
|
|
1867
1405
|
if (onlyDisable) {
|
|
1868
1406
|
breakpoint.setEnabled(hasDisabled);
|
|
@@ -1872,12 +1410,12 @@ export class DebuggerPlugin extends Plugin {
|
|
|
1872
1410
|
}
|
|
1873
1411
|
}
|
|
1874
1412
|
|
|
1875
|
-
private async createNewBreakpoint(
|
|
1876
|
-
if (this.
|
|
1413
|
+
private async createNewBreakpoint(line: CodeMirror.Line, condition: string, enabled: boolean): Promise<void> {
|
|
1414
|
+
if (!this.editor || !SourceFrame.SourceFrame.isBreakableLine(this.editor.state, line)) {
|
|
1877
1415
|
return;
|
|
1878
1416
|
}
|
|
1879
1417
|
Host.userMetrics.actionTaken(Host.UserMetrics.Action.ScriptsBreakpointSet);
|
|
1880
|
-
const origin = this.transformer.editorLocationToUILocation(
|
|
1418
|
+
const origin = this.transformer.editorLocationToUILocation(line.number - 1);
|
|
1881
1419
|
await this.setBreakpoint(origin.lineNumber, origin.columnNumber, condition, enabled);
|
|
1882
1420
|
}
|
|
1883
1421
|
|
|
@@ -1896,25 +1434,48 @@ export class DebuggerPlugin extends Plugin {
|
|
|
1896
1434
|
this.liveLocationPool.disposeAll();
|
|
1897
1435
|
const callFrame = UI.Context.Context.instance().flavor(SDK.DebuggerModel.CallFrame);
|
|
1898
1436
|
if (!callFrame) {
|
|
1899
|
-
this.
|
|
1900
|
-
|
|
1437
|
+
this.setExecutionLocation(null);
|
|
1438
|
+
} else {
|
|
1439
|
+
await Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().createCallFrameLiveLocation(
|
|
1440
|
+
callFrame.location(), async(liveLocation: Bindings.LiveLocation.LiveLocation): Promise<void> => {
|
|
1441
|
+
const uiLocation = await liveLocation.uiLocation();
|
|
1442
|
+
if (uiLocation && uiLocation.uiSourceCode.url() === this.uiSourceCode.url()) {
|
|
1443
|
+
this.setExecutionLocation(uiLocation);
|
|
1444
|
+
} else {
|
|
1445
|
+
this.setExecutionLocation(null);
|
|
1446
|
+
}
|
|
1447
|
+
}, this.liveLocationPool);
|
|
1901
1448
|
}
|
|
1902
|
-
await Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().createCallFrameLiveLocation(
|
|
1903
|
-
callFrame.location(), this.executionLineChanged.bind(this), this.liveLocationPool);
|
|
1904
1449
|
}
|
|
1905
1450
|
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1451
|
+
private setExecutionLocation(executionLocation: Workspace.UISourceCode.UILocation|null): void {
|
|
1452
|
+
if (this.executionLocation === executionLocation || !this.editor) {
|
|
1453
|
+
return;
|
|
1909
1454
|
}
|
|
1910
|
-
this.
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1455
|
+
this.executionLocation = executionLocation;
|
|
1456
|
+
|
|
1457
|
+
if (executionLocation) {
|
|
1458
|
+
const editorLocation =
|
|
1459
|
+
this.transformer.uiLocationToEditorLocation(executionLocation.lineNumber, executionLocation.columnNumber);
|
|
1460
|
+
const decorations =
|
|
1461
|
+
this.computeExecutionDecorations(this.editor.state, editorLocation.lineNumber, editorLocation.columnNumber);
|
|
1462
|
+
this.editor.dispatch({effects: executionLine.update.of(decorations)});
|
|
1463
|
+
this.updateValueDecorations();
|
|
1464
|
+
if (this.controlDown) {
|
|
1465
|
+
this.showContinueToLocations();
|
|
1914
1466
|
}
|
|
1915
|
-
|
|
1467
|
+
} else {
|
|
1468
|
+
this.editor.dispatch({
|
|
1469
|
+
effects: [
|
|
1470
|
+
executionLine.update.of(CodeMirror.Decoration.none),
|
|
1471
|
+
continueToMarkers.update.of(CodeMirror.Decoration.none),
|
|
1472
|
+
valueDecorations.update.of(CodeMirror.Decoration.none),
|
|
1473
|
+
],
|
|
1474
|
+
});
|
|
1916
1475
|
}
|
|
1476
|
+
}
|
|
1917
1477
|
|
|
1478
|
+
dispose(): void {
|
|
1918
1479
|
this.hideIgnoreListInfobar();
|
|
1919
1480
|
if (this.sourceMapInfobar) {
|
|
1920
1481
|
this.sourceMapInfobar.dispose();
|
|
@@ -1922,7 +1483,6 @@ export class DebuggerPlugin extends Plugin {
|
|
|
1922
1483
|
if (this.prettyPrintInfobar) {
|
|
1923
1484
|
this.prettyPrintInfobar.dispose();
|
|
1924
1485
|
}
|
|
1925
|
-
this.scriptsPanel.element.removeEventListener('scroll', this.boundPopoverHelperHide, true);
|
|
1926
1486
|
for (const script of this.scriptFileForDebuggerModel.values()) {
|
|
1927
1487
|
script.removeEventListener(
|
|
1928
1488
|
Bindings.ResourceScriptMapping.ResourceScriptFile.Events.DidMergeToVM, this.didMergeToVM, this);
|
|
@@ -1931,21 +1491,13 @@ export class DebuggerPlugin extends Plugin {
|
|
|
1931
1491
|
}
|
|
1932
1492
|
this.scriptFileForDebuggerModel.clear();
|
|
1933
1493
|
|
|
1934
|
-
this.textEditor.element.removeEventListener('keydown', this.boundKeyDown, true);
|
|
1935
|
-
this.textEditor.element.removeEventListener('keyup', this.boundKeyUp, true);
|
|
1936
|
-
this.textEditor.element.removeEventListener('mousemove', this.boundMouseMove, false);
|
|
1937
|
-
this.textEditor.element.removeEventListener('mousedown', this.boundMouseDown, true);
|
|
1938
|
-
this.textEditor.element.removeEventListener('focusout', this.boundBlur, false);
|
|
1939
|
-
this.textEditor.element.removeEventListener('wheel', this.boundWheel, true);
|
|
1940
|
-
|
|
1941
|
-
this.textEditor.removeEventListener(SourceFrame.SourcesTextEditor.Events.GutterClick, this.boundGutterClick, this);
|
|
1942
1494
|
this.popoverHelper.hidePopover();
|
|
1943
1495
|
this.popoverHelper.dispose();
|
|
1944
1496
|
|
|
1945
1497
|
this.breakpointManager.removeEventListener(
|
|
1946
|
-
Bindings.BreakpointManager.Events.BreakpointAdded, this.
|
|
1498
|
+
Bindings.BreakpointManager.Events.BreakpointAdded, this.breakpointChange, this);
|
|
1947
1499
|
this.breakpointManager.removeEventListener(
|
|
1948
|
-
Bindings.BreakpointManager.Events.BreakpointRemoved, this.
|
|
1500
|
+
Bindings.BreakpointManager.Events.BreakpointRemoved, this.breakpointChange, this);
|
|
1949
1501
|
this.uiSourceCode.removeEventListener(
|
|
1950
1502
|
Workspace.UISourceCode.Events.WorkingCopyChanged, this.workingCopyChanged, this);
|
|
1951
1503
|
this.uiSourceCode.removeEventListener(
|
|
@@ -1959,98 +1511,469 @@ export class DebuggerPlugin extends Plugin {
|
|
|
1959
1511
|
.removeChangeListener(this.showIgnoreListInfobarIfNeeded, this);
|
|
1960
1512
|
super.dispose();
|
|
1961
1513
|
|
|
1962
|
-
this.clearExecutionLine();
|
|
1963
1514
|
UI.Context.Context.instance().removeFlavorChangeListener(SDK.DebuggerModel.CallFrame, this.callFrameChanged, this);
|
|
1964
1515
|
this.liveLocationPool.disposeAll();
|
|
1965
1516
|
}
|
|
1966
1517
|
}
|
|
1967
1518
|
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1519
|
+
// Infobar panel state
|
|
1520
|
+
|
|
1521
|
+
const addInfobar = CodeMirror.StateEffect.define<UI.Infobar.Infobar>();
|
|
1522
|
+
const removeInfobar = CodeMirror.StateEffect.define<UI.Infobar.Infobar>();
|
|
1523
|
+
|
|
1524
|
+
const infobarState = CodeMirror.StateField.define<UI.Infobar.Infobar[]>({
|
|
1525
|
+
create(): UI.Infobar.Infobar[] {
|
|
1526
|
+
return [];
|
|
1527
|
+
},
|
|
1528
|
+
update(current, tr): UI.Infobar.Infobar[] {
|
|
1529
|
+
for (const effect of tr.effects) {
|
|
1530
|
+
if (effect.is(addInfobar)) {
|
|
1531
|
+
current = current.concat(effect.value);
|
|
1532
|
+
} else if (effect.is(removeInfobar)) {
|
|
1533
|
+
current = current.filter(b => b !== effect.value);
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
return current;
|
|
1537
|
+
},
|
|
1538
|
+
provide: (field): CodeMirror.Extension => CodeMirror.showPanel.computeN(
|
|
1539
|
+
[field],
|
|
1540
|
+
(state): (() => CodeMirror.Panel)[] =>
|
|
1541
|
+
state.field(field).map((bar): (() => CodeMirror.Panel) => (): CodeMirror.Panel => ({dom: bar.element}))),
|
|
1542
|
+
});
|
|
1543
|
+
|
|
1544
|
+
// Enumerate non-breakable lines (lines without a known corresponding
|
|
1545
|
+
// position in the UISource).
|
|
1546
|
+
async function computeNonBreakableLines(
|
|
1547
|
+
state: CodeMirror.EditorState, sourceCode: Workspace.UISourceCode.UISourceCode): Promise<readonly number[]> {
|
|
1548
|
+
const linePositions = [];
|
|
1549
|
+
if (Bindings.CompilerScriptMapping.CompilerScriptMapping.uiSourceCodeOrigin(sourceCode).length) {
|
|
1550
|
+
for (let i = 0; i < state.doc.lines; i++) {
|
|
1551
|
+
const lineHasMapping = Bindings.CompilerScriptMapping.CompilerScriptMapping.uiLineHasMapping(sourceCode, i);
|
|
1552
|
+
if (!lineHasMapping) {
|
|
1553
|
+
linePositions.push(state.doc.line(i + 1).from);
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
} else {
|
|
1557
|
+
const {pluginManager} = Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance();
|
|
1558
|
+
if (!pluginManager) {
|
|
1559
|
+
return [];
|
|
1560
|
+
}
|
|
1561
|
+
const mappedLines = await pluginManager.getMappedLines(sourceCode);
|
|
1562
|
+
if (!mappedLines) {
|
|
1563
|
+
return [];
|
|
1564
|
+
}
|
|
1565
|
+
for (let i = 0; i < state.doc.lines; i++) {
|
|
1566
|
+
if (!mappedLines.has(i)) {
|
|
1567
|
+
linePositions.push(state.doc.line(i + 1).from);
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1991
1570
|
}
|
|
1571
|
+
return linePositions;
|
|
1572
|
+
}
|
|
1992
1573
|
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1574
|
+
// Breakpoint markers
|
|
1575
|
+
|
|
1576
|
+
type BreakpointDecoration = {
|
|
1577
|
+
content: CodeMirror.DecorationSet,
|
|
1578
|
+
gutter: CodeMirror.RangeSet<CodeMirror.GutterMarker>,
|
|
1579
|
+
};
|
|
1580
|
+
|
|
1581
|
+
const setBreakpointDeco = CodeMirror.StateEffect.define<BreakpointDecoration>();
|
|
1582
|
+
const muteBreakpoints = CodeMirror.StateEffect.define<null>();
|
|
1583
|
+
|
|
1584
|
+
function muteGutterMarkers(markers: CodeMirror.RangeSet<CodeMirror.GutterMarker>, doc: CodeMirror.Text):
|
|
1585
|
+
CodeMirror.RangeSet<CodeMirror.GutterMarker> {
|
|
1586
|
+
const newMarkers: CodeMirror.Range<CodeMirror.GutterMarker>[] = [];
|
|
1587
|
+
markers.between(0, doc.length, (from, _to, marker) => {
|
|
1588
|
+
let className: string = marker.elementClass;
|
|
1589
|
+
if (!/cm-breakpoint-disabled/.test(className)) {
|
|
1590
|
+
className += ' cm-breakpoint-disabled';
|
|
1996
1591
|
}
|
|
1997
|
-
|
|
1998
|
-
|
|
1592
|
+
newMarkers.push(new BreakpointGutterMarker(className).range(from));
|
|
1593
|
+
});
|
|
1594
|
+
return CodeMirror.RangeSet.of(newMarkers, false);
|
|
1595
|
+
}
|
|
1596
|
+
|
|
1597
|
+
// Holds the inline breakpoint marker decorations and the gutter
|
|
1598
|
+
// markers for lines with breakpoints. When the set of active markers
|
|
1599
|
+
// changes in non-muted state (the editor content matches the original
|
|
1600
|
+
// file), it is recomputed and updated with `setBreakpointDeco`. When
|
|
1601
|
+
// the editor content goes out of sync with the original file, the
|
|
1602
|
+
// `muteBreakpoints` effect hides the inline markers and makes sure
|
|
1603
|
+
// all gutter markers are displayed as disabled.
|
|
1604
|
+
const breakpointMarkers = CodeMirror.StateField.define<BreakpointDecoration>({
|
|
1605
|
+
create(): BreakpointDecoration {
|
|
1606
|
+
return {content: CodeMirror.RangeSet.empty, gutter: CodeMirror.RangeSet.empty};
|
|
1607
|
+
},
|
|
1608
|
+
update(deco, tr): BreakpointDecoration {
|
|
1609
|
+
if (!tr.changes.empty) {
|
|
1610
|
+
deco = {content: deco.content.map(tr.changes), gutter: deco.gutter.map(tr.changes)};
|
|
1611
|
+
}
|
|
1612
|
+
for (const effect of tr.effects) {
|
|
1613
|
+
if (effect.is(setBreakpointDeco)) {
|
|
1614
|
+
deco = effect.value;
|
|
1615
|
+
} else if (effect.is(muteBreakpoints)) {
|
|
1616
|
+
deco = {content: CodeMirror.RangeSet.empty, gutter: muteGutterMarkers(deco.gutter, tr.state.doc)};
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
return deco;
|
|
1620
|
+
},
|
|
1621
|
+
provide: field =>
|
|
1622
|
+
[CodeMirror.EditorView.decorations.from(field, deco => deco.content),
|
|
1623
|
+
CodeMirror.lineNumberMarkers.from(field, deco => deco.gutter)],
|
|
1624
|
+
});
|
|
1625
|
+
|
|
1626
|
+
class BreakpointInlineMarker extends CodeMirror.WidgetType {
|
|
1627
|
+
class: string;
|
|
1628
|
+
|
|
1629
|
+
constructor(readonly breakpoint: Bindings.BreakpointManager.Breakpoint|null, readonly parent: DebuggerPlugin) {
|
|
1630
|
+
super();
|
|
1631
|
+
// Eagerly compute DOM class so that the widget is recreated when it changes.
|
|
1632
|
+
this.class = 'cm-inlineBreakpoint';
|
|
1633
|
+
const condition = breakpoint ? breakpoint.condition() : '';
|
|
1634
|
+
if (condition.includes(LogpointPrefix)) {
|
|
1635
|
+
this.class += ' cm-inlineBreakpoint-logpoint';
|
|
1636
|
+
} else if (condition) {
|
|
1637
|
+
this.class += ' cm-inlineBreakpoint-conditional';
|
|
1999
1638
|
}
|
|
2000
|
-
if (
|
|
2001
|
-
|
|
1639
|
+
if (!breakpoint?.enabled()) {
|
|
1640
|
+
this.class += ' cm-inlineBreakpoint-disabled';
|
|
2002
1641
|
}
|
|
2003
|
-
return 0;
|
|
2004
1642
|
}
|
|
2005
1643
|
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
const isConditionalBreakpoint = Boolean(this.condition) && !isLogpoint;
|
|
2009
|
-
this.element.classList.toggle('cm-inline-logpoint', isLogpoint);
|
|
2010
|
-
this.element.classList.toggle('cm-inline-breakpoint-conditional', isConditionalBreakpoint);
|
|
2011
|
-
this.element.classList.toggle('cm-inline-disabled', !this.enabled);
|
|
1644
|
+
eq(other: BreakpointInlineMarker): boolean {
|
|
1645
|
+
return other.class === this.class && other.breakpoint === this.breakpoint;
|
|
2012
1646
|
}
|
|
2013
1647
|
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
1648
|
+
toDOM(): HTMLElement {
|
|
1649
|
+
const span = document.createElement('span');
|
|
1650
|
+
span.className = this.class;
|
|
1651
|
+
span.addEventListener('click', (event: MouseEvent) => {
|
|
1652
|
+
this.parent.onInlineBreakpointMarkerClick(event, this.breakpoint);
|
|
1653
|
+
event.consume();
|
|
1654
|
+
});
|
|
1655
|
+
span.addEventListener('contextmenu', (event: MouseEvent) => {
|
|
1656
|
+
this.parent.onInlineBreakpointMarkerContextMenu(event, this.breakpoint);
|
|
1657
|
+
event.consume();
|
|
1658
|
+
});
|
|
1659
|
+
return span;
|
|
2026
1660
|
}
|
|
2027
1661
|
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
return;
|
|
2031
|
-
}
|
|
2032
|
-
this.bookmark.clear();
|
|
2033
|
-
this.bookmark = null;
|
|
1662
|
+
ignoreEvent(): boolean {
|
|
1663
|
+
return true;
|
|
2034
1664
|
}
|
|
1665
|
+
}
|
|
2035
1666
|
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
1667
|
+
class BreakpointGutterMarker extends CodeMirror.GutterMarker {
|
|
1668
|
+
constructor(readonly elementClass: string) {
|
|
1669
|
+
super();
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
eq(other: BreakpointGutterMarker): boolean {
|
|
1673
|
+
return other.elementClass === this.elementClass;
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1677
|
+
function mostSpecificBreakpoint(
|
|
1678
|
+
a: Bindings.BreakpointManager.Breakpoint, b: Bindings.BreakpointManager.Breakpoint): number {
|
|
1679
|
+
if (a.enabled() !== b.enabled()) {
|
|
1680
|
+
return a.enabled() ? -1 : 1;
|
|
1681
|
+
}
|
|
1682
|
+
if (a.bound() !== b.bound()) {
|
|
1683
|
+
return a.bound() ? -1 : 1;
|
|
1684
|
+
}
|
|
1685
|
+
if (Boolean(a.condition()) !== Boolean(b.condition())) {
|
|
1686
|
+
return Boolean(a.condition()) ? -1 : 1;
|
|
1687
|
+
}
|
|
1688
|
+
return 0;
|
|
1689
|
+
}
|
|
1690
|
+
|
|
1691
|
+
// Generic helper for creating pairs of editor state fields and
|
|
1692
|
+
// effects to model imperatively updated decorations.
|
|
1693
|
+
|
|
1694
|
+
function defineStatefulDecoration(): {
|
|
1695
|
+
update: CodeMirror.StateEffectType<CodeMirror.DecorationSet>,
|
|
1696
|
+
field: CodeMirror.StateField<CodeMirror.DecorationSet>,
|
|
1697
|
+
} {
|
|
1698
|
+
const update = CodeMirror.StateEffect.define<CodeMirror.DecorationSet>();
|
|
1699
|
+
const field = CodeMirror.StateField.define<CodeMirror.DecorationSet>({
|
|
1700
|
+
create(): CodeMirror.DecorationSet {
|
|
1701
|
+
return CodeMirror.Decoration.none;
|
|
1702
|
+
},
|
|
1703
|
+
update(deco, tr): CodeMirror.DecorationSet {
|
|
1704
|
+
return tr.effects.reduce((deco, effect) => effect.is(update) ? effect.value : deco, deco.map(tr.changes));
|
|
1705
|
+
},
|
|
1706
|
+
provide: field => CodeMirror.EditorView.decorations.from(field),
|
|
1707
|
+
});
|
|
1708
|
+
return {update, field};
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
// Execution line highlight
|
|
1712
|
+
|
|
1713
|
+
const executionLineDeco = CodeMirror.Decoration.line({attributes: {class: 'cm-executionLine'}});
|
|
1714
|
+
const executionTokenDeco = CodeMirror.Decoration.mark({attributes: {class: 'cm-executionToken'}});
|
|
1715
|
+
const executionLine = defineStatefulDecoration();
|
|
1716
|
+
|
|
1717
|
+
// Continue-to markers
|
|
1718
|
+
|
|
1719
|
+
const continueToMark = CodeMirror.Decoration.mark({class: 'cm-continueToLocation'});
|
|
1720
|
+
const asyncContinueToMark = CodeMirror.Decoration.mark({class: 'cm-continueToLocation cm-continueToLocation-async'});
|
|
1721
|
+
|
|
1722
|
+
const continueToMarkers = defineStatefulDecoration();
|
|
1723
|
+
|
|
1724
|
+
const noMarkers = {}, hasContinueMarkers = {
|
|
1725
|
+
class: 'cm-hasContinueMarkers',
|
|
1726
|
+
};
|
|
1727
|
+
|
|
1728
|
+
// Add a class to the content element when there are active
|
|
1729
|
+
// continue-to markers. This hides the background on the current
|
|
1730
|
+
// execution line.
|
|
1731
|
+
const markIfContinueTo =
|
|
1732
|
+
CodeMirror.EditorView.contentAttributes.compute([continueToMarkers.field], (state): Record<string, string> => {
|
|
1733
|
+
return state.field(continueToMarkers.field).size ? hasContinueMarkers : noMarkers;
|
|
1734
|
+
});
|
|
1735
|
+
|
|
1736
|
+
// Variable value decorations
|
|
1737
|
+
|
|
1738
|
+
class ValueDecoration extends CodeMirror.WidgetType {
|
|
1739
|
+
constructor(readonly pairs: [string, SDK.RemoteObject.RemoteObject][]) {
|
|
1740
|
+
super();
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
eq(other: ValueDecoration): boolean {
|
|
1744
|
+
return this.pairs.length === other.pairs.length &&
|
|
1745
|
+
this.pairs.every((p, i) => p[0] === other.pairs[i][0] && p[1] === other.pairs[i][1]);
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
toDOM(): HTMLElement {
|
|
1749
|
+
const formatter = new ObjectUI.RemoteObjectPreviewFormatter.RemoteObjectPreviewFormatter();
|
|
1750
|
+
const widget = document.createElement('div');
|
|
1751
|
+
widget.classList.add('cm-variableValues');
|
|
1752
|
+
let first = true;
|
|
1753
|
+
for (const [name, value] of this.pairs) {
|
|
1754
|
+
if (first) {
|
|
1755
|
+
first = false;
|
|
1756
|
+
} else {
|
|
1757
|
+
UI.UIUtils.createTextChild(widget, ', ');
|
|
1758
|
+
}
|
|
1759
|
+
const nameValuePair = (widget.createChild('span') as HTMLElement);
|
|
1760
|
+
UI.UIUtils.createTextChild(nameValuePair, name + ' = ');
|
|
1761
|
+
const propertyCount = value.preview ? value.preview.properties.length : 0;
|
|
1762
|
+
const entryCount = value.preview && value.preview.entries ? value.preview.entries.length : 0;
|
|
1763
|
+
if (value.preview && propertyCount + entryCount < 10) {
|
|
1764
|
+
formatter.appendObjectPreview(nameValuePair, value.preview, false /* isEntry */);
|
|
1765
|
+
} else {
|
|
1766
|
+
const propertyValue = ObjectUI.ObjectPropertiesSection.ObjectPropertiesSection.createPropertyValue(
|
|
1767
|
+
value, /* wasThrown */ false, /* showPreview */ false);
|
|
1768
|
+
nameValuePair.appendChild(propertyValue.element);
|
|
1769
|
+
}
|
|
2044
1770
|
}
|
|
2045
|
-
|
|
1771
|
+
return widget;
|
|
2046
1772
|
}
|
|
1773
|
+
}
|
|
2047
1774
|
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
1775
|
+
const valueDecorations = defineStatefulDecoration();
|
|
1776
|
+
|
|
1777
|
+
// Evaluated expression mark for pop-over
|
|
1778
|
+
|
|
1779
|
+
const evalExpressionMark = CodeMirror.Decoration.mark({class: 'cm-evaluatedExpression'});
|
|
1780
|
+
|
|
1781
|
+
const evalExpression = defineStatefulDecoration();
|
|
1782
|
+
|
|
1783
|
+
// Styling for plugin-local elements
|
|
1784
|
+
|
|
1785
|
+
const theme = CodeMirror.EditorView.baseTheme({
|
|
1786
|
+
'.cm-lineNumbers .cm-gutterElement': {
|
|
1787
|
+
'&:hover, &.cm-breakpoint': {
|
|
1788
|
+
borderStyle: 'solid',
|
|
1789
|
+
borderWidth: '1px 4px 1px 1px',
|
|
1790
|
+
marginRight: '-4px',
|
|
1791
|
+
paddingLeft: '8px',
|
|
1792
|
+
// Make sure text doesn't move down due to the border above it.
|
|
1793
|
+
lineHeight: 'calc(1.2em - 2px)',
|
|
1794
|
+
position: 'relative',
|
|
1795
|
+
},
|
|
1796
|
+
'&:hover': {
|
|
1797
|
+
WebkitBorderImage: lineNumberArrow('#ebeced', '#ebeced'),
|
|
1798
|
+
},
|
|
1799
|
+
'&.cm-breakpoint': {
|
|
1800
|
+
color: '#fff',
|
|
1801
|
+
WebkitBorderImage: lineNumberArrow('#4285f4', '#1a73e8'),
|
|
1802
|
+
},
|
|
1803
|
+
'&.cm-breakpoint-conditional': {
|
|
1804
|
+
WebkitBorderImage: lineNumberArrow('#f29900', '#e37400'),
|
|
1805
|
+
'&::before': {
|
|
1806
|
+
content: '"?"',
|
|
1807
|
+
position: 'absolute',
|
|
1808
|
+
top: 0,
|
|
1809
|
+
left: '1px',
|
|
1810
|
+
},
|
|
1811
|
+
},
|
|
1812
|
+
'&.cm-breakpoint-logpoint': {
|
|
1813
|
+
WebkitBorderImage: lineNumberArrow('#f439a0', '#d01884'),
|
|
1814
|
+
'&::before': {
|
|
1815
|
+
content: '"‥"',
|
|
1816
|
+
position: 'absolute',
|
|
1817
|
+
top: '-3px',
|
|
1818
|
+
left: '1px',
|
|
1819
|
+
},
|
|
1820
|
+
},
|
|
1821
|
+
},
|
|
1822
|
+
'&dark .cm-lineNumbers .cm-gutterElement': {
|
|
1823
|
+
'&:hover': {
|
|
1824
|
+
WebkitBorderImage: lineNumberArrow('#3c4043', '#3c4043'),
|
|
1825
|
+
},
|
|
1826
|
+
'&.cm-breakpoint': {
|
|
1827
|
+
WebkitBorderImage: lineNumberArrow('#5186EC', '#1a73e8'),
|
|
1828
|
+
},
|
|
1829
|
+
'&.cm-breakpoint-conditional': {
|
|
1830
|
+
WebkitBorderImage: lineNumberArrow('#e9a33a', '#e37400'),
|
|
1831
|
+
},
|
|
1832
|
+
'&.cm-breakpoint-logpoint': {
|
|
1833
|
+
WebkitBorderImage: lineNumberArrow('#E54D9B', '#d01884'),
|
|
1834
|
+
},
|
|
1835
|
+
},
|
|
1836
|
+
':host-context(.breakpoints-deactivated) & .cm-lineNumbers .cm-gutterElement.cm-breakpoint, .cm-lineNumbers .cm-gutterElement.cm-breakpoint-disabled':
|
|
1837
|
+
{
|
|
1838
|
+
color: '#1a73e8',
|
|
1839
|
+
WebkitBorderImage: lineNumberArrow('#d9e7fd', '#1a73e8'),
|
|
1840
|
+
'&.cm-breakpoint-conditional': {
|
|
1841
|
+
color: '#e37400',
|
|
1842
|
+
WebkitBorderImage: lineNumberArrow('#fcebcc', '#e37400'),
|
|
1843
|
+
},
|
|
1844
|
+
'&.cm-breakpoint-logpoint': {
|
|
1845
|
+
color: '#d01884',
|
|
1846
|
+
WebkitBorderImage: lineNumberArrow('#fdd7ec', '#f439a0'),
|
|
1847
|
+
},
|
|
1848
|
+
},
|
|
1849
|
+
':host-context(.breakpoints-deactivated) &dark .cm-lineNumbers .cm-gutterElement.cm-breakpoint, &dark .cm-lineNumbers .cm-gutterElement.cm-breakpoint-disabled':
|
|
1850
|
+
{
|
|
1851
|
+
WebkitBorderImage: lineNumberArrow('#2a384e', '#1a73e8'),
|
|
1852
|
+
'&.cm-breakpoint-conditional': {
|
|
1853
|
+
WebkitBorderImage: lineNumberArrow('#4d3c1d', '#e37400'),
|
|
1854
|
+
},
|
|
1855
|
+
'&.cm-breakpoint-logpoint': {
|
|
1856
|
+
WebkitBorderImage: lineNumberArrow('#4e283d', '#f439a0'),
|
|
1857
|
+
},
|
|
1858
|
+
},
|
|
1859
|
+
|
|
1860
|
+
'.cm-inlineBreakpoint': {
|
|
1861
|
+
cursor: 'pointer',
|
|
1862
|
+
position: 'relative',
|
|
1863
|
+
top: '1px',
|
|
1864
|
+
content: inlineBreakpointArrow('#4285F4', '#1A73E8'),
|
|
1865
|
+
height: '10px',
|
|
1866
|
+
'&.cm-inlineBreakpoint-conditional': {
|
|
1867
|
+
content: inlineConditionalBreakpointArrow('#F29900', '#E37400'),
|
|
1868
|
+
},
|
|
1869
|
+
'&.cm-inlineBreakpoint-logpoint': {
|
|
1870
|
+
content: inlineLogpointArrow('#F439A0', '#D01884'),
|
|
1871
|
+
},
|
|
1872
|
+
},
|
|
1873
|
+
'&dark .cm-inlineBreakpoint': {
|
|
1874
|
+
content: inlineBreakpointArrow('#5186EC', '#1A73E8'),
|
|
1875
|
+
'&.cm-inlineBreakpoint-conditional': {
|
|
1876
|
+
content: inlineConditionalBreakpointArrow('#e9a33a', '#E37400'),
|
|
1877
|
+
},
|
|
1878
|
+
'&.cm-inlineBreakpoint-logpoint': {
|
|
1879
|
+
content: inlineLogpointArrow('#E54D9B', '#D01884'),
|
|
1880
|
+
},
|
|
1881
|
+
},
|
|
1882
|
+
':host-context(.breakpoints-deactivated) & .cm-inlineBreakpoint, .cm-inlineBreakpoint-disabled': {
|
|
1883
|
+
content: inlineBreakpointArrow('#4285F4', '#1A73E8', '0.2'),
|
|
1884
|
+
'&.cm-inlineBreakpoint-conditional': {
|
|
1885
|
+
content: inlineConditionalBreakpointArrow('#F9AB00', '#E37400', '0.2'),
|
|
1886
|
+
},
|
|
1887
|
+
'&.cm-inlineBreakpoint-logpoint': {
|
|
1888
|
+
content: inlineLogpointArrow('#F439A0', '#D01884', '0.2'),
|
|
1889
|
+
},
|
|
1890
|
+
},
|
|
1891
|
+
|
|
1892
|
+
'.cm-executionLine': {
|
|
1893
|
+
backgroundColor: 'var(--color-execution-line-background)',
|
|
1894
|
+
outline: '1px solid var(--color-execution-line-outline)',
|
|
1895
|
+
'.cm-hasContinueMarkers &': {
|
|
1896
|
+
backgroundColor: 'transparent',
|
|
1897
|
+
},
|
|
1898
|
+
'&.cm-highlightedLine': {
|
|
1899
|
+
animation: 'cm-fading-highlight-execution 2s 0s',
|
|
1900
|
+
},
|
|
1901
|
+
},
|
|
1902
|
+
'.cm-executionToken': {
|
|
1903
|
+
backgroundColor: 'var(--color-execution-token-background)',
|
|
1904
|
+
},
|
|
1905
|
+
'@keyframes cm-fading-highlight-execution': {
|
|
1906
|
+
from: {
|
|
1907
|
+
backgroundColor: 'var(--color-highlighted-line)',
|
|
1908
|
+
},
|
|
1909
|
+
to: {
|
|
1910
|
+
backgroundColor: 'var(--color-execution-line-background)',
|
|
1911
|
+
},
|
|
1912
|
+
},
|
|
1913
|
+
|
|
1914
|
+
'.cm-continueToLocation': {
|
|
1915
|
+
cursor: 'pointer',
|
|
1916
|
+
backgroundColor: 'var(--color-continue-to-location)',
|
|
1917
|
+
'&:hover': {
|
|
1918
|
+
backgroundColor: 'var(--color-continue-to-location-hover)',
|
|
1919
|
+
border: '1px solid var(--color-continue-to-location-hover-border)',
|
|
1920
|
+
margin: '0 -1px',
|
|
1921
|
+
},
|
|
1922
|
+
'&.cm-continueToLocation-async': {
|
|
1923
|
+
backgroundColor: 'var(--color-continue-to-location-async)',
|
|
1924
|
+
'&:hover': {
|
|
1925
|
+
backgroundColor: 'var(--color-continue-to-location-async-hover)',
|
|
1926
|
+
border: '1px solid var(--color-continue-to-location-async-hover-border)',
|
|
1927
|
+
margin: '0 -1px',
|
|
1928
|
+
},
|
|
1929
|
+
},
|
|
1930
|
+
},
|
|
1931
|
+
|
|
1932
|
+
'.cm-evaluatedExpression': {
|
|
1933
|
+
backgroundColor: 'var(--color-evaluated-expression)',
|
|
1934
|
+
border: '1px solid var(--color-evaluated-expression-border)',
|
|
1935
|
+
margin: '0 -1px',
|
|
1936
|
+
},
|
|
1937
|
+
|
|
1938
|
+
'.cm-variableValues': {
|
|
1939
|
+
display: 'inline',
|
|
1940
|
+
whiteSpace: 'nowrap',
|
|
1941
|
+
overflow: 'hidden',
|
|
1942
|
+
textOverflow: 'ellipsis',
|
|
1943
|
+
maxWidth: '1000px',
|
|
1944
|
+
opacity: '80%',
|
|
1945
|
+
backgroundColor: 'var(--color-variable-values)',
|
|
1946
|
+
marginLeft: '10px',
|
|
1947
|
+
padding: '0 5px',
|
|
1948
|
+
userSelect: 'text',
|
|
1949
|
+
'.cm-executionLine &': {
|
|
1950
|
+
backgroundColor: 'transparent',
|
|
1951
|
+
opacity: '50%',
|
|
1952
|
+
},
|
|
1953
|
+
},
|
|
1954
|
+
});
|
|
1955
|
+
|
|
1956
|
+
function lineNumberArrow(color: string, outline: string): string {
|
|
1957
|
+
return `url('data:image/svg+xml,<svg height="11" width="26" xmlns="http://www.w3.org/2000/svg"><path d="M22.8.5l2.7 5-2.7 5H.5V.5z" fill="${
|
|
1958
|
+
encodeURIComponent(color)}" stroke="${encodeURIComponent(outline)}"/></svg>') 1 3 1 1`;
|
|
2054
1959
|
}
|
|
2055
1960
|
|
|
2056
|
-
|
|
1961
|
+
function inlineBreakpointArrow(color: string, outline: string, opacity: string = '1'): string {
|
|
1962
|
+
return `url('data:image/svg+xml,<svg width="11" height="12" viewBox="0 0 11 12" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M0.5 0.5H5.80139C6.29382 0.5 6.7549 0.741701 7.03503 1.14669L10.392 6L7.03503 10.8533C6.7549 11.2583 6.29382 11.5 5.80139 11.5H0.5V0.5Z" fill="${
|
|
1963
|
+
encodeURIComponent(
|
|
1964
|
+
color)}" stroke="${encodeURIComponent(outline)}" fill-opacity="${encodeURIComponent(opacity)}"/></svg>')`;
|
|
1965
|
+
}
|
|
1966
|
+
|
|
1967
|
+
function inlineConditionalBreakpointArrow(color: string, outline: string, opacity: string = '1'): string {
|
|
1968
|
+
return `url('data:image/svg+xml,<svg width="11" height="12" viewBox="0 0 11 12" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M0.5 0.5H5.80139C6.29382 0.5 6.75489 0.741701 7.03503 1.14669L10.392 6L7.03503 10.8533C6.75489 11.2583 6.29382 11.5 5.80138 11.5H0.5V0.5Z" fill="${
|
|
1969
|
+
encodeURIComponent(color)}" fill-opacity="${encodeURIComponent(opacity)}" stroke="${
|
|
1970
|
+
encodeURIComponent(
|
|
1971
|
+
outline)}"/><path d="M3.51074 7.75635H4.68408V9H3.51074V7.75635ZM4.68408 7.23779H3.51074V6.56104C3.51074 6.271 3.55615 6.02344 3.64697 5.81836C3.73779 5.61328 3.90039 5.39648 4.13477 5.16797L4.53027 4.77686C4.71484 4.59814 4.83936 4.4502 4.90381 4.33301C4.97119 4.21582 5.00488 4.09424 5.00488 3.96826C5.00488 3.77197 4.9375 3.62402 4.80273 3.52441C4.66797 3.4248 4.46582 3.375 4.19629 3.375C3.9502 3.375 3.69238 3.42773 3.42285 3.5332C3.15625 3.63574 2.88232 3.78955 2.60107 3.99463V2.81689C2.88818 2.65283 3.17822 2.52979 3.47119 2.44775C3.76709 2.36279 4.06299 2.32031 4.35889 2.32031C4.95068 2.32031 5.41504 2.45801 5.75195 2.7334C6.08887 3.00879 6.25732 3.38818 6.25732 3.87158C6.25732 4.09424 6.20752 4.30225 6.10791 4.49561C6.0083 4.68604 5.8208 4.91602 5.54541 5.18555L5.15869 5.56348C4.95947 5.75684 4.83203 5.91504 4.77637 6.03809C4.7207 6.16113 4.69287 6.31201 4.69287 6.49072C4.69287 6.51709 4.69141 6.54785 4.68848 6.58301C4.68848 6.61816 4.68701 6.65625 4.68408 6.69727V7.23779Z" fill="white"/></svg>')`;
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1974
|
+
function inlineLogpointArrow(color: string, outline: string, opacity: string = '1'): string {
|
|
1975
|
+
return `url('data:image/svg+xml,<svg width="11" height="12" viewBox="0 0 11 12" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M0.5 0.5H5.80139C6.29382 0.5 6.7549 0.741701 7.03503 1.14669L10.392 6L7.03503 10.8533C6.7549 11.2583 6.29382 11.5 5.80139 11.5H0.5V0.5Z" fill="${
|
|
1976
|
+
encodeURIComponent(color)}" stroke="${encodeURIComponent(outline)}" fill-opacity="${
|
|
1977
|
+
encodeURIComponent(
|
|
1978
|
+
opacity)}"/><circle cx="3" cy="6" r="1" fill="white"/><circle cx="7" cy="6" r="1" fill="white"/></svg>')`;
|
|
1979
|
+
}
|