
Previously, we were at an ACE editor published between 1.1.8 and 1.1.9. This caused multiple issues and was especially a problem for the upcoming pair programming feature. Further, updating ace is a long-time priority, see https://github.com/openHPI/codeocean/issues/250. Now, we are not yet updating to the latest version, but rather to the next minor version. This already contains breaking changes, and we are currently interested to keep the number of changes as low as possible. Further updating ACE might be still a future task. The new ACE version 1.2.0 is taken from this tag: https://github.com/ajaxorg/ace-builds/releases/tag/v1.2.0. We are using the src build (not minified, not in the noconflict version), since the same was used before as well. Further, we need to change our migration for storing editor events. Since the table is not yet used (in production), we also update the enum.
185 lines
5.3 KiB
JavaScript
185 lines
5.3 KiB
JavaScript
define("ace/ext/whitespace",["require","exports","module","ace/lib/lang"], function(require, exports, module) {
|
|
"use strict";
|
|
|
|
var lang = require("../lib/lang");
|
|
exports.$detectIndentation = function(lines, fallback) {
|
|
var stats = [];
|
|
var changes = [];
|
|
var tabIndents = 0;
|
|
var prevSpaces = 0;
|
|
var max = Math.min(lines.length, 1000);
|
|
for (var i = 0; i < max; i++) {
|
|
var line = lines[i];
|
|
if (!/^\s*[^*+\-\s]/.test(line))
|
|
continue;
|
|
|
|
if (line[0] == "\t") {
|
|
tabIndents++;
|
|
prevSpaces = -Number.MAX_VALUE;
|
|
} else {
|
|
var spaces = line.match(/^ */)[0].length;
|
|
if (spaces && line[spaces] != "\t") {
|
|
var diff = spaces - prevSpaces;
|
|
if (diff > 0 && !(prevSpaces%diff) && !(spaces%diff))
|
|
changes[diff] = (changes[diff] || 0) + 1;
|
|
|
|
stats[spaces] = (stats[spaces] || 0) + 1;
|
|
}
|
|
prevSpaces = spaces;
|
|
}
|
|
while (i < max && line[line.length - 1] == "\\")
|
|
line = lines[i++];
|
|
}
|
|
|
|
function getScore(indent) {
|
|
var score = 0;
|
|
for (var i = indent; i < stats.length; i += indent)
|
|
score += stats[i] || 0;
|
|
return score;
|
|
}
|
|
|
|
var changesTotal = changes.reduce(function(a,b){return a+b}, 0);
|
|
|
|
var first = {score: 0, length: 0};
|
|
var spaceIndents = 0;
|
|
for (var i = 1; i < 12; i++) {
|
|
var score = getScore(i);
|
|
if (i == 1) {
|
|
spaceIndents = score;
|
|
score = stats[1] ? 0.9 : 0.8;
|
|
if (!stats.length)
|
|
score = 0;
|
|
} else
|
|
score /= spaceIndents;
|
|
|
|
if (changes[i])
|
|
score += changes[i] / changesTotal;
|
|
|
|
if (score > first.score)
|
|
first = {score: score, length: i};
|
|
}
|
|
|
|
if (first.score && first.score > 1.4)
|
|
var tabLength = first.length;
|
|
|
|
if (tabIndents > spaceIndents + 1) {
|
|
if (tabLength == 1 || spaceIndents < tabIndents / 4 || first.score < 1.8)
|
|
tabLength = undefined;
|
|
return {ch: "\t", length: tabLength};
|
|
}
|
|
if (spaceIndents > tabIndents + 1)
|
|
return {ch: " ", length: tabLength};
|
|
};
|
|
|
|
exports.detectIndentation = function(session) {
|
|
var lines = session.getLines(0, 1000);
|
|
var indent = exports.$detectIndentation(lines) || {};
|
|
|
|
if (indent.ch)
|
|
session.setUseSoftTabs(indent.ch == " ");
|
|
|
|
if (indent.length)
|
|
session.setTabSize(indent.length);
|
|
return indent;
|
|
};
|
|
|
|
exports.trimTrailingSpace = function(session, trimEmpty) {
|
|
var doc = session.getDocument();
|
|
var lines = doc.getAllLines();
|
|
|
|
var min = trimEmpty ? -1 : 0;
|
|
|
|
for (var i = 0, l=lines.length; i < l; i++) {
|
|
var line = lines[i];
|
|
var index = line.search(/\s+$/);
|
|
|
|
if (index > min)
|
|
doc.removeInLine(i, index, line.length);
|
|
}
|
|
};
|
|
|
|
exports.convertIndentation = function(session, ch, len) {
|
|
var oldCh = session.getTabString()[0];
|
|
var oldLen = session.getTabSize();
|
|
if (!len) len = oldLen;
|
|
if (!ch) ch = oldCh;
|
|
|
|
var tab = ch == "\t" ? ch: lang.stringRepeat(ch, len);
|
|
|
|
var doc = session.doc;
|
|
var lines = doc.getAllLines();
|
|
|
|
var cache = {};
|
|
var spaceCache = {};
|
|
for (var i = 0, l=lines.length; i < l; i++) {
|
|
var line = lines[i];
|
|
var match = line.match(/^\s*/)[0];
|
|
if (match) {
|
|
var w = session.$getStringScreenWidth(match)[0];
|
|
var tabCount = Math.floor(w/oldLen);
|
|
var reminder = w%oldLen;
|
|
var toInsert = cache[tabCount] || (cache[tabCount] = lang.stringRepeat(tab, tabCount));
|
|
toInsert += spaceCache[reminder] || (spaceCache[reminder] = lang.stringRepeat(" ", reminder));
|
|
|
|
if (toInsert != match) {
|
|
doc.removeInLine(i, 0, match.length);
|
|
doc.insertInLine({row: i, column: 0}, toInsert);
|
|
}
|
|
}
|
|
}
|
|
session.setTabSize(len);
|
|
session.setUseSoftTabs(ch == " ");
|
|
};
|
|
|
|
exports.$parseStringArg = function(text) {
|
|
var indent = {};
|
|
if (/t/.test(text))
|
|
indent.ch = "\t";
|
|
else if (/s/.test(text))
|
|
indent.ch = " ";
|
|
var m = text.match(/\d+/);
|
|
if (m)
|
|
indent.length = parseInt(m[0], 10);
|
|
return indent;
|
|
};
|
|
|
|
exports.$parseArg = function(arg) {
|
|
if (!arg)
|
|
return {};
|
|
if (typeof arg == "string")
|
|
return exports.$parseStringArg(arg);
|
|
if (typeof arg.text == "string")
|
|
return exports.$parseStringArg(arg.text);
|
|
return arg;
|
|
};
|
|
|
|
exports.commands = [{
|
|
name: "detectIndentation",
|
|
exec: function(editor) {
|
|
exports.detectIndentation(editor.session);
|
|
}
|
|
}, {
|
|
name: "trimTrailingSpace",
|
|
exec: function(editor) {
|
|
exports.trimTrailingSpace(editor.session);
|
|
}
|
|
}, {
|
|
name: "convertIndentation",
|
|
exec: function(editor, arg) {
|
|
var indent = exports.$parseArg(arg);
|
|
exports.convertIndentation(editor.session, indent.ch, indent.length);
|
|
}
|
|
}, {
|
|
name: "setIndentation",
|
|
exec: function(editor, arg) {
|
|
var indent = exports.$parseArg(arg);
|
|
indent.length && editor.session.setTabSize(indent.length);
|
|
indent.ch && editor.session.setUseSoftTabs(indent.ch == " ");
|
|
}
|
|
}];
|
|
|
|
});
|
|
(function() {
|
|
window.require(["ace/ext/whitespace"], function() {});
|
|
})();
|
|
|