diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
commit | 43a97878ce14b72f0981164f87f2e35e14151312 (patch) | |
tree | 620249daf56c0258faa40cbdcf9cfba06de2a846 /devtools/client/debugger/panel.js | |
parent | Initial commit. (diff) | |
download | firefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip |
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'devtools/client/debugger/panel.js')
-rw-r--r-- | devtools/client/debugger/panel.js | 285 |
1 files changed, 285 insertions, 0 deletions
diff --git a/devtools/client/debugger/panel.js b/devtools/client/debugger/panel.js new file mode 100644 index 0000000000..3f1940ae45 --- /dev/null +++ b/devtools/client/debugger/panel.js @@ -0,0 +1,285 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ + +"use strict"; + +const { MultiLocalizationHelper } = require("devtools/shared/l10n"); +const { + FluentL10n, +} = require("devtools/client/shared/fluent-l10n/fluent-l10n"); + +loader.lazyRequireGetter( + this, + "openContentLink", + "resource://devtools/client/shared/link.js", + true +); +loader.lazyRequireGetter( + this, + "features", + "resource://devtools/client/debugger/src/utils/prefs.js", + true +); +loader.lazyRequireGetter( + this, + "registerStoreObserver", + "resource://devtools/client/shared/redux/subscriber.js", + true +); + +const DBG_STRINGS_URI = [ + "devtools/client/locales/debugger.properties", + // These are used in the AppErrorBoundary component + "devtools/client/locales/startup.properties", + "devtools/client/locales/components.properties", +]; +const L10N = new MultiLocalizationHelper(...DBG_STRINGS_URI); + +async function getNodeFront(gripOrFront, toolbox) { + // Given a NodeFront + if ("actorID" in gripOrFront) { + return new Promise(resolve => resolve(gripOrFront)); + } + + const inspectorFront = await toolbox.target.getFront("inspector"); + return inspectorFront.getNodeFrontFromNodeGrip(gripOrFront); +} + +class DebuggerPanel { + constructor(iframeWindow, toolbox, commands) { + this.panelWin = iframeWindow; + this.panelWin.L10N = L10N; + + this.toolbox = toolbox; + this.commands = commands; + } + + async open() { + // whypaused-* strings are in devtools/shared as they're used in the PausedDebuggerOverlay as well + const fluentL10n = new FluentL10n(); + await fluentL10n.init(["devtools/shared/debugger-paused-reasons.ftl"]); + + const { + actions, + store, + selectors, + client, + } = await this.panelWin.Debugger.bootstrap({ + commands: this.commands, + fluentBundles: fluentL10n.getBundles(), + resourceCommand: this.toolbox.resourceCommand, + workers: { + sourceMapLoader: this.toolbox.sourceMapLoader, + parserWorker: this.toolbox.parserWorker, + }, + panel: this, + }); + + this._actions = actions; + this._store = store; + this._selectors = selectors; + this._client = client; + + registerStoreObserver(this._store, this._onDebuggerStateChange.bind(this)); + + return this; + } + + _onDebuggerStateChange(state, oldState) { + const { getCurrentThread } = this._selectors; + + const currentThreadActorID = getCurrentThread(state); + if ( + currentThreadActorID && + currentThreadActorID !== getCurrentThread(oldState) + ) { + const threadFront = this.commands.client.getFrontByID( + currentThreadActorID + ); + this.toolbox.selectTarget(threadFront?.targetFront.actorID); + } + } + + getVarsForTests() { + return { + store: this._store, + selectors: this._selectors, + actions: this._actions, + client: this._client, + }; + } + + _getState() { + return this._store.getState(); + } + + getToolboxStore() { + return this.toolbox.store; + } + + openLink(url) { + openContentLink(url); + } + + async openConsoleAndEvaluate(input) { + const { hud } = await this.toolbox.selectTool("webconsole"); + hud.ui.wrapper.dispatchEvaluateExpression(input); + } + + async openInspector() { + this.toolbox.selectTool("inspector"); + } + + async openElementInInspector(gripOrFront) { + const onSelectInspector = this.toolbox.selectTool("inspector"); + const onGripNodeToFront = getNodeFront(gripOrFront, this.toolbox); + + const [front, inspector] = await Promise.all([ + onGripNodeToFront, + onSelectInspector, + ]); + + const onInspectorUpdated = inspector.once("inspector-updated"); + const onNodeFrontSet = this.toolbox.selection.setNodeFront(front, { + reason: "debugger", + }); + + return Promise.all([onNodeFrontSet, onInspectorUpdated]); + } + + highlightDomElement(gripOrFront) { + if (!this._highlight) { + const { highlight, unhighlight } = this.toolbox.getHighlighter(); + this._highlight = highlight; + this._unhighlight = unhighlight; + } + + return this._highlight(gripOrFront); + } + + unHighlightDomElement() { + if (!this._unhighlight) { + return Promise.resolve(); + } + + return this._unhighlight(); + } + + /** + * Return the Frame Actor ID of the currently selected frame, + * or null if the debugger isn't paused. + */ + getSelectedFrameActorID() { + const thread = this._selectors.getCurrentThread(this._getState()); + const selectedFrame = this._selectors.getSelectedFrame( + this._getState(), + thread + ); + if (selectedFrame) { + return selectedFrame.id; + } + return null; + } + + getMappedExpression(expression) { + return this._actions.getMappedExpression(expression); + } + + /** + * Return the source-mapped variables for the current scope. + * @returns {{[String]: String} | null} A dictionary mapping original variable names to generated + * variable names if map scopes is enabled, otherwise null. + */ + getMappedVariables() { + if (!this._selectors.isMapScopesEnabled(this._getState())) { + return null; + } + const thread = this._selectors.getCurrentThread(this._getState()); + return this._selectors.getSelectedScopeMappings(this._getState(), thread); + } + + isPaused() { + const thread = this._selectors.getCurrentThread(this._getState()); + return this._selectors.getIsPaused(this._getState(), thread); + } + + selectSourceURL(url, line, column) { + const cx = this._selectors.getContext(this._getState()); + return this._actions.selectSourceURL(cx, url, { line, column }); + } + + async selectWorker(workerDescriptorFront) { + const threadActorID = workerDescriptorFront.threadFront?.actorID; + + const isThreadAvailable = this._selectors + .getThreads(this._getState()) + .find(x => x.actor === threadActorID); + + if (!features.windowlessServiceWorkers) { + console.error( + "Selecting a worker needs the pref debugger.features.windowless-service-workers set to true" + ); + return; + } + + if (!isThreadAvailable) { + console.error(`Worker ${threadActorID} is not available for debugging`); + return; + } + + // select worker's thread + this.selectThread(threadActorID); + + // select worker's source + const source = this.getSourceByURL(workerDescriptorFront._url); + const sourceActor = this._selectors.getFirstSourceActorForGeneratedSource( + this._getState(), + source.id, + threadActorID + ); + await this.selectSource(source.id, sourceActor.actor, 1, 1); + } + + selectThread(threadActorID) { + const cx = this._selectors.getContext(this._getState()); + this._actions.selectThread(cx, threadActorID); + } + + async selectSource(sourceId, sourceActorId, line, column) { + const cx = this._selectors.getContext(this._getState()); + const location = { sourceId, line, column }; + + await this._actions.selectSource(cx, sourceId, sourceActorId, location); + if (this._selectors.hasLogpoint(this._getState(), location)) { + this._actions.openConditionalPanel(location, true); + } + } + + getSourceActorsForSource(sourceId) { + return this._selectors.getSourceActorsForSource(this._getState(), sourceId); + } + + getSourceByActorId(sourceId) { + return this._selectors.getSourceByActorId(this._getState(), sourceId); + } + + getSourceByURL(sourceURL) { + return this._selectors.getSourceByURL(this._getState(), sourceURL); + } + + getSource(sourceId) { + return this._selectors.getSource(this._getState(), sourceId); + } + + getLocationSource(location) { + return this._selectors.getLocationSource(this._getState(), location); + } + + destroy() { + this.panelWin.Debugger.destroy(); + this.emit("destroyed"); + } +} + +exports.DebuggerPanel = DebuggerPanel; |