Skip to content

Commit

Permalink
Bug 1887649 - [devtools] Show the conditional/log breakpoint panel in…
Browse files Browse the repository at this point in the history
… codemirror 6 r=devtools-reviewers,nchevobbe

Differential Revision: https://phabricator.services.mozilla.com/D205578
  • Loading branch information
bomsy committed Apr 30, 2024
1 parent 1322481 commit f482d50
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,16 @@
right: -16px;
}

.new-breakpoint.has-condition .CodeMirror-gutter-wrapper svg {
.new-breakpoint.has-condition .CodeMirror-gutter-wrapper svg,
/* Codemirror 6*/
.cm6-gutter-breakpoint .breakpoint-marker.has-condition svg {
fill: var(--breakpoint-condition-fill);
stroke: var(--breakpoint-condition-stroke);
}

.new-breakpoint.has-log .CodeMirror-gutter-wrapper svg {
.new-breakpoint.has-log .CodeMirror-gutter-wrapper svg,
/* Codemirror 6*/
.cm6-gutter-breakpoint .breakpoint-marker.has-log svg {
fill: var(--logpoint-fill);
stroke: var(--logpoint-stroke);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,8 @@
/* Match the color of the placeholder text to existing inputs in the Debugger */
color: var(--theme-text-color-alt);
}

/* Removing the line padding for Codemirror 6 */
.cm-line:has(div.conditional-breakpoint-panel) {
padding: 0;
}
71 changes: 59 additions & 12 deletions devtools/client/debugger/src/components/Editor/ConditionalPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import ReactDOM from "devtools/client/shared/vendor/react-dom";
import PropTypes from "devtools/client/shared/vendor/react-prop-types";
import { connect } from "devtools/client/shared/vendor/react-redux";
import { toEditorLine } from "../../utils/editor/index";
import { prefs } from "../../utils/prefs";
import { createEditor } from "../../utils/editor/create-editor";
import { prefs, features } from "../../utils/prefs";
import actions from "../../actions/index";

import {
Expand All @@ -21,6 +22,7 @@ import {
} from "../../selectors/index";

const classnames = require("resource://devtools/client/shared/classnames.js");
const CONDITIONAL_BP_MARKER = "conditional-breakpoint-panel-marker";

function addNewLine(doc) {
const cursor = doc.getCursor();
Expand Down Expand Up @@ -49,6 +51,7 @@ export class ConditionalPanel extends PureComponent {
log: PropTypes.bool.isRequired,
openConditionalPanel: PropTypes.func.isRequired,
setBreakpointOptions: PropTypes.func.isRequired,
selectedSource: PropTypes.object.isRequired,
};
}

Expand Down Expand Up @@ -111,25 +114,66 @@ export class ConditionalPanel extends PureComponent {
}
};

showConditionalPanel(prevProps) {
const { location, editor, breakpoint, selectedSource } = this.props;
// When breakpoint is removed
if (prevProps?.breakpoint && !breakpoint) {
editor.removeLineContentMarker(CONDITIONAL_BP_MARKER);
return;
}
if (selectedSource.id !== location.source.id) {
editor.removeLineContentMarker(CONDITIONAL_BP_MARKER);
return;
}
const editorLine = toEditorLine(location.source.id, location.line || 0);
editor.setLineContentMarker({
id: CONDITIONAL_BP_MARKER,
condition: line => line == editorLine,
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")
);
return this.renderConditionalPanel(this.props, breakpointPanelEditor);
},
});
}

// FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=1774507
UNSAFE_componentWillMount() {
return this.renderToWidget(this.props);
if (features.codemirrorNext) {
this.showConditionalPanel();
} else {
this.renderToWidget(this.props);
}
}

// FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=1774507
UNSAFE_componentWillUpdate() {
return this.clearConditionalPanel();
if (!features.codemirrorNext) {
this.clearConditionalPanel();
}
}

