kopia lustrzana https://github.com/c9/core
284 wiersze
11 KiB
JavaScript
284 wiersze
11 KiB
JavaScript
/**
|
|
* Cloud9 Language Foundation
|
|
*
|
|
* @copyright 2013, Ajax.org B.V.
|
|
*/
|
|
define(function(require, exports, module) {
|
|
main.consumes = [
|
|
"Plugin", "tabManager", "language", "ui", "dialog.error"
|
|
];
|
|
main.provides = ["language.marker"];
|
|
return main;
|
|
|
|
function main(options, imports, register) {
|
|
var language = imports.language;
|
|
var tabs = imports.tabManager;
|
|
var ui = imports.ui;
|
|
var showError = imports["dialog.error"].show;
|
|
|
|
var Range = require("ace/range").Range;
|
|
var Anchor = require('ace/anchor').Anchor;
|
|
var comparePoints = Range.comparePoints;
|
|
|
|
var MAX_COLUMN = 5000;
|
|
|
|
function SimpleAnchor(row, column) {
|
|
this.row = row;
|
|
this.column = column || 0;
|
|
}
|
|
|
|
SimpleAnchor.prototype.onChange = Anchor.prototype.onChange;
|
|
SimpleAnchor.prototype.setPosition = function(row, column) {
|
|
this.row = row;
|
|
this.column = column;
|
|
};
|
|
|
|
language.once("initWorker", function(e) {
|
|
ui.insertCss(require("text!./marker.css"), language);
|
|
|
|
var lastStaticMarkers = [];
|
|
var lastHighlightMarkers = [];
|
|
var lastHighlightMarkersString = "[]";
|
|
var lastStaticMarkersTab = null;
|
|
var lastHighlightMarkersTab = null;
|
|
|
|
e.worker.on("markers", function(event) {
|
|
var tab = tabs.findTab(event.data.path);
|
|
if (!tab) return;
|
|
|
|
var editor = tab.editor;
|
|
// TODO for background tabs editor.ace.session is wrong
|
|
if (tab.document !== editor.ace.session.c9doc)
|
|
return;
|
|
lastStaticMarkers = event.data;
|
|
lastStaticMarkersTab = tab;
|
|
var markers = lastHighlightMarkersTab === tab
|
|
? lastStaticMarkers.concat(lastHighlightMarkers)
|
|
: lastStaticMarkers;
|
|
addMarkers(markers, editor.ace);
|
|
});
|
|
e.worker.on("highlightMarkers", function(event) {
|
|
var tab = tabs.findTab(event.data.path);
|
|
if (!tab) return;
|
|
|
|
var editor = tab.editor;
|
|
|
|
// Use a poor man's deep equals to check for changes
|
|
// since we don't want to reposition old error markers
|
|
// needlessly
|
|
var string = JSON.stringify(event.data);
|
|
if (lastHighlightMarkersTab === tab && string === lastHighlightMarkersString)
|
|
return;
|
|
lastHighlightMarkers = event.data;
|
|
lastHighlightMarkersString = string;
|
|
lastHighlightMarkersTab = tab;
|
|
var markers = lastStaticMarkersTab === tab
|
|
? lastHighlightMarkers.concat(lastStaticMarkers)
|
|
: lastHighlightMarkers;
|
|
addMarkers(markers, editor.ace);
|
|
});
|
|
|
|
e.worker.on("change", function(event, worker) {
|
|
onChange(worker.$doc, event);
|
|
});
|
|
});
|
|
|
|
var disabledMarkerTypes = {};
|
|
|
|
function removeMarkers(session) {
|
|
var markers = session.markerAnchors;
|
|
for (var i = 0; i < markers.length; i++) {
|
|
session.removeMarker(markers[i].id);
|
|
}
|
|
session.markerAnchors = [];
|
|
session.setAnnotations([]);
|
|
}
|
|
|
|
|
|
function addMarkers(annos, editor) {
|
|
if (!editor)
|
|
return;
|
|
|
|
var ignoredMarkers = language.getIgnoredMarkers();
|
|
var mySession = editor.session;
|
|
if (!mySession.markerAnchors) mySession.markerAnchors = [];
|
|
removeMarkers(mySession);
|
|
mySession.languageAnnos = [];
|
|
|
|
var lastLine = mySession.getDocument().getLength() - 1;
|
|
var sel = editor.getSelectionRange();
|
|
var showOccurenceMarkers = !editor.inMultiSelectMode
|
|
&& (sel.isEmpty() ? true : sel.isMultiLine() ? false : null);
|
|
var occurrenceMarkers = [];
|
|
var ignoreInfoMarkers = annos.length > 1000;
|
|
annos.forEach(function(anno) {
|
|
// Certain annotations can temporarily be disabled
|
|
if (disabledMarkerTypes[anno.type])
|
|
return;
|
|
if (ignoreInfoMarkers && anno.type == "info")
|
|
return;
|
|
// Multi-line markers are not supported, and typically are a result from a bad error recover, ignore
|
|
if (anno.pos.el && anno.pos.sl !== anno.pos.el)
|
|
return;
|
|
|
|
var pos = anno.pos || {};
|
|
|
|
if (pos.sl > lastLine)
|
|
pos.sl = lastLine;
|
|
|
|
if (pos.sc > MAX_COLUMN)
|
|
return;
|
|
|
|
var range = new Range(pos.sl, pos.sc || 0, pos.el, pos.ec || 0);
|
|
if (anno.type == "occurrence_other" || anno.type == "occurrence_main") {
|
|
if (!showOccurenceMarkers) {
|
|
if (showOccurenceMarkers === false)
|
|
return;
|
|
if (range.containsRange(sel))
|
|
showOccurenceMarkers = true;
|
|
occurrenceMarkers.push(mySession.markerAnchors.length);
|
|
}
|
|
}
|
|
|
|
mySession.markerAnchors.push(anno);
|
|
|
|
anno.start = new SimpleAnchor(pos.sl, pos.sc);
|
|
|
|
if (pos.sc !== undefined && pos.ec !== undefined) {
|
|
anno.range = range;
|
|
anno.id = mySession.addMarker(anno.range, "language_highlight_" + (anno.type ? anno.type : "default"));
|
|
anno.range.start = anno.start;
|
|
anno.colDiff = pos.ec - pos.sc;
|
|
anno.rowDiff = pos.el - pos.sl;
|
|
}
|
|
|
|
try {
|
|
if (!anno.message || anno.message.match(ignoredMarkers))
|
|
return;
|
|
}
|
|
catch (e) {
|
|
showError("Illegal ignore message filter: " + e.message);
|
|
}
|
|
var gutterAnno = {
|
|
guttertext: anno.message,
|
|
type: anno.type || anno.level || "warning",
|
|
text: anno.message,
|
|
pos: anno.pos,
|
|
resolutions: anno.resolutions,
|
|
row: pos.sl
|
|
};
|
|
anno.gutterAnno = gutterAnno;
|
|
mySession.languageAnnos.push(gutterAnno);
|
|
});
|
|
|
|
if (!showOccurenceMarkers) {
|
|
for (var i = occurrenceMarkers.length; i--;) {
|
|
var markerI = occurrenceMarkers[i];
|
|
mySession.removeMarker(mySession.markerAnchors[markerI].id);
|
|
mySession.markerAnchors.splice(markerI, 1);
|
|
}
|
|
}
|
|
|
|
mySession.setAnnotations(mySession.languageAnnos);
|
|
}
|
|
|
|
/**
|
|
* Temporarily disable certain types of markers (e.g. when refactoring)
|
|
*/
|
|
function disableMarkerType(type, ace) {
|
|
disabledMarkerTypes[type] = true;
|
|
var session = ace.getSession();
|
|
var markers = session.getMarkers(false);
|
|
for (var id in markers) {
|
|
// All language analysis' markers are prefixed with language_highlight
|
|
if (markers[id].clazz === 'language_highlight_' + type)
|
|
session.removeMarker(id);
|
|
}
|
|
}
|
|
|
|
function enableMarkerType(type) {
|
|
disabledMarkerTypes[type] = false;
|
|
}
|
|
|
|
/**
|
|
* Called when text in editor is updated
|
|
* This attempts to predict how the worker is going to adapt markers based on the given edit
|
|
* it does so instanteously, rather than with a 500ms delay, thereby avoid ugly box bouncing etc.
|
|
*/
|
|
function onChange(session, delta) {
|
|
var isInserting = delta.action[0] !== "r";
|
|
var text = delta.lines[0];
|
|
var adaptingId = text && text.search(/[^a-zA-Z0-9\$_]/) === -1;
|
|
var languageAnnos = [];
|
|
var markers = session.markerAnchors || [];
|
|
var foundOne = false;
|
|
var marker, start;
|
|
if (!isInserting) { // Removing some text
|
|
// Run through markers
|
|
for (var i = markers.length; i--;) {
|
|
marker = markers[i];
|
|
|
|
if (comparePoints(delta.start, marker.start) < 0 && comparePoints(delta.end, marker.start) > 0) {
|
|
session.removeMarker(marker.id);
|
|
foundOne = true;
|
|
continue;
|
|
}
|
|
else if (adaptingId && marker.range && marker.range.contains(delta.start.row, delta.start.column)) {
|
|
foundOne = true;
|
|
marker.colDiff -= text.length;
|
|
}
|
|
|
|
start = marker.start;
|
|
start.onChange(delta);
|
|
if (marker.range) {
|
|
marker.range.end.row = start.row + marker.rowDiff;
|
|
marker.range.end.column = start.column + marker.colDiff;
|
|
}
|
|
|
|
if (marker.gutterAnno) {
|
|
languageAnnos.push(marker.gutterAnno);
|
|
marker.gutterAnno.row = marker.start.row;
|
|
}
|
|
}
|
|
// Didn't find any markers, therefore there will not be any anchors or annotations either
|
|
if (!foundOne)
|
|
return;
|
|
}
|
|
else { // Inserting some text
|
|
// Run through markers
|
|
for (var i = markers.length; i--;) {
|
|
marker = markers[i];
|
|
// Only if inserting an identifier
|
|
if (marker.range && marker.range.contains(delta.start.row, delta.start.column)) {
|
|
foundOne = true;
|
|
if (adaptingId) {
|
|
marker.colDiff += text.length;
|
|
} else if (Range.comparePoints(delta.start, marker.range.start) > 0)
|
|
session.removeMarker(marker.id);
|
|
}
|
|
|
|
start = marker.start;
|
|
start.onChange(delta);
|
|
if (marker.range) {
|
|
marker.range.end.row = start.row + marker.rowDiff;
|
|
marker.range.end.column = start.column + marker.colDiff;
|
|
}
|
|
|
|
if (marker.gutterAnno) {
|
|
languageAnnos.push(marker.gutterAnno);
|
|
marker.gutterAnno.row = marker.start.row;
|
|
}
|
|
}
|
|
}
|
|
session._dispatchEvent("changeBackMarker");
|
|
session.setAnnotations(languageAnnos);
|
|
}
|
|
|
|
register(null, {
|
|
"language.marker": {
|
|
disableMarkerType: disableMarkerType,
|
|
enableMarkerType: enableMarkerType
|
|
}
|
|
});
|
|
}
|
|
}); |