mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 930928 - Shader compilation errors should be displayed in the editor, r=rcampbell,anton
This commit is contained in:
parent
24a44f10ae
commit
fa839ec160
@ -159,7 +159,7 @@ var Scratchpad = {
|
||||
{
|
||||
this._dirty = aValue;
|
||||
if (!aValue && this.editor)
|
||||
this.editor.markClean();
|
||||
this.editor.setClean();
|
||||
this._updateTitle();
|
||||
},
|
||||
|
||||
|
@ -15,6 +15,7 @@ Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
|
||||
const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
|
||||
const promise = require("sdk/core/promise");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const {Tooltip} = require("devtools/shared/widgets/Tooltip");
|
||||
const Editor = require("devtools/sourceeditor/editor");
|
||||
|
||||
// The panel's window global is an EventEmitter firing the following events:
|
||||
@ -31,11 +32,14 @@ const EVENTS = {
|
||||
};
|
||||
|
||||
const STRINGS_URI = "chrome://browser/locale/devtools/shadereditor.properties"
|
||||
const HIGHLIGHT_COLOR = [1, 0, 0, 1];
|
||||
const TYPING_MAX_DELAY = 500;
|
||||
const HIGHLIGHT_COLOR = [1, 0, 0, 1]; // rgba
|
||||
const TYPING_MAX_DELAY = 500; // ms
|
||||
const SHADERS_AUTOGROW_ITEMS = 4;
|
||||
const GUTTER_ERROR_PANEL_OFFSET_X = 7; // px
|
||||
const GUTTER_ERROR_PANEL_DELAY = 100; // ms
|
||||
const DEFAULT_EDITOR_CONFIG = {
|
||||
mode: Editor.modes.text,
|
||||
gutters: ["errors"],
|
||||
lineNumbers: true,
|
||||
showAnnotationRuler: true
|
||||
};
|
||||
@ -426,6 +430,9 @@ let ShadersEditorsView = {
|
||||
*/
|
||||
_onChanged: function(type) {
|
||||
setNamedTimeout("gl-typed", TYPING_MAX_DELAY, () => this._doCompile(type));
|
||||
|
||||
// Remove all the gutter markers and line classes from the editor.
|
||||
this._cleanEditor(type);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -442,13 +449,117 @@ let ShadersEditorsView = {
|
||||
|
||||
try {
|
||||
yield shaderActor.compile(editor.getText());
|
||||
window.emit(EVENTS.SHADER_COMPILED, null);
|
||||
// TODO: remove error gutter markers, after bug 919709 lands.
|
||||
} catch (error) {
|
||||
window.emit(EVENTS.SHADER_COMPILED, error);
|
||||
// TODO: add error gutter markers, after bug 919709 lands.
|
||||
this._onSuccessfulCompilation();
|
||||
} catch (e) {
|
||||
this._onFailedCompilation(type, editor, e);
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Called uppon a successful shader compilation.
|
||||
*/
|
||||
_onSuccessfulCompilation: function() {
|
||||
// Signal that the shader was compiled successfully.
|
||||
window.emit(EVENTS.SHADER_COMPILED, null);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called uppon an unsuccessful shader compilation.
|
||||
*/
|
||||
_onFailedCompilation: function(type, editor, errors) {
|
||||
let lineCount = editor.lineCount();
|
||||
let currentLine = editor.getCursor().line;
|
||||
let listeners = { mouseenter: this._onMarkerMouseEnter };
|
||||
|
||||
function matchLinesAndMessages(string) {
|
||||
return {
|
||||
// First number that is not equal to 0.
|
||||
lineMatch: string.match(/\d{2,}|[1-9]/),
|
||||
// The string after all the numbers, semicolons and spaces.
|
||||
textMatch: string.match(/[^\s\d:][^\r\n|]*/)
|
||||
};
|
||||
}
|
||||
function discardInvalidMatches(e) {
|
||||
// Discard empty line and text matches.
|
||||
return e.lineMatch && e.textMatch;
|
||||
}
|
||||
function sanitizeValidMatches(e) {
|
||||
return {
|
||||
// Drivers might yield retarded line numbers under some obscure
|
||||
// circumstances. Don't throw the errors away in those cases,
|
||||
// just display them on the currently edited line.
|
||||
line: e.lineMatch[0] > lineCount ? currentLine : e.lineMatch[0] - 1,
|
||||
// Trim whitespace from the beginning and the end of the message,
|
||||
// and replace all other occurences of double spaces to a single space.
|
||||
text: e.textMatch[0].trim().replace(/\s{2,}/g, " ")
|
||||
};
|
||||
}
|
||||
function sortByLine(first, second) {
|
||||
// Sort all the errors ascending by their corresponding line number.
|
||||
return first.line > second.line ? 1 : -1;
|
||||
}
|
||||
function groupSameLineMessages(accumulator, current) {
|
||||
// Group errors corresponding to the same line number to a single object.
|
||||
let previous = accumulator[accumulator.length - 1];
|
||||
if (!previous || previous.line != current.line) {
|
||||
return [...accumulator, {
|
||||
line: current.line,
|
||||
messages: [current.text]
|
||||
}];
|
||||
} else {
|
||||
previous.messages.push(current.text);
|
||||
return accumulator;
|
||||
}
|
||||
}
|
||||
function displayErrors({ line, messages }) {
|
||||
// Add gutter markers and line classes for every error in the source.
|
||||
editor.addMarker(line, "errors", "error");
|
||||
editor.setMarkerListeners(line, "errors", "error", listeners, messages);
|
||||
editor.addLineClass(line, "error-line");
|
||||
}
|
||||
|
||||
(this._errors[type] = errors.link
|
||||
.split("ERROR")
|
||||
.map(matchLinesAndMessages)
|
||||
.filter(discardInvalidMatches)
|
||||
.map(sanitizeValidMatches)
|
||||
.sort(sortByLine)
|
||||
.reduce(groupSameLineMessages, []))
|
||||
.forEach(displayErrors);
|
||||
|
||||
// Signal that the shader wasn't compiled successfully.
|
||||
window.emit(EVENTS.SHADER_COMPILED, errors);
|
||||
},
|
||||
|
||||
/**
|
||||
* Event listener for the 'mouseenter' event on a marker in the editor gutter.
|
||||
*/
|
||||
_onMarkerMouseEnter: function(line, node, messages) {
|
||||
if (node._markerErrorsTooltip) {
|
||||
return;
|
||||
}
|
||||
|
||||
let tooltip = node._markerErrorsTooltip = new Tooltip(document);
|
||||
tooltip.defaultOffsetX = GUTTER_ERROR_PANEL_OFFSET_X;
|
||||
tooltip.setTextContent.apply(tooltip, messages);
|
||||
tooltip.startTogglingOnHover(node, () => true, GUTTER_ERROR_PANEL_DELAY);
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes all the gutter markers and line classes from the editor.
|
||||
*/
|
||||
_cleanEditor: function(type) {
|
||||
this._getEditor(type).then(editor => {
|
||||
editor.removeAllMarkers("errors");
|
||||
this._errors[type].forEach(e => editor.removeLineClass(e.line));
|
||||
this._errors[type].length = 0;
|
||||
});
|
||||
},
|
||||
|
||||
_errors: {
|
||||
vs: [],
|
||||
fs: []
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -9,6 +9,8 @@ support-files =
|
||||
[browser_se_aaa_run_first_leaktest.js]
|
||||
[browser_se_bfcache.js]
|
||||
[browser_se_editors-contents.js]
|
||||
[browser_se_editors-error-gutter.js]
|
||||
[browser_se_editors-error-tooltip.js]
|
||||
[browser_se_editors-lazy-init.js]
|
||||
[browser_se_first-run.js]
|
||||
[browser_se_navigation.js]
|
||||
|
@ -0,0 +1,156 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests if error indicators are shown in the editor's gutter and text area
|
||||
* when there's a shader compilation error.
|
||||
*/
|
||||
|
||||
function ifWebGLSupported() {
|
||||
let [target, debuggee, panel] = yield initShaderEditor(SIMPLE_CANVAS_URL);
|
||||
let { gFront, EVENTS, ShadersEditorsView } = panel.panelWin;
|
||||
|
||||
reload(target);
|
||||
yield once(gFront, "program-linked");
|
||||
|
||||
let vsEditor = yield ShadersEditorsView._getEditor("vs");
|
||||
let fsEditor = yield ShadersEditorsView._getEditor("fs");
|
||||
|
||||
vsEditor.replaceText("vec3", { line: 7, ch: 22 }, { line: 7, ch: 26 });
|
||||
let vertError = yield once(panel.panelWin, EVENTS.SHADER_COMPILED);
|
||||
checkHasVertFirstError(true, vertError);
|
||||
checkHasVertSecondError(false, vertError);
|
||||
info("Error marks added in the vertex shader editor.");
|
||||
|
||||
vsEditor.insertText(" ", { line: 1, ch: 0 });
|
||||
is(vsEditor.getText(1), " precision lowp float;", "Typed space.");
|
||||
checkHasVertFirstError(false, vertError);
|
||||
checkHasVertSecondError(false, vertError);
|
||||
info("Error marks removed while typing in the vertex shader editor.");
|
||||
|
||||
let vertError = yield once(panel.panelWin, EVENTS.SHADER_COMPILED);
|
||||
checkHasVertFirstError(true, vertError);
|
||||
checkHasVertSecondError(false, vertError);
|
||||
info("Error marks were re-added after recompiling the vertex shader.");
|
||||
|
||||
fsEditor.replaceText("vec4", { line: 2, ch: 14 }, { line: 2, ch: 18 });
|
||||
let fragError = yield once(panel.panelWin, EVENTS.SHADER_COMPILED);
|
||||
checkHasVertFirstError(true, vertError);
|
||||
checkHasVertSecondError(false, vertError);
|
||||
checkHasFragError(true, fragError);
|
||||
info("Error marks added in the fragment shader editor.");
|
||||
|
||||
fsEditor.insertText(" ", { line: 1, ch: 0 });
|
||||
is(fsEditor.getText(1), " precision lowp float;", "Typed space.");
|
||||
checkHasVertFirstError(true, vertError);
|
||||
checkHasVertSecondError(false, vertError);
|
||||
checkHasFragError(false, fragError);
|
||||
info("Error marks removed while typing in the fragment shader editor.");
|
||||
|
||||
let fragError = yield once(panel.panelWin, EVENTS.SHADER_COMPILED);
|
||||
checkHasVertFirstError(true, vertError);
|
||||
checkHasVertSecondError(false, vertError);
|
||||
checkHasFragError(true, fragError);
|
||||
info("Error marks were re-added after recompiling the fragment shader.");
|
||||
|
||||
vsEditor.replaceText("2", { line: 3, ch: 19 }, { line: 3, ch: 20 });
|
||||
checkHasVertFirstError(false, vertError);
|
||||
checkHasVertSecondError(false, vertError);
|
||||
checkHasFragError(true, fragError);
|
||||
info("Error marks removed while typing in the vertex shader editor again.");
|
||||
|
||||
let vertError = yield once(panel.panelWin, EVENTS.SHADER_COMPILED);
|
||||
checkHasVertFirstError(true, vertError);
|
||||
checkHasVertSecondError(true, vertError);
|
||||
checkHasFragError(true, fragError);
|
||||
info("Error marks were re-added after recompiling the fragment shader again.");
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
|
||||
function checkHasVertFirstError(bool, error) {
|
||||
ok(error, "Vertex shader compiled with errors.");
|
||||
isnot(error.link, "", "The linkage status should not be empty.");
|
||||
|
||||
let line = 7;
|
||||
info("Checking first vertex shader error on line " + line + "...");
|
||||
|
||||
is(vsEditor.hasMarker(line, "errors", "error"), bool,
|
||||
"Error is " + (bool ? "" : "not ") + "shown in the editor's gutter.");
|
||||
is(vsEditor.hasLineClass(line, "error-line"), bool,
|
||||
"Error style is " + (bool ? "" : "not ") + "applied to the faulty line.");
|
||||
|
||||
let parsed = ShadersEditorsView._errors.vs;
|
||||
is(parsed.length >= 1, bool,
|
||||
"There's " + (bool ? ">= 1" : "< 1") + " parsed vertex shader error(s).");
|
||||
|
||||
if (bool) {
|
||||
is(parsed[0].line, line,
|
||||
"The correct line was parsed.");
|
||||
is(parsed[0].messages.length, 2,
|
||||
"There are 2 parsed messages.");
|
||||
ok(parsed[0].messages[0].contains("'constructor' : too many arguments"),
|
||||
"The correct first message was parsed.");
|
||||
ok(parsed[0].messages[1].contains("'assign' : cannot convert from"),
|
||||
"The correct second message was parsed.");
|
||||
}
|
||||
}
|
||||
|
||||
function checkHasVertSecondError(bool, error) {
|
||||
ok(error, "Vertex shader compiled with errors.");
|
||||
isnot(error.link, "", "The linkage status should not be empty.");
|
||||
|
||||
let line = 8;
|
||||
info("Checking second vertex shader error on line " + line + "...");
|
||||
|
||||
is(vsEditor.hasMarker(line, "errors", "error"), bool,
|
||||
"Error is " + (bool ? "" : "not ") + "shown in the editor's gutter.");
|
||||
is(vsEditor.hasLineClass(line, "error-line"), bool,
|
||||
"Error style is " + (bool ? "" : "not ") + "applied to the faulty line.");
|
||||
|
||||
let parsed = ShadersEditorsView._errors.vs;
|
||||
is(parsed.length >= 2, bool,
|
||||
"There's " + (bool ? ">= 2" : "< 2") + " parsed vertex shader error(s).");
|
||||
|
||||
if (bool) {
|
||||
is(parsed[1].line, line,
|
||||
"The correct line was parsed.");
|
||||
is(parsed[1].messages.length, 1,
|
||||
"There is 1 parsed message.");
|
||||
ok(parsed[1].messages[0].contains("'assign' : cannot convert from"),
|
||||
"The correct message was parsed.");
|
||||
}
|
||||
}
|
||||
|
||||
function checkHasFragError(bool, error) {
|
||||
ok(error, "Fragment shader compiled with errors.");
|
||||
isnot(error.link, "", "The linkage status should not be empty.");
|
||||
|
||||
let line = 5;
|
||||
info("Checking first vertex shader error on line " + line + "...");
|
||||
|
||||
is(fsEditor.hasMarker(line, "errors", "error"), bool,
|
||||
"Error is " + (bool ? "" : "not ") + "shown in the editor's gutter.");
|
||||
is(fsEditor.hasLineClass(line, "error-line"), bool,
|
||||
"Error style is " + (bool ? "" : "not ") + "applied to the faulty line.");
|
||||
|
||||
let parsed = ShadersEditorsView._errors.fs;
|
||||
is(parsed.length >= 1, bool,
|
||||
"There's " + (bool ? ">= 2" : "< 1") + " parsed fragment shader error(s).");
|
||||
|
||||
if (bool) {
|
||||
is(parsed[0].line, line,
|
||||
"The correct line was parsed.");
|
||||
is(parsed[0].messages.length, 1,
|
||||
"There is 1 parsed message.");
|
||||
ok(parsed[0].messages[0].contains("'constructor' : too many arguments"),
|
||||
"The correct message was parsed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function once(aTarget, aEvent) {
|
||||
let deferred = promise.defer();
|
||||
aTarget.once(aEvent, (aName, aData) => deferred.resolve(aData));
|
||||
return deferred.promise;
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests if error tooltips can be opened from the editor's gutter when there's
|
||||
* a shader compilation error.
|
||||
*/
|
||||
|
||||
function ifWebGLSupported() {
|
||||
let [target, debuggee, panel] = yield initShaderEditor(SIMPLE_CANVAS_URL);
|
||||
let { gFront, EVENTS, ShadersEditorsView } = panel.panelWin;
|
||||
|
||||
reload(target);
|
||||
yield once(gFront, "program-linked");
|
||||
|
||||
let vsEditor = yield ShadersEditorsView._getEditor("vs");
|
||||
let fsEditor = yield ShadersEditorsView._getEditor("fs");
|
||||
|
||||
vsEditor.replaceText("vec3", { line: 7, ch: 22 }, { line: 7, ch: 26 });
|
||||
yield once(panel.panelWin, EVENTS.SHADER_COMPILED);
|
||||
|
||||
// Synthesizing 'mouseenter' events doesn't work, hack around this by
|
||||
// manually calling the event listener with the expected arguments.
|
||||
let editorDocument = vsEditor.container.contentDocument;
|
||||
let marker = editorDocument.querySelector(".error");
|
||||
let parsed = ShadersEditorsView._errors.vs[0].messages;
|
||||
ShadersEditorsView._onMarkerMouseEnter(7, marker, parsed);
|
||||
|
||||
let tooltip = marker._markerErrorsTooltip;
|
||||
ok(tooltip, "A tooltip was created successfully.");
|
||||
|
||||
let content = tooltip.content;
|
||||
ok(tooltip.content,
|
||||
"Some tooltip's content was set.");
|
||||
is(tooltip.content.className, "devtools-tooltip-simple-text-container",
|
||||
"The tooltip's content container was created correctly.");
|
||||
|
||||
let messages = content.childNodes;
|
||||
is(messages.length, 2,
|
||||
"There are two messages displayed in the tooltip.");
|
||||
is(messages[0].className, "devtools-tooltip-simple-text",
|
||||
"The first message was created correctly.");
|
||||
is(messages[1].className, "devtools-tooltip-simple-text",
|
||||
"The second message was created correctly.");
|
||||
|
||||
ok(messages[0].textContent.contains("'constructor' : too many arguments"),
|
||||
"The first message contains the correct text.");
|
||||
ok(messages[1].textContent.contains("'assign' : cannot convert"),
|
||||
"The second message contains the correct text.");
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
}
|
||||
|
||||
function once(aTarget, aEvent) {
|
||||
let deferred = promise.defer();
|
||||
aTarget.once(aEvent, (aName, aData) => deferred.resolve(aData));
|
||||
return deferred.promise;
|
||||
}
|
@ -2,7 +2,8 @@
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests if editing a vertex and a fragment shader works properly.
|
||||
* Tests if editing a vertex and a fragment shader would permanently store
|
||||
* their new source on the backend and reshow it in the frontend when required.
|
||||
*/
|
||||
|
||||
function ifWebGLSupported() {
|
||||
|
@ -95,6 +95,10 @@ function Tooltip(doc) {
|
||||
module.exports.Tooltip = Tooltip;
|
||||
|
||||
Tooltip.prototype = {
|
||||
defaultPosition: "before_start",
|
||||
defaultOffsetX: 0,
|
||||
defaultOffsetY: 0,
|
||||
|
||||
/**
|
||||
* Show the tooltip. It might be wise to append some content first if you
|
||||
* don't want the tooltip to be empty. You may access the content of the
|
||||
@ -105,9 +109,12 @@ Tooltip.prototype = {
|
||||
* https://developer.mozilla.org/en-US/docs/XUL/PopupGuide/Positioning
|
||||
* Defaults to before_start
|
||||
*/
|
||||
show: function(anchor, position="before_start") {
|
||||
show: function(anchor,
|
||||
position = this.defaultPosition,
|
||||
x = this.defaultOffsetX,
|
||||
y = this.defaultOffsetY) {
|
||||
this.panel.hidden = false;
|
||||
this.panel.openPopup(anchor, position);
|
||||
this.panel.openPopup(anchor, position, x, y);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -257,6 +264,28 @@ Tooltip.prototype = {
|
||||
return this.panel.firstChild;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets some text as the content of this tooltip.
|
||||
*
|
||||
* @param string[] messages
|
||||
* A list of text messages.
|
||||
*/
|
||||
setTextContent: function(...messages) {
|
||||
let vbox = this.doc.createElement("vbox");
|
||||
vbox.className = "devtools-tooltip-simple-text-container";
|
||||
vbox.setAttribute("flex", "1");
|
||||
|
||||
for (let text of messages) {
|
||||
let description = this.doc.createElement("description");
|
||||
description.setAttribute("flex", "1");
|
||||
description.className = "devtools-tooltip-simple-text";
|
||||
description.textContent = text;
|
||||
vbox.appendChild(description);
|
||||
}
|
||||
|
||||
this.content = vbox;
|
||||
},
|
||||
|
||||
/**
|
||||
* Fill the tooltip with an image, displayed over a tiled background useful
|
||||
* for transparent images.
|
||||
|
@ -1,15 +1,25 @@
|
||||
/* 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/. */
|
||||
|
||||
.errors,
|
||||
.breakpoints {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.breakpoint, .debugLocation, .breakpoint-debugLocation {
|
||||
.error, .breakpoint, .debugLocation, .breakpoint-debugLocation {
|
||||
display: inline-block;
|
||||
margin-left: 5px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
background-size: 12px;
|
||||
background-position: center;
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
.error {
|
||||
background-image: url("chrome://browser/skin/devtools/orion-error.png");
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
.breakpoint {
|
||||
@ -23,4 +33,8 @@
|
||||
.breakpoint.debugLocation {
|
||||
background-image: url("chrome://browser/skin/devtools/orion-debug-location.png"),
|
||||
url("chrome://browser/skin/devtools/orion-breakpoint.png");
|
||||
}
|
||||
}
|
||||
|
||||
.error-line {
|
||||
background: rgba(255,0,0,0.2);
|
||||
}
|
||||
|
@ -6,38 +6,6 @@
|
||||
|
||||
const dbginfo = new WeakMap();
|
||||
|
||||
// Private functions
|
||||
|
||||
/**
|
||||
* Adds a marker to the breakpoints gutter.
|
||||
* Type should be either a 'breakpoint' or a 'debugLocation'.
|
||||
*/
|
||||
function addMarker(cm, line, type) {
|
||||
let info = cm.lineInfo(line);
|
||||
|
||||
if (info.gutterMarkers)
|
||||
return void info.gutterMarkers.breakpoints.classList.add(type);
|
||||
|
||||
let mark = cm.getWrapperElement().ownerDocument.createElement("div");
|
||||
mark.className = type;
|
||||
mark.innerHTML = "";
|
||||
|
||||
cm.setGutterMarker(info.line, "breakpoints", mark);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a marker from the breakpoints gutter.
|
||||
* Type should be either a 'breakpoint' or a 'debugLocation'.
|
||||
*/
|
||||
function removeMarker(cm, line, type) {
|
||||
let info = cm.lineInfo(line);
|
||||
|
||||
if (!info || !info.gutterMarkers)
|
||||
return;
|
||||
|
||||
info.gutterMarkers.breakpoints.classList.remove(type);
|
||||
}
|
||||
|
||||
// These functions implement search within the debugger. Since
|
||||
// search in the debugger is different from other components,
|
||||
// we can't use search.js CodeMirror addon. This is a slightly
|
||||
@ -155,7 +123,7 @@ function addBreakpoint(ctx, line, cond) {
|
||||
let meta = dbginfo.get(ed);
|
||||
let info = cm.lineInfo(line);
|
||||
|
||||
addMarker(cm, line, "breakpoint");
|
||||
ed.addMarker(line, "breakpoints", "breakpoint");
|
||||
meta.breakpoints[line] = { condition: cond };
|
||||
|
||||
info.handle.on("delete", function onDelete() {
|
||||
@ -179,7 +147,7 @@ function removeBreakpoint(ctx, line) {
|
||||
let info = cm.lineInfo(line);
|
||||
|
||||
meta.breakpoints[info.line] = null;
|
||||
removeMarker(cm, info.line, "breakpoint");
|
||||
ed.removeMarker(info.line, "breakpoints", "breakpoint");
|
||||
ed.emit("breakpointRemoved", line);
|
||||
}
|
||||
|
||||
@ -203,11 +171,11 @@ function getBreakpoints(ctx) {
|
||||
* display the line on which the Debugger is currently paused.
|
||||
*/
|
||||
function setDebugLocation(ctx, line) {
|
||||
let { ed, cm } = ctx;
|
||||
let { ed } = ctx;
|
||||
let meta = dbginfo.get(ed);
|
||||
|
||||
meta.debugLocation = line;
|
||||
addMarker(cm, line, "debugLocation");
|
||||
ed.addMarker(line, "breakpoints", "debugLocation");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -226,11 +194,11 @@ function getDebugLocation(ctx) {
|
||||
* also removes a visual anchor from the breakpoints gutter.
|
||||
*/
|
||||
function clearDebugLocation(ctx) {
|
||||
let { ed, cm } = ctx;
|
||||
let { ed } = ctx;
|
||||
let meta = dbginfo.get(ed);
|
||||
|
||||
if (meta.debugLocation != null) {
|
||||
removeMarker(cm, meta.debugLocation, "debugLocation");
|
||||
ed.removeMarker(meta.debugLocation, "breakpoints", "debugLocation");
|
||||
meta.debugLocation = null;
|
||||
}
|
||||
}
|
||||
|
@ -340,7 +340,7 @@ Editor.prototype = {
|
||||
* Replaces contents of a text area within the from/to {line, ch}
|
||||
* range. If neither from nor to arguments are provided works
|
||||
* exactly like setText. If only from object is provided, inserts
|
||||
* text at that point.
|
||||
* text at that point, *overwriting* as many characters as needed.
|
||||
*/
|
||||
replaceText: function (value, from, to) {
|
||||
let cm = editors.get(this);
|
||||
@ -356,6 +356,15 @@ Editor.prototype = {
|
||||
cm.replaceRange(value, from, to);
|
||||
},
|
||||
|
||||
/**
|
||||
* Inserts text at the specified {line, ch} position, shifting existing
|
||||
* contents as necessary.
|
||||
*/
|
||||
insertText: function (value, at) {
|
||||
let cm = editors.get(this);
|
||||
cm.replaceRange(value, at, at);
|
||||
},
|
||||
|
||||
/**
|
||||
* Deselects contents of the text area.
|
||||
*/
|
||||
@ -370,7 +379,7 @@ Editor.prototype = {
|
||||
* Marks the contents as clean and returns the current
|
||||
* version number.
|
||||
*/
|
||||
markClean: function () {
|
||||
setClean: function () {
|
||||
let cm = editors.get(this);
|
||||
this.version = cm.changeGeneration();
|
||||
return this.version;
|
||||
@ -519,6 +528,120 @@ Editor.prototype = {
|
||||
this.setFirstVisibleLine(topLine);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns whether a marker of a specified class exists in a line's gutter.
|
||||
*/
|
||||
hasMarker: function (line, gutterName, markerClass) {
|
||||
let cm = editors.get(this);
|
||||
let info = cm.lineInfo(line);
|
||||
if (!info)
|
||||
return false;
|
||||
|
||||
let gutterMarkers = info.gutterMarkers;
|
||||
if (!gutterMarkers)
|
||||
return false;
|
||||
|
||||
let marker = gutterMarkers[gutterName];
|
||||
if (!marker)
|
||||
return false;
|
||||
|
||||
return marker.classList.contains(markerClass);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a marker with a specified class to a line's gutter. If another marker
|
||||
* exists on that line, the new marker class is added to its class list.
|
||||
*/
|
||||
addMarker: function (line, gutterName, markerClass) {
|
||||
let cm = editors.get(this);
|
||||
let info = cm.lineInfo(line);
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
let gutterMarkers = info.gutterMarkers;
|
||||
if (gutterMarkers) {
|
||||
let marker = gutterMarkers[gutterName];
|
||||
if (marker) {
|
||||
marker.classList.add(markerClass);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let marker = cm.getWrapperElement().ownerDocument.createElement("div");
|
||||
marker.className = markerClass;
|
||||
cm.setGutterMarker(info.line, gutterName, marker);
|
||||
},
|
||||
|
||||
/**
|
||||
* The reverse of addMarker. Removes a marker of a specified class from a
|
||||
* line's gutter.
|
||||
*/
|
||||
removeMarker: function (line, gutterName, markerClass) {
|
||||
if (!this.hasMarker(line, gutterName, markerClass))
|
||||
return;
|
||||
|
||||
let cm = editors.get(this);
|
||||
cm.lineInfo(line).gutterMarkers[gutterName].classList.remove(markerClass);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove all gutter markers in the gutter with the given name.
|
||||
*/
|
||||
removeAllMarkers: function (gutterName) {
|
||||
let cm = editors.get(this);
|
||||
cm.clearGutter(gutterName);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles attaching a set of events listeners on a marker. They should
|
||||
* be passed as an object literal with keys as event names and values as
|
||||
* function listeners. The line number, marker node and optional data
|
||||
* will be passed as arguments to the function listener.
|
||||
*
|
||||
* You don't need to worry about removing these event listeners.
|
||||
* They're automatically orphaned when clearing markers.
|
||||
*/
|
||||
setMarkerListeners: function(line, gutterName, markerClass, events, data) {
|
||||
if (!this.hasMarker(line, gutterName, markerClass))
|
||||
return;
|
||||
|
||||
let cm = editors.get(this);
|
||||
let marker = cm.lineInfo(line).gutterMarkers[gutterName];
|
||||
|
||||
for (let name in events) {
|
||||
let listener = events[name].bind(this, line, marker, data);
|
||||
marker.addEventListener(name, listener);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns whether a line is decorated using the specified class name.
|
||||
*/
|
||||
hasLineClass: function (line, className) {
|
||||
let cm = editors.get(this);
|
||||
let info = cm.lineInfo(line);
|
||||
if (!info)
|
||||
return false;
|
||||
|
||||
return info.wrapClass == className;
|
||||
},
|
||||
|
||||
/**
|
||||
* Set a CSS class name for the given line, including the text and gutter.
|
||||
*/
|
||||
addLineClass: function (line, className) {
|
||||
let cm = editors.get(this);
|
||||
cm.addLineClass(line, "wrap", className);
|
||||
},
|
||||
|
||||
/**
|
||||
* The reverse of addLineClass.
|
||||
*/
|
||||
removeLineClass: function (line, className) {
|
||||
let cm = editors.get(this);
|
||||
cm.removeLineClass(line, "wrap", className);
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
this.container = null;
|
||||
this.config = null;
|
||||
|
@ -376,7 +376,7 @@ StyleSheetEditor.prototype = {
|
||||
if (callback) {
|
||||
callback(returnFile);
|
||||
}
|
||||
this.sourceEditor.markClean();
|
||||
this.sourceEditor.setClean();
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
|
BIN
browser/themes/linux/devtools/orion-error.png
Normal file
BIN
browser/themes/linux/devtools/orion-error.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
@ -143,6 +143,7 @@ browser.jar:
|
||||
skin/classic/browser/devtools/orion.css (devtools/orion.css)
|
||||
skin/classic/browser/devtools/orion-container.css (devtools/orion-container.css)
|
||||
skin/classic/browser/devtools/orion-task.png (devtools/orion-task.png)
|
||||
skin/classic/browser/devtools/orion-error.png (devtools/orion-error.png)
|
||||
skin/classic/browser/devtools/orion-breakpoint.png (devtools/orion-breakpoint.png)
|
||||
skin/classic/browser/devtools/orion-debug-location.png (devtools/orion-debug-location.png)
|
||||
skin/classic/browser/devtools/breadcrumbs-scrollbutton.png (devtools/breadcrumbs-scrollbutton.png)
|
||||
|
BIN
browser/themes/osx/devtools/orion-error.png
Normal file
BIN
browser/themes/osx/devtools/orion-error.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
@ -232,6 +232,7 @@ browser.jar:
|
||||
skin/classic/browser/devtools/orion.css (devtools/orion.css)
|
||||
skin/classic/browser/devtools/orion-container.css (devtools/orion-container.css)
|
||||
skin/classic/browser/devtools/orion-task.png (devtools/orion-task.png)
|
||||
skin/classic/browser/devtools/orion-error.png (devtools/orion-error.png)
|
||||
skin/classic/browser/devtools/orion-breakpoint.png (devtools/orion-breakpoint.png)
|
||||
skin/classic/browser/devtools/orion-debug-location.png (devtools/orion-debug-location.png)
|
||||
* skin/classic/browser/devtools/webconsole.css (devtools/webconsole.css)
|
||||
|
@ -121,11 +121,29 @@
|
||||
background: #eee;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.devtools-tooltip.devtools-tooltip-panel .panel-arrowcontent {
|
||||
/* If the tooltip uses a <panel> XUL element instead */
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.devtools-tooltip-simple-text {
|
||||
background: linear-gradient(1deg, transparent 0%, rgba(94,136,176,0.1) 100%);
|
||||
max-width: 400px;
|
||||
margin: 0 -4px; /* Compensate for the .panel-arrowcontent padding. */
|
||||
padding: 8px 12px;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.devtools-tooltip-simple-text:first-child {
|
||||
margin-top: -4px;
|
||||
}
|
||||
|
||||
.devtools-tooltip-simple-text:last-child {
|
||||
margin-bottom: -4px;
|
||||
}
|
||||
|
||||
.devtools-tooltip-tiles {
|
||||
background-color: #eee;
|
||||
background-image: linear-gradient(45deg, #ccc 25%, transparent 25%, transparent 75%, #ccc 75%, #ccc),
|
||||
|
BIN
browser/themes/windows/devtools/orion-error.png
Normal file
BIN
browser/themes/windows/devtools/orion-error.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
@ -167,6 +167,7 @@ browser.jar:
|
||||
skin/classic/browser/devtools/orion.css (devtools/orion.css)
|
||||
skin/classic/browser/devtools/orion-container.css (devtools/orion-container.css)
|
||||
skin/classic/browser/devtools/orion-task.png (devtools/orion-task.png)
|
||||
skin/classic/browser/devtools/orion-error.png (devtools/orion-error.png)
|
||||
skin/classic/browser/devtools/orion-breakpoint.png (devtools/orion-breakpoint.png)
|
||||
skin/classic/browser/devtools/orion-debug-location.png (devtools/orion-debug-location.png)
|
||||
* skin/classic/browser/devtools/webconsole.css (devtools/webconsole.css)
|
||||
@ -444,6 +445,7 @@ browser.jar:
|
||||
skin/classic/aero/browser/devtools/orion.css (devtools/orion.css)
|
||||
skin/classic/aero/browser/devtools/orion-container.css (devtools/orion-container.css)
|
||||
skin/classic/aero/browser/devtools/orion-task.png (devtools/orion-task.png)
|
||||
skin/classic/aero/browser/devtools/orion-error.png (devtools/orion-error.png)
|
||||
skin/classic/aero/browser/devtools/orion-breakpoint.png (devtools/orion-breakpoint.png)
|
||||
skin/classic/aero/browser/devtools/orion-debug-location.png (devtools/orion-debug-location.png)
|
||||
* skin/classic/aero/browser/devtools/webconsole.css (devtools/webconsole.css)
|
||||
|
Loading…
Reference in New Issue
Block a user