mirror of
https://github.com/overleaf/overleaf.git
synced 2025-04-22 19:37:38 +00:00
Merge pull request #544 from sharelatex/ja-update-ace
Update Ace with new context tracking linter
This commit is contained in:
commit
e5c01df9a8
5 changed files with 293 additions and 4057 deletions
|
@ -347,10 +347,6 @@ define [
|
|||
catch
|
||||
mode = "ace/mode/plain_text"
|
||||
|
||||
# Give beta users the next release of the syntax checker
|
||||
if mode is "ace/mode/latex" and window.user?.betaProgram
|
||||
mode = "ace/mode/latex_beta"
|
||||
|
||||
# create our new session
|
||||
session = new EditSession(lines, mode)
|
||||
|
||||
|
|
|
@ -606,7 +606,7 @@ var createLatexWorker = function (session) {
|
|||
};
|
||||
worker.on("lint", function(results) {
|
||||
if(docChangePending) { docChangePending = false; };
|
||||
hints = results.data;
|
||||
hints = results.data.errors;
|
||||
if (hints.length > 100) {
|
||||
hints = hints.slice(0, 100); // limit to 100 errors
|
||||
};
|
||||
|
|
|
@ -1,655 +0,0 @@
|
|||
ace.define("ace/mode/latex_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"], function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("../lib/oop");
|
||||
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
|
||||
|
||||
var LatexHighlightRules = function() {
|
||||
|
||||
this.$rules = {
|
||||
"start" : [{
|
||||
token : "comment",
|
||||
regex : "%.*$"
|
||||
}, {
|
||||
token : ["keyword", "lparen", "variable.parameter", "rparen", "lparen", "storage.type", "rparen"],
|
||||
regex : "(\\\\(?:documentclass|usepackage|input))(?:(\\[)([^\\]]*)(\\]))?({)([^}]*)(})"
|
||||
}, {
|
||||
token : ["keyword","lparen", "variable.parameter", "rparen"],
|
||||
regex : "(\\\\(?:label|v?ref|cite(?:[^{]*)))(?:({)([^}]*)(}))?"
|
||||
}, {
|
||||
token : ["storage.type", "lparen", "variable.parameter", "rparen"],
|
||||
regex : "(\\\\(?:begin|end))({)(\\w*)(})"
|
||||
}, {
|
||||
token : "storage.type",
|
||||
regex : "\\\\[a-zA-Z]+"
|
||||
}, {
|
||||
token : "lparen",
|
||||
regex : "[[({]"
|
||||
}, {
|
||||
token : "rparen",
|
||||
regex : "[\\])}]"
|
||||
}, {
|
||||
token : "constant.character.escape",
|
||||
regex : "\\\\[^a-zA-Z]?"
|
||||
}, {
|
||||
token : "string",
|
||||
regex : "\\${1,2}",
|
||||
next : "equation"
|
||||
}],
|
||||
"equation" : [{
|
||||
token : "comment",
|
||||
regex : "%.*$"
|
||||
}, {
|
||||
token : "string",
|
||||
regex : "\\${1,2}",
|
||||
next : "start"
|
||||
}, {
|
||||
token : "constant.character.escape",
|
||||
regex : "\\\\(?:[^a-zA-Z]|[a-zA-Z]+)"
|
||||
}, {
|
||||
token : "error",
|
||||
regex : "^\\s*$",
|
||||
next : "start"
|
||||
}, {
|
||||
defaultToken : "string"
|
||||
}]
|
||||
|
||||
};
|
||||
};
|
||||
oop.inherits(LatexHighlightRules, TextHighlightRules);
|
||||
|
||||
exports.LatexHighlightRules = LatexHighlightRules;
|
||||
|
||||
});
|
||||
|
||||
ace.define("ace/mode/folding/latex",["require","exports","module","ace/lib/oop","ace/mode/folding/fold_mode","ace/range","ace/token_iterator"], function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("../../lib/oop");
|
||||
var BaseFoldMode = require("./fold_mode").FoldMode;
|
||||
var Range = require("../../range").Range;
|
||||
var TokenIterator = require("../../token_iterator").TokenIterator;
|
||||
|
||||
var FoldMode = exports.FoldMode = function() {};
|
||||
|
||||
oop.inherits(FoldMode, BaseFoldMode);
|
||||
|
||||
(function() {
|
||||
|
||||
this.foldingStartMarker = /^\s*\\(begin)|(section|subsection|paragraph)\b|{\s*$/;
|
||||
this.foldingStopMarker = /^\s*\\(end)\b|^\s*}/;
|
||||
|
||||
this.getFoldWidgetRange = function(session, foldStyle, row) {
|
||||
var line = session.doc.getLine(row);
|
||||
var match = this.foldingStartMarker.exec(line);
|
||||
if (match) {
|
||||
if (match[1])
|
||||
return this.latexBlock(session, row, match[0].length - 1);
|
||||
if (match[2])
|
||||
return this.latexSection(session, row, match[0].length - 1);
|
||||
|
||||
return this.openingBracketBlock(session, "{", row, match.index);
|
||||
}
|
||||
|
||||
var match = this.foldingStopMarker.exec(line);
|
||||
if (match) {
|
||||
if (match[1])
|
||||
return this.latexBlock(session, row, match[0].length - 1);
|
||||
|
||||
return this.closingBracketBlock(session, "}", row, match.index + match[0].length);
|
||||
}
|
||||
};
|
||||
|
||||
this.latexBlock = function(session, row, column) {
|
||||
var keywords = {
|
||||
"\\begin": 1,
|
||||
"\\end": -1
|
||||
};
|
||||
|
||||
var stream = new TokenIterator(session, row, column);
|
||||
var token = stream.getCurrentToken();
|
||||
if (!token || !(token.type == "storage.type" || token.type == "constant.character.escape"))
|
||||
return;
|
||||
|
||||
var val = token.value;
|
||||
var dir = keywords[val];
|
||||
|
||||
var getType = function() {
|
||||
var token = stream.stepForward();
|
||||
var type = token.type == "lparen" ?stream.stepForward().value : "";
|
||||
if (dir === -1) {
|
||||
stream.stepBackward();
|
||||
if (type)
|
||||
stream.stepBackward();
|
||||
}
|
||||
return type;
|
||||
};
|
||||
var stack = [getType()];
|
||||
var startColumn = dir === -1 ? stream.getCurrentTokenColumn() : session.getLine(row).length;
|
||||
var startRow = row;
|
||||
|
||||
stream.step = dir === -1 ? stream.stepBackward : stream.stepForward;
|
||||
while(token = stream.step()) {
|
||||
if (!token || !(token.type == "storage.type" || token.type == "constant.character.escape"))
|
||||
continue;
|
||||
var level = keywords[token.value];
|
||||
if (!level)
|
||||
continue;
|
||||
var type = getType();
|
||||
if (level === dir)
|
||||
stack.unshift(type);
|
||||
else if (stack.shift() !== type || !stack.length)
|
||||
break;
|
||||
}
|
||||
|
||||
if (stack.length)
|
||||
return;
|
||||
|
||||
var row = stream.getCurrentTokenRow();
|
||||
if (dir === -1)
|
||||
return new Range(row, session.getLine(row).length, startRow, startColumn);
|
||||
stream.stepBackward();
|
||||
return new Range(startRow, startColumn, row, stream.getCurrentTokenColumn());
|
||||
};
|
||||
|
||||
this.latexSection = function(session, row, column) {
|
||||
var keywords = ["\\subsection", "\\section", "\\begin", "\\end", "\\paragraph"];
|
||||
|
||||
var stream = new TokenIterator(session, row, column);
|
||||
var token = stream.getCurrentToken();
|
||||
if (!token || token.type != "storage.type")
|
||||
return;
|
||||
|
||||
var startLevel = keywords.indexOf(token.value);
|
||||
var stackDepth = 0
|
||||
var endRow = row;
|
||||
|
||||
while(token = stream.stepForward()) {
|
||||
if (token.type !== "storage.type")
|
||||
continue;
|
||||
var level = keywords.indexOf(token.value);
|
||||
|
||||
if (level >= 2) {
|
||||
if (!stackDepth)
|
||||
endRow = stream.getCurrentTokenRow() - 1;
|
||||
stackDepth += level == 2 ? 1 : - 1;
|
||||
if (stackDepth < 0)
|
||||
break
|
||||
} else if (level >= startLevel)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!stackDepth)
|
||||
endRow = stream.getCurrentTokenRow() - 1;
|
||||
|
||||
while (endRow > row && !/\S/.test(session.getLine(endRow)))
|
||||
endRow--;
|
||||
|
||||
return new Range(
|
||||
row, session.getLine(row).length,
|
||||
endRow, session.getLine(endRow).length
|
||||
);
|
||||
};
|
||||
|
||||
}).call(FoldMode.prototype);
|
||||
|
||||
});
|
||||
|
||||
ace.define("ace/mode/behaviour/latex",["require","exports","module","ace/lib/oop","ace/mode/behaviour","ace/token_iterator","ace/lib/lang"], function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("../../lib/oop");
|
||||
var Behaviour = require("../behaviour").Behaviour;
|
||||
var TokenIterator = require("../../token_iterator").TokenIterator;
|
||||
var lang = require("../../lib/lang");
|
||||
|
||||
var SAFE_INSERT_IN_TOKENS =
|
||||
["text", "paren.rparen", "punctuation.operator"];
|
||||
var SAFE_INSERT_BEFORE_TOKENS =
|
||||
["text", "paren.rparen", "punctuation.operator", "comment"];
|
||||
|
||||
var context;
|
||||
var contextCache = {};
|
||||
var initContext = function(editor) {
|
||||
var id = -1;
|
||||
if (editor.multiSelect) {
|
||||
id = editor.selection.index;
|
||||
if (contextCache.rangeCount != editor.multiSelect.rangeCount)
|
||||
contextCache = {rangeCount: editor.multiSelect.rangeCount};
|
||||
}
|
||||
if (contextCache[id])
|
||||
return context = contextCache[id];
|
||||
context = contextCache[id] = {
|
||||
autoInsertedBrackets: 0,
|
||||
autoInsertedRow: -1,
|
||||
autoInsertedLineEnd: "",
|
||||
maybeInsertedBrackets: 0,
|
||||
maybeInsertedRow: -1,
|
||||
maybeInsertedLineStart: "",
|
||||
maybeInsertedLineEnd: ""
|
||||
};
|
||||
};
|
||||
|
||||
var getWrapped = function(selection, selected, opening, closing) {
|
||||
var rowDiff = selection.end.row - selection.start.row;
|
||||
return {
|
||||
text: opening + selected + closing,
|
||||
selection: [
|
||||
0,
|
||||
selection.start.column + 1,
|
||||
rowDiff,
|
||||
selection.end.column + (rowDiff ? 0 : 1)
|
||||
]
|
||||
};
|
||||
};
|
||||
|
||||
var LatexBehaviour = function() {
|
||||
this.add("braces", "insertion", function(state, action, editor, session, text) {
|
||||
if (editor.completer && editor.completer.popup && editor.completer.popup.isOpen) {
|
||||
return;
|
||||
}
|
||||
var cursor = editor.getCursorPosition();
|
||||
var line = session.doc.getLine(cursor.row);
|
||||
var lastChar = line[cursor.column-1];
|
||||
if (lastChar === '\\') {
|
||||
return;
|
||||
}
|
||||
if (text == '{') {
|
||||
initContext(editor);
|
||||
var selection = editor.getSelectionRange();
|
||||
var selected = session.doc.getTextRange(selection);
|
||||
if (selected !== "" && editor.getWrapBehavioursEnabled()) {
|
||||
return getWrapped(selection, selected, '{', '}');
|
||||
} else if (LatexBehaviour.isSaneInsertion(editor, session)) {
|
||||
LatexBehaviour.recordAutoInsert(editor, session, "}");
|
||||
return {
|
||||
text: '{}',
|
||||
selection: [1, 1]
|
||||
};
|
||||
}
|
||||
} else if (text == '}') {
|
||||
initContext(editor);
|
||||
var rightChar = line.substring(cursor.column, cursor.column + 1);
|
||||
if (rightChar == '}') {
|
||||
var matching = session.$findOpeningBracket('}', {column: cursor.column + 1, row: cursor.row});
|
||||
if (matching !== null && LatexBehaviour.isAutoInsertedClosing(cursor, line, text)) {
|
||||
LatexBehaviour.popAutoInsertedClosing();
|
||||
return {
|
||||
text: '',
|
||||
selection: [1, 1]
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.add("braces", "deletion", function(state, action, editor, session, range) {
|
||||
if (editor.completer && editor.completer.popup && editor.completer.popup.isOpen) {
|
||||
return;
|
||||
}
|
||||
var selected = session.doc.getTextRange(range);
|
||||
if (!range.isMultiLine() && selected == '{') {
|
||||
initContext(editor);
|
||||
var line = session.doc.getLine(range.start.row);
|
||||
var rightChar = line.substring(range.start.column + 1, range.start.column + 2);
|
||||
if (rightChar == '}') {
|
||||
range.end.column++;
|
||||
return range;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.add("brackets", "insertion", function(state, action, editor, session, text) {
|
||||
if (editor.completer && editor.completer.popup && editor.completer.popup.isOpen) {
|
||||
return;
|
||||
}
|
||||
var cursor = editor.getCursorPosition();
|
||||
var line = session.doc.getLine(cursor.row);
|
||||
var lastChar = line[cursor.column-1];
|
||||
if (lastChar === '\\') {
|
||||
return;
|
||||
}
|
||||
if (text == '[') {
|
||||
initContext(editor);
|
||||
var selection = editor.getSelectionRange();
|
||||
var selected = session.doc.getTextRange(selection);
|
||||
if (selected !== "" && editor.getWrapBehavioursEnabled()) {
|
||||
return getWrapped(selection, selected, '[', ']');
|
||||
} else if (LatexBehaviour.isSaneInsertion(editor, session)) {
|
||||
LatexBehaviour.recordAutoInsert(editor, session, "]");
|
||||
return {
|
||||
text: '[]',
|
||||
selection: [1, 1]
|
||||
};
|
||||
}
|
||||
} else if (text == ']') {
|
||||
initContext(editor);
|
||||
var rightChar = line.substring(cursor.column, cursor.column + 1);
|
||||
if (rightChar == ']') {
|
||||
var matching = session.$findOpeningBracket(']', {column: cursor.column + 1, row: cursor.row});
|
||||
if (matching !== null && LatexBehaviour.isAutoInsertedClosing(cursor, line, text)) {
|
||||
LatexBehaviour.popAutoInsertedClosing();
|
||||
return {
|
||||
text: '',
|
||||
selection: [1, 1]
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.add("brackets", "deletion", function(state, action, editor, session, range) {
|
||||
if (editor.completer && editor.completer.popup && editor.completer.popup.isOpen) {
|
||||
return;
|
||||
}
|
||||
var selected = session.doc.getTextRange(range);
|
||||
if (!range.isMultiLine() && selected == '[') {
|
||||
initContext(editor);
|
||||
var line = session.doc.getLine(range.start.row);
|
||||
var rightChar = line.substring(range.start.column + 1, range.start.column + 2);
|
||||
if (rightChar == ']') {
|
||||
range.end.column++;
|
||||
return range;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.add("dollars", "insertion", function(state, action, editor, session, text) {
|
||||
var cursor = editor.getCursorPosition();
|
||||
var line = session.doc.getLine(cursor.row);
|
||||
var lastChar = line[cursor.column-1];
|
||||
if (lastChar === '\\') {
|
||||
return;
|
||||
}
|
||||
if (text == '$') {
|
||||
if (this.lineCommentStart && this.lineCommentStart.indexOf(text) != -1)
|
||||
return;
|
||||
initContext(editor);
|
||||
var quote = text;
|
||||
var selection = editor.getSelectionRange();
|
||||
var selected = session.doc.getTextRange(selection);
|
||||
if (selected !== "" && selected !== "$" && editor.getWrapBehavioursEnabled()) {
|
||||
return getWrapped(selection, selected, quote, quote);
|
||||
} else if (!selected) {
|
||||
var leftChar = line.substring(cursor.column-1, cursor.column);
|
||||
var rightChar = line.substring(cursor.column, cursor.column + 1);
|
||||
|
||||
var token = session.getTokenAt(cursor.row, cursor.column);
|
||||
var rightToken = session.getTokenAt(cursor.row, cursor.column + 1);
|
||||
|
||||
var stringBefore = token && /string|escape/.test(token.type);
|
||||
var stringAfter = !rightToken || /string|escape/.test(rightToken.type);
|
||||
|
||||
var pair;
|
||||
if (rightChar == quote) {
|
||||
pair = stringBefore !== stringAfter;
|
||||
if (pair && /string\.end/.test(rightToken.type))
|
||||
pair = false;
|
||||
} else {
|
||||
if (stringBefore && !stringAfter)
|
||||
return null; // wrap string with different quote
|
||||
if (stringBefore && stringAfter)
|
||||
return null; // do not pair quotes inside strings
|
||||
var wordRe = session.$mode.tokenRe;
|
||||
wordRe.lastIndex = 0;
|
||||
var isWordBefore = wordRe.test(leftChar);
|
||||
wordRe.lastIndex = 0;
|
||||
var isWordAfter = wordRe.test(leftChar);
|
||||
if (isWordBefore || isWordAfter)
|
||||
return null; // before or after alphanumeric
|
||||
if (rightChar && !/[\s;,.})\]\\]/.test(rightChar))
|
||||
return null; // there is rightChar and it isn't closing
|
||||
pair = true;
|
||||
}
|
||||
return {
|
||||
text: pair ? quote + quote : "",
|
||||
selection: [1,1]
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.add("dollars", "deletion", function(state, action, editor, session, range) {
|
||||
var selected = session.doc.getTextRange(range);
|
||||
if (!range.isMultiLine() && (selected == '$')) {
|
||||
initContext(editor);
|
||||
var line = session.doc.getLine(range.start.row);
|
||||
var rightChar = line.substring(range.start.column + 1, range.start.column + 2);
|
||||
if (rightChar == selected) {
|
||||
range.end.column++;
|
||||
return range;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
|
||||
LatexBehaviour.isSaneInsertion = function(editor, session) {
|
||||
var cursor = editor.getCursorPosition();
|
||||
var iterator = new TokenIterator(session, cursor.row, cursor.column);
|
||||
if (!this.$matchTokenType(iterator.getCurrentToken() || "text", SAFE_INSERT_IN_TOKENS)) {
|
||||
var iterator2 = new TokenIterator(session, cursor.row, cursor.column + 1);
|
||||
if (!this.$matchTokenType(iterator2.getCurrentToken() || "text", SAFE_INSERT_IN_TOKENS))
|
||||
return false;
|
||||
}
|
||||
iterator.stepForward();
|
||||
return iterator.getCurrentTokenRow() !== cursor.row ||
|
||||
this.$matchTokenType(iterator.getCurrentToken() || "text", SAFE_INSERT_BEFORE_TOKENS);
|
||||
};
|
||||
|
||||
LatexBehaviour.$matchTokenType = function(token, types) {
|
||||
return types.indexOf(token.type || token) > -1;
|
||||
};
|
||||
|
||||
LatexBehaviour.recordAutoInsert = function(editor, session, bracket) {
|
||||
var cursor = editor.getCursorPosition();
|
||||
var line = session.doc.getLine(cursor.row);
|
||||
if (!this.isAutoInsertedClosing(cursor, line, context.autoInsertedLineEnd[0]))
|
||||
context.autoInsertedBrackets = 0;
|
||||
context.autoInsertedRow = cursor.row;
|
||||
context.autoInsertedLineEnd = bracket + line.substr(cursor.column);
|
||||
context.autoInsertedBrackets++;
|
||||
};
|
||||
|
||||
LatexBehaviour.isAutoInsertedClosing = function(cursor, line, bracket) {
|
||||
return context.autoInsertedBrackets > 0 &&
|
||||
cursor.row === context.autoInsertedRow &&
|
||||
bracket === context.autoInsertedLineEnd[0] &&
|
||||
line.substr(cursor.column) === context.autoInsertedLineEnd;
|
||||
};
|
||||
|
||||
LatexBehaviour.popAutoInsertedClosing = function() {
|
||||
context.autoInsertedLineEnd = context.autoInsertedLineEnd.substr(1);
|
||||
context.autoInsertedBrackets--;
|
||||
};
|
||||
|
||||
|
||||
oop.inherits(LatexBehaviour, Behaviour);
|
||||
|
||||
exports.LatexBehaviour = LatexBehaviour;
|
||||
});
|
||||
|
||||
ace.define("ace/mode/latex_beta",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/latex_highlight_rules","ace/mode/folding/latex","ace/range","ace/worker/worker_client","ace/mode/behaviour/latex"], function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("../lib/oop");
|
||||
var TextMode = require("./text").Mode;
|
||||
var LatexHighlightRules = require("./latex_highlight_rules").LatexHighlightRules;
|
||||
var LatexFoldMode = require("./folding/latex").FoldMode;
|
||||
var Range = require("../range").Range;
|
||||
var WorkerClient = require("ace/worker/worker_client").WorkerClient;
|
||||
var LatexBehaviour = require("./behaviour/latex").LatexBehaviour;
|
||||
|
||||
var createLatexWorker = function (session) {
|
||||
var doc = session.getDocument();
|
||||
var selection = session.getSelection();
|
||||
var cursorAnchor = selection.lead;
|
||||
|
||||
var savedRange = {};
|
||||
var suppressions = [];
|
||||
var hints = [];
|
||||
var changeHandler = null;
|
||||
var docChangePending = false;
|
||||
var firstPass = true;
|
||||
|
||||
var worker = new WorkerClient(["ace"], "ace/mode/latex_beta_worker", "LatexWorker");
|
||||
worker.attachToDocument(doc);
|
||||
var docChangeHandler = doc.on("change", function () {
|
||||
docChangePending = true;
|
||||
if(changeHandler) {
|
||||
clearTimeout(changeHandler);
|
||||
changeHandler = null;
|
||||
}
|
||||
});
|
||||
|
||||
var cursorHandler = selection.on("changeCursor", function () {
|
||||
if (docChangePending) { return; } ;
|
||||
changeHandler = setTimeout(function () {
|
||||
updateMarkers({cursorMoveOnly:true});
|
||||
suppressions = [];
|
||||
changeHandler = null;
|
||||
}, 100);
|
||||
});
|
||||
|
||||
var updateMarkers = function (options) {
|
||||
if (!options) { options = {};};
|
||||
var cursorMoveOnly = options.cursorMoveOnly;
|
||||
var annotations = [];
|
||||
var newRange = {};
|
||||
var cursor = selection.getCursor();
|
||||
var maxRow = session.getLength() - 1;
|
||||
var maxCol = (maxRow > 0) ? session.getLine(maxRow).length : 0;
|
||||
var cursorAtEndOfDocument = (cursor.row == maxRow) && (cursor.column === maxCol);
|
||||
|
||||
suppressions = [];
|
||||
|
||||
for (var i = 0, len = hints.length; i<len; i++) {
|
||||
var hint = hints[i];
|
||||
|
||||
var suppressedChanges = 0;
|
||||
var hintRange = new Range(hint.start_row, hint.start_col, hint.end_row, hint.end_col);
|
||||
|
||||
var cursorInRange = hintRange.insideEnd(cursor.row, cursor.column);
|
||||
var cursorAtStart = hintRange.isStart(cursor.row, cursor.column - 1); // cursor after start not before
|
||||
var cursorAtEnd = hintRange.isEnd(cursor.row, cursor.column);
|
||||
if (hint.suppressIfEditing && (cursorAtStart || cursorAtEnd)) {
|
||||
suppressions.push(hintRange);
|
||||
if (!hint.suppressed) { suppressedChanges++; };
|
||||
hint.suppressed = true;
|
||||
continue;
|
||||
}
|
||||
var isCascadeError = false;
|
||||
for (var j = 0, suplen = suppressions.length; j < suplen; j++) {
|
||||
var badRange = suppressions[j];
|
||||
if (badRange.intersects(hintRange)) {
|
||||
isCascadeError = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(isCascadeError) {
|
||||
if (!hint.suppressed) { suppressedChanges++; };
|
||||
hint.suppressed = true;
|
||||
continue;
|
||||
};
|
||||
|
||||
if (hint.suppressed) { suppressedChanges++; };
|
||||
hint.suppressed = false;
|
||||
|
||||
annotations.push(hint);
|
||||
if (hint.type === "info") {
|
||||
continue;
|
||||
};
|
||||
var key = hintRange.toString() + (cursorInRange ? "+cursor" : "");
|
||||
newRange[key] = {hint: hint, cursorInRange: cursorInRange, range: hintRange};
|
||||
}
|
||||
for (key in newRange) {
|
||||
if (!savedRange[key]) { // doesn't exist in already displayed errors
|
||||
var new_range = newRange[key].range;
|
||||
cursorInRange = newRange[key].cursorInRange;
|
||||
hint = newRange[key].hint;
|
||||
var errorAtStart = (hint.row === hint.start_row && hint.column === hint.start_col);
|
||||
var movableStart = (cursorInRange && !errorAtStart) && !cursorAtEndOfDocument;
|
||||
var movableEnd = (cursorInRange && errorAtStart) && !cursorAtEndOfDocument;
|
||||
var a = movableStart ? cursorAnchor : doc.createAnchor(new_range.start);
|
||||
var b = movableEnd ? cursorAnchor : doc.createAnchor(new_range.end);
|
||||
var range = new Range();
|
||||
range.start = a;
|
||||
range.end = b;
|
||||
var cssClass = "ace_error-marker";
|
||||
if (hint.type === "warning") { cssClass = "ace_highlight-marker"; };
|
||||
range.id = session.addMarker(range, cssClass, "text");
|
||||
savedRange[key] = range;
|
||||
}
|
||||
}
|
||||
for (key in savedRange) {
|
||||
if (!newRange[key]) { // no longer present in list of errors to display
|
||||
range = savedRange[key];
|
||||
if (range.start !== cursorAnchor) { range.start.detach(); }
|
||||
if (range.end !== cursorAnchor) { range.end.detach(); }
|
||||
session.removeMarker(range.id);
|
||||
delete savedRange[key];
|
||||
}
|
||||
}
|
||||
if (!cursorMoveOnly || suppressedChanges) {
|
||||
if (firstPass) {
|
||||
if (annotations.length > 0) {
|
||||
var originalAnnotations = session.getAnnotations();
|
||||
session.setAnnotations(originalAnnotations.concat(annotations));
|
||||
};
|
||||
firstPass = false;
|
||||
} else {
|
||||
session.setAnnotations(annotations);
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
worker.on("lint", function(results) {
|
||||
if(docChangePending) { docChangePending = false; };
|
||||
hints = results.data;
|
||||
if (hints.length > 100) {
|
||||
hints = hints.slice(0, 100); // limit to 100 errors
|
||||
};
|
||||
updateMarkers();
|
||||
});
|
||||
worker.on("terminate", function() {
|
||||
if(changeHandler) {
|
||||
clearTimeout(changeHandler);
|
||||
changeHandler = null;
|
||||
}
|
||||
doc.off("change", docChangeHandler);
|
||||
selection.off("changeCursor", cursorHandler);
|
||||
for (var key in savedRange) {
|
||||
var range = savedRange[key];
|
||||
if (range.start !== cursorAnchor) { range.start.detach(); }
|
||||
if (range.end !== cursorAnchor) { range.end.detach(); }
|
||||
session.removeMarker(range.id);
|
||||
}
|
||||
savedRange = {};
|
||||
hints = [];
|
||||
suppressions = [];
|
||||
session.clearAnnotations();
|
||||
});
|
||||
|
||||
return worker;
|
||||
};
|
||||
|
||||
var Mode = function() {
|
||||
this.HighlightRules = LatexHighlightRules;
|
||||
this.foldingRules = new LatexFoldMode();
|
||||
this.$behaviour = new LatexBehaviour();
|
||||
this.createWorker = createLatexWorker;
|
||||
};
|
||||
oop.inherits(Mode, TextMode);
|
||||
|
||||
(function() {
|
||||
this.type = "text";
|
||||
|
||||
this.lineCommentStart = "%";
|
||||
|
||||
this.$id = "ace/mode/latex_beta";
|
||||
}).call(Mode.prototype);
|
||||
|
||||
exports.Mode = Mode;
|
||||
|
||||
});
|
|
@ -1419,6 +1419,34 @@ var LatexWorker = exports.LatexWorker = function(sender) {
|
|||
|
||||
oop.inherits(LatexWorker, Mirror);
|
||||
|
||||
(function() {
|
||||
var disabled = false;
|
||||
this.onUpdate = function() {
|
||||
if (disabled) { return ; };
|
||||
|
||||
var value = this.doc.getValue();
|
||||
var errors = [];
|
||||
var contexts = [];
|
||||
try {
|
||||
if (value) {
|
||||
var result = Parse(value);
|
||||
errors = result.errors;
|
||||
contexts = result.contexts;
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
disabled = true;
|
||||
this.sender.emit("fatal-error", e);
|
||||
errors = [];
|
||||
}
|
||||
this.sender.emit("lint", {
|
||||
errors: errors,
|
||||
contexts: contexts
|
||||
});
|
||||
};
|
||||
|
||||
}).call(LatexWorker.prototype);
|
||||
|
||||
var Tokenise = function (text) {
|
||||
var Tokens = [];
|
||||
var Comments = [];
|
||||
|
@ -1503,22 +1531,8 @@ var Tokenise = function (text) {
|
|||
}
|
||||
idx = SPECIAL.lastIndex = nextSpecialPos;
|
||||
}
|
||||
} else if (code === "{") { // open group
|
||||
Tokens.push([lineNumber, code, pos]);
|
||||
} else if (code === "}") { // close group
|
||||
Tokens.push([lineNumber, code, pos]);
|
||||
} else if (code === "$") { // math mode
|
||||
Tokens.push([lineNumber, code, pos]);
|
||||
} else if (code === "&") { // tabalign
|
||||
Tokens.push([lineNumber, code, pos]);
|
||||
} else if (code === "#") { // macro parameter
|
||||
Tokens.push([lineNumber, code, pos]);
|
||||
} else if (code === "^") { // superscript
|
||||
Tokens.push([lineNumber, code, pos]);
|
||||
} else if (code === "_") { // subscript
|
||||
Tokens.push([lineNumber, code, pos]);
|
||||
} else if (code === "~") { // active character (space)
|
||||
Tokens.push([lineNumber, code, pos]);
|
||||
} else if (["{", "}", "$", "&", "#", "^", "_", "~"].indexOf(code) > -1) { // special characters
|
||||
Tokens.push([lineNumber, code, pos, pos+1]);
|
||||
} else {
|
||||
throw "unrecognised character " + code;
|
||||
}
|
||||
|
@ -1539,15 +1553,15 @@ var read1arg = function (TokeniseResult, k, options) {
|
|||
};
|
||||
|
||||
var open = Tokens[k+1];
|
||||
var env = Tokens[k+2];
|
||||
var delimiter = Tokens[k+2];
|
||||
var close = Tokens[k+3];
|
||||
var envName;
|
||||
var delimiterName;
|
||||
|
||||
if(open && open[1] === "\\") {
|
||||
envName = open[4]; // array element 4 is command sequence
|
||||
delimiterName = open[4]; // array element 4 is command sequence
|
||||
return k + 1;
|
||||
} else if(open && open[1] === "{" && env && env[1] === "\\" && close && close[1] === "}") {
|
||||
envName = env[4]; // NOTE: if we were actually using this, keep track of * above
|
||||
} else if(open && open[1] === "{" && delimiter && delimiter[1] === "\\" && close && close[1] === "}") {
|
||||
delimiterName = delimiter[4]; // NOTE: if we were actually using this, keep track of * above
|
||||
return k + 3; // array element 4 is command sequence
|
||||
} else {
|
||||
return null;
|
||||
|
@ -1579,21 +1593,21 @@ var read1name = function (TokeniseResult, k) {
|
|||
var text = TokeniseResult.text;
|
||||
|
||||
var open = Tokens[k+1];
|
||||
var env = Tokens[k+2];
|
||||
var delimiter = Tokens[k+2];
|
||||
var close = Tokens[k+3];
|
||||
|
||||
if(open && open[1] === "{" && env && env[1] === "Text" && close && close[1] === "}") {
|
||||
var envName = text.substring(env[2], env[3]);
|
||||
if(open && open[1] === "{" && delimiter && delimiter[1] === "Text" && close && close[1] === "}") {
|
||||
var delimiterName = text.substring(delimiter[2], delimiter[3]);
|
||||
return k + 3;
|
||||
} else if (open && open[1] === "{" && env && env[1] === "Text") {
|
||||
envName = "";
|
||||
} else if (open && open[1] === "{" && delimiter && delimiter[1] === "Text") {
|
||||
delimiterName = "";
|
||||
for (var j = k + 2, tok; (tok = Tokens[j]); j++) {
|
||||
if (tok[1] === "Text") {
|
||||
var str = text.substring(tok[2], tok[3]);
|
||||
if (!str.match(/^\S*$/)) { break; }
|
||||
envName = envName + str;
|
||||
delimiterName = delimiterName + str;
|
||||
} else if (tok[1] === "_") {
|
||||
envName = envName + "_";
|
||||
delimiterName = delimiterName + "_";
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
@ -1644,6 +1658,7 @@ var readOptionalParams = function(TokeniseResult, k) {
|
|||
};
|
||||
var count = 0;
|
||||
var nextToken = Tokens[k+1];
|
||||
if (!nextToken) { return null };
|
||||
var pos = nextToken[2];
|
||||
|
||||
for (var i = pos, end = text.length; i < end; i++) {
|
||||
|
@ -1788,7 +1803,7 @@ var InterpretTokens = function (TokeniseResult, ErrorReporter) {
|
|||
|
||||
var TokenErrorFromTo = ErrorReporter.TokenErrorFromTo;
|
||||
var TokenError = ErrorReporter.TokenError;
|
||||
var Environments = new EnvHandler(ErrorReporter);
|
||||
var Environments = new EnvHandler(TokeniseResult, ErrorReporter);
|
||||
|
||||
var nextGroupMathMode = null; // if the next group should have
|
||||
var nextGroupMathModeStack = [] ; // tracking all nextGroupMathModes
|
||||
|
@ -1815,28 +1830,28 @@ var InterpretTokens = function (TokeniseResult, ErrorReporter) {
|
|||
if (type === "\\") {
|
||||
if (seq === "begin" || seq === "end") {
|
||||
var open = Tokens[i+1];
|
||||
var env = Tokens[i+2];
|
||||
var delimiter = Tokens[i+2];
|
||||
var close = Tokens[i+3];
|
||||
if(open && open[1] === "{" && env && env[1] === "Text" && close && close[1] === "}") {
|
||||
var envName = text.substring(env[2], env[3]);
|
||||
Environments.push({command: seq, name: envName, token: token, closeToken: close});
|
||||
if(open && open[1] === "{" && delimiter && delimiter[1] === "Text" && close && close[1] === "}") {
|
||||
var delimiterName = text.substring(delimiter[2], delimiter[3]);
|
||||
Environments.push({command: seq, name: delimiterName, token: token, closeToken: close});
|
||||
i = i + 3; // advance past these tokens
|
||||
} else {
|
||||
if (open && open[1] === "{" && env && env[1] === "Text") {
|
||||
envName = "";
|
||||
if (open && open[1] === "{" && delimiter && delimiter[1] === "Text") {
|
||||
delimiterName = "";
|
||||
for (var j = i + 2, tok; (tok = Tokens[j]); j++) {
|
||||
if (tok[1] === "Text") {
|
||||
var str = text.substring(tok[2], tok[3]);
|
||||
if (!str.match(/^\S*$/)) { break; }
|
||||
envName = envName + str;
|
||||
delimiterName = delimiterName + str;
|
||||
} else if (tok[1] === "_") {
|
||||
envName = envName + "_";
|
||||
delimiterName = delimiterName + "_";
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (tok && tok[1] === "}") {
|
||||
Environments.push({command: seq, name: envName, token: token, closeToken: close});
|
||||
Environments.push({command: seq, name: delimiterName, token: token, closeToken: close});
|
||||
i = j; // advance past these tokens
|
||||
continue;
|
||||
}
|
||||
|
@ -1844,8 +1859,8 @@ var InterpretTokens = function (TokeniseResult, ErrorReporter) {
|
|||
var endToken = null;
|
||||
if (open && open[1] === "{") {
|
||||
endToken = open; // we've got a {
|
||||
if (env && env[1] === "Text") {
|
||||
endToken = env.slice(); // we've got some text following the {
|
||||
if (delimiter && delimiter[1] === "Text") {
|
||||
endToken = delimiter.slice(); // we've got some text following the {
|
||||
start = endToken[2]; end = endToken[3];
|
||||
for (j = start; j < end; j++) {
|
||||
var char = text[j];
|
||||
|
@ -1978,7 +1993,12 @@ var InterpretTokens = function (TokeniseResult, ErrorReporter) {
|
|||
var nextIsDollar = lookAhead && lookAhead[1] === "$";
|
||||
currentMathMode = Environments.getMathMode() ; // returns null / $(inline) / $$(display)
|
||||
if (nextIsDollar && (!currentMathMode || currentMathMode.command == "$$")) {
|
||||
Environments.push({command:"$$", token:token});
|
||||
if (currentMathMode && currentMathMode.command == "$$") {
|
||||
var delimiterToken = lookAhead;
|
||||
} else {
|
||||
var delimiterToken = token;
|
||||
}
|
||||
Environments.push({command:"$$", token:delimiterToken});
|
||||
i = i + 1;
|
||||
} else {
|
||||
Environments.push({command:"$", token:token});
|
||||
|
@ -1999,74 +2019,174 @@ var InterpretTokens = function (TokeniseResult, ErrorReporter) {
|
|||
return Environments;
|
||||
};
|
||||
|
||||
var EnvHandler = function (ErrorReporter) {
|
||||
var DocumentTree = function(TokeniseResult) {
|
||||
var tree = {
|
||||
children: []
|
||||
};
|
||||
var stack = [tree];
|
||||
|
||||
this.openEnv = function(startDelimiter) {
|
||||
var currentNode = this.getCurrentNode();
|
||||
var newNode = {
|
||||
startDelimiter: startDelimiter,
|
||||
children: []
|
||||
};
|
||||
currentNode.children.push(newNode);
|
||||
stack.push(newNode);
|
||||
};
|
||||
|
||||
this.closeEnv = function(endDelimiter) {
|
||||
if (stack.length == 1) {
|
||||
return null
|
||||
}
|
||||
var currentNode = stack.pop();
|
||||
currentNode.endDelimiter = endDelimiter;
|
||||
return currentNode.startDelimiter;
|
||||
};
|
||||
|
||||
this.getNthPreviousNode = function(n) {
|
||||
var offset = stack.length - n - 1;
|
||||
if (offset < 0)
|
||||
return null;
|
||||
return stack[offset];
|
||||
}
|
||||
|
||||
this.getCurrentNode = function() {
|
||||
return this.getNthPreviousNode(0);
|
||||
}
|
||||
|
||||
this.getCurrentDelimiter = function() {
|
||||
return this.getCurrentNode().startDelimiter;
|
||||
};
|
||||
|
||||
this.getPreviousDelimiter = function() {
|
||||
var node = this.getNthPreviousNode(1);
|
||||
if (!node)
|
||||
return null
|
||||
return node.startDelimiter;
|
||||
}
|
||||
|
||||
this.getDepth = function() {
|
||||
return (stack.length - 1) // Root node doesn't count
|
||||
}
|
||||
|
||||
this.getContexts = function() {
|
||||
var linePosition = TokeniseResult.linePosition;
|
||||
|
||||
function tokenToRange(token) {
|
||||
var line = token[0], start = token[2], end = token[3];
|
||||
var start_col = start - linePosition[line];
|
||||
if (!end) { end = start + 1; } ;
|
||||
var end_col = end - linePosition[line];
|
||||
return {
|
||||
start: {
|
||||
row: line,
|
||||
column: start_col
|
||||
},
|
||||
end: {
|
||||
row: line,
|
||||
column: end_col
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function getContextsFromNode(node) {
|
||||
if (node.startDelimiter && node.startDelimiter.mathMode) {
|
||||
var context = {
|
||||
type: "math",
|
||||
range: {
|
||||
start: tokenToRange(node.startDelimiter.token).start
|
||||
}
|
||||
};
|
||||
if (node.endDelimiter) {
|
||||
var closeToken = node.endDelimiter.closeToken || node.endDelimiter.token;
|
||||
context.range.end = tokenToRange(closeToken).end;
|
||||
};
|
||||
return [context];
|
||||
} else {
|
||||
var contexts = [];
|
||||
for (var i = 0; i < node.children.length; i++) {
|
||||
var child = node.children[i];
|
||||
contexts = contexts.concat(getContextsFromNode(child));
|
||||
}
|
||||
return contexts;
|
||||
}
|
||||
};
|
||||
|
||||
return getContextsFromNode(tree);
|
||||
}
|
||||
}
|
||||
|
||||
var EnvHandler = function (TokeniseResult, ErrorReporter) {
|
||||
var ErrorTo = ErrorReporter.EnvErrorTo;
|
||||
var ErrorFromTo = ErrorReporter.EnvErrorFromTo;
|
||||
var ErrorFrom = ErrorReporter.EnvErrorFrom;
|
||||
|
||||
var envs = [];
|
||||
var delimiters = [];
|
||||
|
||||
var state = [];
|
||||
var document = new DocumentTree(TokeniseResult);
|
||||
var documentClosed = null;
|
||||
var inVerbatim = false;
|
||||
var verbatimRanges = [];
|
||||
|
||||
this.Environments = envs;
|
||||
|
||||
this.push = function (newEnv) {
|
||||
this.setEnvProps(newEnv);
|
||||
this.checkAndUpdateState(newEnv);
|
||||
envs.push(newEnv);
|
||||
|
||||
this.getDocument = function() {
|
||||
return document;
|
||||
};
|
||||
|
||||
this._endVerbatim = function (thisEnv) {
|
||||
var lastEnv = state.pop();
|
||||
if (lastEnv && lastEnv.name === thisEnv.name) {
|
||||
this.push = function (newDelimiter) {
|
||||
this.setDelimiterProps(newDelimiter);
|
||||
this.checkAndUpdateState(newDelimiter);
|
||||
delimiters.push(newDelimiter);
|
||||
};
|
||||
|
||||
this._endVerbatim = function (thisDelimiter) {
|
||||
var lastDelimiter = document.getCurrentDelimiter();
|
||||
if (lastDelimiter && lastDelimiter.name === thisDelimiter.name) {
|
||||
inVerbatim = false;
|
||||
verbatimRanges.push({start: lastEnv.token[2], end: thisEnv.token[2]});
|
||||
} else {
|
||||
if(lastEnv) { state.push(lastEnv); } ;
|
||||
document.closeEnv(thisDelimiter);
|
||||
verbatimRanges.push({start: lastDelimiter.token[2], end: thisDelimiter.token[2]});
|
||||
}
|
||||
};
|
||||
|
||||
var invalidEnvs = [];
|
||||
|
||||
this._end = function (thisEnv) {
|
||||
this._end = function (thisDelimiter) {
|
||||
do {
|
||||
var lastEnv = state.pop();
|
||||
var lastDelimiter = document.getCurrentDelimiter();
|
||||
var retry = false;
|
||||
var i;
|
||||
|
||||
if (closedBy(lastEnv, thisEnv)) {
|
||||
if (thisEnv.command === "end" && thisEnv.name === "document" && !documentClosed) {
|
||||
documentClosed = thisEnv;
|
||||
if (closedBy(lastDelimiter, thisDelimiter)) {
|
||||
document.closeEnv(thisDelimiter);
|
||||
if (thisDelimiter.command === "end" && thisDelimiter.name === "document" && !documentClosed) {
|
||||
documentClosed = thisDelimiter;
|
||||
};
|
||||
return;
|
||||
} else if (!lastEnv) {
|
||||
} else if (!lastDelimiter) {
|
||||
if (documentClosed) {
|
||||
ErrorFromTo(documentClosed, thisEnv, "\\end{" + documentClosed.name + "} is followed by unexpected content",{errorAtStart: true, type: "info"});
|
||||
ErrorFromTo(documentClosed, thisDelimiter, "\\end{" + documentClosed.name + "} is followed by unexpected content",{errorAtStart: true, type: "info"});
|
||||
} else {
|
||||
ErrorTo(thisEnv, "unexpected " + getName(thisEnv));
|
||||
ErrorTo(thisDelimiter, "unexpected " + getName(thisDelimiter));
|
||||
}
|
||||
} else if (invalidEnvs.length > 0 && (i = indexOfClosingEnvInArray(invalidEnvs, thisEnv) > -1)) {
|
||||
} else if (invalidEnvs.length > 0 && (i = indexOfClosingEnvInArray(invalidEnvs, thisDelimiter) > -1)) {
|
||||
invalidEnvs.splice(i, 1);
|
||||
if (lastEnv) { state.push(lastEnv); } ;
|
||||
return;
|
||||
} else {
|
||||
var status = reportError(lastEnv, thisEnv);
|
||||
if (envPrecedence(lastEnv) < envPrecedence(thisEnv)) {
|
||||
invalidEnvs.push(lastEnv);
|
||||
var status = reportError(lastDelimiter, thisDelimiter);
|
||||
if (delimiterPrecedence(lastDelimiter) < delimiterPrecedence(thisDelimiter)) {
|
||||
document.closeEnv();
|
||||
invalidEnvs.push(lastDelimiter);
|
||||
retry = true;
|
||||
} else {
|
||||
var prevLastEnv = state.pop();
|
||||
if(prevLastEnv) {
|
||||
if (thisEnv.name === prevLastEnv.name) {
|
||||
var prevDelimiter = document.getPreviousDelimiter();
|
||||
if(prevDelimiter) {
|
||||
if (thisDelimiter.name === prevDelimiter.name) {
|
||||
document.closeEnv() // Close current env
|
||||
document.closeEnv(thisDelimiter) // Close previous env
|
||||
return;
|
||||
} else {
|
||||
state.push(prevLastEnv);
|
||||
}
|
||||
}
|
||||
invalidEnvs.push(lastEnv);
|
||||
invalidEnvs.push(lastDelimiter);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2082,28 +2202,28 @@ var EnvHandler = function (ErrorReporter) {
|
|||
"$$": "$$"
|
||||
};
|
||||
|
||||
var closedBy = function (lastEnv, thisEnv) {
|
||||
if (!lastEnv) {
|
||||
var closedBy = function (lastDelimiter, thisDelimiter) {
|
||||
if (!lastDelimiter) {
|
||||
return false ;
|
||||
} else if (thisEnv.command === "end") {
|
||||
return lastEnv.command === "begin" && lastEnv.name === thisEnv.name;
|
||||
} else if (thisEnv.command === CLOSING_DELIMITER[lastEnv.command]) {
|
||||
} else if (thisDelimiter.command === "end") {
|
||||
return lastDelimiter.command === "begin" && lastDelimiter.name === thisDelimiter.name;
|
||||
} else if (thisDelimiter.command === CLOSING_DELIMITER[lastDelimiter.command]) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
var indexOfClosingEnvInArray = function (envs, thisEnv) {
|
||||
for (var i = 0, n = envs.length; i < n ; i++) {
|
||||
if (closedBy(envs[i], thisEnv)) {
|
||||
var indexOfClosingEnvInArray = function (delimiters, thisDelimiter) {
|
||||
for (var i = 0, n = delimiters.length; i < n ; i++) {
|
||||
if (closedBy(delimiters[i], thisDelimiter)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
var envPrecedence = function (env) {
|
||||
var delimiterPrecedence = function (delimiter) {
|
||||
var openScore = {
|
||||
"{" : 1,
|
||||
"left" : 2,
|
||||
|
@ -2118,14 +2238,14 @@ var EnvHandler = function (ErrorReporter) {
|
|||
"$$" : 5,
|
||||
"end": 4
|
||||
};
|
||||
if (env.command) {
|
||||
return openScore[env.command] || closeScore[env.command];
|
||||
if (delimiter.command) {
|
||||
return openScore[delimiter.command] || closeScore[delimiter.command];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
var getName = function(env) {
|
||||
var getName = function(delimiter) {
|
||||
var description = {
|
||||
"{" : "open group {",
|
||||
"}" : "close group }",
|
||||
|
@ -2138,12 +2258,12 @@ var EnvHandler = function (ErrorReporter) {
|
|||
"left" : "\\left",
|
||||
"right" : "\\right"
|
||||
};
|
||||
if (env.command === "begin" || env.command === "end") {
|
||||
return "\\" + env.command + "{" + env.name + "}";
|
||||
} else if (env.command in description) {
|
||||
return description[env.command];
|
||||
if (delimiter.command === "begin" || delimiter.command === "end") {
|
||||
return "\\" + delimiter.command + "{" + delimiter.name + "}";
|
||||
} else if (delimiter.command in description) {
|
||||
return description[delimiter.command];
|
||||
} else {
|
||||
return env.command;
|
||||
return delimiter.command;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2151,81 +2271,81 @@ var EnvHandler = function (ErrorReporter) {
|
|||
var UNCLOSED_GROUP = 2;
|
||||
var UNCLOSED_ENV = 3;
|
||||
|
||||
var reportError = function(lastEnv, thisEnv) {
|
||||
if (!lastEnv) { // unexpected close, nothing was open!
|
||||
var reportError = function(lastDelimiter, thisDelimiter) {
|
||||
if (!lastDelimiter) { // unexpected close, nothing was open!
|
||||
if (documentClosed) {
|
||||
ErrorFromTo(documentClosed, thisEnv, "\\end{" + documentClosed.name + "} is followed by unexpected end group }",{errorAtStart: true, type: "info"});
|
||||
ErrorFromTo(documentClosed, thisDelimiter, "\\end{" + documentClosed.name + "} is followed by unexpected end group }",{errorAtStart: true, type: "info"});
|
||||
} else {
|
||||
ErrorTo(thisEnv, "unexpected " + getName(thisEnv));
|
||||
ErrorTo(thisDelimiter, "unexpected " + getName(thisDelimiter));
|
||||
};
|
||||
return EXTRA_CLOSE;
|
||||
} else if (lastEnv.command === "{" && thisEnv.command === "end") {
|
||||
ErrorFromTo(lastEnv, thisEnv, "unclosed " + getName(lastEnv) + " found at " + getName(thisEnv),
|
||||
} else if (lastDelimiter.command === "{" && thisDelimiter.command === "end") {
|
||||
ErrorFromTo(lastDelimiter, thisDelimiter, "unclosed " + getName(lastDelimiter) + " found at " + getName(thisDelimiter),
|
||||
{suppressIfEditing:true, errorAtStart: true, type:"warning"});
|
||||
return UNCLOSED_GROUP;
|
||||
} else {
|
||||
var pLast = envPrecedence(lastEnv);
|
||||
var pThis = envPrecedence(thisEnv);
|
||||
var pLast = delimiterPrecedence(lastDelimiter);
|
||||
var pThis = delimiterPrecedence(thisDelimiter);
|
||||
if (pThis > pLast) {
|
||||
ErrorFromTo(lastEnv, thisEnv, "unclosed " + getName(lastEnv) + " found at " + getName(thisEnv),
|
||||
ErrorFromTo(lastDelimiter, thisDelimiter, "unclosed " + getName(lastDelimiter) + " found at " + getName(thisDelimiter),
|
||||
{suppressIfEditing:true, errorAtStart: true});
|
||||
} else {
|
||||
ErrorFromTo(lastEnv, thisEnv, "unexpected " + getName(thisEnv) + " after " + getName(lastEnv));
|
||||
ErrorFromTo(lastDelimiter, thisDelimiter, "unexpected " + getName(thisDelimiter) + " after " + getName(lastDelimiter));
|
||||
}
|
||||
return UNCLOSED_ENV;
|
||||
};
|
||||
};
|
||||
|
||||
this._beginMathMode = function (thisEnv) {
|
||||
this._beginMathMode = function (thisDelimiter) {
|
||||
var currentMathMode = this.getMathMode(); // undefined, null, $, $$, name of mathmode env
|
||||
if (currentMathMode) {
|
||||
ErrorFrom(thisEnv, getName(thisEnv) + " used inside existing math mode " + getName(currentMathMode),
|
||||
ErrorFrom(thisDelimiter, getName(thisDelimiter) + " used inside existing math mode " + getName(currentMathMode),
|
||||
{suppressIfEditing:true, errorAtStart: true, mathMode:true});
|
||||
};
|
||||
thisEnv.mathMode = thisEnv;
|
||||
state.push(thisEnv);
|
||||
thisDelimiter.mathMode = thisDelimiter;
|
||||
document.openEnv(thisDelimiter);
|
||||
};
|
||||
|
||||
this._toggleMathMode = function (thisEnv) {
|
||||
var lastEnv = state.pop();
|
||||
if (closedBy(lastEnv, thisEnv)) {
|
||||
this._toggleMathMode = function (thisDelimiter) {
|
||||
var lastDelimiter = document.getCurrentDelimiter();
|
||||
if (closedBy(lastDelimiter, thisDelimiter)) {
|
||||
document.closeEnv(thisDelimiter)
|
||||
return;
|
||||
} else {
|
||||
if (lastEnv) {state.push(lastEnv);}
|
||||
if (lastEnv && lastEnv.mathMode) {
|
||||
this._end(thisEnv);
|
||||
if (lastDelimiter && lastDelimiter.mathMode) {
|
||||
this._end(thisDelimiter);
|
||||
} else {
|
||||
thisEnv.mathMode = thisEnv;
|
||||
state.push(thisEnv);
|
||||
thisDelimiter.mathMode = thisDelimiter;
|
||||
document.openEnv(thisDelimiter);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
this.getMathMode = function () {
|
||||
var n = state.length;
|
||||
if (n > 0) {
|
||||
return state[n-1].mathMode;
|
||||
var currentDelimiter = document.getCurrentDelimiter();
|
||||
if (currentDelimiter) {
|
||||
return currentDelimiter.mathMode;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
this.insideGroup = function () {
|
||||
var n = state.length;
|
||||
if (n > 0) {
|
||||
return (state[n-1].command === "{");
|
||||
var currentDelimiter = document.getCurrentDelimiter();
|
||||
if (currentDelimiter) {
|
||||
return (currentDelimiter.command === "{");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
var resetMathMode = function () {
|
||||
var n = state.length;
|
||||
if (n > 0) {
|
||||
var lastMathMode = state[n-1].mathMode;
|
||||
var currentDelimiter = document.getCurrentDelimiter();
|
||||
if (currentDelimiter) {
|
||||
var lastMathMode = currentDelimiter.mathMode;
|
||||
do {
|
||||
var lastEnv = state.pop();
|
||||
} while (lastEnv && lastEnv !== lastMathMode);
|
||||
var lastDelimiter = document.closeEnv();
|
||||
} while (lastDelimiter && lastDelimiter !== lastMathMode);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
@ -2233,42 +2353,42 @@ var EnvHandler = function (ErrorReporter) {
|
|||
|
||||
this.resetMathMode = resetMathMode;
|
||||
|
||||
var getNewMathMode = function (currentMathMode, thisEnv) {
|
||||
var getNewMathMode = function (currentMathMode, thisDelimiter) {
|
||||
var newMathMode = null;
|
||||
|
||||
if (thisEnv.command === "{") {
|
||||
if (thisEnv.mathMode !== null) {
|
||||
newMathMode = thisEnv.mathMode;
|
||||
if (thisDelimiter.command === "{") {
|
||||
if (thisDelimiter.mathMode !== null) {
|
||||
newMathMode = thisDelimiter.mathMode;
|
||||
} else {
|
||||
newMathMode = currentMathMode;
|
||||
}
|
||||
} else if (thisEnv.command === "left") {
|
||||
} else if (thisDelimiter.command === "left") {
|
||||
if (currentMathMode === null) {
|
||||
ErrorFrom(thisEnv, "\\left can only be used in math mode", {mathMode: true});
|
||||
ErrorFrom(thisDelimiter, "\\left can only be used in math mode", {mathMode: true});
|
||||
};
|
||||
newMathMode = currentMathMode;
|
||||
} else if (thisEnv.command === "begin") {
|
||||
var name = thisEnv.name;
|
||||
} else if (thisDelimiter.command === "begin") {
|
||||
var name = thisDelimiter.name;
|
||||
if (name) {
|
||||
if (name.match(/^(document|figure|center|enumerate|itemize|table|abstract|proof|lemma|theorem|definition|proposition|corollary|remark|notation|thebibliography)$/)) {
|
||||
if (currentMathMode) {
|
||||
ErrorFromTo(currentMathMode, thisEnv, thisEnv.name + " used inside " + getName(currentMathMode),
|
||||
ErrorFromTo(currentMathMode, thisDelimiter, thisDelimiter.name + " used inside " + getName(currentMathMode),
|
||||
{suppressIfEditing:true, errorAtStart: true, mathMode: true});
|
||||
resetMathMode();
|
||||
};
|
||||
newMathMode = null;
|
||||
} else if (name.match(/^(array|gathered|split|aligned|alignedat)\*?$/)) {
|
||||
if (currentMathMode === null) {
|
||||
ErrorFrom(thisEnv, thisEnv.name + " not inside math mode", {mathMode: true});
|
||||
ErrorFrom(thisDelimiter, thisDelimiter.name + " not inside math mode", {mathMode: true});
|
||||
};
|
||||
newMathMode = currentMathMode;
|
||||
} else if (name.match(/^(math|displaymath|equation|eqnarray|multline|align|gather|flalign|alignat)\*?$/)) {
|
||||
if (currentMathMode) {
|
||||
ErrorFromTo(currentMathMode, thisEnv, thisEnv.name + " used inside " + getName(currentMathMode),
|
||||
ErrorFromTo(currentMathMode, thisDelimiter, thisDelimiter.name + " used inside " + getName(currentMathMode),
|
||||
{suppressIfEditing:true, errorAtStart: true, mathMode: true});
|
||||
resetMathMode();
|
||||
};
|
||||
newMathMode = thisEnv;
|
||||
newMathMode = thisDelimiter;
|
||||
} else {
|
||||
newMathMode = undefined; // undefined means we don't know if we are in math mode or not
|
||||
}
|
||||
|
@ -2277,41 +2397,41 @@ var EnvHandler = function (ErrorReporter) {
|
|||
return newMathMode;
|
||||
};
|
||||
|
||||
this.checkAndUpdateState = function (thisEnv) {
|
||||
this.checkAndUpdateState = function (thisDelimiter) {
|
||||
if (inVerbatim) {
|
||||
if (thisEnv.command === "end") {
|
||||
this._endVerbatim(thisEnv);
|
||||
if (thisDelimiter.command === "end") {
|
||||
this._endVerbatim(thisDelimiter);
|
||||
} else {
|
||||
return; // ignore anything in verbatim environments
|
||||
}
|
||||
} else if(thisEnv.command === "begin" || thisEnv.command === "{" || thisEnv.command === "left") {
|
||||
if (thisEnv.verbatim) {inVerbatim = true;};
|
||||
} else if(thisDelimiter.command === "begin" || thisDelimiter.command === "{" || thisDelimiter.command === "left") {
|
||||
if (thisDelimiter.verbatim) {inVerbatim = true;};
|
||||
var currentMathMode = this.getMathMode(); // undefined, null, $, $$, name of mathmode env
|
||||
var newMathMode = getNewMathMode(currentMathMode, thisEnv);
|
||||
thisEnv.mathMode = newMathMode;
|
||||
state.push(thisEnv);
|
||||
} else if (thisEnv.command === "end") {
|
||||
this._end(thisEnv);
|
||||
} else if (thisEnv.command === "(" || thisEnv.command === "[") {
|
||||
this._beginMathMode(thisEnv);
|
||||
} else if (thisEnv.command === ")" || thisEnv.command === "]") {
|
||||
this._end(thisEnv);
|
||||
} else if (thisEnv.command === "}") {
|
||||
this._end(thisEnv);
|
||||
} else if (thisEnv.command === "right") {
|
||||
this._end(thisEnv);
|
||||
} else if (thisEnv.command === "$" || thisEnv.command === "$$") {
|
||||
this._toggleMathMode(thisEnv);
|
||||
var newMathMode = getNewMathMode(currentMathMode, thisDelimiter);
|
||||
thisDelimiter.mathMode = newMathMode;
|
||||
document.openEnv(thisDelimiter);
|
||||
} else if (thisDelimiter.command === "end") {
|
||||
this._end(thisDelimiter);
|
||||
} else if (thisDelimiter.command === "(" || thisDelimiter.command === "[") {
|
||||
this._beginMathMode(thisDelimiter);
|
||||
} else if (thisDelimiter.command === ")" || thisDelimiter.command === "]") {
|
||||
this._end(thisDelimiter);
|
||||
} else if (thisDelimiter.command === "}") {
|
||||
this._end(thisDelimiter);
|
||||
} else if (thisDelimiter.command === "right") {
|
||||
this._end(thisDelimiter);
|
||||
} else if (thisDelimiter.command === "$" || thisDelimiter.command === "$$") {
|
||||
this._toggleMathMode(thisDelimiter);
|
||||
}
|
||||
};
|
||||
|
||||
this.close = function () {
|
||||
while (state.length > 0) {
|
||||
var thisEnv = state.pop();
|
||||
if (thisEnv.command === "{") {
|
||||
ErrorFrom(thisEnv, "unclosed group {", {type:"warning"});
|
||||
while (document.getDepth() > 0) {
|
||||
var thisDelimiter = document.closeEnv();
|
||||
if (thisDelimiter.command === "{") {
|
||||
ErrorFrom(thisDelimiter, "unclosed group {", {type:"warning"});
|
||||
} else {
|
||||
ErrorFrom(thisEnv, "unclosed " + getName(thisEnv));
|
||||
ErrorFrom(thisDelimiter, "unclosed " + getName(thisDelimiter));
|
||||
}
|
||||
}
|
||||
var vlen = verbatimRanges.length;
|
||||
|
@ -2331,10 +2451,10 @@ var EnvHandler = function (ErrorReporter) {
|
|||
}
|
||||
};
|
||||
|
||||
this.setEnvProps = function (env) {
|
||||
var name = env.name ;
|
||||
this.setDelimiterProps = function (delimiter) {
|
||||
var name = delimiter.name ;
|
||||
if (name && name.match(/^(verbatim|boxedverbatim|lstlisting|minted|Verbatim)$/)) {
|
||||
env.verbatim = true;
|
||||
delimiter.verbatim = true;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -2458,9 +2578,9 @@ var ErrorReporter = function (TokeniseResult) {
|
|||
errors.push(err);
|
||||
};
|
||||
|
||||
this.EnvErrorFrom = function (env, message, options) {
|
||||
this.EnvErrorFrom = function (delimiter, message, options) {
|
||||
if(!options) { options = {} ; };
|
||||
var token = env.token;
|
||||
var token = delimiter.token;
|
||||
var line = token[0], type = token[1], start = token[2], end = token[3];
|
||||
var start_col = start - linePosition[line];
|
||||
var end_col = Infinity;
|
||||
|
@ -2481,29 +2601,11 @@ var Parse = function (text) {
|
|||
var Reporter = new ErrorReporter(TokeniseResult);
|
||||
var Environments = InterpretTokens(TokeniseResult, Reporter);
|
||||
Environments.close();
|
||||
return Reporter.getErrors();
|
||||
return {
|
||||
errors: Reporter.getErrors(),
|
||||
contexts: Environments.getDocument().getContexts()
|
||||
}
|
||||
};
|
||||
|
||||
(function() {
|
||||
var disabled = false;
|
||||
|
||||
this.onUpdate = function() {
|
||||
if (disabled) { return ; };
|
||||
|
||||
var value = this.doc.getValue();
|
||||
var errors = [];
|
||||
try {
|
||||
if (value)
|
||||
errors = Parse(value);
|
||||
} catch (e) {
|
||||
disabled = true;
|
||||
errors = [];
|
||||
}
|
||||
this.sender.emit("lint", errors);
|
||||
};
|
||||
|
||||
}).call(LatexWorker.prototype);
|
||||
|
||||
});
|
||||
|
||||
ace.define("ace/lib/es5-shim",["require","exports","module"], function(require, exports, module) {
|
||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue