forked from mirrors/gecko-dev
Update imports to use FOLDER/index, instead of relying on nodeJS require behavior (which will look for the index file when importing FOLDER) Differential Revision: https://phabricator.services.mozilla.com/D198423
436 lines
13 KiB
JavaScript
436 lines
13 KiB
JavaScript
/* 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/>. */
|
|
|
|
import { showMenu } from "../../context-menu/menu";
|
|
|
|
import { copyToTheClipboard } from "../../utils/clipboard";
|
|
import {
|
|
isPretty,
|
|
getRawSourceURL,
|
|
getFilename,
|
|
shouldBlackbox,
|
|
findBlackBoxRange,
|
|
} from "../../utils/source";
|
|
import { toSourceLine } from "../../utils/editor/index";
|
|
import { downloadFile } from "../../utils/utils";
|
|
import { features } from "../../utils/prefs";
|
|
import { isFulfilled } from "../../utils/async-value";
|
|
|
|
import { createBreakpointItems } from "./editor-breakpoint";
|
|
|
|
import {
|
|
getPrettySource,
|
|
getIsCurrentThreadPaused,
|
|
isSourceWithMap,
|
|
getBlackBoxRanges,
|
|
isSourceOnSourceMapIgnoreList,
|
|
isSourceMapIgnoreListEnabled,
|
|
getEditorWrapping,
|
|
} from "../../selectors/index";
|
|
|
|
import { continueToHere } from "../../actions/pause/continueToHere";
|
|
import { jumpToMappedLocation } from "../../actions/sources/select";
|
|
import {
|
|
showSource,
|
|
toggleInlinePreview,
|
|
toggleEditorWrapping,
|
|
} from "../../actions/ui";
|
|
import { toggleBlackBox } from "../../actions/sources/blackbox";
|
|
import { addExpression } from "../../actions/expressions";
|
|
import { evaluateInConsole } from "../../actions/toolbox";
|
|
|
|
export function showEditorContextMenu(event, editor, location) {
|
|
return async ({ dispatch, getState }) => {
|
|
const { source } = location;
|
|
const state = getState();
|
|
const blackboxedRanges = getBlackBoxRanges(state);
|
|
const isPaused = getIsCurrentThreadPaused(state);
|
|
const hasMappedLocation =
|
|
(source.isOriginal ||
|
|
isSourceWithMap(state, source.id) ||
|
|
isPretty(source)) &&
|
|
!getPrettySource(state, source.id);
|
|
const isSourceOnIgnoreList =
|
|
isSourceMapIgnoreListEnabled(state) &&
|
|
isSourceOnSourceMapIgnoreList(state, source);
|
|
const editorWrappingEnabled = getEditorWrapping(state);
|
|
|
|
showMenu(
|
|
event,
|
|
editorMenuItems({
|
|
blackboxedRanges,
|
|
hasMappedLocation,
|
|
location,
|
|
isPaused,
|
|
editorWrappingEnabled,
|
|
selectionText: editor.codeMirror.getSelection().trim(),
|
|
isTextSelected: editor.codeMirror.somethingSelected(),
|
|
editor,
|
|
isSourceOnIgnoreList,
|
|
dispatch,
|
|
})
|
|
);
|
|
};
|
|
}
|
|
|
|
export function showEditorGutterContextMenu(event, editor, location, lineText) {
|
|
return async ({ dispatch, getState }) => {
|
|
const { source } = location;
|
|
const state = getState();
|
|
const blackboxedRanges = getBlackBoxRanges(state);
|
|
const isPaused = getIsCurrentThreadPaused(state);
|
|
const isSourceOnIgnoreList =
|
|
isSourceMapIgnoreListEnabled(state) &&
|
|
isSourceOnSourceMapIgnoreList(state, source);
|
|
|
|
showMenu(event, [
|
|
...createBreakpointItems(location, lineText, dispatch),
|
|
{ type: "separator" },
|
|
continueToHereItem(location, isPaused, dispatch),
|
|
{ type: "separator" },
|
|
blackBoxLineMenuItem(
|
|
source,
|
|
editor,
|
|
blackboxedRanges,
|
|
isSourceOnIgnoreList,
|
|
location.line,
|
|
dispatch
|
|
),
|
|
]);
|
|
};
|
|
}
|
|
|
|
// Menu Items
|
|
const continueToHereItem = (location, isPaused, dispatch) => ({
|
|
accesskey: L10N.getStr("editor.continueToHere.accesskey"),
|
|
disabled: !isPaused,
|
|
click: () => dispatch(continueToHere(location)),
|
|
id: "node-menu-continue-to-here",
|
|
label: L10N.getStr("editor.continueToHere.label"),
|
|
});
|
|
|
|
const copyToClipboardItem = selectionText => ({
|
|
id: "node-menu-copy-to-clipboard",
|
|
label: L10N.getStr("copyToClipboard.label"),
|
|
accesskey: L10N.getStr("copyToClipboard.accesskey"),
|
|
disabled: selectionText.length === 0,
|
|
click: () => copyToTheClipboard(selectionText),
|
|
});
|
|
|
|
const copySourceItem = selectedContent => ({
|
|
id: "node-menu-copy-source",
|
|
label: L10N.getStr("copySource.label"),
|
|
accesskey: L10N.getStr("copySource.accesskey"),
|
|
disabled: false,
|
|
click: () =>
|
|
selectedContent.type === "text" &&
|
|
copyToTheClipboard(selectedContent.value),
|
|
});
|
|
|
|
const copySourceUri2Item = selectedSource => ({
|
|
id: "node-menu-copy-source-url",
|
|
label: L10N.getStr("copySourceUri2"),
|
|
accesskey: L10N.getStr("copySourceUri2.accesskey"),
|
|
disabled: !selectedSource.url,
|
|
click: () => copyToTheClipboard(getRawSourceURL(selectedSource.url)),
|
|
});
|
|
|
|
const jumpToMappedLocationItem = (location, hasMappedLocation, dispatch) => ({
|
|
id: "node-menu-jump",
|
|
label: L10N.getFormatStr(
|
|
"editor.jumpToMappedLocation1",
|
|
location.source.isOriginal
|
|
? L10N.getStr("generated")
|
|
: L10N.getStr("original")
|
|
),
|
|
accesskey: L10N.getStr("editor.jumpToMappedLocation1.accesskey"),
|
|
disabled: !hasMappedLocation,
|
|
click: () => dispatch(jumpToMappedLocation(location)),
|
|
});
|
|
|
|
const showSourceMenuItem = (selectedSource, dispatch) => ({
|
|
id: "node-menu-show-source",
|
|
label: L10N.getStr("sourceTabs.revealInTree"),
|
|
accesskey: L10N.getStr("sourceTabs.revealInTree.accesskey"),
|
|
disabled: !selectedSource.url,
|
|
click: () => dispatch(showSource(selectedSource.id)),
|
|
});
|
|
|
|
const blackBoxMenuItem = (
|
|
selectedSource,
|
|
blackboxedRanges,
|
|
isSourceOnIgnoreList,
|
|
dispatch
|
|
) => {
|
|
const isBlackBoxed = !!blackboxedRanges[selectedSource.url];
|
|
return {
|
|
id: "node-menu-blackbox",
|
|
label: isBlackBoxed
|
|
? L10N.getStr("ignoreContextItem.unignore")
|
|
: L10N.getStr("ignoreContextItem.ignore"),
|
|
accesskey: isBlackBoxed
|
|
? L10N.getStr("ignoreContextItem.unignore.accesskey")
|
|
: L10N.getStr("ignoreContextItem.ignore.accesskey"),
|
|
disabled: isSourceOnIgnoreList || !shouldBlackbox(selectedSource),
|
|
click: () => dispatch(toggleBlackBox(selectedSource)),
|
|
};
|
|
};
|
|
|
|
const blackBoxLineMenuItem = (
|
|
selectedSource,
|
|
editor,
|
|
blackboxedRanges,
|
|
isSourceOnIgnoreList,
|
|
// the clickedLine is passed when the context menu
|
|
// is opened from the gutter, it is not available when the
|
|
// the context menu is opened from the editor.
|
|
clickedLine = null,
|
|
dispatch
|
|
) => {
|
|
const { codeMirror } = editor;
|
|
const from = codeMirror.getCursor("from");
|
|
const to = codeMirror.getCursor("to");
|
|
|
|
const startLine = clickedLine ?? toSourceLine(selectedSource.id, from.line);
|
|
const endLine = clickedLine ?? toSourceLine(selectedSource.id, to.line);
|
|
|
|
const blackboxRange = findBlackBoxRange(selectedSource, blackboxedRanges, {
|
|
start: startLine,
|
|
end: endLine,
|
|
});
|
|
|
|
const selectedLineIsBlackBoxed = !!blackboxRange;
|
|
|
|
const isSingleLine = selectedLineIsBlackBoxed
|
|
? blackboxRange.start.line == blackboxRange.end.line
|
|
: startLine == endLine;
|
|
|
|
const isSourceFullyBlackboxed =
|
|
blackboxedRanges[selectedSource.url] &&
|
|
!blackboxedRanges[selectedSource.url].length;
|
|
|
|
// The ignore/unignore line context menu item should be disabled when
|
|
// 1) The source is on the sourcemap ignore list
|
|
// 2) The whole source is blackboxed or
|
|
// 3) Multiple lines are blackboxed or
|
|
// 4) Multiple lines are selected in the editor
|
|
const shouldDisable =
|
|
isSourceOnIgnoreList || isSourceFullyBlackboxed || !isSingleLine;
|
|
|
|
return {
|
|
id: "node-menu-blackbox-line",
|
|
label: !selectedLineIsBlackBoxed
|
|
? L10N.getStr("ignoreContextItem.ignoreLine")
|
|
: L10N.getStr("ignoreContextItem.unignoreLine"),
|
|
accesskey: !selectedLineIsBlackBoxed
|
|
? L10N.getStr("ignoreContextItem.ignoreLine.accesskey")
|
|
: L10N.getStr("ignoreContextItem.unignoreLine.accesskey"),
|
|
disabled: shouldDisable,
|
|
click: () => {
|
|
const selectionRange = {
|
|
start: {
|
|
line: startLine,
|
|
column: clickedLine == null ? from.ch : 0,
|
|
},
|
|
end: {
|
|
line: endLine,
|
|
column: clickedLine == null ? to.ch : 0,
|
|
},
|
|
};
|
|
|
|
dispatch(
|
|
toggleBlackBox(
|
|
selectedSource,
|
|
!selectedLineIsBlackBoxed,
|
|
selectedLineIsBlackBoxed ? [blackboxRange] : [selectionRange]
|
|
)
|
|
);
|
|
},
|
|
};
|
|
};
|
|
|
|
const blackBoxLinesMenuItem = (
|
|
selectedSource,
|
|
editor,
|
|
blackboxedRanges,
|
|
isSourceOnIgnoreList,
|
|
clickedLine = null,
|
|
dispatch
|
|
) => {
|
|
const { codeMirror } = editor;
|
|
const from = codeMirror.getCursor("from");
|
|
const to = codeMirror.getCursor("to");
|
|
|
|
const startLine = toSourceLine(selectedSource.id, from.line);
|
|
const endLine = toSourceLine(selectedSource.id, to.line);
|
|
|
|
const blackboxRange = findBlackBoxRange(selectedSource, blackboxedRanges, {
|
|
start: startLine,
|
|
end: endLine,
|
|
});
|
|
|
|
const selectedLinesAreBlackBoxed = !!blackboxRange;
|
|
|
|
return {
|
|
id: "node-menu-blackbox-lines",
|
|
label: !selectedLinesAreBlackBoxed
|
|
? L10N.getStr("ignoreContextItem.ignoreLines")
|
|
: L10N.getStr("ignoreContextItem.unignoreLines"),
|
|
accesskey: !selectedLinesAreBlackBoxed
|
|
? L10N.getStr("ignoreContextItem.ignoreLines.accesskey")
|
|
: L10N.getStr("ignoreContextItem.unignoreLines.accesskey"),
|
|
disabled: isSourceOnIgnoreList,
|
|
click: () => {
|
|
const selectionRange = {
|
|
start: {
|
|
line: startLine,
|
|
column: from.ch,
|
|
},
|
|
end: {
|
|
line: endLine,
|
|
column: to.ch,
|
|
},
|
|
};
|
|
|
|
dispatch(
|
|
toggleBlackBox(
|
|
selectedSource,
|
|
!selectedLinesAreBlackBoxed,
|
|
selectedLinesAreBlackBoxed ? [blackboxRange] : [selectionRange]
|
|
)
|
|
);
|
|
},
|
|
};
|
|
};
|
|
|
|
const watchExpressionItem = (selectedSource, selectionText, dispatch) => ({
|
|
id: "node-menu-add-watch-expression",
|
|
label: L10N.getStr("expressions.label"),
|
|
accesskey: L10N.getStr("expressions.accesskey"),
|
|
click: () => dispatch(addExpression(selectionText)),
|
|
});
|
|
|
|
const evaluateInConsoleItem = (selectedSource, selectionText, dispatch) => ({
|
|
id: "node-menu-evaluate-in-console",
|
|
label: L10N.getStr("evaluateInConsole.label"),
|
|
click: () => dispatch(evaluateInConsole(selectionText)),
|
|
});
|
|
|
|
const downloadFileItem = (selectedSource, selectedContent) => ({
|
|
id: "node-menu-download-file",
|
|
label: L10N.getStr("downloadFile.label"),
|
|
accesskey: L10N.getStr("downloadFile.accesskey"),
|
|
click: () => downloadFile(selectedContent, getFilename(selectedSource)),
|
|
});
|
|
|
|
const inlinePreviewItem = dispatch => ({
|
|
id: "node-menu-inline-preview",
|
|
label: features.inlinePreview
|
|
? L10N.getStr("inlinePreview.hide.label")
|
|
: L10N.getStr("inlinePreview.show.label"),
|
|
click: () => dispatch(toggleInlinePreview(!features.inlinePreview)),
|
|
});
|
|
|
|
const editorWrappingItem = (editorWrappingEnabled, dispatch) => ({
|
|
id: "node-menu-editor-wrapping",
|
|
label: editorWrappingEnabled
|
|
? L10N.getStr("editorWrapping.hide.label")
|
|
: L10N.getStr("editorWrapping.show.label"),
|
|
click: () => dispatch(toggleEditorWrapping(!editorWrappingEnabled)),
|
|
});
|
|
|
|
function editorMenuItems({
|
|
blackboxedRanges,
|
|
location,
|
|
selectionText,
|
|
hasMappedLocation,
|
|
isTextSelected,
|
|
isPaused,
|
|
editorWrappingEnabled,
|
|
editor,
|
|
isSourceOnIgnoreList,
|
|
dispatch,
|
|
}) {
|
|
const items = [];
|
|
|
|
const { source } = location;
|
|
|
|
const content =
|
|
source.content && isFulfilled(source.content) ? source.content.value : null;
|
|
|
|
items.push(
|
|
jumpToMappedLocationItem(location, hasMappedLocation, dispatch),
|
|
continueToHereItem(location, isPaused, dispatch),
|
|
{ type: "separator" },
|
|
copyToClipboardItem(selectionText),
|
|
...(!source.isWasm
|
|
? [
|
|
...(content ? [copySourceItem(content)] : []),
|
|
copySourceUri2Item(source),
|
|
]
|
|
: []),
|
|
...(content ? [downloadFileItem(source, content)] : []),
|
|
{ type: "separator" },
|
|
showSourceMenuItem(source, dispatch),
|
|
{ type: "separator" },
|
|
blackBoxMenuItem(source, blackboxedRanges, isSourceOnIgnoreList, dispatch)
|
|
);
|
|
|
|
const startLine = toSourceLine(
|
|
source.id,
|
|
editor.codeMirror.getCursor("from").line
|
|
);
|
|
const endLine = toSourceLine(
|
|
source.id,
|
|
editor.codeMirror.getCursor("to").line
|
|
);
|
|
|
|
// Find any blackbox ranges that exist for the selected lines
|
|
const blackboxRange = findBlackBoxRange(source, blackboxedRanges, {
|
|
start: startLine,
|
|
end: endLine,
|
|
});
|
|
|
|
const isMultiLineSelection = blackboxRange
|
|
? blackboxRange.start.line !== blackboxRange.end.line
|
|
: startLine !== endLine;
|
|
|
|
// When the range is defined and is an empty array,
|
|
// the whole source is blackboxed
|
|
const theWholeSourceIsBlackBoxed =
|
|
blackboxedRanges[source.url] && !blackboxedRanges[source.url].length;
|
|
|
|
if (!theWholeSourceIsBlackBoxed) {
|
|
const blackBoxSourceLinesMenuItem = isMultiLineSelection
|
|
? blackBoxLinesMenuItem
|
|
: blackBoxLineMenuItem;
|
|
|
|
items.push(
|
|
blackBoxSourceLinesMenuItem(
|
|
source,
|
|
editor,
|
|
blackboxedRanges,
|
|
isSourceOnIgnoreList,
|
|
null,
|
|
dispatch
|
|
)
|
|
);
|
|
}
|
|
|
|
if (isTextSelected) {
|
|
items.push(
|
|
{ type: "separator" },
|
|
watchExpressionItem(source, selectionText, dispatch),
|
|
evaluateInConsoleItem(source, selectionText, dispatch)
|
|
);
|
|
}
|
|
|
|
items.push(
|
|
{ type: "separator" },
|
|
inlinePreviewItem(dispatch),
|
|
editorWrappingItem(editorWrappingEnabled, dispatch)
|
|
);
|
|
|
|
return items;
|
|
}
|