зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1913189 - [devtools] Use CodeMirror 6 in conditional breakpoint. r=bomsy.
Differential Revision: https://phabricator.services.mozilla.com/D220685
This commit is contained in:
Родитель
f3480bca05
Коммит
1aa477dd15
|
@ -47,3 +47,13 @@
|
|||
/* Match the color of the placeholder text to existing inputs in the Debugger */
|
||||
color: var(--theme-text-color-alt);
|
||||
}
|
||||
|
||||
/* cm6 style */
|
||||
.conditional-breakpoint-panel .inline-codemirror-container {
|
||||
flex: 1 1 100%;
|
||||
|
||||
/* We already set an outline on the conditional panel, so hide the default codemirror one */
|
||||
.cm-editor.cm-focused {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ export class ConditionalPanel extends PureComponent {
|
|||
constructor() {
|
||||
super();
|
||||
this.cbPanel = null;
|
||||
this.breakpointPanelEditor = null;
|
||||
}
|
||||
|
||||
static get propTypes() {
|
||||
|
@ -49,28 +50,68 @@ export class ConditionalPanel extends PureComponent {
|
|||
};
|
||||
}
|
||||
|
||||
removeBreakpointPanelEditor() {
|
||||
if (this.breakpointPanelEditor) {
|
||||
this.breakpointPanelEditor.destroy();
|
||||
}
|
||||
this.breakpointPanelEditor = null;
|
||||
}
|
||||
|
||||
keepFocusOnInput() {
|
||||
if (this.input) {
|
||||
this.input.focus();
|
||||
} else if (this.breakpointPanelEditor) {
|
||||
this.breakpointPanelEditor.focus();
|
||||
}
|
||||
}
|
||||
|
||||
saveAndClose = () => {
|
||||
if (this.input) {
|
||||
this.setBreakpoint(this.input.value.trim());
|
||||
/**
|
||||
* Set the breakpoint/logpoint if expression isn't empty, and close the panel.
|
||||
*
|
||||
* @param {String} expression: The expression that will be used for setting the
|
||||
* conditional breakpoint/logpoint
|
||||
*/
|
||||
saveAndClose = (expression = null) => {
|
||||
if (expression) {
|
||||
this.setBreakpoint(expression.trim());
|
||||
}
|
||||
|
||||
this.props.closeConditionalPanel();
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle inline editor keydown event
|
||||
*
|
||||
* @param {Event} e: The keydown event
|
||||
*/
|
||||
onKey = e => {
|
||||
if (e.key === "Enter" && !e.shiftKey) {
|
||||
this.saveAndClose();
|
||||
this.saveAndClose(this.input?.value);
|
||||
} else if (e.key === "Escape") {
|
||||
this.props.closeConditionalPanel();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle inline editor blur event
|
||||
*
|
||||
* @param {Event} e: The blur event
|
||||
*/
|
||||
onBlur = e => {
|
||||
if (
|
||||
// if there is no event
|
||||
// or if the focus is the conditional panel
|
||||
// do not close the conditional panel
|
||||
!e ||
|
||||
(e?.relatedTarget &&
|
||||
e.relatedTarget.closest(".conditional-breakpoint-panel"))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.closeConditionalPanel();
|
||||
};
|
||||
|
||||
setBreakpoint(value) {
|
||||
const { log, breakpoint } = this.props;
|
||||
// If breakpoint is `pending`, props will not contain a breakpoint.
|
||||
|
@ -105,17 +146,20 @@ export class ConditionalPanel extends PureComponent {
|
|||
};
|
||||
|
||||
showConditionalPanel(prevProps) {
|
||||
const { location, editor, breakpoint, selectedSource } = this.props;
|
||||
const { location, log, editor, breakpoint, selectedSource } = this.props;
|
||||
if (!selectedSource || !location) {
|
||||
this.removeBreakpointPanelEditor();
|
||||
return;
|
||||
}
|
||||
// When breakpoint is removed
|
||||
if (prevProps?.breakpoint && !breakpoint) {
|
||||
editor.removeLineContentMarker(markerTypes.CONDITIONAL_BP_MARKER);
|
||||
this.removeBreakpointPanelEditor();
|
||||
return;
|
||||
}
|
||||
if (selectedSource.id !== location.source.id) {
|
||||
editor.removeLineContentMarker(markerTypes.CONDITIONAL_BP_MARKER);
|
||||
this.removeBreakpointPanelEditor();
|
||||
return;
|
||||
}
|
||||
const line = toEditorLine(location.source.id, location.line || 0);
|
||||
|
@ -124,12 +168,42 @@ export class ConditionalPanel extends PureComponent {
|
|||
lines: [{ line }],
|
||||
renderAsBlock: true,
|
||||
createLineElementNode: () => {
|
||||
// Create a Codemirror 5 editor for the breakpoint panel
|
||||
// TODO: Switch to use Codemirror 6 version Bug 1890205
|
||||
const breakpointPanelEditor = createEditor();
|
||||
breakpointPanelEditor.appendToLocalElement(
|
||||
document.createElement("div")
|
||||
);
|
||||
// Create a Codemirror editor for the breakpoint panel
|
||||
|
||||
const onEnterKeyMapConfig = {
|
||||
preventDefault: true,
|
||||
stopPropagation: true,
|
||||
run: () => this.saveAndClose(breakpointPanelEditor.getText(null)),
|
||||
};
|
||||
|
||||
const breakpointPanelEditor = createEditor({
|
||||
cm6: features.codemirrorNext,
|
||||
readOnly: false,
|
||||
lineNumbers: false,
|
||||
placeholder: L10N.getStr(
|
||||
log
|
||||
? "editor.conditionalPanel.logPoint.placeholder2"
|
||||
: "editor.conditionalPanel.placeholder2"
|
||||
),
|
||||
keyMap: [
|
||||
{
|
||||
key: "Enter",
|
||||
...onEnterKeyMapConfig,
|
||||
},
|
||||
{
|
||||
key: "Mod-Enter",
|
||||
...onEnterKeyMapConfig,
|
||||
},
|
||||
{
|
||||
key: "Escape",
|
||||
preventDefault: true,
|
||||
stopPropagation: true,
|
||||
run: () => this.props.closeConditionalPanel(),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
this.breakpointPanelEditor = breakpointPanelEditor;
|
||||
return this.renderConditionalPanel(this.props, breakpointPanelEditor);
|
||||
},
|
||||
});
|
||||
|
@ -168,6 +242,7 @@ export class ConditionalPanel extends PureComponent {
|
|||
} else {
|
||||
this.clearConditionalPanel();
|
||||
}
|
||||
this.removeBreakpointPanelEditor();
|
||||
}
|
||||
|
||||
renderToWidget(props) {
|
||||
|
@ -209,57 +284,55 @@ export class ConditionalPanel extends PureComponent {
|
|||
}
|
||||
}
|
||||
|
||||
createEditor = (input, editor) => {
|
||||
const { log, closeConditionalPanel } = this.props;
|
||||
const codeMirror = editor.CodeMirror.fromTextArea(input, {
|
||||
mode: "javascript",
|
||||
theme: "mozilla",
|
||||
placeholder: L10N.getStr(
|
||||
log
|
||||
? "editor.conditionalPanel.logPoint.placeholder2"
|
||||
: "editor.conditionalPanel.placeholder2"
|
||||
),
|
||||
cursorBlinkRate: prefs.cursorBlinkRate,
|
||||
});
|
||||
setupAndAppendInlineEditor = (el, editor) => {
|
||||
const { log } = this.props;
|
||||
|
||||
codeMirror.on("keydown", (cm, e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.codemirrorIgnore = true;
|
||||
}
|
||||
});
|
||||
if (features.codemirrorNext) {
|
||||
editor.appendToLocalElement(el);
|
||||
editor.on("blur", e => this.onBlur(e));
|
||||
|
||||
codeMirror.on("blur", (cm, e) => {
|
||||
if (
|
||||
// if there is no event
|
||||
// or if the focus is the conditional panel
|
||||
// do not close the conditional panel
|
||||
!e ||
|
||||
(e?.relatedTarget &&
|
||||
e.relatedTarget.closest(".conditional-breakpoint-panel"))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
editor.setText(this.getDefaultValue());
|
||||
editor.focus();
|
||||
editor.selectAll();
|
||||
} else {
|
||||
const codeMirror = editor.CodeMirror.fromTextArea(el, {
|
||||
mode: "javascript",
|
||||
theme: "mozilla",
|
||||
placeholder: L10N.getStr(
|
||||
log
|
||||
? "editor.conditionalPanel.logPoint.placeholder2"
|
||||
: "editor.conditionalPanel.placeholder2"
|
||||
),
|
||||
cursorBlinkRate: prefs.cursorBlinkRate,
|
||||
});
|
||||
|
||||
closeConditionalPanel();
|
||||
});
|
||||
codeMirror.on("keydown", (cm, e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.codemirrorIgnore = true;
|
||||
}
|
||||
});
|
||||
|
||||
const codeMirrorWrapper = codeMirror.getWrapperElement();
|
||||
codeMirror.on("blur", (cm, e) => this.onBlur(e));
|
||||
|
||||
codeMirrorWrapper.addEventListener("keydown", e => {
|
||||
codeMirror.save();
|
||||
this.onKey(e);
|
||||
});
|
||||
const codeMirrorWrapper = codeMirror.getWrapperElement();
|
||||
|
||||
this.input = input;
|
||||
this.codeMirror = codeMirror;
|
||||
codeMirror.focus();
|
||||
codeMirror.execCommand("selectAll");
|
||||
codeMirrorWrapper.addEventListener("keydown", e => {
|
||||
codeMirror.save();
|
||||
this.onKey(e);
|
||||
});
|
||||
|
||||
this.input = el;
|
||||
this.codeMirror = codeMirror;
|
||||
codeMirror.focus();
|
||||
codeMirror.execCommand("selectAll");
|
||||
}
|
||||
};
|
||||
|
||||
getDefaultValue() {
|
||||
const { breakpoint, log } = this.props;
|
||||
const options = breakpoint?.options || {};
|
||||
return log ? options.logValue : options.condition;
|
||||
const value = log ? options.logValue : options.condition;
|
||||
return value || "";
|
||||
}
|
||||
|
||||
renderConditionalPanel(props, editor) {
|
||||
|
@ -285,10 +358,15 @@ export class ConditionalPanel extends PureComponent {
|
|||
},
|
||||
"»"
|
||||
),
|
||||
textarea({
|
||||
defaultValue,
|
||||
ref: input => this.createEditor(input, editor),
|
||||
})
|
||||
features.codemirrorNext
|
||||
? div({
|
||||
className: "inline-codemirror-container",
|
||||
ref: el => this.setupAndAppendInlineEditor(el, editor),
|
||||
})
|
||||
: textarea({
|
||||
defaultValue,
|
||||
ref: input => this.setupAndAppendInlineEditor(input, editor),
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -5,7 +5,13 @@
|
|||
import SourceEditor from "devtools/client/shared/sourceeditor/editor";
|
||||
import { features, prefs } from "../prefs";
|
||||
|
||||
export function createEditor(useCm6 = false) {
|
||||
/**
|
||||
* Create a SourceEditor
|
||||
*
|
||||
* @param {Object} config: SourceEditor config object
|
||||
* @returns
|
||||
*/
|
||||
export function createEditor(config = { cm6: false }) {
|
||||
const gutters = ["breakpoints", "hit-markers", "CodeMirror-linenumbers"];
|
||||
|
||||
if (features.codeFolding) {
|
||||
|
@ -14,7 +20,6 @@ export function createEditor(useCm6 = false) {
|
|||
|
||||
return new SourceEditor({
|
||||
mode: SourceEditor.modes.js,
|
||||
cm6: useCm6,
|
||||
foldGutter: features.codeFolding,
|
||||
enableCodeFolding: features.codeFolding,
|
||||
readOnly: true,
|
||||
|
@ -37,6 +42,7 @@ export function createEditor(useCm6 = false) {
|
|||
"Ctrl-G": false,
|
||||
},
|
||||
cursorBlinkRate: prefs.cursorBlinkRate,
|
||||
...config,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -47,7 +53,7 @@ export function createEditor(useCm6 = false) {
|
|||
* @returns {CodeMirror}
|
||||
*/
|
||||
export function createHeadlessEditor(useCm6) {
|
||||
const editor = createEditor(useCm6);
|
||||
const editor = createEditor({ cm6: useCm6 });
|
||||
editor.appendToLocalElement(document.createElement("div"));
|
||||
return editor;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ export function getEditor(useCm6) {
|
|||
return editor;
|
||||
}
|
||||
|
||||
editor = createEditor(useCm6);
|
||||
editor = createEditor({ cm6: useCm6 });
|
||||
return editor;
|
||||
}
|
||||
|
||||
|
|
|
@ -647,8 +647,14 @@ class Editor extends EventEmitter {
|
|||
|
||||
const {
|
||||
codemirror,
|
||||
codemirrorView: { EditorView, lineNumbers, drawSelection },
|
||||
codemirrorState: { EditorState, Compartment },
|
||||
codemirrorView: {
|
||||
drawSelection,
|
||||
EditorView,
|
||||
keymap,
|
||||
lineNumbers,
|
||||
placeholder,
|
||||
},
|
||||
codemirrorState: { EditorState, Compartment, Prec },
|
||||
codemirrorSearch: { highlightSelectionMatches },
|
||||
codemirrorLanguage: {
|
||||
syntaxTreeAvailable,
|
||||
|
@ -750,6 +756,14 @@ class Editor extends EventEmitter {
|
|||
extensions.push(codemirrorLangJavascript.javascript());
|
||||
}
|
||||
|
||||
if (this.config.placeholder) {
|
||||
extensions.push(placeholder(this.config.placeholder));
|
||||
}
|
||||
|
||||
if (this.config.keyMap) {
|
||||
extensions.push(Prec.highest(keymap.of(this.config.keyMap)));
|
||||
}
|
||||
|
||||
if (Services.prefs.prefHasUserValue(CARET_BLINK_TIME)) {
|
||||
// We need to multiply the preference value by 2 to match Firefox cursor rate
|
||||
const cursorBlinkRate = Services.prefs.getIntPref(CARET_BLINK_TIME) * 2;
|
||||
|
@ -768,6 +782,11 @@ class Editor extends EventEmitter {
|
|||
cm.isDocumentLoadComplete = false;
|
||||
this.#ownerDoc.sourceEditor = { editor: this, cm };
|
||||
editors.set(this, cm);
|
||||
|
||||
// For now, we only need to pipe the blur event
|
||||
cm.contentDOM.addEventListener("blur", e => this.emit("blur", e), {
|
||||
signal: this.#abortController?.signal,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3284,6 +3303,29 @@ class Editor extends EventEmitter {
|
|||
}
|
||||
return outputNode.innerHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Focus the CodeMirror editor
|
||||
*/
|
||||
focus() {
|
||||
const cm = editors.get(this);
|
||||
cm.focus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the whole document
|
||||
*/
|
||||
selectAll() {
|
||||
const cm = editors.get(this);
|
||||
if (this.config.cm6) {
|
||||
cm.dispatch({
|
||||
selection: { anchor: 0, head: cm.state.doc.length },
|
||||
userEvent: "select",
|
||||
});
|
||||
} else {
|
||||
cm.execCommand("selectAll");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Since Editor is a thin layer over CodeMirror some methods
|
||||
|
|
Загрузка…
Ссылка в новой задаче