componentDidUpdate() {
componentDidUpdate(prevProps) {
if (features.codemirrorNext) {
this.showConditionalPanel(prevProps);
}
this.keepFocusOnInput();
}

componentWillUnmount() {
// This is called if CodeMirror is re-initializing itself before the
// user closes the conditional panel. Clear the widget, and re-render it
// as soon as this component gets remounted
return this.clearConditionalPanel();
const { editor } = this.props;
if (features.codemirrorNext) {
editor.removeLineContentMarker(CONDITIONAL_BP_MARKER);
} else {
this.clearConditionalPanel();
}
}

renderToWidget(props) {
Expand All @@ -141,7 +185,7 @@ export class ConditionalPanel extends PureComponent {
const editorLine = toEditorLine(location.source.id, location.line || 0);
this.cbPanel = editor.codeMirror.addLineWidget(
editorLine,
this.renderConditionalPanel(props),
this.renderConditionalPanel(props, editor),
{
coverGutter: true,
noHScroll: true,
Expand All @@ -168,8 +212,8 @@ export class ConditionalPanel extends PureComponent {
}
}

createEditor = input => {
const { log, editor, closeConditionalPanel } = this.props;
createEditor = (input, editor) => {
const { log, closeConditionalPanel } = this.props;
const codeMirror = editor.CodeMirror.fromTextArea(input, {
mode: "javascript",
theme: "mozilla",
Expand All @@ -189,8 +233,11 @@ export class ConditionalPanel extends PureComponent {

codeMirror.on("blur", (cm, e) => {
if (
e?.relatedTarget &&
e.relatedTarget.closest(".conditional-breakpoint-panel")
// if there is no actual element getting the focus or the focus is the conditional panel
// do not close the conditional panel
e?.relatedTarget == null ||
(e?.relatedTarget &&
e.relatedTarget.closest(".conditional-breakpoint-panel"))
) {
return;
}
Expand All @@ -217,7 +264,7 @@ export class ConditionalPanel extends PureComponent {
return log ? options.logValue : options.condition;
}

renderConditionalPanel(props) {
renderConditionalPanel(props, editor) {
const { log } = props;
const defaultValue = this.getDefaultValue();

Expand All @@ -239,7 +286,7 @@ export class ConditionalPanel extends PureComponent {
),
textarea({
defaultValue,
ref: input => this.createEditor(input),
ref: input => this.createEditor(input, editor),
})
),
panel
Expand Down
51 changes: 24 additions & 27 deletions devtools/client/debugger/src/components/Editor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ class Editor extends PureComponent {
}
};

componentDidUpdate(prevProps) {
componentDidUpdate() {
const {
selectedSource,
blackboxedRanges,
Expand All @@ -298,30 +298,8 @@ class Editor extends PureComponent {

// Sets the breakables lines for codemirror 6
if (features.codemirrorNext) {
const shouldUpdateBreakableLines =
prevProps.breakableLines.size !== this.props.breakableLines.size ||
prevProps.selectedSource?.id !== selectedSource.id;

const isSourceWasm = isWasm(selectedSource.id);

if (shouldUpdateBreakableLines) {
editor.setLineGutterMarkers([
{
id: "empty-line-marker",
lineClassName: "empty-line",
condition: line => {
const lineNumber = fromEditorLine(
selectedSource.id,
line,
isSourceWasm
);
return !breakableLines.has(lineNumber);
},
},
]);
}

function condition(line) {
function blackboxCondition(line) {
const lineNumber = fromEditorLine(selectedSource.id, line);

return isLineBlackboxed(
Expand All @@ -332,16 +310,29 @@ class Editor extends PureComponent {
}

editor.setLineGutterMarkers([
{
id: "empty-line-marker",
lineClassName: "empty-line",
condition: line => {
const lineNumber = fromEditorLine(
selectedSource.id,
line,
isSourceWasm
);
return !breakableLines.has(lineNumber);
},
},
{
id: "blackboxed-line-gutter-marker",
lineClassName: "blackboxed-line",
condition,
condition: blackboxCondition,
},
]);

editor.setLineContentMarker({
id: "blackboxed-line-marker",
lineClassName: "blackboxed-line",
condition,
condition: blackboxCondition,
});
}
}
Expand Down Expand Up @@ -824,7 +815,13 @@ class Editor extends PureComponent {
editor,
}),
React.createElement(DebugLine, { editor, selectedSource }),
React.createElement(Exceptions, { editor })
React.createElement(Exceptions, { editor }),
conditionalPanelLocation
? React.createElement(ConditionalPanel, {
editor,
selectedSource,
})
: null
);
}

Expand Down
32 changes: 24 additions & 8 deletions devtools/client/shared/sourceeditor/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -707,10 +707,17 @@ class Editor extends EventEmitter {
*/
#lineContentMarkersExtension({ markers, domEventHandlers }) {
const {
codemirrorView: { Decoration, ViewPlugin },
codemirrorView: { Decoration, ViewPlugin, WidgetType },
codemirrorState: { RangeSetBuilder, RangeSet },
} = this.#CodeMirror6;

class LineContentWidget extends WidgetType {
constructor(createElementNode) {
super();
this.toDOM = createElementNode;
}
}

// Build and return the decoration set
function buildDecorations(view) {
if (!markers) {
Expand All @@ -720,13 +727,20 @@ class Editor extends EventEmitter {
for (const { from, to } of view.visibleRanges) {
for (let pos = from; pos <= to; ) {
const line = view.state.doc.lineAt(pos);
for (const { lineClassName, condition } of markers) {
if (condition(line.number)) {
builder.add(
line.from,
line.from,
Decoration.line({ class: lineClassName })
);
for (const marker of markers) {
if (marker.condition(line.number)) {
if (marker.lineClassName) {
const classDecoration = Decoration.line({
class: marker.lineClassName,
});
builder.add(line.from, line.from, classDecoration);
}
if (marker.createLineElementNode) {
const nodeDecoration = Decoration.widget({
widget: new LineContentWidget(marker.createLineElementNode),
});
builder.add(line.to, line.to, nodeDecoration);
}
}
}
pos = line.to + 1;
Expand Down Expand Up @@ -798,6 +812,8 @@ class Editor extends EventEmitter {
* @property {string} marker.lineClassName - The css class to add to the line
* @property {function} marker.condition - The condition that decides if the marker/class gets added or removed.
* The line is passed as an argument.
* @property {function} marker.createLineElementNode - This should return the DOM element which
* is used for the marker. This is optional.
*/
setLineContentMarker(marker) {
const cm = editors.get(this);
Expand Down

0 comments on commit f482d50

Please sign in to comment.