mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 23:02:20 +00:00
Bug 1884651 - [devtools] Rendering debug lines when paused in code mirror 6 r=devtools-reviewers,nchevobbe
In this patch - we begin to render debug lines when paused. - New APIs are added to add and remove line content markers Differential Revision: https://phabricator.services.mozilla.com/D204243
This commit is contained in:
parent
f62619c3ac
commit
334badc332
@ -6,6 +6,7 @@ import { PureComponent } from "devtools/client/shared/vendor/react";
|
||||
import PropTypes from "devtools/client/shared/vendor/react-prop-types";
|
||||
import {
|
||||
toEditorPosition,
|
||||
fromEditorLine,
|
||||
getDocument,
|
||||
hasDocument,
|
||||
startOperation,
|
||||
@ -21,12 +22,16 @@ import {
|
||||
getSourceTextContent,
|
||||
getCurrentThread,
|
||||
} from "../../selectors/index";
|
||||
import { isWasm } from "../../utils/wasm";
|
||||
import { features } from "../../utils/prefs";
|
||||
|
||||
export class DebugLine extends PureComponent {
|
||||
debugExpression;
|
||||
|
||||
static get propTypes() {
|
||||
return {
|
||||
editor: PropTypes.object,
|
||||
selectedSource: PropTypes.object,
|
||||
location: PropTypes.object,
|
||||
why: PropTypes.object,
|
||||
};
|
||||
@ -34,21 +39,62 @@ export class DebugLine extends PureComponent {
|
||||
|
||||
componentDidMount() {
|
||||
const { why, location } = this.props;
|
||||
if (features.codemirrorNext) {
|
||||
return;
|
||||
}
|
||||
this.setDebugLine(why, location);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
const { why, location } = this.props;
|
||||
if (features.codemirrorNext) {
|
||||
return;
|
||||
}
|
||||
this.clearDebugLine(why, location);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { why, location } = this.props;
|
||||
const { why, location, editor, selectedSource } = this.props;
|
||||
|
||||
startOperation();
|
||||
this.clearDebugLine(prevProps.why, prevProps.location);
|
||||
this.setDebugLine(why, location);
|
||||
endOperation();
|
||||
if (!selectedSource) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
prevProps.location == this.props.location &&
|
||||
prevProps.selectedSource?.id == selectedSource?.id
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (features.codemirrorNext) {
|
||||
const { lineClass } = this.getTextClasses(why);
|
||||
// Remove the debug line marker when no longer paused, or the selected source
|
||||
// is no longer the source where the pause occured.
|
||||
if (!location || location.source.id !== selectedSource.id) {
|
||||
editor.removeLineContentMarker("debug-line-marker");
|
||||
} else {
|
||||
const isSourceWasm = isWasm(selectedSource.id);
|
||||
editor.setLineContentMarker({
|
||||
id: "debug-line-marker",
|
||||
lineClassName: lineClass,
|
||||
condition(line) {
|
||||
const lineNumber = fromEditorLine(
|
||||
selectedSource.id,
|
||||
line,
|
||||
isSourceWasm
|
||||
);
|
||||
const editorLocation = toEditorPosition(location);
|
||||
return editorLocation.line == lineNumber;
|
||||
},
|
||||
});
|
||||
}
|
||||
} else {
|
||||
startOperation();
|
||||
this.clearDebugLine(prevProps.why, prevProps.location);
|
||||
this.setDebugLine(why, location);
|
||||
endOperation();
|
||||
}
|
||||
}
|
||||
|
||||
setDebugLine(why, location) {
|
||||
@ -125,7 +171,10 @@ const mapStateToProps = state => {
|
||||
return {};
|
||||
}
|
||||
const sourceTextContent = getSourceTextContent(state, location);
|
||||
if (!isDocumentReady(location, sourceTextContent)) {
|
||||
if (
|
||||
!features.codemirrorNext &&
|
||||
!isDocumentReady(location, sourceTextContent)
|
||||
) {
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
|
@ -121,7 +121,9 @@ html[dir="rtl"] .editor-mount {
|
||||
background-color: var(--debug-expression-error-background);
|
||||
}
|
||||
|
||||
.new-debug-line > .CodeMirror-line {
|
||||
.new-debug-line > .CodeMirror-line,
|
||||
/* For CM6 */
|
||||
.cm-editor .cm-line.new-debug-line {
|
||||
background-color: transparent !important;
|
||||
outline: var(--debug-line-border) solid 1px;
|
||||
}
|
||||
@ -132,7 +134,9 @@ html[dir="rtl"] .editor-mount {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.new-debug-line-error > .CodeMirror-line {
|
||||
.new-debug-line-error > .CodeMirror-line,
|
||||
/* For CM6 */
|
||||
.cm-editor .cm-line.new-debug-line-error {
|
||||
background-color: var(--debug-expression-error-background) !important;
|
||||
outline: var(--debug-line-error-border) solid 1px;
|
||||
}
|
||||
|
@ -794,9 +794,14 @@ class Editor extends PureComponent {
|
||||
const { editor } = this.state;
|
||||
|
||||
if (features.codemirrorNext) {
|
||||
return React.createElement(Breakpoints, {
|
||||
editor,
|
||||
});
|
||||
return React.createElement(
|
||||
React.Fragment,
|
||||
null,
|
||||
React.createElement(Breakpoints, {
|
||||
editor,
|
||||
}),
|
||||
React.createElement(DebugLine, { editor, selectedSource })
|
||||
);
|
||||
}
|
||||
|
||||
if (!selectedSource || !editor || !getDocument(selectedSource.id)) {
|
||||
|
@ -167,6 +167,7 @@ class Editor extends EventEmitter {
|
||||
#prefObserver;
|
||||
#win;
|
||||
#lineGutterMarkers = new Map();
|
||||
#lineContentMarkers = new Map();
|
||||
|
||||
#updateListener = null;
|
||||
|
||||
@ -625,6 +626,7 @@ class Editor extends EventEmitter {
|
||||
const lineWrapCompartment = new Compartment();
|
||||
const lineNumberCompartment = new Compartment();
|
||||
const lineNumberMarkersCompartment = new Compartment();
|
||||
const lineContentMarkerCompartment = new Compartment();
|
||||
|
||||
this.#compartments = {
|
||||
tabSizeCompartment,
|
||||
@ -632,6 +634,7 @@ class Editor extends EventEmitter {
|
||||
lineWrapCompartment,
|
||||
lineNumberCompartment,
|
||||
lineNumberMarkersCompartment,
|
||||
lineContentMarkerCompartment,
|
||||
};
|
||||
|
||||
const indentStr = (this.config.indentWithTabs ? "\t" : " ").repeat(
|
||||
@ -673,6 +676,7 @@ class Editor extends EventEmitter {
|
||||
}
|
||||
}),
|
||||
lineNumberMarkersCompartment.of([]),
|
||||
lineContentMarkerCompartment.of(this.#lineContentMarkersExtension([])),
|
||||
// keep last so other extension take precedence
|
||||
codemirror.minimalSetup,
|
||||
];
|
||||
@ -689,6 +693,98 @@ class Editor extends EventEmitter {
|
||||
editors.set(this, cm);
|
||||
}
|
||||
|
||||
/**
|
||||
* This creates the extension used to manage the rendering of markers
|
||||
* for in editor line content.
|
||||
* @param {Array} markers - The current list of markers
|
||||
* @returns {Array<ViewPlugin>} showLineContentDecorations - An extension which is an array containing the view
|
||||
* which manages the rendering of the line content markers.
|
||||
*/
|
||||
#lineContentMarkersExtension(markers) {
|
||||
const {
|
||||
codemirrorView: { Decoration, ViewPlugin },
|
||||
codemirrorState: { RangeSetBuilder },
|
||||
} = this.#CodeMirror6;
|
||||
|
||||
// Build and return the decoration set
|
||||
function buildDecorations(view) {
|
||||
const builder = new RangeSetBuilder();
|
||||
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 })
|
||||
);
|
||||
}
|
||||
}
|
||||
pos = line.to + 1;
|
||||
}
|
||||
}
|
||||
return builder.finish();
|
||||
}
|
||||
|
||||
// The view which handles rendering and updating the
|
||||
// markers decorations
|
||||
const showLineContentDecorations = ViewPlugin.fromClass(
|
||||
class {
|
||||
decorations;
|
||||
constructor(view) {
|
||||
this.decorations = buildDecorations(view);
|
||||
}
|
||||
update(update) {
|
||||
if (update.docChanged || update.viewportChanged) {
|
||||
this.decorations = buildDecorations(update.view);
|
||||
}
|
||||
}
|
||||
},
|
||||
{ decorations: v => v.decorations }
|
||||
);
|
||||
|
||||
return [showLineContentDecorations];
|
||||
}
|
||||
|
||||
/**
|
||||
* This adds a marker used to add classes to editor line based on a condition.
|
||||
* @property {object} marker - The rule rendering a marker or class.
|
||||
* @property {object} marker.id - The unique identifier for this marker
|
||||
* @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.
|
||||
*/
|
||||
setLineContentMarker(marker) {
|
||||
const cm = editors.get(this);
|
||||
this.#lineContentMarkers.set(marker.id, marker);
|
||||
|
||||
cm.dispatch({
|
||||
effects: this.#compartments.lineContentMarkerCompartment.reconfigure(
|
||||
this.#lineContentMarkersExtension(
|
||||
Array.from(this.#lineContentMarkers.values())
|
||||
)
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* This removes the marker which has the specified className
|
||||
* @param {string} markerId - The unique identifier for this marker
|
||||
*/
|
||||
removeLineContentMarker(markerId) {
|
||||
const cm = editors.get(this);
|
||||
this.#lineContentMarkers.delete(markerId);
|
||||
|
||||
cm.dispatch({
|
||||
effects: this.#compartments.lineContentMarkerCompartment.reconfigure(
|
||||
this.#lineContentMarkersExtension(
|
||||
Array.from(this.#lineContentMarkers.values())
|
||||
)
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set event listeners for the line gutter
|
||||
* @param {Object} domEventHandlers
|
||||
|
Loading…
Reference in New Issue
Block a user