This commit is contained in:
Resolver Developers 2011-08-10 14:07:00 +01:00
commit 707346c920
165 changed files with 47150 additions and 8364 deletions

View file

@ -134,6 +134,7 @@ var Anchor = exports.Anchor = function(doc, row, column) {
};
this.setPosition = function(row, column, noClip) {
var pos;
if (noClip) {
pos = {
row: row,

View file

@ -1,8 +1,7 @@
.ace_editor {
position: absolute;
overflow: hidden;
font-family: "Menlo", "Monaco", "Courier New", monospace;
font-family: Monaco, "Menlo", "Courier New", monospace;
font-size: 12px;
}
@ -81,6 +80,7 @@
opacity: 0;
background: transparent;
appearance: none;
-moz-appearance: none;
border: none;
resize: none;
outline: none;
@ -97,7 +97,6 @@
}
.ace_text-layer {
font-family: Monaco, "Courier New", monospace;
color: black;
}
@ -109,7 +108,7 @@
.ace_cursor-layer {
z-index: 4;
cursor: text;
pointer-events: none;
/* setting pointer-events: none; here will break mouse wheel scrolling in Safari */
}
.ace_cursor {

View file

@ -87,7 +87,7 @@ var Document = function(text) {
this.$detectNewLine = function(text) {
var match = text.match(/^.*?(\r?\n)/m);
var match = text.match(/^.*?(\r\n|\r|\n)/m);
if (match) {
this.$autoNewLine = match[1];
} else {
@ -111,7 +111,8 @@ var Document = function(text) {
this.$autoNewLine = "\n";
this.$newLineMode = "auto";
this.setNewLineMode = function(newLineMode) {
if (this.$newLineMode === newLineMode) return;
if (this.$newLineMode === newLineMode)
return;
this.$newLineMode = newLineMode;
};
@ -183,14 +184,12 @@ var Document = function(text) {
var firstLine = lines.splice(0, 1)[0];
var lastLine = lines.length == 0 ? null : lines.splice(lines.length - 1, 1)[0];
this._dispatchEvent("changeStart");
position = this.insertInLine(position, firstLine);
if (lastLine !== null) {
position = this.insertNewLine(position); // terminate first line
position = this.insertLines(position.row, lines);
position = this.insertInLine(position, lastLine || "");
}
this._dispatchEvent("changeEnd");
return position;
};
@ -202,7 +201,6 @@ var Document = function(text) {
args.push.apply(args, lines);
this.$lines.splice.apply(this.$lines, args);
this._dispatchEvent("changeStart");
var range = new Range(row, 0, row + lines.length, 0);
var delta = {
action: "insertLines",
@ -210,7 +208,6 @@ var Document = function(text) {
lines: lines
};
this._dispatchEvent("change", { data: delta });
this._dispatchEvent("changeEnd");
return range.end;
},
@ -218,7 +215,6 @@ var Document = function(text) {
position = this.$clipPosition(position);
var line = this.$lines[position.row] || "";
this._dispatchEvent("changeStart");
this.$lines[position.row] = line.substring(0, position.column);
this.$lines.splice(position.row + 1, 0, line.substring(position.column, line.length));
@ -233,7 +229,6 @@ var Document = function(text) {
text: this.getNewLineCharacter()
};
this._dispatchEvent("change", { data: delta });
this._dispatchEvent("changeEnd");
return end;
};
@ -244,7 +239,6 @@ var Document = function(text) {
var line = this.$lines[position.row] || "";
this._dispatchEvent("changeStart");
this.$lines[position.row] = line.substring(0, position.column) + text
+ line.substring(position.column);
@ -259,7 +253,6 @@ var Document = function(text) {
text: text
};
this._dispatchEvent("change", { data: delta });
this._dispatchEvent("changeEnd");
return end;
};
@ -275,7 +268,6 @@ var Document = function(text) {
var firstRow = range.start.row;
var lastRow = range.end.row;
this._dispatchEvent("changeStart");
if (range.isMultiLine()) {
var firstFullRow = range.start.column == 0 ? firstRow : firstRow + 1;
var lastFullRow = lastRow - 1;
@ -294,7 +286,6 @@ var Document = function(text) {
else {
this.removeInLine(firstRow, range.start.column, range.end.column);
}
this._dispatchEvent("changeEnd");
return range.start;
};
@ -306,7 +297,6 @@ var Document = function(text) {
var line = this.getLine(row);
var removed = line.substring(startColumn, endColumn);
var newLine = line.substring(0, startColumn) + line.substring(endColumn, line.length);
this._dispatchEvent("changeStart");
this.$lines.splice(row, 1, newLine);
var delta = {
@ -315,7 +305,6 @@ var Document = function(text) {
text: removed
};
this._dispatchEvent("change", { data: delta });
this._dispatchEvent("changeEnd");
return range.start;
};
@ -327,7 +316,6 @@ var Document = function(text) {
* @return {String[]} The removed lines
*/
this.removeLines = function(firstRow, lastRow) {
this._dispatchEvent("changeStart");
var range = new Range(firstRow, 0, lastRow + 1, 0);
var removed = this.$lines.splice(firstRow, lastRow - firstRow + 1);
@ -338,7 +326,6 @@ var Document = function(text) {
lines: removed
};
this._dispatchEvent("change", { data: delta });
this._dispatchEvent("changeEnd");
return removed;
};
@ -349,7 +336,6 @@ var Document = function(text) {
var range = new Range(row, firstLine.length, row+1, 0);
var line = firstLine + secondLine;
this._dispatchEvent("changeStart");
this.$lines.splice(row, 2, line);
var delta = {
@ -358,7 +344,6 @@ var Document = function(text) {
text: this.getNewLineCharacter()
};
this._dispatchEvent("change", { data: delta });
this._dispatchEvent("changeEnd");
};
this.replace = function(range, text) {
@ -370,7 +355,6 @@ var Document = function(text) {
if (text == this.getTextRange(range))
return range.end;
this._dispatchEvent("changeStart");
this.remove(range);
if (text) {
var end = this.insert(range.start, text);
@ -378,7 +362,6 @@ var Document = function(text) {
else {
end = range.start;
}
this._dispatchEvent("changeEnd");
return end;
};

View file

@ -56,7 +56,6 @@ var EditSession = function(text, mode) {
this.$backMarkers = {};
this.$markerId = 1;
this.$rowCache = [];
this.$rowCacheSize = 1000;
this.$wrapData = [];
this.$foldData = [];
this.$foldData.toString = function() {
@ -66,7 +65,6 @@ var EditSession = function(text, mode) {
});
return str;
}
this.$docChangeCounter = 0;
if (text instanceof Document) {
this.setDocument(text);
@ -92,8 +90,6 @@ var EditSession = function(text, mode) {
this.doc = doc;
doc.on("change", this.onChange.bind(this));
doc.on("changeStart", this.onChangeStart.bind(this));
doc.on("changeEnd", this.onChangeEnd.bind(this));
this.on("changeFold", this.onChangeFold.bind(this));
};
@ -101,10 +97,6 @@ var EditSession = function(text, mode) {
return this.doc;
};
this.onChangeStart = function() {
this.$docChangeCounter ++;
};
this.$resetRowCache = function(row) {
if (row == 0) {
this.$rowCache = [];
@ -117,29 +109,6 @@ var EditSession = function(text, mode) {
return;
}
}
}
this.onChangeEnd = function() {
this.$docChangeCounter --;
if (this.$docChangeCounter == 0
&& !this.$fromUndo && this.$undoManager)
{
if (this.$deltasFold.length) {
this.$deltas.push({
group: "fold",
deltas: this.$deltasFold
});
this.$deltasFold = [];
}
if (this.$deltasDoc) {
this.$deltas.push({
group: "doc",
deltas: this.$deltasDoc
});
this.$deltasDoc = [];
}
this.$informUndoManager.schedule();
}
};
this.onChangeFold = function(e) {
@ -162,6 +131,8 @@ var EditSession = function(text, mode) {
folds: removedFolds
});
}
this.$informUndoManager.schedule();
}
this.bgTokenizer.start(delta.range.start.row);
@ -170,6 +141,9 @@ var EditSession = function(text, mode) {
this.setValue = function(text) {
this.doc.setValue(text);
this.selection.moveCursorTo(0, 0);
this.selection.clearSelection();
this.$resetRowCache(0);
this.$deltas = [];
this.$deltasDoc = [];
@ -201,19 +175,37 @@ var EditSession = function(text, mode) {
this.$deltasDoc = [];
this.$deltasFold = [];
if (this.$informUndoManager) {
if (this.$informUndoManager)
this.$informUndoManager.cancel();
}
if (undoManager) {
var self = this;
this.$syncInformUndoManager = function() {
self.$informUndoManager.cancel();
if (self.$deltas.length > 0)
undoManager.execute({
action : "aceupdate",
args : [self.$deltas, self]
if (self.$deltasFold.length) {
self.$deltas.push({
group: "fold",
deltas: self.$deltasFold
});
self.$deltasFold = [];
}
if (self.$deltasDoc.length) {
self.$deltas.push({
group: "doc",
deltas: self.$deltasDoc
});
self.$deltasDoc = [];
}
if (self.$deltas.length > 0) {
undoManager.execute({
action: "aceupdate",
args: [self.$deltas, self]
});
}
self.$deltas = [];
}
this.$informUndoManager =
@ -392,9 +384,6 @@ var EditSession = function(text, mode) {
}
};
this.tokenRe = /^[\w\d]+/g;
this.nonTokenRe = /^(?:[^\w\d]|[\u3040-\u309F]|[\u30A0-\u30FF]|[\u4E00-\u9FFF\uF900-\uFAFF\u3400-\u4DBF])+/g;
this.getWordRange = function(row, column) {
var line = this.getLine(row);
@ -485,6 +474,9 @@ var EditSession = function(text, mode) {
this.bgTokenizer.setDocument(this.getDocument());
this.bgTokenizer.start(0);
this.tokenRe = mode.tokenRe;
this.nonTokenRe = mode.nonTokenRe;
this._dispatchEvent("changeMode");
};
@ -898,6 +890,28 @@ var EditSession = function(text, mode) {
this.$clipRowToDocument = function(row) {
return Math.max(0, Math.min(row, this.doc.getLength()-1));
};
this.$clipPositionToDocument = function(row, column) {
column = Math.max(0, column);
if (row < 0) {
row = 0;
column = 0;
} else {
var len = this.doc.getLength();
if (row >= len) {
row = len - 1;
column = this.doc.getLine(len-1).length;
} else {
column = Math.min(this.doc.getLine(row).length, column);
}
}
return {
row: row,
column: column
};
};
// WRAPMODE
this.$wrapLimit = 80;
@ -1352,6 +1366,9 @@ var EditSession = function(text, mode) {
return [screenColumn, column];
}
/**
* Returns the number of rows required to render this row on the screen
*/
this.getRowLength = function(row) {
if (!this.$useWrapMode || !this.$wrapData[row]) {
return 1;
@ -1360,15 +1377,16 @@ var EditSession = function(text, mode) {
}
}
/**
* Returns the height in pixels required to render this row on the screen
**/
this.getRowHeight = function(config, row) {
return this.getRowLength(row) * config.lineHeight;
}
this.getScreenLastRowColumn = function(screenRow) {
// Note: This won't work if someone has more then
// 1.7976931348623158e+307 characters in one row. But I think we can
// live with this limitation ;)
return this.screenToDocumentColumn(screenRow, Number.MAX_VALUE / 10)
//return this.screenToDocumentColumn(screenRow, Number.MAX_VALUE / 10)
return this.documentToScreenColumn(screenRow, this.doc.getLine(screenRow).length);
};
this.getDocumentLastRowColumn = function(docRow, docColumn) {
@ -1405,6 +1423,13 @@ var EditSession = function(text, mode) {
};
this.screenToDocumentPosition = function(screenRow, screenColumn) {
if (screenRow < 0) {
return {
row: 0,
column: 0
}
}
var line;
var docRow = 0;
var docColumn = 0;
@ -1412,45 +1437,44 @@ var EditSession = function(text, mode) {
var foldLineRowLength;
var row = 0;
var rowLength = 0;
var splits = null;
var rowCache = this.$rowCache;
var doCache = !rowCache.length;
for (var i = 0; i < rowCache.length; i++) {
if (rowCache[i].screenRow < screenRow) {
row = rowCache[i].screenRow;
docRow = rowCache[i].docRow;
doCache = i == rowCache.length - 1;
}
else {
break;
}
}
var docRowCacheLast = docRow;
var doCache = !rowCache.length || i == rowCache.length;
// clamp row before clamping column, for selection on last line
var maxRow = this.getLength() - 1;
var foldLine = this.getNextFold(docRow);
var foldStart = foldLine ?foldLine.start.row :Infinity;
var foldStart = foldLine ? foldLine.start.row : Infinity;
while (row <= screenRow) {
if (doCache
&& docRow - docRowCacheLast > this.$rowCacheSize) {
rowCache.push({
docRow: docRow,
screenRow: row
});
docRowCacheLast = docRow;
}
rowLength = this.getRowLength(docRow);
if (row + rowLength - 1 >= screenRow || docRow >= maxRow) {
break;
} else {
row += rowLength;
docRow++;
if(docRow > foldStart) {
if (docRow > foldStart) {
docRow = foldLine.end.row+1;
foldLine = this.getNextFold(docRow);
foldStart = foldLine ?foldLine.start.row :Infinity;
foldStart = foldLine ? foldLine.start.row : Infinity;
}
}
if (doCache) {
rowCache.push({
docRow: docRow,
screenRow: row
});
}
}
if (foldLine && foldLine.start.row <= docRow)
@ -1460,6 +1484,7 @@ var EditSession = function(text, mode) {
foldLine = null;
}
var splits = [];
if (this.$useWrapMode) {
splits = this.$wrapData[docRow];
if (splits) {
@ -1473,6 +1498,10 @@ var EditSession = function(text, mode) {
docColumn += this.$getStringScreenWidth(line, screenColumn)[1];
// clip row at the end of the document
if (row + splits.length < screenRow)
docColumn = Number.MAX_VALUE;
// Need to do some clamping action here.
if (this.$useWrapMode) {
if (docColumn >= column) {
@ -1488,7 +1517,7 @@ var EditSession = function(text, mode) {
if (foldLine) {
return foldLine.idxToPosition(docColumn);
}
return {
row: docRow,
column: docColumn
@ -1497,10 +1526,15 @@ var EditSession = function(text, mode) {
this.documentToScreenPosition = function(docRow, docColumn) {
// Normalize the passed in arguments.
if (docColumn == null) {
docColumn = docRow.column;
docRow = docRow.row;
}
if (typeof docColumn === "undefined")
var pos = this.$clipPositionToDocument(docRow.row, docRow.column);
else
pos = this.$clipPositionToDocument(docRow, docColumn);
docRow = pos.row;
docColumn = pos.column;
var LL = this.$rowCache.length;
var wrapData;
// Special case in wrapMode if the doc is at the end of the document.
@ -1530,16 +1564,16 @@ var EditSession = function(text, mode) {
var rowEnd, row = 0;
var rowCache = this.$rowCache;
//
var doCache = !rowCache.length;
for (var i = 0; i < rowCache.length; i++) {
if (rowCache[i].docRow < docRow) {
screenRow = rowCache[i].screenRow;
row = rowCache[i].docRow;
doCache = i == rowCache.length - 1;
} else {
break;
}
}
var docRowCacheLast = row;
var doCache = !rowCache.length || i == rowCache.length;
var foldLine = this.getNextFold(row);
var foldStart = foldLine ?foldLine.start.row :Infinity;
@ -1551,20 +1585,20 @@ var EditSession = function(text, mode) {
break;
foldLine = this.getNextFold(rowEnd);
foldStart = foldLine ?foldLine.start.row :Infinity;
} else {
rowEnd = row + 1;
}
if (doCache
&& row - docRowCacheLast > this.$rowCacheSize) {
rowCache.push({
docRow: row,
screenRow: screenRow
});
docRowCacheLast = row;
else {
rowEnd = row + 1;
}
screenRow += this.getRowLength(row);
row = rowEnd;
if (doCache) {
rowCache.push({
docRow: row,
screenRow: screenRow
});
}
}
// Calculate the text line that is displayed in docRow on the screen.
@ -1586,7 +1620,8 @@ var EditSession = function(text, mode) {
screenRowOffset++;
}
textLine = textLine.substring(
wrapRow[screenRowOffset - 1] || 0, textLine.length);
wrapRow[screenRowOffset - 1] || 0, textLine.length
);
}
return {

View file

@ -0,0 +1,79 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Julian Viereck <julian DOT viereck AT gmail DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
/**
* Simple fold-data struct.
**/
var Fold = exports.Fold = function(range, placeholder) {
this.foldLine = null;
this.placeholder = placeholder;
this.range = range;
this.start = range.start;
this.end = range.end;
this.sameRow = range.start.row == range.end.row;
this.subFolds = [];
};
(function() {
this.toString = function() {
return '"' + this.placeholder + '" ' + this.range.toString();
};
this.setFoldLine = function(foldLine) {
this.foldLine = foldLine;
this.subFolds.forEach(function(fold) {
fold.setFoldLine(foldLine);
});
};
this.clone = function() {
var range = this.range.clone();
var fold = new Fold(range, this.placeholder);
this.subFolds.forEach(function(subFold) {
fold.subFolds.push(subFold.clone());
});
return fold;
};
}).call(Fold.prototype);
});

View file

@ -40,40 +40,7 @@ define(function(require, exports, module) {
var Range = require("ace/range").Range;
var FoldLine = require("ace/edit_session/fold_line").FoldLine;
/**
* Simple fold-data struct.
**/
function Fold(range, placeholder) {
this.foldLine = null;
this.placeholder = placeholder;
this.range = range;
this.start = range.start;
this.end = range.end;
this.sameRow = range.start.row == range.end.row;
this.subFolds = [];
}
Fold.prototype.toString = function() {
return '"' + this.placeholder + '" ' + this.range.toString();
}
Fold.prototype.setFoldLine = function(foldLine) {
this.foldLine = foldLine;
this.subFolds.forEach(function(fold) {
fold.setFoldLine(foldLine);
});
}
Fold.prototype.clone = function() {
var range = this.range.clone();
var fold = new Fold(range, this.placeholder);
this.subFolds.forEach(function(subFold) {
fold.subFolds.push(subFold.clone());
});
return fold;
}
var Fold = require("ace/edit_session/fold").Fold;
function Folding() {
/**
@ -83,25 +50,22 @@ function Folding() {
*/
this.getFoldAt = function(row, column, side) {
var foldLine = this.getFoldLine(row);
if (foldLine) {
var folds = foldLine.folds,
fold;
for (var i = 0; i < folds.length; i++) {
fold = folds[i];
if (fold.range.contains(row, column)) {
if (side == 1 && fold.range.isEnd(row, column)) {
continue;
} else if (side == -1 && fold.range.isStart(row, column)) {
continue;
}
return fold;
}
}
} else {
if (!foldLine)
return null;
var folds = foldLine.folds;
for (var i = 0; i < folds.length; i++) {
var fold = folds[i];
if (fold.range.contains(row, column)) {
if (side == 1 && fold.range.isEnd(row, column)) {
continue;
} else if (side == -1 && fold.range.isStart(row, column)) {
continue;
}
return fold;
}
}
}
};
/**
* Returns all folds in the given range. Note, that this will return folds
@ -109,33 +73,30 @@ function Folding() {
*/
this.getFoldsInRange = function(range) {
range = range.clone();
var start = range.start,
end = range.end;
var foldLines = this.$foldData,
folds,
fold;
var cmp,
foundFolds = [];
var start = range.start;
var end = range.end;
var foldLines = this.$foldData;
var foundFolds = [];
start.column += 1;
end.column -= 1;
for (var i = 0; i < foldLines.length; i++) {
cmp = foldLines[i].range.compareRange(range);
// Range is before foldLine. No intersection. This means,
// there might be other foldLines that intersect.
var cmp = foldLines[i].range.compareRange(range);
if (cmp == 2) {
// Range is before foldLine. No intersection. This means,
// there might be other foldLines that intersect.
continue;
} else
// Range is after foldLine. There can't be any other foldLines then,
// so let's give up.
if (cmp == -2) {
}
else if (cmp == -2) {
// Range is after foldLine. There can't be any other foldLines then,
// so let's give up.
break;
}
folds = foldLines[i].folds;
var folds = foldLines[i].folds;
for (var j = 0; j < folds.length; j++) {
fold = folds[j];
var fold = folds[j];
cmp = fold.range.compareRange(range);
if (cmp == -2) {
break;
@ -171,46 +132,44 @@ function Folding() {
*/
this.getFoldStringAt = function(row, column, trim, foldLine) {
var foldLine = foldLine || this.getFoldLine(row);
if (!foldLine) {
if (!foldLine)
return null;
} else {
var fold, lastFold, cmp, str;
lastFold = {
end: { column: 0 }
};
// TODO: Refactor to use getNextFoldTo function.
for (var i = 0; i < foldLine.folds.length; i++) {
fold = foldLine.folds[i];
cmp = fold.range.compareEnd(row, column);
if (cmp == -1) {
str = this.getLine(fold.start.row).
substring(lastFold.end.column, fold.start.column);
break;
} else if (cmp == 0) {
return null;
}
lastFold = fold;
var lastFold = {
end: { column: 0 }
};
// TODO: Refactor to use getNextFoldTo function.
for (var i = 0; i < foldLine.folds.length; i++) {
var fold = foldLine.folds[i];
var cmp = fold.range.compareEnd(row, column);
if (cmp == -1) {
var str = this
.getLine(fold.start.row)
.substring(lastFold.end.column, fold.start.column);
break;
}
if (!str) {
str = this.getLine(fold.start.row).
substring(lastFold.end.column);
}
if (trim == -1) {
return str.substring(0, column - lastFold.end.column);
} else if (trim == 1) {
return str.substring(column - lastFold.end.column)
} else {
return str;
else if (cmp == 0) {
return null;
}
lastFold = fold;
}
if (!str)
str = this.getLine(fold.start.row).substring(lastFold.end.column);
if (trim == -1)
return str.substring(0, column - lastFold.end.column);
else if (trim == 1)
return str.substring(column - lastFold.end.column)
else
return str;
}
this.getFoldLine = function(docRow, startFoldLine) {
var foldData = this.$foldData;
var i = 0;
if(startFoldLine)
if (startFoldLine)
i = foldData.indexOf(startFoldLine);
if(i == -1)
if (i == -1)
i = 0;
for (i; i < foldData.length; i++) {
var foldLine = foldData[i];
@ -227,9 +186,9 @@ function Folding() {
this.getNextFold = function(docRow, startFoldLine) {
var foldData = this.$foldData, ans;
var i = 0;
if(startFoldLine)
if (startFoldLine)
i = foldData.indexOf(startFoldLine);
if(i == -1)
if (i == -1)
i = 0;
for (i; i < foldData.length; i++) {
var foldLine = foldData[i];
@ -246,7 +205,7 @@ function Folding() {
var foldLine = foldData[i],
end = foldLine.end.row,
start = foldLine.start.row;
if(end >= last) {
if (end >= last) {
if(start < last) {
if(start >= first)
rowCount -= last-start;
@ -279,76 +238,52 @@ function Folding() {
* The new created Fold object or an existing fold object in case the
* passed in range fits an existing fold exactly.
*/
this.addFold = function(placeholder, startRow, startColumn, endRow, endColumn) {
var range;
this.addFold = function(placeholder, range) {
var foldData = this.$foldData;
var foldRow = null;
var foldLine;
var fold;
var argsFold;
var folds;
var added = false;
if (placeholder instanceof Fold) {
argsFold = placeholder;
startRow = argsFold.range;
placeholder = argsFold.placeholder;
}
// Normalize parameters.
if (!(startRow instanceof Range)) {
range = new Range(startRow, startColumn, endRow, endColumn);
} else {
range = startRow;
startRow = range.start.row;
startColumn = range.start.column;
endRow = range.end.row;
endColumn = range.end.column;
}
if (placeholder instanceof Fold)
var fold = placeholder;
else
fold = new Fold(range, placeholder);
var startRow = fold.start.row;
var startColumn = fold.start.column;
var endRow = fold.end.row;
var endColumn = fold.end.column;
// --- Some checking ---
if (placeholder.length < 2) {
if (fold.placeholder.length < 2)
throw "Placeholder has to be at least 2 characters";
}
if (startRow == endRow && endColumn - startColumn < 2) {
if (startRow == endRow && endColumn - startColumn < 2)
throw "The range has to be at least 2 characters width";
}
fold = this.getFoldAt(startRow, startColumn, 1);
if (fold
&& fold.range.isEnd(endRow, endColumn)
&& fold.range.isStart(startRow, startColumn))
{
var existingFold = this.getFoldAt(startRow, startColumn, 1);
if (
existingFold
&& existingFold.range.isEnd(endRow, endColumn)
&& existingFold.range.isStart(startRow, startColumn)
) {
return fold;
}
fold = this.getFoldAt(startRow, startColumn, 1);
if (fold && !fold.range.isStart(startRow, startColumn)) {
existingFold = this.getFoldAt(startRow, startColumn, 1);
if (existingFold && !existingFold.range.isStart(startRow, startColumn))
throw "A fold can't start inside of an already existing fold";
}
fold = this.getFoldAt(endRow, endColumn, -1);
if (fold && !fold.range.isEnd(endRow, endColumn)) {
existingFold = this.getFoldAt(endRow, endColumn, -1);
if (existingFold && !existingFold.range.isEnd(endRow, endColumn))
throw "A fold can't end inside of an already existing fold";
}
if (endRow >= this.doc.getLength()) {
if (endRow >= this.doc.getLength())
throw "End of fold is outside of the document.";
}
if (endColumn > this.getLine(endRow).length
|| startColumn > this.getLine(startRow).length)
{
if (endColumn > this.getLine(endRow).length || startColumn > this.getLine(startRow).length)
throw "End of fold is outside of the document.";
}
// --- Start adding the fold ---
// Use the passed in fold or create a new one.
fold = argsFold || new Fold(range, placeholder);
// Check if there are folds in the range we create the new fold for.
folds = this.getFoldsInRange(range);
var folds = this.getFoldsInRange(fold.range);
if (folds.length > 0) {
// Remove the folds from fold data.
this.removeFolds(folds);
@ -357,12 +292,13 @@ function Folding() {
}
for (var i = 0; i < foldData.length; i++) {
foldLine = foldData[i];
var foldLine = foldData[i];
if (endRow == foldLine.start.row) {
foldLine.addFold(fold);
added = true;
break;
} else if (startRow == foldLine.end.row) {
}
else if (startRow == foldLine.end.row) {
foldLine.addFold(fold);
added = true;
if (!fold.sameRow) {
@ -375,18 +311,17 @@ function Folding() {
}
}
break;
} else if (endRow <= foldLine.start.row) {
}
else if (endRow <= foldLine.start.row) {
break;
}
}
if (!added) {
if (!added)
foldLine = this.$addFoldLine(new FoldLine(this.$foldData, fold));
}
if (this.$useWrapMode) {
if (this.$useWrapMode)
this.$updateWrapData(foldLine.start.row, foldLine.start.row);
}
// Notify that fold data has changed.
this.$modified = true;

View file

@ -155,6 +155,18 @@ module.exports = {
assert.equal(session.getValue(), ["1", "1", "2", "3"].join("\n"));
},
"test: getScreenLastRowColumn": function() {
var session = new EditSession([
"juhu",
"12\t\t34",
"ぁぁa"
]);
assert.equal(session.getScreenLastRowColumn(0), 4);
assert.equal(session.getScreenLastRowColumn(1), 10);
assert.equal(session.getScreenLastRowColumn(2), 5);
},
"test: convert document to screen coordinates" : function() {
var session = new EditSession("01234\t567890\t1234");
session.setTabSize(4);
@ -187,9 +199,20 @@ module.exports = {
assert.equal(session.documentToScreenColumn(0, 3), 9);
},
"test: documentToScreen with soft wrap and multibyte characters": function() {
var tabSize = 4;
var wrapLimit = 12;
"test: documentToScreen without soft wrap": function() {
var session = new EditSession([
"juhu",
"12\t\t34",
"ぁぁa"
]);
assert.position(session.documentToScreenPosition(0, 3), 0, 3);
assert.position(session.documentToScreenPosition(1, 3), 1, 4);
assert.position(session.documentToScreenPosition(1, 4), 1, 8);
assert.position(session.documentToScreenPosition(2, 2), 2, 4);
},
"test: documentToScreen with soft wrap": function() {
var session = new EditSession(["foo bar foo bar"]);
session.setUseWrapMode(true);
session.setWrapLimitRange(12, 12);
@ -197,6 +220,9 @@ module.exports = {
assert.position(session.documentToScreenPosition(0, 11), 0, 11);
assert.position(session.documentToScreenPosition(0, 12), 1, 0);
},
"test: documentToScreen with soft wrap and multibyte characters": function() {
session = new EditSession(["ぁぁa"]);
session.setUseWrapMode(true);
@ -208,6 +234,13 @@ module.exports = {
assert.position(session.documentToScreenPosition(0, 4), 2, 1);
},
"test: documentToScreen should clip position to the document boundaries": function() {
var session = new EditSession("foo bar\njuhu kinners");
assert.position(session.documentToScreenPosition(-1, 4), 0, 0);
assert.position(session.documentToScreenPosition(3, 0), 1, 12);
},
"test: convert screen to document coordinates" : function() {
var session = new EditSession("01234\t567890\t1234");
session.setTabSize(4);
@ -233,9 +266,7 @@ module.exports = {
assert.equal(session.screenToDocumentColumn(0, 14), 13);
},
"test: screenToDocument with soft wrap and multi byte characters": function() {
var tabSize = 4;
var wrapLimit = 12;
"test: screenToDocument with soft wrap": function() {
var session = new EditSession(["foo bar foo bar"]);
session.setUseWrapMode(true);
session.setWrapLimitRange(12, 12);
@ -246,7 +277,9 @@ module.exports = {
// Check if the position is clamped the right way.
assert.position(session.screenToDocumentPosition(0, 12), 0, 11);
assert.position(session.screenToDocumentPosition(0, 20), 0, 11);
},
"test: screenToDocument with soft wrap and multi byte characters": function() {
session = new EditSession(["ぁ a"]);
session.setUseWrapMode(true);
session.adjustWrapLimit(80);
@ -257,6 +290,18 @@ module.exports = {
assert.position(session.screenToDocumentPosition(0, 4), 0, 3);
assert.position(session.screenToDocumentPosition(0, 5), 0, 3);
},
"test: screenToDocument should clip position to the document boundaries": function() {
var session = new EditSession("foo bar\njuhu kinners");
assert.position(session.screenToDocumentPosition(-1, 4), 0, 0);
assert.position(session.screenToDocumentPosition(0, -1), 0, 0);
assert.position(session.screenToDocumentPosition(0, 30), 0, 7);
assert.position(session.screenToDocumentPosition(2, 4), 1, 12);
assert.position(session.screenToDocumentPosition(1, 30), 1, 12);
assert.position(session.screenToDocumentPosition(20, 50), 1, 12);
assert.position(session.screenToDocumentPosition(20, 5), 1, 12);
},
"test: wrapLine split function" : function() {
var splits;
@ -526,9 +571,10 @@ module.exports = {
"test fold one-line text insert": function() {
// These are mostly test for the FoldLine.addRemoveChars function.
var session = createFoldTestSession(),
undoManager = session.getUndoManager(),
foldLines = session.$foldData;
var session = createFoldTestSession();
var undoManager = session.getUndoManager();
var foldLines = session.$foldData;
function insert(row, column, text) {
session.insert({row: row, column: column}, text);
@ -731,45 +777,45 @@ module.exports = {
// Adding a fold. The split position is inside of the fold. As placeholder
// are not splitable, the split should be before the split.
session.addFold("woot", 0, 4, 0, 15);
session.addFold("woot", new Range(0, 4, 0, 15));
assertWrap([4], [8], [8]);
// Remove the fold again which should reset the wrapData.
removeFoldAssertWrap(0, 4, [8], [8], [8]);
session.addFold("woot", 0, 6, 0, 9);
session.addFold("woot", new Range(0, 6, 0, 9));
assertWrap([6, 13], [8], [8]);
removeFoldAssertWrap(0, 6, [8], [8], [8]);
// The fold fits into the wrap limit - no split expected.
session.addFold("woot", 0, 3, 0, 15);
session.addFold("woot", new Range(0, 3, 0, 15));
assertWrap([], [8], [8]);
removeFoldAssertWrap(0, 4, [8], [8], [8]);
// Fold after split position should be all fine.
session.addFold("woot", 0, 8, 0, 15);
session.addFold("woot", new Range(0, 8, 0, 15));
assertWrap([8], [8], [8]);
removeFoldAssertWrap(0, 8, [8], [8], [8]);
// Fold's placeholder is far too long for wrapSplit.
session.addFold("woot0123456789", 0, 8, 0, 15);
session.addFold("woot0123456789", new Range(0, 8, 0, 15));
assertWrap([8], [8], [8]);
removeFoldAssertWrap(0, 8, [8], [8], [8]);
// Fold's placeholder is far too long for wrapSplit
// + content at the end of the line
session.addFold("woot0123456789", 0, 6, 0, 8);
session.addFold("woot0123456789", new Range(0, 6, 0, 8));
assertWrap([6, 20], [8], [8]);
removeFoldAssertWrap(0, 8, [8], [8], [8]);
session.addFold("woot0123456789", 0, 6, 0, 8);
session.addFold("woot0123456789", 0, 8, 0, 10);
session.addFold("woot0123456789", new Range(0, 6, 0, 8));
session.addFold("woot0123456789", new Range(0, 8, 0, 10));
assertWrap([6, 20, 34], [8], [8]);
session.removeFold(session.getFoldAt(0, 7));
removeFoldAssertWrap(0, 8, [8], [8], [8]);
session.addFold("woot0123456789", 0, 7, 0, 9);
session.addFold("woot0123456789", 0, 13, 0, 15);
session.addFold("woot0123456789", new Range(0, 7, 0, 9));
session.addFold("woot0123456789", new Range(0, 13, 0, 15));
assertWrap([7, 21, 25], [8], [8]);
session.removeFold(session.getFoldAt(0, 7));
removeFoldAssertWrap(0, 14, [8], [8], [8]);
@ -778,15 +824,15 @@ module.exports = {
// Add a fold over two lines. Note, that the wrapData[1] stays the
// same. This is an implementation detail and expected behavior.
session.addFold("woot", 0, 8, 1, 15);
session.addFold("woot", new Range(0, 8, 1, 15));
assertWrap([8], [8 /* See comments */], [8]);
removeFoldAssertWrap(0, 8, [8], [8], [8]);
session.addFold("woot", 0, 9, 1, 11);
session.addFold("woot", new Range(0, 9, 1, 11));
assertWrap([8, 14], [8 /* See comments */], [8]);
removeFoldAssertWrap(0, 9, [8], [8], [8]);
session.addFold("woot", 0, 9, 1, 15);
session.addFold("woot", new Range(0, 9, 1, 15));
assertWrap([8], [8 /* See comments */], [8]);
removeFoldAssertWrap(0, 9, [8], [8], [8]);
@ -797,14 +843,10 @@ module.exports = {
var session = createFoldTestSession();
var fold;
function tryAddFold(
placeholder,
startRow, startColumn, endRow, endColumn, shouldFail)
{
function tryAddFold(placeholder, range, shouldFail) {
var fail = false;
try {
fold = session.addFold(placeholder,
startRow, startColumn, endRow, endColumn);
fold = session.addFold(placeholder, range);
} catch (e) {
fail = true;
}
@ -813,19 +855,19 @@ module.exports = {
}
}
tryAddFold("foo", 0, 13, 0, 17, true);
tryAddFold("foo", 0, 14, 0, 18, true);
tryAddFold("foo", 0, 13, 0, 18, false);
tryAddFold("foo", new Range(0, 13, 0, 17), true);
tryAddFold("foo", new Range(0, 14, 0, 18), true);
tryAddFold("foo", new Range(0, 13, 0, 18), false);
assert.equal(session.$foldData[0].folds.length, 1);
tryAddFold("f", 0, 13, 0, 18, true);
tryAddFold("foo", 0, 18, 0, 21, false);
tryAddFold("f", new Range(0, 13, 0, 18), true);
tryAddFold("foo", new Range(0, 18, 0, 21), false);
assert.equal(session.$foldData[0].folds.length, 2);
session.removeFold(fold);
tryAddFold("foo", 0, 18, 0, 22, true);
tryAddFold("foo", 0, 18, 0, 19, true);
tryAddFold("foo", 0, 22, 1, 10, true);
tryAddFold("foo", new Range(0, 18, 0, 22), true);
tryAddFold("foo", new Range(0, 18, 0, 19), true);
tryAddFold("foo", new Range(0, 22, 1, 10), true);
},
"test add subfolds": function() {
@ -835,7 +877,7 @@ module.exports = {
oldFold = foldData[0].folds[0];
fold = session.addFold("fold0", 0, 10, 0, 21);
fold = session.addFold("fold0", new Range(0, 10, 0, 21));
assert.equal(foldData[0].folds.length, 1);
assert.equal(fold.subFolds.length, 1);
assert.equal(fold.subFolds[0], oldFold);
@ -845,7 +887,7 @@ module.exports = {
assert.equal(foldData[0].folds[0], oldFold);
assert.equal(fold.subFolds.length, 0);
fold = session.addFold("fold0", 0, 13, 2, 10);
fold = session.addFold("fold0", new Range(0, 13, 2, 10));
assert.equal(foldData.length, 1);
assert.equal(fold.subFolds.length, 2);
assert.equal(fold.subFolds[0], oldFold);
@ -861,5 +903,5 @@ module.exports = {
});
if (typeof module !== "undefined" && module === require.main) {
require("asyncjs/test").testcase(module.exports).exec()
require("asyncjs").test.testcase(module.exports).exec()
}

View file

@ -115,7 +115,8 @@ var Editor =function(renderer, session) {
};
this.setSession = function(session) {
if (this.session == session) return;
if (this.session == session)
return;
if (this.session) {
var oldSession = this.session;
@ -253,7 +254,7 @@ var Editor =function(renderer, session) {
var pos = self.session.findMatchingBracket(self.getCursorPosition());
if (pos) {
var range = new Range(pos.row, pos.column, pos.row, pos.column+1);
self.session.$bracketHighlight = self.session.addMarker(range, "ace_bracket");
self.session.$bracketHighlight = self.session.addMarker(range, "ace_bracket", "text");
}
}, 10);
};
@ -271,6 +272,10 @@ var Editor =function(renderer, session) {
}
this.textInput.focus();
};
this.isFocused = function() {
return this.textInput.isFocused();
};
this.blur = function() {
this.textInput.blur();
@ -339,7 +344,7 @@ var Editor =function(renderer, session) {
} else {
range = new Range(cursor.row, 0, cursor.row+1, 0);
}
session.$highlightLineMarker = session.addMarker(range, "ace_active_line", "line");
session.$highlightLineMarker = session.addMarker(range, "ace_active_line", "background");
}
};
@ -426,14 +431,14 @@ var Editor =function(renderer, session) {
var mode = session.getMode();
var cursor = this.getCursorPosition();
if (this.getBehavioursEnabled()) {
// Get a transform if the current mode wants one.
var transform = mode.transformAction(session.getState(cursor.row), 'insertion', this, session, text);
if (transform)
text = transform.text;
}
text = text.replace("\t", this.session.getTabString());
// remove selected text
@ -449,13 +454,13 @@ var Editor =function(renderer, session) {
this.clearSelection();
var start = cursor.column;
var lineState = session.getState(cursor.row);
var start = cursor.column;
var lineState = session.getState(cursor.row);
var shouldOutdent = mode.checkOutdent(lineState, session.getLine(cursor.row), text);
var line = session.getLine(cursor.row);
var lineIndent = mode.getNextLineIndent(lineState, line.slice(0, cursor.column), session.getTabString());
var end = session.insert(cursor, text);
var line = session.getLine(cursor.row);
var lineIndent = mode.getNextLineIndent(lineState, line.slice(0, cursor.column), session.getTabString());
var end = session.insert(cursor, text);
if (transform && transform.selection) {
if (transform.selection.length == 2) { // Transform relative to the current column
this.selection.setSelectionRange(
@ -469,7 +474,7 @@ var Editor =function(renderer, session) {
transform.selection[3]));
}
}
var lineState = session.getState(cursor.row);
// TODO disabled multiline auto indent
@ -515,8 +520,27 @@ var Editor =function(renderer, session) {
}
};
this.onTextInput = function(text) {
this.keyBinding.onTextInput(text);
this.onTextInput = function(text, notPasted) {
// In case the text was not pasted and we got only one character, then
// handel it as a command key stroke.
if (notPasted && text.length == 1) {
// Note: The `null` as `keyCode` is important here, as there are
// some checks in the code for `keyCode == 0` meaning the text comes
// from the keyBinding.onTextInput code path.
var handled = this.keyBinding.onCommandKey({}, 0, null, text);
// Check if the text was handled. If not, then handled it as "normal"
// text and insert it to the editor directly. This shouldn't be done
// using the this.keyBinding.onTextInput(text) function, as it would
// make the `text` get sent to the keyboardHandler twice, which might
// turn out to be a bad thing in case there is a custome keyboard
// handler like the StateHandler.
if (!handled) {
this.insert(text);
}
} else {
this.keyBinding.onTextInput(text);
}
};
this.onCommandKey = function(e, hashId, keyCode) {
@ -619,12 +643,12 @@ var Editor =function(renderer, session) {
this.getReadOnly = function() {
return this.$readOnly;
};
this.$modeBehaviours = false;
this.$modeBehaviours = true;
this.setBehavioursEnabled = function (enabled) {
this.$modeBehaviours = enabled;
}
this.getBehavioursEnabled = function () {
return this.$modeBehaviours;
}
@ -646,7 +670,7 @@ var Editor =function(renderer, session) {
if (this.selection.isEmpty())
this.selection.selectLeft();
var range = this.getSelectionRange();
if (this.getBehavioursEnabled()) {
var session = this.session;
@ -798,7 +822,14 @@ var Editor =function(renderer, session) {
return;
var rows = this.$getSelectedRows();
this.session.remove(new Range(rows.first, 0, rows.last+1, 0));
if (rows.last == 0 || rows.last+1 < this.session.getLength())
var range = new Range(rows.first, 0, rows.last+1, 0)
else
var range = new Range(
rows.first-1, this.session.getLine(rows.first).length,
rows.last, this.session.getLine(rows.last).length
);
this.session.remove(range);
this.clearSelection();
};
@ -1001,11 +1032,11 @@ var Editor =function(renderer, session) {
};
this.gotoLine = function(lineNumber, row) {
this.gotoLine = function(lineNumber, column) {
this.selection.clearSelection();
this.$blockScrolling += 1;
this.moveCursorTo(lineNumber-1, row || 0);
this.moveCursorTo(lineNumber-1, column || 0);
this.$blockScrolling -= 1;
if (!this.isRowVisible(this.getCursorPosition().row)) {
@ -1093,6 +1124,9 @@ var Editor =function(renderer, session) {
this.$search.set(options);
var range = this.$search.find(this.session);
if (!range)
return;
this.$tryReplace(range, replacement);
if (range !== null)
this.selection.setSelectionRange(range);

View file

@ -150,6 +150,16 @@ module.exports = {
editor.navigateUp();
assert.position(editor.getCursorPosition(), 0, 1);
},
"test: typing text should update the desired column": function() {
var editor = new Editor(new MockRenderer(), new EditSession(["1234", "1234567890"]));
editor.navigateTo(0, 3);
editor.insert("juhu");
editor.navigateDown();
assert.position(editor.getCursorPosition(), 1, 7);
}
};

View file

@ -67,13 +67,13 @@ module.exports = {
editor.removeLines();
assert.equal(session.toString(), "a\n");
assert.position(editor.getCursorPosition(), 1, 0);
assert.equal(session.toString(), "a");
assert.position(editor.getCursorPosition(), 0, 1);
editor.removeLines();
assert.equal(session.toString(), "a\n");
assert.position(editor.getCursorPosition(), 1, 0);
assert.equal(session.toString(), "");
assert.position(editor.getCursorPosition(), 0, 0);
},
"test: delete multiple selected lines" : function() {
@ -98,15 +98,15 @@ module.exports = {
assert.position(editor.getCursorPosition(), 0, 0);
},
"test: delete last" : function() {
"test: delete last should also delete the new line of the previous line" : function() {
var session = new EditSession(["a", "b", "c"].join("\n"));
var editor = new Editor(new MockRenderer(), session);
editor.moveCursorTo(2, 1);
editor.removeLines();
assert.equal(session.toString(), "a\nb\n");
assert.position(editor.getCursorPosition(), 2, 0);
assert.equal(session.toString(), "a\nb");
assert.position(editor.getCursorPosition(), 1, 1);
},
"test: indent block" : function() {
@ -382,33 +382,32 @@ module.exports = {
editor.removeLines();
var step1 = session.toString();
assert.equal(step1, "222\n333");
session.$informUndoManager.call();
session.$syncInformUndoManager();
editor.removeLines();
var step2 = session.toString();
assert.equal(step2, "333");
session.$informUndoManager.call();
session.$syncInformUndoManager();
editor.removeLines();
var step3 = session.toString();
assert.equal(step3, "");
session.$informUndoManager.call();
session.$syncInformUndoManager();
undoManager.undo();
session.$informUndoManager.call();
session.$syncInformUndoManager();
assert.equal(session.toString(), step2);
undoManager.undo();
session.$informUndoManager.call();
session.$syncInformUndoManager();
assert.equal(session.toString(), step1);
undoManager.undo();
session.$informUndoManager.call();
session.$syncInformUndoManager();
assert.equal(session.toString(), initialText);
undoManager.undo();
session.$informUndoManager.call();
session.$syncInformUndoManager();
assert.equal(session.toString(), initialText);
},

View file

@ -88,22 +88,27 @@ var KeyBinding = function(editor) {
}
}
var success = false;
if (toExecute) {
var success = canon.exec(toExecute.command,
success = canon.exec(toExecute.command,
env, "editor", toExecute.args);
if (success) {
return event.stopEvent(e);
event.stopEvent(e);
}
}
return success;
};
this.onCommandKey = function(e, hashId, keyCode) {
var keyString = keyUtil.keyCodeToString(keyCode);
this.$callKeyboardHandler(e, hashId, keyString, keyCode);
this.onCommandKey = function(e, hashId, keyCode, keyString) {
// In case there is no keyString, try to interprete the keyCode.
if (!keyString) {
keyString = keyUtil.keyCodeToString(keyCode);
}
return this.$callKeyboardHandler(e, hashId, keyString, keyCode);
};
this.onTextInput = function(text) {
this.$callKeyboardHandler({}, 0, text, 0);
return this.$callKeyboardHandler({}, 0, text, 0);
}
}).call(KeyBinding.prototype);

View file

@ -46,6 +46,10 @@ var vimStates = {
key: "i",
then: "insertMode"
},
{
key: "d",
then: "deleteMode"
},
{
key: "a",
exec: "gotoright",
@ -160,6 +164,13 @@ var vimStates = {
exec: "overwrite",
then: "start"
}
],
deleteMode: [
{
key: "d",
exec: "removeline",
then: "start"
}
]
};

View file

@ -54,6 +54,7 @@ var TextInput = function(parentNode, host) {
var inCompostion = false;
var copied = false;
var pasted = false;
var tempStyle = '';
function sendText(valueToSend) {
@ -63,16 +64,21 @@ var TextInput = function(parentNode, host) {
if (value.charCodeAt(value.length-1) == PLACEHOLDER.charCodeAt(0)) {
value = value.slice(0, -1);
if (value)
host.onTextInput(value);
} else
host.onTextInput(value);
host.onTextInput(value, !pasted);
}
else {
host.onTextInput(value, !pasted);
}
// If editor is no longer focused we quit immediately, since
// it means that something else like CLI is in charge now.
if (!isFocused()) return false;
// it means that something else is in charge now.
if (!isFocused())
return false;
}
}
copied = false;
pasted = false;
// Safari doesn't fire copy events if no text is selected
text.value = PLACEHOLDER;
@ -80,6 +86,13 @@ var TextInput = function(parentNode, host) {
}
var onTextInput = function(e) {
setTimeout(function () {
if (!inCompostion)
sendText(e.data);
}, 0);
};
var onKeyPress = function(e) {
if (useragent.isIE && text.value.charCodeAt(0) > 128) return;
setTimeout(function() {
if (!inCompostion)
@ -89,10 +102,6 @@ var TextInput = function(parentNode, host) {
var onCompositionStart = function(e) {
inCompostion = true;
if (!useragent.isIE) {
sendText();
text.value = "";
};
host.onCompositionStart();
if (!useragent.isGecko) setTimeout(onCompositionUpdate, 0);
};
@ -105,14 +114,6 @@ var TextInput = function(parentNode, host) {
var onCompositionEnd = function(e) {
inCompostion = false;
host.onCompositionEnd();
if (useragent.isGecko) {
sendText();
} else {
setTimeout(function () {
if (!inCompostion)
sendText();
}, 0);
}
};
var onCopy = function(e) {
@ -143,7 +144,6 @@ var TextInput = function(parentNode, host) {
};
event.addCommandKeyListener(text, host.onCommandKey.bind(host));
event.addListener(text, "keypress", onTextInput);
if (useragent.isIE) {
var keytable = { 13:1, 27:1 };
event.addListener(text, "keyup", function (e) {
@ -155,26 +155,41 @@ var TextInput = function(parentNode, host) {
inCompostion ? onCompositionUpdate() : onCompositionStart();
});
};
event.addListener(text, "textInput", onTextInput);
if (text.attachEvent) {
// Old IE + Opera
event.addListener(text, "propertychange", onKeyPress);
}
else {
if (useragent.isChrome || useragent.isSafari)
event.addListener(text, "textInput", onTextInput);
else if (useragent.isIE)
// IE9
event.addListener(text, "textinput", onTextInput);
else
// All browsers except old IE
event.addListener(text, "input", onTextInput);
}
event.addListener(text, "paste", function(e) {
// Mark that the next input text comes from past.
pasted = true;
// Some browsers support the event.clipboardData API. Use this to get
// the pasted content which increases speed if pasting a lot of lines.
if (e.clipboardData && e.clipboardData.getData) {
sendText(e.clipboardData.getData("text/plain"));
e.preventDefault();
} else
// If a browser doesn't support any of the things above, use the regular
// method to detect the pasted input.
{
onTextInput();
}
else {
// If a browser doesn't support any of the things above, use the regular
// method to detect the pasted input.
onKeyPress();
}
});
if (!useragent.isIE) {
event.addListener(text, "propertychange", onTextInput);
};
if (useragent.isIE) {
event.addListener(text, "beforecopy", function(e) {
event.addListener(text, "beforecopy", function(e) {
var copyText = host.getCopyText();
if(copyText)
clipboardData.setData("Text", copyText);

View file

@ -55,6 +55,11 @@ var Cursor = function(parentEl) {
(function() {
this.$padding = 0;
this.setPadding = function(padding) {
this.$padding = padding;
};
this.setSession = function(session) {
this.session = session;
};
@ -66,7 +71,7 @@ var Cursor = function(parentEl) {
};
this.showCursor = function() {
this.isVisible = true;
this.isVisible = true;
dom.removeCssClass(this.cursor, "ace_hidden");
this.cursor.style.visibility = "visible";
this.restartTimer();
@ -97,7 +102,8 @@ var Cursor = function(parentEl) {
var position = this.session.selection.getCursor();
var pos = this.session.documentToScreenPosition(position);
var cursorLeft = Math.round(pos.column * this.config.characterWidth);
var cursorLeft = Math.round(this.$padding +
pos.column * this.config.characterWidth);
var cursorTop = (pos.row - (onScreen ? this.config.firstRowScreen : 0)) *
this.config.lineHeight;

View file

@ -50,6 +50,11 @@ var Marker = function(parentEl) {
(function() {
this.$padding = 0;
this.setPadding = function(padding) {
this.$padding = padding;
};
this.setSession = function(session) {
this.session = session;
};
@ -65,7 +70,8 @@ var Marker = function(parentEl) {
this.config = config;
var html = [];
var html = [];
for ( var key in this.markers) {
var marker = this.markers[key];
@ -73,21 +79,28 @@ var Marker = function(parentEl) {
if (range.isEmpty()) continue;
range = range.toScreenRange(this.session);
if (marker.renderer) {
var top = this.$getTop(range.start.row, config);
var left = Math.round(range.start.column * config.characterWidth);
var left = Math.round(
this.$padding + range.start.column * config.characterWidth
);
marker.renderer(html, range, left, top, config);
}
else if (range.isMultiLine()) {
if (marker.type == "text") {
this.drawTextMarker(html, range, marker.clazz, config);
} else {
this.drawMultiLineMarker(html, range, marker.clazz, config);
this.drawMultiLineMarker(
html, range, marker.clazz, config,
marker.type
);
}
}
else {
this.drawSingleLineMarker(html, range, marker.clazz, config);
this.drawSingleLineMarker(
html, range, marker.clazz, config,
null, marker.type
);
}
}
this.element = dom.setInnerHtml(this.element, html.join(""));
@ -97,33 +110,44 @@ var Marker = function(parentEl) {
return (row - layerConfig.firstRowScreen) * layerConfig.lineHeight;
};
/**
* Draws a marker, which spans a range of text in a single line
*/
this.drawTextMarker = function(stringBuilder, range, clazz, layerConfig) {
// selection start
var row = range.start.row;
var lineRange = new Range(row, range.start.column,
row, this.session.getScreenLastRowColumn(row));
this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig, 1);
var lineRange = new Range(
row, range.start.column,
row, this.session.getScreenLastRowColumn(row)
);
this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig, 1, "text");
// selection end
var row = range.end.row;
var lineRange = new Range(row, 0, row, range.end.column);
this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig);
row = range.end.row;
lineRange = new Range(row, 0, row, range.end.column);
this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig, 0, "text");
for (var row = range.start.row + 1; row < range.end.row; row++) {
for (row = range.start.row + 1; row < range.end.row; row++) {
lineRange.start.row = row;
lineRange.end.row = row;
lineRange.end.column = this.session.getScreenLastRowColumn(row);
this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig, 1);
this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig, 1, "text");
}
};
this.drawMultiLineMarker = function(stringBuilder, range, clazz, layerConfig) {
/**
* Draws a multi line marker, where lines span the full width
*/
this.drawMultiLineMarker = function(stringBuilder, range, clazz, layerConfig, type) {
// from selection start to the end of the line
var padding = type === "background" ? 0 : this.$padding;
var height = layerConfig.lineHeight;
var width = Math.round(layerConfig.width - (range.start.column * layerConfig.characterWidth));
var top = this.$getTop(range.start.row, layerConfig);
var left = Math.round(range.start.column * layerConfig.characterWidth);
var left = Math.round(
padding + range.start.column * layerConfig.characterWidth
);
stringBuilder.push(
"<div class='", clazz, "' style='",
@ -134,35 +158,49 @@ var Marker = function(parentEl) {
);
// from start of the last line to the selection end
var top = this.$getTop(range.end.row, layerConfig);
var width = Math.round(range.end.column * layerConfig.characterWidth);
top = this.$getTop(range.end.row, layerConfig);
width = Math.round(range.end.column * layerConfig.characterWidth);
stringBuilder.push(
"<div class='", clazz, "' style='",
"height:", height, "px;",
"width:", width, "px;",
"top:", top, "px;",
"width:", width, "px;'></div>"
"left:", padding, "px;'></div>"
);
// all the complete lines
var height = (range.end.row - range.start.row - 1) * layerConfig.lineHeight;
height = (range.end.row - range.start.row - 1) * layerConfig.lineHeight;
if (height < 0)
return;
var top = this.$getTop(range.start.row + 1, layerConfig);
top = this.$getTop(range.start.row + 1, layerConfig);
width = layerConfig.width;
stringBuilder.push(
"<div class='", clazz, "' style='",
"height:", height, "px;",
"width:", layerConfig.width, "px;",
"top:", top, "px;'></div>"
"width:", width, "px;",
"top:", top, "px;",
"left:", padding, "px;'></div>"
);
};
this.drawSingleLineMarker = function(stringBuilder, range, clazz, layerConfig, extraLength) {
/**
* Draws a marker which covers one single full line
*/
this.drawSingleLineMarker = function(stringBuilder, range, clazz, layerConfig, extraLength, type) {
var padding = type === "background" ? 0 : this.$padding;
var height = layerConfig.lineHeight;
var width = Math.round((range.end.column + (extraLength || 0) - range.start.column) * layerConfig.characterWidth);
if (type === "background")
var width = layerConfig.width;
else
width = Math.round((range.end.column + (extraLength || 0) - range.start.column) * layerConfig.characterWidth);
var top = this.$getTop(range.start.row, layerConfig);
var left = Math.round(range.start.column * layerConfig.characterWidth);
var left = Math.round(
padding + range.start.column * layerConfig.characterWidth
);
stringBuilder.push(
"<div class='", clazz, "' style='",

View file

@ -49,6 +49,7 @@ var EventEmitter = require("pilot/event_emitter").EventEmitter;
var Text = function(parentEl) {
this.element = dom.createElement("div");
this.element.className = "ace_layer ace_text-layer";
this.element.style.width = "auto";
parentEl.appendChild(this.element);
this.$characterSize = this.$measureSizes() || {width: 0, height: 0};
@ -63,6 +64,12 @@ var Text = function(parentEl) {
this.EOL_CHAR = "&not;";
this.TAB_CHAR = "&rarr;";
this.SPACE_CHAR = "&middot;";
this.$padding = 0;
this.setPadding = function(padding) {
this.$padding = padding;
this.element.style.padding = "0 " + padding + "px";
};
this.getLineHeight = function() {
return this.$characterSize.height || 1;
@ -186,8 +193,8 @@ var Text = function(parentEl) {
var first = Math.max(firstRow, config.firstRow);
var last = Math.min(lastRow, config.lastRow);
var lineElements = this.element.childNodes,
lineElementsIdx = 0;
var lineElements = this.element.childNodes;
var lineElementsIdx = 0;
for (var row = config.firstRow; row < first; row++) {
var foldLine = this.session.getFoldLine(row);
@ -208,7 +215,7 @@ var Text = function(parentEl) {
var html = [];
var tokens = this.session.getTokens(i, i);
this.$renderLine(html, i, tokens[0].tokens);
this.$renderLine(html, i, tokens[0].tokens, true);
lineElement = dom.setInnerHtml(lineElement, html.join(""));
i = this.session.getRowFoldEnd(i);
@ -264,9 +271,7 @@ var Text = function(parentEl) {
if(row > lastRow)
break;
var lineEl = dom.createElement("div");
lineEl.className = "ace_line";
var container = dom.createElement("div");
var html = [];
// Get the tokens per line as there might be some lines in between
@ -275,11 +280,13 @@ var Text = function(parentEl) {
// this call once for that big block of unfolded lines.
var tokens = this.session.getTokens(row, row);
if (tokens.length == 1)
this.$renderLine(html, row, tokens[0].tokens);
this.$renderLine(html, row, tokens[0].tokens, false);
// don't use setInnerHtml since we are working with an empty DIV
lineEl.innerHTML = html.join("");
fragment.appendChild(lineEl);
container.innerHTML = html.join("");
var lines = container.childNodes
while(lines.length)
fragment.appendChild(lines[0]);
row++;
}
@ -306,15 +313,13 @@ var Text = function(parentEl) {
if(row > lastRow)
break;
html.push("<div class='ace_line'>");
// Get the tokens per line as there might be some lines in between
// beeing folded.
// OPTIMIZE: If there is a long block of unfolded lines, just make
// this call once for that big block of unfolded lines.
var tokens = this.session.getTokens(row, row);
if (tokens.length == 1)
this.$renderLine(html, row, tokens[0].tokens);
html.push("</div>");
this.$renderLine(html, row, tokens[0].tokens, false);
row++;
}
@ -344,6 +349,14 @@ var Text = function(parentEl) {
return "&amp;";
} else if (c == "<") {
return "&lt;";
} else if (c == "\u3000") {
// U+3000 is both invisible AND full-width, so must be handled uniquely
var classToUse = self.showInvisibles ? "ace_cjk ace_invisible" : "ace_cjk";
var space = self.showInvisibles ? self.SPACE_CHAR : "";
screenColumn += 1;
return "<span class='" + classToUse + "' style='width:" +
(self.config.characterWidth * 2) +
"px'>" + space + "</span>";
} else if (c.match(/[\v\f \u00a0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000]/)) {
if (self.showInvisibles) {
var space = new Array(c.length+1).join(self.SPACE_CHAR);
@ -371,7 +384,7 @@ var Text = function(parentEl) {
return screenColumn + value.length;
};
this.$renderLineCore = function(stringBuilder, lastRow, tokens, splits) {
this.$renderLineCore = function(stringBuilder, lastRow, tokens, splits, onlyContents) {
var chars = 0;
var split = 0;
var splitChars;
@ -379,36 +392,44 @@ var Text = function(parentEl) {
var screenColumn = 0;
var self = this;
function addToken(token, value) {
screenColumn = self.$renderToken(
stringBuilder, screenColumn, token, value);
}
if (!splits || splits.length == 0) {
if (!splits || splits.length == 0)
splitChars = Number.MAX_VALUE;
} else {
else
splitChars = splits[0];
}
stringBuilder.push("<div style='height:",
this.config.lineHeight, "px",
"'>");
if (!onlyContents) {
stringBuilder.push("<div class='ace_line' style='height:",
this.config.lineHeight, "px",
"'>"
);
}
for (var i = 0; i < tokens.length; i++) {
var token = tokens[i];
var value = token.value;
if (chars + value.length < splitChars) {
addToken(token, value);
screenColumn = self.$renderToken(
stringBuilder, screenColumn, token, value
);
chars += value.length;
} else {
}
else {
while (chars + value.length >= splitChars) {
addToken(token, value.substring(0, splitChars - chars));
screenColumn = self.$renderToken(
stringBuilder, screenColumn,
token, value.substring(0, splitChars - chars)
);
value = value.substring(splitChars - chars);
chars = splitChars;
stringBuilder.push("</div>",
"<div style='height:",
this.config.lineHeight, "px",
"'>");
if (!onlyContents) {
stringBuilder.push("</div>",
"<div class='ace_line' style='height:",
this.config.lineHeight, "px",
"'>"
);
}
split ++;
screenColumn = 0;
@ -416,33 +437,35 @@ var Text = function(parentEl) {
}
if (value.length != 0) {
chars += value.length;
addToken(token, value);
screenColumn = self.$renderToken(
stringBuilder, screenColumn, token, value
);
}
}
}
if (this.showInvisibles) {
if (lastRow !== this.session.getLength() - 1) {
if (lastRow !== this.session.getLength() - 1)
stringBuilder.push("<span class='ace_invisible'>" + this.EOL_CHAR + "</span>");
} else {
else
stringBuilder.push("<span class='ace_invisible'>" + this.EOF_CHAR + "</span>");
}
}
stringBuilder.push("</div>");
if (!onlyContents)
stringBuilder.push("</div>");
};
this.$renderLine = function(stringBuilder, row, tokens) {
this.$renderLine = function(stringBuilder, row, tokens, onlyContents) {
// Check if the line to render is folded or not. If not, things are
// simple, otherwise, we need to fake some things...
if (!this.session.isRowFolded(row)) {
var splits = this.session.getRowSplitData(row);
this.$renderLineCore(stringBuilder, row, tokens, splits);
this.$renderLineCore(stringBuilder, row, tokens, splits, onlyContents);
} else {
this.$renderFoldLine(stringBuilder, row, tokens);
this.$renderFoldLine(stringBuilder, row, tokens, onlyContents);
}
};
this.$renderFoldLine = function(stringBuilder, row, tokens) {
this.$renderFoldLine = function(stringBuilder, row, tokens, onlyContents) {
var session = this.session,
foldLine = session.getFoldLine(row),
renderTokens = [];
@ -505,11 +528,14 @@ var Text = function(parentEl) {
// TODO: Build a fake splits array!
var splits = this.session.$useWrapMode?this.session.$wrapData[row]:null;
this.$renderLineCore(stringBuilder, row, renderTokens, splits);
this.$renderLineCore(stringBuilder, row, renderTokens, splits, onlyContents);
};
this.destroy = function() {
clearInterval(this.$pollSizeChangesTimer);
if (this.$measureNode)
this.$measureNode.parentNode.removeChild(this.$measureNode);
delete this.$measureNode;
};
}).call(Text.prototype);

View file

@ -49,29 +49,52 @@ var JavaScriptMode = require("ace/mode/javascript").Mode;
module.exports = {
"test: render line with hard tabs should render the same as lines with soft tabs" : function() {
var session = new EditSession("a\ta\ta\t\na a a \n");
session.setMode(new JavaScriptMode());
var textLayer = new TextLayer(document.createElement("div"));
textLayer.setSession(session);
textLayer.$computeTabString();
textLayer.config = {
setUp: function(next) {
this.session = new EditSession("");
this.session.setMode(new JavaScriptMode());
this.textLayer = new TextLayer(document.createElement("div"));
this.textLayer.setSession(this.session);
this.textLayer.config = {
characterWidth: 10,
lineHeight: 20
};
next()
},
"test: render line with hard tabs should render the same as lines with soft tabs" : function() {
this.session.setValue("a\ta\ta\t\na a a \n");
this.textLayer.$computeTabString();
// row with hard tabs
var row = 0;
var tokens = session.getTokens(row, row)[0].tokens;
var tokens = this.session.getTokens(row, row)[0].tokens;
var stringBuilder = [];
textLayer.$renderLine(stringBuilder, row, tokens);
this.textLayer.$renderLine(stringBuilder, row, tokens);
// row with soft tabs
row = 1;
tokens = session.getTokens(row, row)[0].tokens;
tokens = this.session.getTokens(row, row)[0].tokens;
var stringBuilder2 = [];
textLayer.$renderLine(stringBuilder2, row, tokens);
this.textLayer.$renderLine(stringBuilder2, row, tokens);
assert.equal(stringBuilder.join(""), stringBuilder2.join(""));
},
"test rendering width of ideographic space (U+3000)" : function() {
this.session.setValue("\u3000");
var tokens = this.session.getTokens(0, 0)[0].tokens;
var stringBuilder = [];
this.textLayer.$renderLine(stringBuilder, 0, tokens, true);
assert.equal(stringBuilder.join(""), "<span class='ace_cjk' style='width:20px'></span>");
this.textLayer.setShowInvisibles(true);
var stringBuilder = [];
this.textLayer.$renderLine(stringBuilder, 0, tokens, true);
assert.equal(
stringBuilder.join(""),
"<span class='ace_cjk ace_invisible' style='width:20px'>" + this.textLayer.SPACE_CHAR + "</span>"
+ "<span class='ace_invisible'>&para;</span>"
);
}
};

View file

@ -42,7 +42,7 @@ var oop = require("pilot/oop");
var Behaviour = require('ace/mode/behaviour').Behaviour;
var CstyleBehaviour = function () {
this.add("braces", "insertion", function (state, action, editor, session, text) {
if (text == '{') {
var selection = editor.getSelectionRange();
@ -76,11 +76,13 @@ var CstyleBehaviour = function () {
var line = session.doc.getLine(cursor.row);
var rightChar = line.substring(cursor.column, cursor.column + 1);
if (rightChar == '}') {
var openBracePos = session.findMatchingBracket({row: cursor.row, column: cursor.column});
var openBracePos = session.findMatchingBracket({row: cursor.row, column: cursor.column + 1});
if (!openBracePos)
return false;
var indent = this.getNextLineIndent(state, line.substring(0, line.length - 1), session.getTabString());
var next_indent = this.$getIndent(session.doc.getLine(openBracePos.row));
return {
text: '\n' + indent + '\n' + next_indent,
selection: [1, indent.length, 1, indent.length]
@ -89,15 +91,15 @@ var CstyleBehaviour = function () {
}
return false;
});
this.add("braces", "deletion", function (state, action, editor, session, range) {
var selected = session.doc.getTextRange(range);
if (!range.isMultiLine() && selected == '{') {
var line = session.doc.getLine(range.start.row);
var rightChar = line.substring(range.end.column, range.end.column + 1);
if (rightChar == '}') {
return new Range(range.start.row, range.start.column,
range.start.row, range.end.column + 1);
range.end.column++;
return range;
}
}
return false;
@ -134,15 +136,15 @@ var CstyleBehaviour = function () {
}
return false;
});
this.add("parens", "deletion", function (state, action, editor, session, range) {
var selected = session.doc.getTextRange(range);
if (!range.isMultiLine() && selected == '(') {
var line = session.doc.getLine(range.start.row);
var rightChar = line.substring(range.start.column + 1, range.start.column + 2);
if (rightChar == ')') {
return new Range(range.start.row, range.start.column,
range.start.row, range.end.column + 1);
range.end.column++;
return range;
}
}
return false;
@ -161,17 +163,17 @@ var CstyleBehaviour = function () {
var cursor = editor.getCursorPosition();
var line = session.doc.getLine(cursor.row);
var leftChar = line.substring(cursor.column-1, cursor.column);
// We're escaped.
if (leftChar == '\\') {
return false;
}
// Find what token we're inside.
var tokens = session.getTokens(selection.start.row, selection.start.row)[0].tokens;
var col = 0, token;
var quotepos = -1; // Track whether we're inside an open quote.
for (var x = 0; x < tokens.length; x++) {
token = tokens[x];
if (token.type == "string") {
@ -184,7 +186,7 @@ var CstyleBehaviour = function () {
}
col += tokens[x].value.length;
}
// Try and be smart about when we auto insert.
if (!token || (quotepos < 0 && token.type !== "comment" && (token.type !== "string" || ((selection.start.column !== token.value.length+col-1) && token.value.lastIndexOf('"') === token.value.length-1)))) {
return {
@ -205,20 +207,20 @@ var CstyleBehaviour = function () {
}
return false;
});
this.add("string_dquotes", "deletion", function (state, action, editor, session, range) {
var selected = session.doc.getTextRange(range);
if (!range.isMultiLine() && selected == '"') {
var line = session.doc.getLine(range.start.row);
var rightChar = line.substring(range.start.column + 1, range.start.column + 2);
if (rightChar == '"') {
return new Range(range.start.row, range.start.column,
range.start.row, range.end.column + 1);
range.end.column++;
return range;
}
}
return false;
});
}
oop.inherits(CstyleBehaviour, Behaviour);

View file

@ -67,96 +67,102 @@ var c_cppHighlightRules = function() {
this.$rules = {
"start" : [
{
token : "comment",
regex : "\\/\\/.*$"
},
new DocCommentHighlightRules().getStartRule("doc-start"),
{
token : "comment", // multi line comment
regex : "\\/\\*",
next : "comment"
}, {
token : "string", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
}, {
token : "string", // multi line string start
regex : '["].*\\\\$',
next : "qqstring"
}, {
token : "string", // single line
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
}, {
token : "string", // multi line string start
regex : "['].*\\\\$",
next : "qstring"
}, {
token : "constant.numeric", // hex
regex : "0[xX][0-9a-fA-F]+\\b"
}, {
token : "constant.numeric", // float
regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
}, {
{
token : "comment",
regex : "\\/\\/.*$"
},
new DocCommentHighlightRules().getStartRule("doc-start"),
{
token : "comment", // multi line comment
merge : true,
regex : "\\/\\*",
next : "comment"
}, {
token : "string", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
}, {
token : "string", // multi line string start
merge : true,
regex : '["].*\\\\$',
next : "qqstring"
}, {
token : "string", // single line
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
}, {
token : "string", // multi line string start
merge : true,
regex : "['].*\\\\$",
next : "qstring"
}, {
token : "constant.numeric", // hex
regex : "0[xX][0-9a-fA-F]+\\b"
}, {
token : "constant.numeric", // float
regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
}, {
token : "constant", // <CONSTANT>
regex : "<[a-zA-Z0-9.]+>"
}, {
}, {
token : "keyword", // pre-compiler directivs
regex : "(?:#include|#pragma|#line|#define|#undef|#ifdef|#else|#elif|#endif|#ifndef)"
}, {
token : function(value) {
if (value == "this")
return "variable.language";
else if (keywords.hasOwnProperty(value))
return "keyword";
else if (buildinConstants.hasOwnProperty(value))
return "constant.language";
else
return "identifier";
},
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
}, {
token : "keyword.operator",
regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|==|=|!=|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|new|delete|typeof|void)"
}, {
token : "lparen",
regex : "[[({]"
}, {
token : "rparen",
regex : "[\\])}]"
}, {
token : "text",
regex : "\\s+"
}
token : function(value) {
if (value == "this")
return "variable.language";
else if (keywords.hasOwnProperty(value))
return "keyword";
else if (buildinConstants.hasOwnProperty(value))
return "constant.language";
else
return "identifier";
},
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
}, {
token : "keyword.operator",
regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|==|=|!=|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|new|delete|typeof|void)"
}, {
token : "lparen",
regex : "[[({]"
}, {
token : "rparen",
regex : "[\\])}]"
}, {
token : "text",
regex : "\\s+"
}
],
"comment" : [
{
token : "comment", // closing comment
regex : ".*?\\*\\/",
next : "start"
}, {
token : "comment", // comment spanning whole line
regex : ".+"
}
{
token : "comment", // closing comment
regex : ".*?\\*\\/",
next : "start"
}, {
token : "comment", // comment spanning whole line
merge : true,
regex : ".+"
}
],
"qqstring" : [
{
token : "string",
regex : '(?:(?:\\\\.)|(?:[^"\\\\]))*?"',
next : "start"
}, {
token : "string",
regex : '.+'
}
token : "string",
regex : '(?:(?:\\\\.)|(?:[^"\\\\]))*?"',
next : "start"
}, {
token : "string",
merge : true,
regex : '.+'
}
],
"qstring" : [
{
token : "string",
regex : "(?:(?:\\\\.)|(?:[^'\\\\]))*?'",
next : "start"
}, {
token : "string",
regex : '.+'
}
{
token : "string",
regex : "(?:(?:\\\\.)|(?:[^'\\\\]))*?'",
next : "start"
}, {
token : "string",
merge : true,
regex : '.+'
}
]
};

View file

@ -49,78 +49,78 @@ var ClojureHighlightRules = function() {
var builtinFunctions = lang.arrayToMap(
('* *1 *2 *3 *agent* *allow-unresolved-vars* *assert* *clojure-version* ' +
'*command-line-args* *compile-files* *compile-path* *e *err* *file* ' +
'*flush-on-newline* *in* *macro-meta* *math-context* *ns* *out* ' +
'*print-dup* *print-length* *print-level* *print-meta* *print-readably* ' +
'*read-eval* *source-path* *use-context-classloader* ' +
'*warn-on-reflection* + - -> -&gt; ->> -&gt;&gt; .. / < &lt; <= &lt;= = ' +
'== > &gt; >= &gt;= accessor aclone ' +
'add-classpath add-watch agent agent-errors aget alength alias all-ns ' +
'alter alter-meta! alter-var-root amap ancestors and apply areduce ' +
'array-map aset aset-boolean aset-byte aset-char aset-double aset-float ' +
'aset-int aset-long aset-short assert assoc assoc! assoc-in associative? ' +
'atom await await-for await1 bases bean bigdec bigint binding bit-and ' +
'bit-and-not bit-clear bit-flip bit-not bit-or bit-set bit-shift-left ' +
'bit-shift-right bit-test bit-xor boolean boolean-array booleans ' +
'bound-fn bound-fn* butlast byte byte-array bytes cast char char-array ' +
'char-escape-string char-name-string char? chars chunk chunk-append ' +
'chunk-buffer chunk-cons chunk-first chunk-next chunk-rest chunked-seq? ' +
'class class? clear-agent-errors clojure-version coll? comment commute ' +
'comp comparator compare compare-and-set! compile complement concat cond ' +
'condp conj conj! cons constantly construct-proxy contains? count ' +
'counted? create-ns create-struct cycle dec decimal? declare definline ' +
'defmacro defmethod defmulti defn defn- defonce defstruct delay delay? ' +
'deliver deref derive descendants destructure disj disj! dissoc dissoc! ' +
'distinct distinct? doall doc dorun doseq dosync dotimes doto double ' +
'double-array doubles drop drop-last drop-while empty empty? ensure ' +
'enumeration-seq eval even? every? false? ffirst file-seq filter find ' +
'find-doc find-ns find-var first float float-array float? floats flush ' +
'fn fn? fnext for force format future future-call future-cancel ' +
'future-cancelled? future-done? future? gen-class gen-interface gensym ' +
'get get-in get-method get-proxy-class get-thread-bindings get-validator ' +
'hash hash-map hash-set identical? identity if-let if-not ifn? import ' +
'in-ns inc init-proxy instance? int int-array integer? interleave intern ' +
'interpose into into-array ints io! isa? iterate iterator-seq juxt key ' +
'keys keyword keyword? last lazy-cat lazy-seq let letfn line-seq list ' +
'list* list? load load-file load-reader load-string loaded-libs locking ' +
'long long-array longs loop macroexpand macroexpand-1 make-array ' +
'make-hierarchy map map? mapcat max max-key memfn memoize merge ' +
'merge-with meta method-sig methods min min-key mod name namespace neg? ' +
'newline next nfirst nil? nnext not not-any? not-empty not-every? not= ' +
'ns ns-aliases ns-imports ns-interns ns-map ns-name ns-publics ' +
'ns-refers ns-resolve ns-unalias ns-unmap nth nthnext num number? odd? ' +
'or parents partial partition pcalls peek persistent! pmap pop pop! ' +
'pop-thread-bindings pos? pr pr-str prefer-method prefers ' +
'primitives-classnames print print-ctor print-doc print-dup print-method ' +
'print-namespace-doc print-simple print-special-doc print-str printf ' +
'println println-str prn prn-str promise proxy proxy-call-with-super ' +
'proxy-mappings proxy-name proxy-super push-thread-bindings pvalues quot ' +
'rand rand-int range ratio? rational? rationalize re-find re-groups ' +
're-matcher re-matches re-pattern re-seq read read-line read-string ' +
'reduce ref ref-history-count ref-max-history ref-min-history ref-set ' +
'refer refer-clojure release-pending-sends rem remove remove-method ' +
'remove-ns remove-watch repeat repeatedly replace replicate require ' +
'reset! reset-meta! resolve rest resultset-seq reverse reversible? rseq ' +
'rsubseq second select-keys send send-off seq seq? seque sequence ' +
'sequential? set set-validator! set? short short-array shorts ' +
'shutdown-agents slurp some sort sort-by sorted-map sorted-map-by ' +
'sorted-set sorted-set-by sorted? special-form-anchor special-symbol? ' +
'split-at split-with str stream? string? struct struct-map subs subseq ' +
'subvec supers swap! symbol symbol? sync syntax-symbol-anchor take ' +
'take-last take-nth take-while test the-ns time to-array to-array-2d ' +
'trampoline transient tree-seq true? type unchecked-add unchecked-dec ' +
'unchecked-divide unchecked-inc unchecked-multiply unchecked-negate ' +
'unchecked-remainder unchecked-subtract underive unquote ' +
'unquote-splicing update-in update-proxy use val vals var-get var-set ' +
'var? vary-meta vec vector vector? when when-first when-let when-not ' +
'while with-bindings with-bindings* with-in-str with-loading-context ' +
'with-local-vars with-meta with-open with-out-str with-precision xml-seq ' +
'zero? zipmap ').split(" ")
'*command-line-args* *compile-files* *compile-path* *e *err* *file* ' +
'*flush-on-newline* *in* *macro-meta* *math-context* *ns* *out* ' +
'*print-dup* *print-length* *print-level* *print-meta* *print-readably* ' +
'*read-eval* *source-path* *use-context-classloader* ' +
'*warn-on-reflection* + - -> -&gt; ->> -&gt;&gt; .. / < &lt; <= &lt;= = ' +
'== > &gt; >= &gt;= accessor aclone ' +
'add-classpath add-watch agent agent-errors aget alength alias all-ns ' +
'alter alter-meta! alter-var-root amap ancestors and apply areduce ' +
'array-map aset aset-boolean aset-byte aset-char aset-double aset-float ' +
'aset-int aset-long aset-short assert assoc assoc! assoc-in associative? ' +
'atom await await-for await1 bases bean bigdec bigint binding bit-and ' +
'bit-and-not bit-clear bit-flip bit-not bit-or bit-set bit-shift-left ' +
'bit-shift-right bit-test bit-xor boolean boolean-array booleans ' +
'bound-fn bound-fn* butlast byte byte-array bytes cast char char-array ' +
'char-escape-string char-name-string char? chars chunk chunk-append ' +
'chunk-buffer chunk-cons chunk-first chunk-next chunk-rest chunked-seq? ' +
'class class? clear-agent-errors clojure-version coll? comment commute ' +
'comp comparator compare compare-and-set! compile complement concat cond ' +
'condp conj conj! cons constantly construct-proxy contains? count ' +
'counted? create-ns create-struct cycle dec decimal? declare definline ' +
'defmacro defmethod defmulti defn defn- defonce defstruct delay delay? ' +
'deliver deref derive descendants destructure disj disj! dissoc dissoc! ' +
'distinct distinct? doall doc dorun doseq dosync dotimes doto double ' +
'double-array doubles drop drop-last drop-while empty empty? ensure ' +
'enumeration-seq eval even? every? false? ffirst file-seq filter find ' +
'find-doc find-ns find-var first float float-array float? floats flush ' +
'fn fn? fnext for force format future future-call future-cancel ' +
'future-cancelled? future-done? future? gen-class gen-interface gensym ' +
'get get-in get-method get-proxy-class get-thread-bindings get-validator ' +
'hash hash-map hash-set identical? identity if-let if-not ifn? import ' +
'in-ns inc init-proxy instance? int int-array integer? interleave intern ' +
'interpose into into-array ints io! isa? iterate iterator-seq juxt key ' +
'keys keyword keyword? last lazy-cat lazy-seq let letfn line-seq list ' +
'list* list? load load-file load-reader load-string loaded-libs locking ' +
'long long-array longs loop macroexpand macroexpand-1 make-array ' +
'make-hierarchy map map? mapcat max max-key memfn memoize merge ' +
'merge-with meta method-sig methods min min-key mod name namespace neg? ' +
'newline next nfirst nil? nnext not not-any? not-empty not-every? not= ' +
'ns ns-aliases ns-imports ns-interns ns-map ns-name ns-publics ' +
'ns-refers ns-resolve ns-unalias ns-unmap nth nthnext num number? odd? ' +
'or parents partial partition pcalls peek persistent! pmap pop pop! ' +
'pop-thread-bindings pos? pr pr-str prefer-method prefers ' +
'primitives-classnames print print-ctor print-doc print-dup print-method ' +
'print-namespace-doc print-simple print-special-doc print-str printf ' +
'println println-str prn prn-str promise proxy proxy-call-with-super ' +
'proxy-mappings proxy-name proxy-super push-thread-bindings pvalues quot ' +
'rand rand-int range ratio? rational? rationalize re-find re-groups ' +
're-matcher re-matches re-pattern re-seq read read-line read-string ' +
'reduce ref ref-history-count ref-max-history ref-min-history ref-set ' +
'refer refer-clojure release-pending-sends rem remove remove-method ' +
'remove-ns remove-watch repeat repeatedly replace replicate require ' +
'reset! reset-meta! resolve rest resultset-seq reverse reversible? rseq ' +
'rsubseq second select-keys send send-off seq seq? seque sequence ' +
'sequential? set set-validator! set? short short-array shorts ' +
'shutdown-agents slurp some sort sort-by sorted-map sorted-map-by ' +
'sorted-set sorted-set-by sorted? special-form-anchor special-symbol? ' +
'split-at split-with str stream? string? struct struct-map subs subseq ' +
'subvec supers swap! symbol symbol? sync syntax-symbol-anchor take ' +
'take-last take-nth take-while test the-ns time to-array to-array-2d ' +
'trampoline transient tree-seq true? type unchecked-add unchecked-dec ' +
'unchecked-divide unchecked-inc unchecked-multiply unchecked-negate ' +
'unchecked-remainder unchecked-subtract underive unquote ' +
'unquote-splicing update-in update-proxy use val vals var-get var-set ' +
'var? vary-meta vec vector vector? when when-first when-let when-not ' +
'while with-bindings with-bindings* with-in-str with-loading-context ' +
'with-local-vars with-meta with-open with-out-str with-precision xml-seq ' +
'zero? zipmap ').split(" ")
);
var keywords = lang.arrayToMap(
('def do fn if let loop monitor-enter monitor-exit new quote recur set! ' +
'throw try var').split(" ")
'throw try var').split(" ")
);
var buildinConstants = lang.arrayToMap(
@ -133,98 +133,82 @@ var ClojureHighlightRules = function() {
this.$rules = {
"start" : [
{
token : "comment",
regex : ";.*$"
}, {
{
token : "comment",
regex : ";.*$"
}, {
token : "comment", // multi line comment
regex : "^\=begin$",
next : "comment"
},
{
token : "keyword", //parens
regex : "[\\(|\\)]"
},
{
token : "keyword", //lists
regex : "[\\'\\(]"
},
{
token : "keyword", //vectors
regex : "[\\[|\\]]"
},
{
token : "keyword", //sets and maps
regex : "[\\{|\\}|\\#\\{|\\#\\}]"
},
{
}, {
token : "keyword", //parens
regex : "[\\(|\\)]"
}, {
token : "keyword", //lists
regex : "[\\'\\(]"
}, {
token : "keyword", //vectors
regex : "[\\[|\\]]"
}, {
token : "keyword", //sets and maps
regex : "[\\{|\\}|\\#\\{|\\#\\}]"
}, {
token : "keyword", // ampersands
regex : '[\\&]'
},
{
}, {
token : "keyword", // metadata
regex : '[\\#\\^\\{]'
},
{
}, {
token : "keyword", // anonymous fn syntactic sugar
regex : '[\\%]'
},
{
}, {
token : "keyword", // deref reader macro
regex : '[@]'
},
{
token : "constant.numeric", // hex
regex : "0[xX][0-9a-fA-F]+\\b"
},
{
token : "constant.numeric", // float
regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
},
{
token : "constant.language",
regex : '[!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+||=|!=|<=|>=|<>|<|>|!|&&]'
},
{
token : function(value) {
if (keywords.hasOwnProperty(value))
return "keyword";
else if (buildinConstants.hasOwnProperty(value))
return "constant.language";
}, {
token : "constant.numeric", // hex
regex : "0[xX][0-9a-fA-F]+\\b"
}, {
token : "constant.numeric", // float
regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
}, {
token : "constant.language",
regex : '[!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+||=|!=|<=|>=|<>|<|>|!|&&]'
}, {
token : function(value) {
if (keywords.hasOwnProperty(value))
return "keyword";
else if (buildinConstants.hasOwnProperty(value))
return "constant.language";
else if (builtinFunctions.hasOwnProperty(value))
return "support.function";
else
return "identifier";
},
// TODO: Unicode escape sequences
// TODO: Unicode identifiers
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
},
{
else
return "identifier";
},
// TODO: Unicode escape sequences
// TODO: Unicode identifiers
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
}, {
token : "string", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
},
{
}, {
token : "string", // symbol
regex : "[:](?:[a-zA-Z]|\d)+"
},
{
token : "string.regexp", //Regular Expressions
regex : '/#"(?:\.|(\\\")|[^\""\n])*"/g'
}
}, {
token : "string.regexp", //Regular Expressions
regex : '/#"(?:\.|(\\\")|[^\""\n])*"/g'
}
],
"comment" : [
{
{
token : "comment", // closing comment
regex : "^\=end$",
next : "start"
}, {
token : "comment", // comment spanning whole line
regex : ".+"
}
token : "comment", // comment spanning whole line
merge : true,
regex : ".+"
}
]
};
};

View file

@ -37,146 +37,158 @@
define(function(require, exports, module) {
require("pilot/oop").inherits(
CoffeeHighlightRules,
require("ace/mode/text_highlight_rules").TextHighlightRules);
require("pilot/oop").inherits(CoffeeHighlightRules,
require("ace/mode/text_highlight_rules").TextHighlightRules);
function CoffeeHighlightRules() {
var identifier = "[$A-Za-z_\\x7f-\\uffff][$\\w\\x7f-\\uffff]*"
, keywordend = "(?![$\\w]|\\s*:)"
, stringfill = {token: "string", regex: ".+"}
;
this.$rules =
{ start:
[ { token: "identifier"
, regex: "(?:@|(?:\\.|::)\\s*)" + identifier
}
, { token: "keyword"
, regex: "(?:t(?:h(?:is|row|en)|ry|ypeof)|s(?:uper|witch)|return|b(?:reak|y)|c(?:ontinue|atch|lass)|i(?:n(?:stanceof)?|s(?:nt)?|f)|e(?:lse|xtends)|f(?:or (?:own)?|inally|unction)|wh(?:ile|en)|n(?:ew|ot?)|d(?:e(?:lete|bugger)|o)|loop|o(?:ff?|[rn])|un(?:less|til)|and|yes)" + keywordend
}
, { token: "constant.language"
, regex: "(?:true|false|null|undefined)" + keywordend
}
, { token: "invalid.illegal"
, regex: "(?:c(?:ase|onst)|default|function|v(?:ar|oid)|with|e(?:num|xport)|i(?:mplements|nterface)|let|p(?:ackage|r(?:ivate|otected)|ublic)|static|yield|__(?:hasProp|extends|slice|bind|indexOf))" + keywordend
}
, { token: "language.support.class"
, regex: "(?:Array|Boolean|Date|Function|Number|Object|R(?:e(?:gExp|ferenceError)|angeError)|S(?:tring|yntaxError)|E(?:rror|valError)|TypeError|URIError)" + keywordend
}
, { token: "language.support.function"
, regex: "(?:Math|JSON|is(?:NaN|Finite)|parse(?:Int|Float)|encodeURI(?:Component)?|decodeURI(?:Component)?)" + keywordend
}
, { token: "identifier"
, regex: identifier
}
, { token: "constant.numeric"
, regex: "(?:0x[\\da-fA-F]+|(?:\\d+(?:\\.\\d+)?|\\.\\d+)(?:[eE][+-]?\\d+)?)"
}
, { token: "string"
, regex: "'''"
, next : "qdoc"
}
, { token: "string"
, regex: '"""'
, next : "qqdoc"
}
, { token: "string"
, regex: "'"
, next : "qstring"
}
, { token: "string"
, regex: '"'
, next : "qqstring"
}
, { token: "string"
, regex: "`"
, next : "js"
}
, { token: "string.regex"
, regex: "///"
, next : "heregex"
}
, { token: "string.regex"
, regex: "/(?!\\s)[^[/\\n\\\\]*(?: (?:\\\\.|\\[[^\\]\\n\\\\]*(?:\\\\.[^\\]\\n\\\\]*)*\\])[^[/\\n\\\\]*)*/[imgy]{0,4}(?!\\w)"
}
, { token: "comment"
, regex: "###(?!#)"
, next : "comment"
}
, { token: "comment"
, regex: "#.*"
}
, { token: "lparen"
, regex: "[({[]"
}
, { token: "rparen"
, regex: "[\\]})]"
}
, { token: "keyword.operator"
, regex: "\\S+"
}
, { token: "text"
, regex: "\\s+"
}
]
, qdoc:
[ { token: "string"
, regex: ".*?'''"
, next : "start"
}
, stringfill
]
, qqdoc:
[ { token: "string"
, regex: '.*?"""'
, next : "start"
}
, stringfill
]
, qstring:
[ { token: "string"
, regex: "[^\\\\']*(?:\\\\.[^\\\\']*)*'"
, next : "start"
}
, stringfill
]
, qqstring:
[ { token: "string"
, regex: '[^\\\\"]*(?:\\\\.[^\\\\"]*)*"'
, next : "start"
}
, stringfill
]
, js:
[ { token: "string"
, regex: "[^\\\\`]*(?:\\\\.[^\\\\`]*)*`"
, next : "start"
}
, stringfill
]
, heregex:
[ { token: "string.regex"
, regex: '.*?///[imgy]{0,4}'
, next : "start"
}
, { token: "comment.regex"
, regex: "\\s+(?:#.*)?"
}
, { token: "string.regex"
, regex: "\\S+"
}
]
, comment:
[ { token: "comment"
, regex: '.*?###'
, next : "start"
}
, { token: "comment"
, regex: ".+"
}
]
};
}
function CoffeeHighlightRules() {
var identifier = "[$A-Za-z_\\x7f-\\uffff][$\\w\\x7f-\\uffff]*";
var keywordend = "(?![$\\w]|\\s*:)";
var stringfill = {
token : "string",
merge : true,
regex : ".+"
};
this.$rules = {
start : [
{
token : "identifier",
regex : "(?:@|(?:\\.|::)\\s*)" + identifier
}, {
token : "keyword",
regex : "(?:t(?:h(?:is|row|en)|ry|ypeof)|s(?:uper|witch)|return|b(?:reak|y)|c(?:ontinue|atch|lass)|i(?:n(?:stanceof)?|s(?:nt)?|f)|e(?:lse|xtends)|f(?:or (?:own)?|inally|unction)|wh(?:ile|en)|n(?:ew|ot?)|d(?:e(?:lete|bugger)|o)|loop|o(?:ff?|[rn])|un(?:less|til)|and|yes)"
+ keywordend
}, {
token : "constant.language",
regex : "(?:true|false|null|undefined)" + keywordend
}, {
token : "invalid.illegal",
regex : "(?:c(?:ase|onst)|default|function|v(?:ar|oid)|with|e(?:num|xport)|i(?:mplements|nterface)|let|p(?:ackage|r(?:ivate|otected)|ublic)|static|yield|__(?:hasProp|extends|slice|bind|indexOf))"
+ keywordend
}, {
token : "language.support.class",
regex : "(?:Array|Boolean|Date|Function|Number|Object|R(?:e(?:gExp|ferenceError)|angeError)|S(?:tring|yntaxError)|E(?:rror|valError)|TypeError|URIError)"
+ keywordend
}, {
token : "language.support.function",
regex : "(?:Math|JSON|is(?:NaN|Finite)|parse(?:Int|Float)|encodeURI(?:Component)?|decodeURI(?:Component)?)"
+ keywordend
}, {
token : "identifier",
regex : identifier
}, {
token : "constant.numeric",
regex : "(?:0x[\\da-fA-F]+|(?:\\d+(?:\\.\\d+)?|\\.\\d+)(?:[eE][+-]?\\d+)?)"
}, {
token : "string",
merge : true,
regex : "'''",
next : "qdoc"
}, {
token : "string",
merge : true,
regex : '"""',
next : "qqdoc"
}, {
token : "string",
merge : true,
regex : "'",
next : "qstring"
}, {
token : "string",
merge : true,
regex : '"',
next : "qqstring"
}, {
token : "string",
merge : true,
regex : "`",
next : "js"
}, {
token : "string.regex",
merge : true,
regex : "///",
next : "heregex"
}, {
token : "string.regex",
regex : "/(?!\\s)[^[/\\n\\\\]*(?: (?:\\\\.|\\[[^\\]\\n\\\\]*(?:\\\\.[^\\]\\n\\\\]*)*\\])[^[/\\n\\\\]*)*/[imgy]{0,4}(?!\\w)"
}, {
token : "comment",
merge : true,
regex : "###(?!#)",
next : "comment"
}, {
token : "comment",
regex : "#.*"
}, {
token : "lparen",
regex : "[({[]"
}, {
token : "rparen",
regex : "[\\]})]"
}, {
token : "keyword.operator",
regex : "\\S+"
}, {
token : "text",
regex : "\\s+"
}],
qdoc : [{
token : "string",
regex : ".*?'''",
next : "start"
}, stringfill],
qqdoc : [{
token : "string",
regex : '.*?"""',
next : "start"
}, stringfill],
qstring : [{
token : "string",
regex : "[^\\\\']*(?:\\\\.[^\\\\']*)*'",
next : "start"
}, stringfill],
qqstring : [{
token : "string",
regex : '[^\\\\"]*(?:\\\\.[^\\\\"]*)*"',
next : "start"
}, stringfill],
js : [{
token : "string",
merge : true,
regex : "[^\\\\`]*(?:\\\\.[^\\\\`]*)*`",
next : "start"
}, stringfill],
heregex : [{
token : "string.regex",
regex : '.*?///[imgy]{0,4}',
next : "start"
}, {
token : "comment.regex",
regex : "\\s+(?:#.*)?"
}, {
token : "string.regex",
merge : true,
regex : "\\S+"
}],
comment : [{
token : "comment",
regex : '.*?###',
next : "start"
}, {
token : "comment",
merge : true,
regex : ".+"
}]
};
}
exports.CoffeeHighlightRules = CoffeeHighlightRules;
exports.CoffeeHighlightRules = CoffeeHighlightRules;
});

View file

@ -8,7 +8,7 @@ var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightR
var CSharpHighlightRules = function() {
var keywords = lang.arrayToMap(
("abstract|event|new|struct|as|explicit|null|switch|base|extern|object|this|bool|false|operator|throw|break|finally|out|true|byte|fixed|override|try|case|float|params|typeof|catch|for|private|uint|char|foreach|protected|ulong|checked|goto|public|unchecked|class|if|readonly|unsafe|const|implicit|ref|ushort|continue|in|return|using|decimal|int|sbyte|virtual|default|interface|sealed|volatile|delegate|internal|short|void|do|is|sizeof|while|double|lock|stackalloc|else|long|static|enum|namespace|string|var|dynamic").split("|")
("abstract|event|new|struct|as|explicit|null|switch|base|extern|object|this|bool|false|operator|throw|break|finally|out|true|byte|fixed|override|try|case|float|params|typeof|catch|for|private|uint|char|foreach|protected|ulong|checked|goto|public|unchecked|class|if|readonly|unsafe|const|implicit|ref|ushort|continue|in|return|using|decimal|int|sbyte|virtual|default|interface|sealed|volatile|delegate|internal|short|void|do|is|sizeof|while|double|lock|stackalloc|else|long|static|enum|namespace|string|var|dynamic").split("|")
);
var buildinConstants = lang.arrayToMap(
@ -21,94 +21,72 @@ var CSharpHighlightRules = function() {
this.$rules = {
"start" : [
{
token : "comment",
regex : "\\/\\/.*$"
},
new DocCommentHighlightRules().getStartRule("doc-start"),
{
token : "comment",
regex : "\\/\\/.*$"
},
new DocCommentHighlightRules().getStartRule("doc-start"),
{
token : "comment", // multi line comment
regex : "\\/\\*",
merge : true,
next : "comment"
}, {
token : "comment", // multi line comment
regex : "\\/\\*\\*",
next : "comment"
}, {
token : "string.regexp",
regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/]\\w*\\s*(?=[).,;]|$)"
}, {
token : "string", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
}, {
token : "string", // single line
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
}, {
token : "constant.numeric", // hex
regex : "0[xX][0-9a-fA-F]+\\b"
}, {
token : "constant.numeric", // float
regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
}, {
token : "constant.language.boolean",
regex : "(?:true|false)\\b"
}, {
token : function(value) {
if (value == "this")
return "variable.language";
else if (keywords.hasOwnProperty(value))
return "keyword";
else if (buildinConstants.hasOwnProperty(value))
return "constant.language";
else
return "identifier";
},
// TODO: Unicode escape sequences
// TODO: Unicode identifiers
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
}, {
token : "keyword.operator",
regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|instanceof|new|delete|typeof|void)"
}, {
token : "lparen",
regex : "[[({]"
}, {
token : "rparen",
regex : "[\\])}]"
}, {
token : "text",
regex : "\\s+"
}
token : "string.regexp",
regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/]\\w*\\s*(?=[).,;]|$)"
}, {
token : "string", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
}, {
token : "string", // single line
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
}, {
token : "constant.numeric", // hex
regex : "0[xX][0-9a-fA-F]+\\b"
}, {
token : "constant.numeric", // float
regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
}, {
token : "constant.language.boolean",
regex : "(?:true|false)\\b"
}, {
token : function(value) {
if (value == "this")
return "variable.language";
else if (keywords.hasOwnProperty(value))
return "keyword";
else if (buildinConstants.hasOwnProperty(value))
return "constant.language";
else
return "identifier";
},
// TODO: Unicode escape sequences
// TODO: Unicode identifiers
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
}, {
token : "keyword.operator",
regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|instanceof|new|delete|typeof|void)"
}, {
token : "lparen",
regex : "[[({]"
}, {
token : "rparen",
regex : "[\\])}]"
}, {
token : "text",
regex : "\\s+"
}
],
"comment" : [
{
token : "comment", // closing comment
regex : ".*?\\*\\/",
next : "start"
}, {
token : "comment", // comment spanning whole line
regex : ".+"
}
],
"qqstring" : [
{
token : "string",
regex : '(?:(?:\\\\.)|(?:[^"\\\\]))*?"',
next : "start"
}, {
token : "string",
regex : '.+'
}
],
"qstring" : [
{
token : "string",
regex : "(?:(?:\\\\.)|(?:[^'\\\\]))*?'",
next : "start"
}, {
token : "string",
regex : '.+'
}
token : "comment", // closing comment
regex : ".*?\\*\\/",
next : "start"
}, {
token : "comment", // comment spanning whole line
merge : true,
regex : ".+"
}
]
};

File diff suppressed because it is too large Load diff

View file

@ -125,6 +125,7 @@ var CssHighlightRules = function() {
var base_ruleset = [
{
token : "comment", // multi line comment
merge : true,
regex : "\\/\\*",
next : "ruleset_comment"
},{
@ -212,66 +213,56 @@ var CssHighlightRules = function() {
}
];
var ruleset = lang.copyArray( base_ruleset );
ruleset.unshift(
{
var ruleset = lang.copyArray(base_ruleset);
ruleset.unshift({
token : "rparen",
regex : "\}",
regex : "\\}",
next: "start"
}
);
});
var media_ruleset = lang.copyArray( base_ruleset );
media_ruleset.unshift(
{
media_ruleset.unshift({
token : "rparen",
regex : "\}",
regex : "\\}",
next: "media"
}
);
});
var base_comment = [
{
var base_comment = [{
token : "comment", // comment spanning whole line
merge : true,
regex : ".+"
}
];
}];
var comment = lang.copyArray( base_comment );
comment.unshift(
{
var comment = lang.copyArray(base_comment);
comment.unshift({
token : "comment", // closing comment
regex : ".*?\\*\\/",
next : "start"
}
);
});
var media_comment = lang.copyArray( base_comment );
media_comment.unshift(
{
var media_comment = lang.copyArray(base_comment);
media_comment.unshift({
token : "comment", // closing comment
regex : ".*?\\*\\/",
next : "media"
}
);
});
var ruleset_comment = lang.copyArray( base_comment );
ruleset_comment.unshift(
{
var ruleset_comment = lang.copyArray(base_comment);
ruleset_comment.unshift({
token : "comment", // closing comment
regex : ".*?\\*\\/",
next : "ruleset"
}
);
});
this.$rules = {
"start" : [ {
"start" : [{
token : "comment", // multi line comment
merge : true,
regex : "\\/\\*",
next : "comment"
}, {
token: "lparen",
regex: "{",
regex: "\\{",
next: "ruleset"
}, {
token: "string",
@ -293,15 +284,16 @@ var CssHighlightRules = function() {
"media" : [ {
token : "comment", // multi line comment
merge : true,
regex : "\\/\\*",
next : "media_comment"
}, {
token: "lparen",
regex: "{",
regex: "\\{",
next: "media_ruleset"
},{
token: "string",
regex: "}",
regex: "\\}",
next: "start"
},{
token: "keyword",

View file

@ -46,6 +46,9 @@ var CssMode = require("ace/mode/css").Mode;
var assert = require("ace/test/assertions");
module.exports = {
name: "CSS",
setUp : function() {
this.mode = new CssMode();
},

View file

@ -45,6 +45,9 @@ var CssMode = require("ace/mode/css").Mode;
var assert = require("ace/test/assertions");
module.exports = {
name: "CSS Tokenizer",
setUp : function() {
this.tokenizer = new CssMode().getTokenizer();
},

View file

@ -54,7 +54,10 @@ oop.inherits(Worker, Mirror);
var value = this.doc.getValue();
result = CSSLint.verify(value);
this.sender.emit("csslint", result.messages);
this.sender.emit("csslint", result.messages.map(function(msg) {
delete msg.rule;
return msg;
}));
};
}).call(Worker.prototype);

View file

@ -48,15 +48,19 @@ var DocCommentHighlightRules = function() {
regex : "@[\\w\\d_]+" // TODO: fix email addresses
}, {
token : "comment.doc",
merge : true,
regex : "\\s+"
}, {
token : "comment.doc",
merge : true,
regex : "TODO"
}, {
token : "comment.doc",
merge : true,
regex : "[^@\\*]+"
}, {
token : "comment.doc",
merge : true,
regex : "."
}]
};
@ -69,14 +73,16 @@ oop.inherits(DocCommentHighlightRules, TextHighlightRules);
this.getStartRule = function(start) {
return {
token : "comment.doc", // doc comment
merge : true,
regex : "\\/\\*(?=\\*)",
next: start
next : start
};
};
this.getEndRule = function (start) {
return {
token : "comment.doc", // closing comment
merge : true,
regex : "\\*\\/",
next : start
};

View file

@ -8,16 +8,16 @@ var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightR
var GroovyHighlightRules = function() {
var keywords = lang.arrayToMap(
("assert|with|abstract|continue|for|new|switch|" +
"assert|default|goto|package|synchronized|" +
"boolean|do|if|private|this|" +
"break|double|implements|protected|throw|" +
"byte|else|import|public|throws|" +
"case|enum|instanceof|return|transient|" +
"catch|extends|int|short|try|" +
"char|final|interface|static|void|" +
"class|finally|long|strictfp|volatile|" +
"def|float|native|super|while").split("|")
("assert|with|abstract|continue|for|new|switch|" +
"assert|default|goto|package|synchronized|" +
"boolean|do|if|private|this|" +
"break|double|implements|protected|throw|" +
"byte|else|import|public|throws|" +
"case|enum|instanceof|return|transient|" +
"catch|extends|int|short|try|" +
"char|final|interface|static|void|" +
"class|finally|long|strictfp|volatile|" +
"def|float|native|super|while").split("|")
);
var buildinConstants = lang.arrayToMap(
@ -59,98 +59,76 @@ var GroovyHighlightRules = function() {
this.$rules = {
"start" : [
{
token : "comment",
regex : "\\/\\/.*$"
},
new DocCommentHighlightRules().getStartRule("doc-start"),
{
token : "comment",
regex : "\\/\\/.*$"
},
new DocCommentHighlightRules().getStartRule("doc-start"),
{
token : "comment", // multi line comment
merge : true,
regex : "\\/\\*",
next : "comment"
}, {
token : "comment", // multi line comment
regex : "\\/\\*\\*",
next : "comment"
}, {
token : "string.regexp",
regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/]\\w*\\s*(?=[).,;]|$)"
}, {
token : "string", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
}, {
token : "string", // single line
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
}, {
token : "constant.numeric", // hex
regex : "0[xX][0-9a-fA-F]+\\b"
}, {
token : "constant.numeric", // float
regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
}, {
token : "constant.language.boolean",
regex : "(?:true|false)\\b"
}, {
token : function(value) {
if (value == "this")
return "variable.language";
else if (keywords.hasOwnProperty(value))
return "keyword";
token : "string.regexp",
regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/]\\w*\\s*(?=[).,;]|$)"
}, {
token : "string", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
}, {
token : "string", // single line
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
}, {
token : "constant.numeric", // hex
regex : "0[xX][0-9a-fA-F]+\\b"
}, {
token : "constant.numeric", // float
regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
}, {
token : "constant.language.boolean",
regex : "(?:true|false)\\b"
}, {
token : function(value) {
if (value == "this")
return "variable.language";
else if (keywords.hasOwnProperty(value))
return "keyword";
else if (langClasses.hasOwnProperty(value))
return "support.function";
else if (importClasses.hasOwnProperty(value))
return "support.function";
else if (buildinConstants.hasOwnProperty(value))
return "constant.language";
else
return "identifier";
},
// TODO: Unicode escape sequences
// TODO: Unicode identifiers
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
}, {
token : "keyword.operator",
regex : "\\?:|\\?\\.|\\*\\.|<=>|=~|==~|\\.@|\\*\\.@|\\.&|as|in|is|!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|instanceof|new|delete|typeof|void)"
}, {
token : "lparen",
regex : "[[({]"
}, {
token : "rparen",
regex : "[\\])}]"
}, {
token : "text",
regex : "\\s+"
}
else if (buildinConstants.hasOwnProperty(value))
return "constant.language";
else
return "identifier";
},
// TODO: Unicode escape sequences
// TODO: Unicode identifiers
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
}, {
token : "keyword.operator",
regex : "\\?:|\\?\\.|\\*\\.|<=>|=~|==~|\\.@|\\*\\.@|\\.&|as|in|is|!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|instanceof|new|delete|typeof|void)"
}, {
token : "lparen",
regex : "[[({]"
}, {
token : "rparen",
regex : "[\\])}]"
}, {
token : "text",
regex : "\\s+"
}
],
"comment" : [
{
token : "comment", // closing comment
regex : ".*?\\*\\/",
next : "start"
}, {
token : "comment", // comment spanning whole line
regex : ".+"
}
],
"qqstring" : [
{
token : "string",
regex : '(?:(?:\\\\.)|(?:[^"\\\\]))*?"',
next : "start"
}, {
token : "string",
regex : '.+'
}
],
"qstring" : [
{
token : "string",
regex : "(?:(?:\\\\.)|(?:[^'\\\\]))*?'",
next : "start"
}, {
token : "string",
regex : '.+'
}
token : "comment", // closing comment
regex : ".*?\\*\\/",
next : "start"
}, {
token : "comment", // comment spanning whole line
merge : true,
regex : ".+"
}
]
};

View file

@ -54,6 +54,7 @@ var HtmlHighlightRules = function() {
regex : '".*?"'
}, {
token : "string", // multi line string start
merge : true,
regex : '["].*$',
next : state + "-qqstring"
}, {
@ -61,6 +62,7 @@ var HtmlHighlightRules = function() {
regex : "'.*?'"
}, {
token : "string", // multi line string start
merge : true,
regex : "['].*$",
next : state + "-qstring"
}]
@ -69,10 +71,12 @@ var HtmlHighlightRules = function() {
function multiLineString(quote, state) {
return [{
token : "string",
merge : true,
regex : ".*" + quote,
next : state
}, {
token : "string",
merge : true,
regex : '.+'
}]
}
@ -80,6 +84,7 @@ var HtmlHighlightRules = function() {
this.$rules = {
start : [ {
token : "text",
merge : true,
regex : "<\\!\\[CDATA\\[",
next : "cdata"
}, {
@ -87,6 +92,7 @@ var HtmlHighlightRules = function() {
regex : "<\\?.*?\\?>"
}, {
token : "comment",
merge : true,
regex : "<\\!--",
next : "comment"
}, {
@ -158,9 +164,11 @@ var HtmlHighlightRules = function() {
next : "start"
}, {
token : "text",
merge : true,
regex : "\\s+"
}, {
token : "text",
merge : true,
regex : ".+"
} ],
@ -170,6 +178,7 @@ var HtmlHighlightRules = function() {
next : "start"
}, {
token : "comment",
merge : true,
regex : ".+"
} ]
};
@ -194,4 +203,4 @@ var HtmlHighlightRules = function() {
oop.inherits(HtmlHighlightRules, TextHighlightRules);
exports.HtmlHighlightRules = HtmlHighlightRules;
});
});

View file

@ -9,16 +9,16 @@ var JavaHighlightRules = function() {
// taken from http://download.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html
var keywords = lang.arrayToMap(
("abstract|continue|for|new|switch|" +
"assert|default|goto|package|synchronized|" +
"boolean|do|if|private|this|" +
"break|double|implements|protected|throw|" +
"byte|else|import|public|throws|" +
"case|enum|instanceof|return|transient|" +
"catch|extends|int|short|try|" +
"char|final|interface|static|void|" +
"class|finally|long|strictfp|volatile|" +
"const|float|native|super|while").split("|")
("abstract|continue|for|new|switch|" +
"assert|default|goto|package|synchronized|" +
"boolean|do|if|private|this|" +
"break|double|implements|protected|throw|" +
"byte|else|import|public|throws|" +
"case|enum|instanceof|return|transient|" +
"catch|extends|int|short|try|" +
"char|final|interface|static|void|" +
"class|finally|long|strictfp|volatile|" +
"const|float|native|super|while").split("|")
);
var buildinConstants = lang.arrayToMap(
@ -60,98 +60,76 @@ var JavaHighlightRules = function() {
this.$rules = {
"start" : [
{
token : "comment",
regex : "\\/\\/.*$"
},
new DocCommentHighlightRules().getStartRule("doc-start"),
{
token : "comment",
regex : "\\/\\/.*$"
},
new DocCommentHighlightRules().getStartRule("doc-start"),
{
token : "comment", // multi line comment
merge : true,
regex : "\\/\\*",
next : "comment"
}, {
token : "comment", // multi line comment
regex : "\\/\\*\\*",
next : "comment"
}, {
token : "string.regexp",
regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/]\\w*\\s*(?=[).,;]|$)"
}, {
token : "string", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
}, {
token : "string", // single line
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
}, {
token : "constant.numeric", // hex
regex : "0[xX][0-9a-fA-F]+\\b"
}, {
token : "constant.numeric", // float
regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
}, {
token : "constant.language.boolean",
regex : "(?:true|false)\\b"
}, {
token : function(value) {
if (value == "this")
return "variable.language";
else if (keywords.hasOwnProperty(value))
return "keyword";
token : "string.regexp",
regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/]\\w*\\s*(?=[).,;]|$)"
}, {
token : "string", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
}, {
token : "string", // single line
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
}, {
token : "constant.numeric", // hex
regex : "0[xX][0-9a-fA-F]+\\b"
}, {
token : "constant.numeric", // float
regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
}, {
token : "constant.language.boolean",
regex : "(?:true|false)\\b"
}, {
token : function(value) {
if (value == "this")
return "variable.language";
else if (keywords.hasOwnProperty(value))
return "keyword";
else if (langClasses.hasOwnProperty(value))
return "support.function";
else if (importClasses.hasOwnProperty(value))
return "support.function";
else if (buildinConstants.hasOwnProperty(value))
return "constant.language";
else
return "identifier";
},
// TODO: Unicode escape sequences
// TODO: Unicode identifiers
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
}, {
token : "keyword.operator",
regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|instanceof|new|delete|typeof|void)"
}, {
token : "lparen",
regex : "[[({]"
}, {
token : "rparen",
regex : "[\\])}]"
}, {
token : "text",
regex : "\\s+"
}
else if (buildinConstants.hasOwnProperty(value))
return "constant.language";
else
return "identifier";
},
// TODO: Unicode escape sequences
// TODO: Unicode identifiers
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
}, {
token : "keyword.operator",
regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|instanceof|new|delete|typeof|void)"
}, {
token : "lparen",
regex : "[[({]"
}, {
token : "rparen",
regex : "[\\])}]"
}, {
token : "text",
regex : "\\s+"
}
],
"comment" : [
{
token : "comment", // closing comment
regex : ".*?\\*\\/",
next : "start"
}, {
token : "comment", // comment spanning whole line
regex : ".+"
}
],
"qqstring" : [
{
token : "string",
regex : '(?:(?:\\\\.)|(?:[^"\\\\]))*?"',
next : "start"
}, {
token : "string",
regex : '.+'
}
],
"qstring" : [
{
token : "string",
regex : "(?:(?:\\\\.)|(?:[^'\\\\]))*?'",
next : "start"
}, {
token : "string",
regex : '.+'
}
token : "comment", // closing comment
regex : ".*?\\*\\/",
next : "start"
}, {
token : "comment", // comment spanning whole line
merge : true,
regex : ".+"
}
]
};

View file

@ -96,7 +96,7 @@ oop.inherits(Mode, TextMode);
}
if (state == "start") {
var match = line.match(/^.*[\{\(\[]\s*$/);
var match = line.match(/^.*[\{\(\[\:]\s*$/);
if (match) {
indent += tab;
}

View file

@ -40,6 +40,7 @@ define(function(require, exports, module) {
var oop = require("pilot/oop");
var lang = require("pilot/lang");
var unicode = require("ace/unicode");
var DocCommentHighlightRules = require("ace/mode/doc_comment_highlight_rules").DocCommentHighlightRules;
var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;
@ -60,6 +61,13 @@ var JavaScriptHighlightRules = function() {
"public|interface|package|protected|static").split("|")
);
// TODO: Unicode escape sequences
var identifierRe = "[" + unicode.packages.L + "\\$_]["
+ unicode.packages.L
+ unicode.packages.Mn + unicode.packages.Mc
+ unicode.packages.Nd
+ unicode.packages.Pc + "\\$_]*\\b";
// regexp must not have capturing parentheses. Use (?:) instead.
// regexps are ordered -> the first match is used
@ -72,16 +80,15 @@ var JavaScriptHighlightRules = function() {
new DocCommentHighlightRules().getStartRule("doc-start"),
{
token : "comment", // multi line comment
merge : true,
regex : "\\/\\*",
next : "comment"
}, {
token : "string.regexp",
regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/]\\w*\\s*(?=[).,;]|$)"
}, {
token : "string", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
}, {
token : "string", // multi line string start
merge : true,
regex : '["].*\\\\$',
next : "qqstring"
}, {
@ -89,6 +96,7 @@ var JavaScriptHighlightRules = function() {
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
}, {
token : "string", // multi line string start
merge : true,
regex : "['].*\\\\$",
next : "qstring"
}, {
@ -115,18 +123,22 @@ var JavaScriptHighlightRules = function() {
else
return "identifier";
},
// TODO: Unicode escape sequences
// TODO: Unicode identifiers
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
regex : identifierRe
}, {
token : "keyword.operator",
regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|instanceof|new|delete|typeof|void)"
regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|instanceof|new|delete|typeof|void)",
next : "regex_allowed"
}, {
token : "lparen",
regex : "[[({]"
regex : "[[({]",
next : "regex_allowed"
}, {
token : "rparen",
regex : "[\\])}]"
}, {
token : "keyword.operator",
regex : "\\/=?",
next : "regex_allowed"
}, {
token: "comment",
regex: "^#!.*$"
@ -135,6 +147,26 @@ var JavaScriptHighlightRules = function() {
regex : "\\s+"
}
],
// regular expressions are only allowed after certain tokens. This
// makes sure we don't mix up regexps with the divison operator
"regex_allowed": [
{
token: "string.regexp",
regex: "\\/(?:(?:\\[(?:\\\\]|[^\\]])+\\])"
+ "|(?:\\\\/|[^\\]/]))*"
+ "[/]\\w*",
next: "start"
}, {
token : "text",
regex : "\\s+"
}, {
// immediately return to the start mode without matching
// anything
token: "empty",
regex: "",
next: "start"
}
],
"comment" : [
{
token : "comment", // closing comment
@ -142,6 +174,7 @@ var JavaScriptHighlightRules = function() {
next : "start"
}, {
token : "comment", // comment spanning whole line
merge : true,
regex : ".+"
}
],
@ -152,6 +185,7 @@ var JavaScriptHighlightRules = function() {
next : "start"
}, {
token : "string",
merge : true,
regex : '.+'
}
],
@ -162,6 +196,7 @@ var JavaScriptHighlightRules = function() {
next : "start"
}, {
token : "string",
merge : true,
regex : '.+'
}
]

View file

@ -75,12 +75,12 @@ module.exports = {
},
"test: toggle comment lines twice should return the original text" : function() {
var session = new EditSession([" abc", "cde", "fg"]);
this.mode.toggleCommentLines("start", session, 0, 2);
this.mode.toggleCommentLines("start", session, 0, 2);
assert.equal([" abc", "cde", "fg"].join("\n"), session.toString());
},
var session = new EditSession([" abc", "cde", "fg"]);
this.mode.toggleCommentLines("start", session, 0, 2);
this.mode.toggleCommentLines("start", session, 0, 2);
assert.equal([" abc", "cde", "fg"].join("\n"), session.toString());
},
"test: toggle comment on multiple lines with one commented line prepend '//' to each line" : function() {
var session = new EditSession(["// abc", "//cde", "fg"]);
@ -99,6 +99,10 @@ module.exports = {
"test: auto indent after opening brace" : function() {
assert.equal(" ", this.mode.getNextLineIndent("start", "if () {", " "));
},
"test: auto indent after case" : function() {
assert.equal(" ", this.mode.getNextLineIndent("start", "case 'juhu':", " "));
},
"test: no auto indent after opening brace in multi line comment" : function() {
assert.equal("", this.mode.getNextLineIndent("start", "/*if () {", " "));

View file

@ -45,6 +45,9 @@ var JavaScriptMode = require("ace/mode/javascript").Mode;
var assert = require("ace/test/assertions");
module.exports = {
name: "JavaScript Tokenizer",
setUp : function() {
this.tokenizer = new JavaScriptMode().getTokenizer();
},
@ -91,22 +94,54 @@ module.exports = {
var tokens = this.tokenizer.getLineTokens(line, "start").tokens;
assert.equal(3, tokens.length);
assert.equal(7, tokens.length);
assert.equal("lparen", tokens[0].type);
assert.equal("text", tokens[1].type);
assert.equal("rparen", tokens[2].type);
assert.equal("lparen", tokens[1].type);
assert.equal("lparen", tokens[2].type);
assert.equal("text", tokens[3].type);
assert.equal("rparen", tokens[4].type);
assert.equal("rparen", tokens[5].type);
assert.equal("rparen", tokens[6].type);
},
"test for last rule in ruleset to catch capturing group bugs" : function() {
var tokens = this.tokenizer.getLineTokens("}", "start").tokens;
assert.equal(1, tokens.length);
assert.equal("rparen", tokens[0].type);
},
"test tokenize regular expressions": function() {
"test tokenize arithmetic expression which looks like a regexp": function() {
var tokens = this.tokenizer.getLineTokens("a/b/c", "start").tokens;
assert.equal(5, tokens.length);
var tokens = this.tokenizer.getLineTokens("a/=b/c", "start").tokens;
assert.equal(5, tokens.length);
},
"test tokenize reg exps" : function() {
var tokens = this.tokenizer.getLineTokens("a=/b/g", "start").tokens;
assert.equal(3, tokens.length);
assert.equal("string.regexp", tokens[2].type);
var tokens = this.tokenizer.getLineTokens("a+/b/g", "start").tokens;
assert.equal(3, tokens.length);
assert.equal("string.regexp", tokens[2].type);
var tokens = this.tokenizer.getLineTokens("a = 1 + /2 + 1/b", "start").tokens;
assert.equal(9, tokens.length);
assert.equal("string.regexp", tokens[8].type);
var tokens = this.tokenizer.getLineTokens("a=/a/ / /a/", "start").tokens;
assert.equal(7, tokens.length);
assert.equal("string.regexp", tokens[2].type);
assert.equal("string.regexp", tokens[6].type);
},
"test tokenize identifier with umlauts": function() {
var tokens = this.tokenizer.getLineTokens("füße", "start").tokens;
assert.equal(1, tokens.length);
}
};

View file

@ -237,9 +237,8 @@ var OcamlHighlightRules = function() {
"Int32|Int64|LargeFile|Lazy|Lexing|List|ListLabels|Make|Map|Marshal|" +
"MoreLabels|Mutex|Nativeint|Num|Obj|Oo|Parsing|Pervasives|Printexc|" +
"Printf|Queue|Random|Scanf|Scanning|Set|Sort|Stack|State|StdLabels|Str|" +
"Stream|String|StringLabels|Sys|Thread|ThreadUnix|Tk|Unix|UnixLabels|Weak")
.split("|"));
"Stream|String|StringLabels|Sys|Thread|ThreadUnix|Tk|Unix|UnixLabels|Weak"
).split("|"));
var decimalInteger = "(?:(?:[1-9]\\d*)|(?:0))";
var octInteger = "(?:0[oO]?[0-7]+)";
@ -262,6 +261,7 @@ var OcamlHighlightRules = function() {
},
{
token : "comment",
merge : true,
regex : '\\(\\*.*',
next : "comment"
},
@ -275,6 +275,7 @@ var OcamlHighlightRules = function() {
},
{
token : "string", // " string
merge : true,
regex : '"',
next : "qstring"
},
@ -328,6 +329,7 @@ var OcamlHighlightRules = function() {
},
{
token : "comment", // comment spanning whole line
merge : true,
regex : ".+"
}
],
@ -339,6 +341,7 @@ var OcamlHighlightRules = function() {
next : "start"
}, {
token : "string",
merge : true,
regex : '.+'
}
]

View file

@ -93,6 +93,7 @@ var PerlHighlightRules = function() {
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
}, {
token : "string", // multi line string start
merge : true,
regex : '["].*\\\\$',
next : "qqstring"
}, {
@ -100,6 +101,7 @@ var PerlHighlightRules = function() {
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
}, {
token : "string", // multi line string start
merge : true,
regex : "['].*\\\\$",
next : "qstring"
}, {
@ -141,6 +143,7 @@ var PerlHighlightRules = function() {
next : "start"
}, {
token : "string",
merge : true,
regex : '.+'
}
],
@ -151,6 +154,7 @@ var PerlHighlightRules = function() {
next : "start"
}, {
token : "string",
merge : true,
regex : '.+'
}
]

File diff suppressed because it is too large Load diff

View file

@ -96,6 +96,7 @@ var PythonHighlightRules = function() {
regex : strPre + '"{3}(?:[^\\\\]|\\\\.)*?"{3}'
}, {
token : "string", // multi line """ string start
merge : true,
regex : strPre + '"{3}.*$',
next : "qqstring"
}, {
@ -106,6 +107,7 @@ var PythonHighlightRules = function() {
regex : strPre + "'{3}(?:[^\\\\]|\\\\.)*?'{3}"
}, {
token : "string", // multi line ''' string start
merge : true,
regex : strPre + "'{3}.*$",
next : "qstring"
}, {
@ -158,14 +160,16 @@ var PythonHighlightRules = function() {
next : "start"
}, {
token : "string",
merge : true,
regex : '.+'
} ],
"qstring" : [ {
token : "string", // multi line ''' string end
token : "string", // multi line ''' string end
regex : "(?:[^\\\\]|\\\\.)*?'{3}",
next : "start"
}, {
token : "string",
merge : true,
regex : '.+'
} ]
};

View file

@ -98,86 +98,91 @@ var RubyHighlightRules = function() {
this.$rules = {
"start" : [
{
token : "comment",
regex : "#.*$"
}, {
{
token : "comment",
regex : "#.*$"
}, {
token : "comment", // multi line comment
merge : true,
regex : "^\=begin$",
next : "comment"
}, {
token : "string.regexp",
regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/]\\w*\\s*(?=[).,;]|$)"
}, {
token : "string.regexp",
regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/]\\w*\\s*(?=[).,;]|$)"
}, {
token : "string", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
}, {
}, {
token : "string", // single line
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
}, {
}, {
token : "string", // backtick string
regex : "[`](?:(?:\\\\.)|(?:[^'\\\\]))*?[`]"
}, {
}, {
token : "text", // namespaces aren't symbols
regex : "::"
}, {
token : "variable.instancce", // instance variable
regex : "@{1,2}(?:[a-zA-Z_]|\d)+"
}, {
}, {
token : "variable.class", // class name
regex : "[A-Z](?:[a-zA-Z_]|\d)+"
}, {
}, {
token : "string", // symbol
regex : "[:](?:[a-zA-Z]|\d)+"
}, {
token : "constant.numeric", // hex
regex : "0[xX][0-9a-fA-F]+\\b"
}, {
token : "constant.numeric", // float
regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
}, {
token : "constant.language.boolean",
regex : "(?:true|false)\\b"
}, {
token : function(value) {
if (value == "self")
return "variable.language";
else if (keywords.hasOwnProperty(value))
return "keyword";
else if (buildinConstants.hasOwnProperty(value))
return "constant.language";
regex : "[:](?:[A-Za-z_]|[@$](?=[a-zA-Z0-9_]))[a-zA-Z0-9_]*[!=?]?"
}, {
token : "constant.numeric", // hex
regex : "0[xX][0-9a-fA-F](?:[0-9a-fA-F]|_(?=[0-9a-fA-F]))*\\b"
}, {
token : "constant.numeric", // float
regex : "[+-]?\\d(?:\\d|_(?=\\d))*(?:(?:\\.\\d(?:\\d|_(?=\\d))*)?(?:[eE][+-]?\\d+)?)?\\b"
}, {
token : "constant.language.boolean",
regex : "(?:true|false)\\b"
}, {
token : function(value) {
if (value == "self")
return "variable.language";
else if (keywords.hasOwnProperty(value))
return "keyword";
else if (buildinConstants.hasOwnProperty(value))
return "constant.language";
else if (builtinVariables.hasOwnProperty(value))
return "variable.language";
else if (builtinFunctions.hasOwnProperty(value))
return "support.function";
else if (value == "debugger")
return "invalid.deprecated";
else
return "identifier";
},
// TODO: Unicode escape sequences
// TODO: Unicode identifiers
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
}, {
token : "keyword.operator",
regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|instanceof|new|delete|typeof|void)"
}, {
token : "lparen",
regex : "[[({]"
}, {
token : "rparen",
regex : "[\\])}]"
}, {
token : "text",
regex : "\\s+"
}
else if (value == "debugger")
return "invalid.deprecated";
else
return "identifier";
},
// TODO: Unicode escape sequences
// TODO: Unicode identifiers
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
}, {
token : "keyword.operator",
regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|instanceof|new|delete|typeof|void)"
}, {
token : "lparen",
regex : "[[({]"
}, {
token : "rparen",
regex : "[\\])}]"
}, {
token : "text",
regex : "\\s+"
}
],
"comment" : [
{
{
token : "comment", // closing comment
regex : "^\=end$",
next : "start"
}, {
token : "comment", // comment spanning whole line
regex : ".+"
}
token : "comment", // comment spanning whole line
merge : true,
regex : ".+"
}
]
};
};

View file

@ -0,0 +1,115 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Trent Ogren <me AT trentogren DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
if (typeof process !== "undefined") {
require("../../../support/paths");
}
define(function(require, exports, module) {
var RubyMode = require("ace/mode/ruby").Mode;
var assert = require("ace/test/assertions");
module.exports = {
name: "Ruby Tokenizer",
setUp : function() {
this.tokenizer = new RubyMode().getTokenizer();
},
"test: symbol tokenizer" : function() {
// https://gist.github.com/1072693
assertValidTokens(this.tokenizer, "string",
[":@thing", ":$thing", ":_thing", ":thing", ":Thing", ":thing1", ":thing_a",
":THING", ":thing!", ":thing=", ":thing?", ":t?"]);
assertInvalidTokens(this.tokenizer, "string",
[":", ":@", ":$", ":1", ":1thing", ":th?ing", ":thi=ng", ":1thing",
":th!ing", ":thing#"]);
},
"test: namespaces aren't symbols" : function() {
var line = "Namespaced::Class";
var tokens = this.tokenizer.getLineTokens(line, "start").tokens;
assert.equal(3, tokens.length);
assert.equal("variable.class", tokens[0].type);
assert.equal("text", tokens[1].type);
assert.equal("variable.class", tokens[2].type);
},
"test: hex tokenizer" : function() {
assertValidTokens(this.tokenizer, "constant.numeric",
["0x9a", "0XA1", "0x9_a"]);
assertInvalidTokens(this.tokenizer, "constant.numeric",
["0x", "0x_9a", "0x9a_"]);
},
"test: float tokenizer" : function() {
assertValidTokens(this.tokenizer, "constant.numeric",
["1", "+1", "-1", "12_345", "0.000_1"]);
assertInvalidTokens(this.tokenizer, "constant.numeric",
["_", "_1", "1_", "1_.0", "0._1"]);
}
};
function assertValidTokens(tokenizer, tokenType, validTokens) {
for (var i = 0, length = validTokens.length; i < length; i++) {
var validToken = validTokens[i],
tokens = tokenizer.getLineTokens(validToken, "start").tokens;
assert.equal(tokens[0].value, validToken,
'"' + validToken + '" should be one token');
assert.equal(tokens[0].type, tokenType,
'"' + validToken + '" should be a "' + tokenType + '" token');
}
}
function assertInvalidTokens(tokenizer, tokenType, invalidTokens) {
for (var i = 0, length = invalidTokens.length; i < length; i++) {
var invalidToken = invalidTokens[i],
tokens = tokenizer.getLineTokens(invalidToken, "start").tokens;
assert.ok(tokens[0].type !== tokenType || tokens[0].value !== invalidToken,
'"' + invalidToken + '" is not a valid "' + tokenType + '"');
}
}
});
if (typeof module !== "undefined" && module === require.main) {
require("asyncjs").test.testcase(module.exports).exec()
}

130
lib/ace/mode/scad.js Normal file
View file

@ -0,0 +1,130 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Gastón Kleiman <gaston.kleiman AT gmail DOT com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("pilot/oop");
var TextMode = require("ace/mode/text").Mode;
var Tokenizer = require("ace/tokenizer").Tokenizer;
var scadHighlightRules = require("ace/mode/scad_highlight_rules").scadHighlightRules;
var MatchingBraceOutdent = require("ace/mode/matching_brace_outdent").MatchingBraceOutdent;
var Range = require("ace/range").Range;
var CstyleBehaviour = require("ace/mode/behaviour/cstyle").CstyleBehaviour;
var Mode = function() {
this.$tokenizer = new Tokenizer(new scadHighlightRules().getRules());
this.$outdent = new MatchingBraceOutdent();
this.$behaviour = new CstyleBehaviour();
};
oop.inherits(Mode, TextMode);
(function() {
this.toggleCommentLines = function(state, doc, startRow, endRow) {
var outdent = true;
var outentedRows = [];
var re = /^(\s*)\/\//;
for (var i=startRow; i<= endRow; i++) {
if (!re.test(doc.getLine(i))) {
outdent = false;
break;
}
}
if (outdent) {
var deleteRange = new Range(0, 0, 0, 0);
for (var i=startRow; i<= endRow; i++)
{
var line = doc.getLine(i);
var m = line.match(re);
deleteRange.start.row = i;
deleteRange.end.row = i;
deleteRange.end.column = m[0].length;
doc.replace(deleteRange, m[1]);
}
}
else {
doc.indentRows(startRow, endRow, "//");
}
};
this.getNextLineIndent = function(state, line, tab) {
var indent = this.$getIndent(line);
var tokenizedLine = this.$tokenizer.getLineTokens(line, state);
var tokens = tokenizedLine.tokens;
var endState = tokenizedLine.state;
if (tokens.length && tokens[tokens.length-1].type == "comment") {
return indent;
}
if (state == "start") {
var match = line.match(/^.*[\{\(\[]\s*$/);
if (match) {
indent += tab;
}
} else if (state == "doc-start") {
if (endState == "start") {
return "";
}
var match = line.match(/^\s*(\/?)\*/);
if (match) {
if (match[1]) {
indent += " ";
}
indent += "* ";
}
}
return indent;
};
this.checkOutdent = function(state, line, input) {
return this.$outdent.checkOutdent(line, input);
};
this.autoOutdent = function(state, doc, row) {
this.$outdent.autoOutdent(doc, row);
};
}).call(Mode.prototype);
exports.Mode = Mode;
});

View file

@ -0,0 +1,167 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Gastón Kleiman <gaston.kleiman AT gmail DOT com>
*
* Based on Bespin's C/C++ Syntax Plugin by Marc McIntyre.
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("pilot/oop");
var lang = require("pilot/lang");
var DocCommentHighlightRules = require("ace/mode/doc_comment_highlight_rules").DocCommentHighlightRules;
var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;
var scadHighlightRules = function() {
var keywords = lang.arrayToMap(
("module|if|else|for").split("|")
);
var buildinConstants = lang.arrayToMap(
("NULL").split("|")
);
// regexp must not have capturing parentheses. Use (?:) instead.
// regexps are ordered -> the first match is used
this.$rules = {
"start" : [
{
token : "comment",
regex : "\\/\\/.*$"
},
new DocCommentHighlightRules().getStartRule("start"),
{
token : "comment", // multi line comment
merge : true,
regex : "\\/\\*",
next : "comment"
}, {
token : "string", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
}, {
token : "string", // multi line string start
regex : '["].*\\\\$',
next : "qqstring"
}, {
token : "string", // single line
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
}, {
token : "string", // multi line string start
regex : "['].*\\\\$",
next : "qstring"
}, {
token : "constant.numeric", // hex
regex : "0[xX][0-9a-fA-F]+\\b"
}, {
token : "constant.numeric", // float
regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
}, {
token : "constant", // <CONSTANT>
regex : "<[a-zA-Z0-9.]+>"
}, {
token : "keyword", // pre-compiler directivs
regex : "(?:use|include)"
}, {
token : function(value) {
if (value == "this")
return "variable.language";
else if (keywords.hasOwnProperty(value))
return "keyword";
else if (buildinConstants.hasOwnProperty(value))
return "constant.language";
else
return "identifier";
},
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
}, {
token : "keyword.operator",
regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|==|=|!=|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|new|delete|typeof|void)"
}, {
token : "lparen",
regex : "[[({]"
}, {
token : "rparen",
regex : "[\\])}]"
}, {
token : "text",
regex : "\\s+"
}
],
"comment" : [
{
token : "comment", // closing comment
regex : ".*?\\*\\/",
next : "start"
}, {
token : "comment", // comment spanning whole line
merge : true,
regex : ".+"
}
],
"qqstring" : [
{
token : "string",
regex : '(?:(?:\\\\.)|(?:[^"\\\\]))*?"',
next : "start"
}, {
token : "string",
merge : true,
regex : '.+'
}
],
"qstring" : [
{
token : "string",
regex : "(?:(?:\\\\.)|(?:[^'\\\\]))*?'",
next : "start"
}, {
token : "string",
merge : true,
regex : '.+'
}
]
};
this.embedRules(DocCommentHighlightRules, "doc-",
[ new DocCommentHighlightRules().getEndRule("start") ]);
};
oop.inherits(scadHighlightRules, TextHighlightRules);
exports.scadHighlightRules = scadHighlightRules;
});

View file

@ -9,7 +9,7 @@ var ScalaHighlightRules = function() {
// taken from http://download.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html
var keywords = lang.arrayToMap(
(
(
"case|default|do|else|for|if|match|while|throw|return|try|catch|finally|yield|" +
"abstract|class|def|extends|final|forSome|implicit|implicits|import|lazy|new|object|" +
"override|package|private|protected|sealed|super|this|trait|type|val|var|with"
@ -60,98 +60,76 @@ var ScalaHighlightRules = function() {
this.$rules = {
"start" : [
{
token : "comment",
regex : "\\/\\/.*$"
},
new DocCommentHighlightRules().getStartRule("doc-start"),
{
token : "comment",
regex : "\\/\\/.*$"
},
new DocCommentHighlightRules().getStartRule("doc-start"),
{
token : "comment", // multi line comment
merge : true,
regex : "\\/\\*",
next : "comment"
}, {
token : "comment", // multi line comment
regex : "\\/\\*\\*",
next : "comment"
}, {
token : "string.regexp",
regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/]\\w*\\s*(?=[).,;]|$)"
}, {
token : "string", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
}, {
token : "string", // single line
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
}, {
token : "constant.numeric", // hex
regex : "0[xX][0-9a-fA-F]+\\b"
}, {
token : "constant.numeric", // float
regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
}, {
token : "constant.language.boolean",
regex : "(?:true|false)\\b"
}, {
token : function(value) {
if (value == "this")
return "variable.language";
else if (keywords.hasOwnProperty(value))
return "keyword";
token : "string.regexp",
regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/]\\w*\\s*(?=[).,;]|$)"
}, {
token : "string", // single line
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
}, {
token : "string", // single line
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
}, {
token : "constant.numeric", // hex
regex : "0[xX][0-9a-fA-F]+\\b"
}, {
token : "constant.numeric", // float
regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
}, {
token : "constant.language.boolean",
regex : "(?:true|false)\\b"
}, {
token : function(value) {
if (value == "this")
return "variable.language";
else if (keywords.hasOwnProperty(value))
return "keyword";
else if (langClasses.hasOwnProperty(value))
return "support.function";
else if (importClasses.hasOwnProperty(value))
return "support.function";
else if (buildinConstants.hasOwnProperty(value))
return "constant.language";
else
return "identifier";
},
// TODO: Unicode escape sequences
// TODO: Unicode identifiers
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
}, {
token : "keyword.operator",
regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|instanceof|new|delete|typeof|void)"
}, {
token : "lparen",
regex : "[[({]"
}, {
token : "rparen",
regex : "[\\])}]"
}, {
token : "text",
regex : "\\s+"
}
else if (buildinConstants.hasOwnProperty(value))
return "constant.language";
else
return "identifier";
},
// TODO: Unicode escape sequences
// TODO: Unicode identifiers
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
}, {
token : "keyword.operator",
regex : "!|\\$|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|instanceof|new|delete|typeof|void)"
}, {
token : "lparen",
regex : "[[({]"
}, {
token : "rparen",
regex : "[\\])}]"
}, {
token : "text",
regex : "\\s+"
}
],
"comment" : [
{
token : "comment", // closing comment
regex : ".*?\\*\\/",
next : "start"
}, {
token : "comment", // comment spanning whole line
regex : ".+"
}
],
"qqstring" : [
{
token : "string",
regex : '(?:(?:\\\\.)|(?:[^"\\\\]))*?"',
next : "start"
}, {
token : "string",
regex : '.+'
}
],
"qstring" : [
{
token : "string",
regex : "(?:(?:\\\\.)|(?:[^'\\\\]))*?'",
next : "start"
}, {
token : "string",
regex : '.+'
}
token : "comment", // closing comment
regex : ".*?\\*\\/",
next : "start"
}, {
token : "comment", // comment spanning whole line
merge : true,
regex : ".+"
}
]
};

View file

@ -42,11 +42,11 @@ var lang = require("pilot/lang");
var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;
var ScssHighlightRules = function() {
var properties = lang.arrayToMap( (function () {
var properties = lang.arrayToMap( (function () {
var browserPrefix = ("-webkit-|-moz-|-o-|-ms-|-svg-|-pie-|-khtml-").split("|");
var browserPrefix = ("-webkit-|-moz-|-o-|-ms-|-svg-|-pie-|-khtml-").split("|");
var prefixProperties = ("appearance|background-clip|background-inline-policy|background-origin|" +
"background-size|binding|border-bottom-colors|border-left-colors|" +
"border-right-colors|border-top-colors|border-end|border-end-color|" +
@ -97,20 +97,20 @@ var ScssHighlightRules = function() {
//All prefixProperties will get the browserPrefix in
//the begning by join the prefixProperties array with the value of browserPrefix
for (var i=0, ln=browserPrefix.length; i<ln; i++) {
Array.prototype.push.apply(
ret,
(( browserPrefix[i] + prefixProperties.join("|" + browserPrefix[i]) ).split("|"))
);
Array.prototype.push.apply(
ret,
(( browserPrefix[i] + prefixProperties.join("|" + browserPrefix[i]) ).split("|"))
);
}
//Add also prefixProperties and properties without any browser prefix
Array.prototype.push.apply(ret, prefixProperties);
Array.prototype.push.apply(ret, properties);
return ret;
})() );
return ret;
})() );
var functions = lang.arrayToMap(
@ -151,19 +151,19 @@ var ScssHighlightRules = function() {
);
var keywords = lang.arrayToMap(
("@mixin|@extend|@include|@import|@media|@debug|@warn|@if|@for|@each|@while|@else|@font-face|@-webkit-keyframes|if|and|!default|module|def|end|declare").split("|")
("@mixin|@extend|@include|@import|@media|@debug|@warn|@if|@for|@each|@while|@else|@font-face|@-webkit-keyframes|if|and|!default|module|def|end|declare").split("|")
)
var tags = lang.arrayToMap(
("a|abbr|acronym|address|applet|area|article|aside|audio|b|base|basefont|bdo|" +
"big|blockquote|body|br|button|canvas|caption|center|cite|code|col|colgroup|" +
"command|datalist|dd|del|details|dfn|dir|div|dl|dt|em|embed|fieldset|" +
"figcaption|figure|font|footer|form|frame|frameset|h1|h2|h3|h4|h5|h6|head|" +
"header|hgroup|hr|html|i|iframe|img|input|ins|keygen|kbd|label|legend|li|" +
"link|map|mark|menu|meta|meter|nav|noframes|noscript|object|ol|optgroup|" +
"option|output|p|param|pre|progress|q|rp|rt|ruby|s|samp|script|section|select|" +
"small|source|span|strike|strong|style|sub|summary|sup|table|tbody|td|" +
"textarea|tfoot|th|thead|time|title|tr|tt|u|ul|var|video|wbr|xmp").split("|")
("a|abbr|acronym|address|applet|area|article|aside|audio|b|base|basefont|bdo|" +
"big|blockquote|body|br|button|canvas|caption|center|cite|code|col|colgroup|" +
"command|datalist|dd|del|details|dfn|dir|div|dl|dt|em|embed|fieldset|" +
"figcaption|figure|font|footer|form|frame|frameset|h1|h2|h3|h4|h5|h6|head|" +
"header|hgroup|hr|html|i|iframe|img|input|ins|keygen|kbd|label|legend|li|" +
"link|map|mark|menu|meta|meter|nav|noframes|noscript|object|ol|optgroup|" +
"option|output|p|param|pre|progress|q|rp|rt|ruby|s|samp|script|section|select|" +
"small|source|span|strike|strong|style|sub|summary|sup|table|tbody|td|" +
"textarea|tfoot|th|thead|time|title|tr|tt|u|ul|var|video|wbr|xmp").split("|")
);
// regexp must not have capturing parentheses. Use (?:) instead.
@ -197,6 +197,7 @@ var ScssHighlightRules = function() {
},
{
token : "comment", // multi line comment
merge : true,
regex : "\\/\\*",
next : "comment"
}, {
@ -204,6 +205,7 @@ var ScssHighlightRules = function() {
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
}, {
token : "string", // multi line string start
merge : true,
regex : '["].*\\\\$',
next : "qqstring"
}, {
@ -211,6 +213,7 @@ var ScssHighlightRules = function() {
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
}, {
token : "string", // multi line string start
merge : true,
regex : "['].*\\\\$",
next : "qstring"
}, {
@ -272,8 +275,8 @@ var ScssHighlightRules = function() {
regex : numRe
}, {
token : function(value) {
if (properties.hasOwnProperty(value.toLowerCase()))
return "support.type";
if (properties.hasOwnProperty(value.toLowerCase()))
return "support.type";
if (keywords.hasOwnProperty(value))
return "keyword";
else if (constants.hasOwnProperty(value))
@ -283,9 +286,9 @@ var ScssHighlightRules = function() {
else if (colors.hasOwnProperty(value.toLowerCase()))
return "support.constant.color";
else if (tags.hasOwnProperty(value.toLowerCase()))
return "variable.language";
return "variable.language";
else
return "text";
return "text";
},
regex : "\\-?[@a-zA-Z_][@a-zA-Z0-9_\\-]*"
}, {
@ -324,6 +327,7 @@ var ScssHighlightRules = function() {
next : "start"
}, {
token : "comment", // comment spanning whole line
merge : true,
regex : ".+"
}
],
@ -334,6 +338,7 @@ var ScssHighlightRules = function() {
next : "start"
}, {
token : "string",
merge : true,
regex : '.+'
}
],
@ -344,11 +349,11 @@ var ScssHighlightRules = function() {
next : "start"
}, {
token : "string",
merge : true,
regex : '.+'
}
]
};
};
oop.inherits(ScssHighlightRules, TextHighlightRules);

View file

@ -43,6 +43,7 @@ define(function(require, exports, module) {
var Tokenizer = require("ace/tokenizer").Tokenizer;
var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;
var Behaviour = require("ace/mode/behaviour").Behaviour;
var unicode = require("ace/unicode");
var Mode = function() {
this.$tokenizer = new Tokenizer(new TextHighlightRules().getRules());
@ -51,6 +52,20 @@ var Mode = function() {
(function() {
this.tokenRe = new RegExp("^["
+ unicode.packages.L
+ unicode.packages.Mn + unicode.packages.Mc
+ unicode.packages.Nd
+ unicode.packages.Pc + "\\$_]+", "g"
);
this.nonTokenRe = new RegExp("^(?:[^"
+ unicode.packages.L
+ unicode.packages.Mn + unicode.packages.Mc
+ unicode.packages.Nd
+ unicode.packages.Pc + "\\$_]|\s])+", "g"
);
this.getTokenizer = function() {
return this.$tokenizer;
};
@ -125,7 +140,7 @@ var Mode = function() {
var ranges = editor.$search.findAll(session);
ranges.forEach(function(range) {
if (!range.contains(cursor.row, cursor.column)) {
var marker = session.addMarker(range, "ace_selected_word");
var marker = session.addMarker(range, "ace_selected_word", "text");
session.$selectionOccurrences.push(marker);
}
});

View file

@ -45,13 +45,13 @@ var TextHighlightRules = function() {
// regexps are ordered -> the first match is used
this.$rules = {
"start" : [ {
"start" : [{
token : "empty_line",
regex : '^$'
}, {
token : "text",
regex : ".+"
} ]
}]
};
};

View file

@ -40,23 +40,7 @@ define(function(require, exports, module) {
var oop = require("pilot/oop");
var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;
var TextileHighlightRules = function()
{
/*
var phraseModifiers = lang.arrayToMap(
("_|*|__|**|??|-|+|^|%|@").split("|")
);
var blockModifiers = lang.arrayToMap(
("h1|h2|h3|h4|h5|h6|bq|p|bc|pre").split("|")
);
*/
/*
var punctuation = lang.arrayToMap(
("-|--|(tm)|(r)|(c)").split("|")
);
*/
var TextileHighlightRules = function() {
this.$rules = {
"start" : [
{
@ -77,13 +61,13 @@ var TextileHighlightRules = function()
{
token : "keyword",
regex : "\\. ",
next : "start",
next : "start"
},
{
token : "keyword",
regex : "\\(",
next : "blocktagproperties"
},
}
],
"blocktagproperties" : [
{
@ -98,7 +82,7 @@ var TextileHighlightRules = function()
{
token : "keyword",
regex : "#"
},
}
]
};
};

View file

@ -46,7 +46,7 @@ var XmlHighlightRules = function() {
// regexps are ordered -> the first match is used
this.$rules = {
start : [ {
start : [{
token : "text",
regex : "<\\!\\[CDATA\\[",
next : "cdata"
@ -55,6 +55,7 @@ var XmlHighlightRules = function() {
regex : "<\\?.*?\\?>"
}, {
token : "comment",
merge : true,
regex : "<\\!--",
next : "comment"
}, {
@ -67,9 +68,9 @@ var XmlHighlightRules = function() {
}, {
token : "text",
regex : "[^<]+"
} ],
}],
tag : [ {
tag : [{
token : "text",
regex : ">",
next : "start"
@ -84,6 +85,7 @@ var XmlHighlightRules = function() {
regex : '".*?"'
}, {
token : "string", // multi line string start
merge : true,
regex : '["].*$',
next : "qqstring"
}, {
@ -91,6 +93,7 @@ var XmlHighlightRules = function() {
regex : "'.*?'"
}, {
token : "string", // multi line string start
merge : true,
regex : "['].*$",
next : "qstring"
}],
@ -101,6 +104,7 @@ var XmlHighlightRules = function() {
next : "tag"
}, {
token : "string",
merge : true,
regex : '.+'
}],
@ -110,10 +114,11 @@ var XmlHighlightRules = function() {
next : "tag"
}, {
token : "string",
merge : true,
regex : '.+'
}],
cdata : [ {
cdata : [{
token : "text",
regex : "\\]\\]>",
next : "start"
@ -123,16 +128,17 @@ var XmlHighlightRules = function() {
}, {
token : "text",
regex : "(?:[^\\]]|\\](?!\\]>))+"
} ],
}],
comment : [ {
comment : [{
token : "comment",
regex : ".*?-->",
next : "start"
}, {
token : "comment",
merge : true,
regex : ".+"
} ]
}]
};
};

View file

@ -45,12 +45,14 @@ var XmlMode = require("ace/mode/xml").Mode;
var assert = require("ace/test/assertions");
module.exports = {
name: "XML Tokenizer",
setUp : function() {
this.tokenizer = new XmlMode().getTokenizer();
},
"test: tokenize1" : function() {
var line = "<Juhu>//Juhu Kinners</Kinners>";
var tokens = this.tokenizer.getLineTokens(line, "start").tokens;

View file

@ -41,6 +41,7 @@ define(function(require, exports, module) {
var event = require("pilot/event");
var dom = require("pilot/dom");
var BrowserFocus = require("pilot/browser_focus").BrowserFocus;
var STATE_UNKNOWN = 0;
var STATE_SELECT = 1;
@ -51,6 +52,8 @@ var DRAG_OFFSET = 5; // pixels
var MouseHandler = function(editor) {
this.editor = editor;
this.browserFocus = new BrowserFocus();
event.addListener(editor.container, "mousedown", function(e) {
editor.focus();
return event.preventDefault(e);
@ -91,6 +94,15 @@ var MouseHandler = function(editor) {
};
this.onMouseDown = function(e) {
// if this click caused the editor to be focused ignore the click
// for selection and cursor placement
if (
!this.browserFocus.isFocused()
|| new Date().getTime() - this.browserFocus.lastFocus < 20
|| !this.editor.isFocused()
)
return;
var pageX = event.getDocumentX(e);
var pageY = event.getDocumentY(e);
var pos = this.$getEventPosition(e);

View file

@ -52,324 +52,628 @@
define(function(require, exports, module) {
exports.options = {
version: 185,
};
(function() {
exports.hostGlobal = this
})();
var tokens = [
// End of source.
"END",
// Operators and punctuators. Some pair-wise order matters, e.g. (+, -)
// and (UNARY_PLUS, UNARY_MINUS).
"\n", ";",
",",
"=",
"?", ":", "CONDITIONAL",
"||",
"&&",
"|",
"^",
"&",
"==", "!=", "===", "!==",
"<", "<=", ">=", ">",
"<<", ">>", ">>>",
"+", "-",
"*", "/", "%",
"!", "~", "UNARY_PLUS", "UNARY_MINUS",
"++", "--",
".",
"[", "]",
"{", "}",
"(", ")",
// Nonterminal tree node type codes.
"SCRIPT", "BLOCK", "LABEL", "FOR_IN", "CALL", "NEW_WITH_ARGS", "INDEX",
"ARRAY_INIT", "OBJECT_INIT", "PROPERTY_INIT", "GETTER", "SETTER",
"GROUP", "LIST", "LET_BLOCK", "ARRAY_COMP", "GENERATOR", "COMP_TAIL",
// Terminals.
"IDENTIFIER", "NUMBER", "STRING", "REGEXP",
// Keywords.
"break",
"case", "catch", "const", "continue",
"debugger", "default", "delete", "do",
"else",
"false", "finally", "for", "function",
"if", "in", "instanceof",
"let",
"new", "null",
"return",
"switch",
"this", "throw", "true", "try", "typeof",
"var", "void",
"yield",
"while", "with",
];
var statementStartTokens = [
"break",
"const", "continue",
"debugger", "do",
"for",
"if",
"return",
"switch",
"throw", "try",
"var",
"yield",
"while", "with",
];
// Operator and punctuator mapping from token to tree node type name.
// NB: because the lexer doesn't backtrack, all token prefixes must themselves
// be valid tokens (e.g. !== is acceptable because its prefixes are the valid
// tokens != and !).
var opTypeNames = {
'\n': "NEWLINE",
';': "SEMICOLON",
',': "COMMA",
'?': "HOOK",
':': "COLON",
'||': "OR",
'&&': "AND",
'|': "BITWISE_OR",
'^': "BITWISE_XOR",
'&': "BITWISE_AND",
'===': "STRICT_EQ",
'==': "EQ",
'=': "ASSIGN",
'!==': "STRICT_NE",
'!=': "NE",
'<<': "LSH",
'<=': "LE",
'<': "LT",
'>>>': "URSH",
'>>': "RSH",
'>=': "GE",
'>': "GT",
'++': "INCREMENT",
'--': "DECREMENT",
'+': "PLUS",
'-': "MINUS",
'*': "MUL",
'/': "DIV",
'%': "MOD",
'!': "NOT",
'~': "BITWISE_NOT",
'.': "DOT",
'[': "LEFT_BRACKET",
']': "RIGHT_BRACKET",
'{': "LEFT_CURLY",
'}': "RIGHT_CURLY",
'(': "LEFT_PAREN",
')': "RIGHT_PAREN"
};
// Hash of keyword identifier to tokens index. NB: we must null __proto__ to
// avoid toString, etc. namespace pollution.
var keywords = {__proto__: null};
// Define const END, etc., based on the token names. Also map name to index.
var tokenIds = {};
// Building up a string to be eval'd in different contexts.
var consts = "const ";
for (var i = 0, j = tokens.length; i < j; i++) {
if (i > 0)
consts += ", ";
var t = tokens[i];
var name;
if (/^[a-z]/.test(t)) {
name = t.toUpperCase();
keywords[t] = i;
} else {
name = (/^\W/.test(t) ? opTypeNames[t] : t);
}
consts += name + " = " + i;
tokenIds[name] = i;
tokens[t] = i;
}
consts += ";";
var isStatementStartCode = {__proto__: null};
for (i = 0, j = statementStartTokens.length; i < j; i++)
isStatementStartCode[keywords[statementStartTokens[i]]] = true;
// Map assignment operators to their indexes in the tokens array.
var assignOps = ['|', '^', '&', '<<', '>>', '>>>', '+', '-', '*', '/', '%'];
for (i = 0, j = assignOps.length; i < j; i++) {
t = assignOps[i];
assignOps[t] = tokens[t];
}
function defineGetter(obj, prop, fn, dontDelete, dontEnum) {
Object.defineProperty(obj, prop,
{ get: fn, configurable: !dontDelete, enumerable: !dontEnum });
}
function defineProperty(obj, prop, val, dontDelete, readOnly, dontEnum) {
Object.defineProperty(obj, prop,
{ value: val, writable: !readOnly, configurable: !dontDelete,
enumerable: !dontEnum });
}
// Returns true if fn is a native function. (Note: SpiderMonkey specific.)
function isNativeCode(fn) {
// Relies on the toString method to identify native code.
return ((typeof fn) === "function") && fn.toString().match(/\[native code\]/);
}
function getPropertyDescriptor(obj, name) {
while (obj) {
if (({}).hasOwnProperty.call(obj, name))
return Object.getOwnPropertyDescriptor(obj, name);
obj = Object.getPrototypeOf(obj);
}
}
function getOwnProperties(obj) {
var map = {};
for (var name in Object.getOwnPropertyNames(obj))
map[name] = Object.getOwnPropertyDescriptor(obj, name);
return map;
}
function makePassthruHandler(obj) {
// Handler copied from
// http://wiki.ecmascript.org/doku.php?id=harmony:proxies&s=proxy%20object#examplea_no-op_forwarding_proxy
return {
getOwnPropertyDescriptor: function(name) {
var desc = Object.getOwnPropertyDescriptor(obj, name);
// a trapping proxy's properties must always be configurable
desc.configurable = true;
return desc;
var narcissus = {
options: {
version: 185,
// Global variables to hide from the interpreter
hiddenHostGlobals: { Narcissus: true },
// Desugar SpiderMonkey language extensions?
desugarExtensions: false
},
getPropertyDescriptor: function(name) {
var desc = getPropertyDescriptor(obj, name);
// a trapping proxy's properties must always be configurable
desc.configurable = true;
return desc;
},
getOwnPropertyNames: function() {
return Object.getOwnPropertyNames(obj);
},
defineProperty: function(name, desc) {
Object.defineProperty(obj, name, desc);
},
"delete": function(name) { return delete obj[name]; },
fix: function() {
if (Object.isFrozen(obj)) {
return getOwnProperties(obj);
hostSupportsEvalConst: (function() {
try {
return eval("(function(s) { eval(s); return x })('const x = true;')");
} catch (e) {
return false;
}
// As long as obj is not frozen, the proxy won't allow itself to be fixed.
return undefined; // will cause a TypeError to be thrown
},
has: function(name) { return name in obj; },
hasOwn: function(name) { return ({}).hasOwnProperty.call(obj, name); },
get: function(receiver, name) { return obj[name]; },
// bad behavior when set fails in non-strict mode
set: function(receiver, name, val) { obj[name] = val; return true; },
enumerate: function() {
var result = [];
for (name in obj) { result.push(name); };
return result;
},
keys: function() { return Object.keys(obj); }
})(),
hostGlobal: this
};
}
Narcissus = narcissus;
// default function used when looking for a property in the global object
function noPropFound() { return undefined; }
var tokens = [
// End of source.
"END",
var hasOwnProperty = ({}).hasOwnProperty;
// Operators and punctuators. Some pair-wise order matters, e.g. (+, -)
// and (UNARY_PLUS, UNARY_MINUS).
"\n", ";",
",",
"=",
"?", ":", "CONDITIONAL",
"||",
"&&",
"|",
"^",
"&",
"==", "!=", "===", "!==",
"<", "<=", ">=", ">",
"<<", ">>", ">>>",
"+", "-",
"*", "/", "%",
"!", "~", "UNARY_PLUS", "UNARY_MINUS",
"++", "--",
".",
"[", "]",
"{", "}",
"(", ")",
function StringMap() {
this.table = Object.create(null, {});
this.size = 0;
}
// Nonterminal tree node type codes.
"SCRIPT", "BLOCK", "LABEL", "FOR_IN", "CALL", "NEW_WITH_ARGS", "INDEX",
"ARRAY_INIT", "OBJECT_INIT", "PROPERTY_INIT", "GETTER", "SETTER",
"GROUP", "LIST", "LET_BLOCK", "ARRAY_COMP", "GENERATOR", "COMP_TAIL",
StringMap.prototype = {
has: function(x) { return hasOwnProperty.call(this.table, x); },
set: function(x, v) {
if (!hasOwnProperty.call(this.table, x))
this.size++;
this.table[x] = v;
},
get: function(x) { return this.table[x]; },
getDef: function(x, thunk) {
if (!hasOwnProperty.call(this.table, x)) {
this.size++;
this.table[x] = thunk();
// Terminals.
"IDENTIFIER", "NUMBER", "STRING", "REGEXP",
// Keywords.
"break",
"case", "catch", "const", "continue",
"debugger", "default", "delete", "do",
"else", "export",
"false", "finally", "for", "function",
"if", "import", "in", "instanceof",
"let", "module",
"new", "null",
"return",
"switch",
"this", "throw", "true", "try", "typeof",
"var", "void",
"yield",
"while", "with",
];
var statementStartTokens = [
"break",
"const", "continue",
"debugger", "do",
"for",
"if",
"return",
"switch",
"throw", "try",
"var",
"yield",
"while", "with",
];
// Whitespace characters (see ECMA-262 7.2)
var whitespaceChars = [
// normal whitespace:
"\u0009", "\u000B", "\u000C", "\u0020", "\u00A0", "\uFEFF",
// high-Unicode whitespace:
"\u1680", "\u180E",
"\u2000", "\u2001", "\u2002", "\u2003", "\u2004", "\u2005", "\u2006",
"\u2007", "\u2008", "\u2009", "\u200A",
"\u202F", "\u205F", "\u3000"
];
var whitespace = {};
for (var i = 0; i < whitespaceChars.length; i++) {
whitespace[whitespaceChars[i]] = true;
}
// Operator and punctuator mapping from token to tree node type name.
// NB: because the lexer doesn't backtrack, all token prefixes must themselves
// be valid tokens (e.g. !== is acceptable because its prefixes are the valid
// tokens != and !).
var opTypeNames = {
'\n': "NEWLINE",
';': "SEMICOLON",
',': "COMMA",
'?': "HOOK",
':': "COLON",
'||': "OR",
'&&': "AND",
'|': "BITWISE_OR",
'^': "BITWISE_XOR",
'&': "BITWISE_AND",
'===': "STRICT_EQ",
'==': "EQ",
'=': "ASSIGN",
'!==': "STRICT_NE",
'!=': "NE",
'<<': "LSH",
'<=': "LE",
'<': "LT",
'>>>': "URSH",
'>>': "RSH",
'>=': "GE",
'>': "GT",
'++': "INCREMENT",
'--': "DECREMENT",
'+': "PLUS",
'-': "MINUS",
'*': "MUL",
'/': "DIV",
'%': "MOD",
'!': "NOT",
'~': "BITWISE_NOT",
'.': "DOT",
'[': "LEFT_BRACKET",
']': "RIGHT_BRACKET",
'{': "LEFT_CURLY",
'}': "RIGHT_CURLY",
'(': "LEFT_PAREN",
')': "RIGHT_PAREN"
};
// Hash of keyword identifier to tokens index. NB: we must null __proto__ to
// avoid toString, etc. namespace pollution.
var keywords = {__proto__: null};
// Define const END, etc., based on the token names. Also map name to index.
var tokenIds = {};
// Building up a string to be eval'd in different contexts.
var consts = Narcissus.hostSupportsEvalConst ? "const " : "var ";
for (var i = 0, j = tokens.length; i < j; i++) {
if (i > 0)
consts += ", ";
var t = tokens[i];
var name;
if (/^[a-z]/.test(t)) {
name = t.toUpperCase();
keywords[t] = i;
} else {
name = (/^\W/.test(t) ? opTypeNames[t] : t);
}
return this.table[x];
},
forEach: function(f) {
var table = this.table;
for (var key in table)
f.call(this, key, table[key]);
},
toString: function() { return "[object StringMap]" }
};
consts += name + " = " + i;
tokenIds[name] = i;
tokens[t] = i;
}
consts += ";";
// non-destructive stack
function Stack(elts) {
this.elts = elts || null;
}
var isStatementStartCode = {__proto__: null};
for (i = 0, j = statementStartTokens.length; i < j; i++)
isStatementStartCode[keywords[statementStartTokens[i]]] = true;
Stack.prototype = {
push: function(x) {
return new Stack({ top: x, rest: this.elts });
},
top: function() {
if (!this.elts)
throw new Error("empty stack");
return this.elts.top;
},
isEmpty: function() {
return this.top === null;
},
find: function(test) {
for (var elts = this.elts; elts; elts = elts.rest) {
if (test(elts.top))
return elts.top;
}
return null;
},
has: function(x) {
return Boolean(this.find(function(elt) { return elt === x }));
},
forEach: function(f) {
for (var elts = this.elts; elts; elts = elts.rest) {
f(elts.top);
// Map assignment operators to their indexes in the tokens array.
var assignOps = ['|', '^', '&', '<<', '>>', '>>>', '+', '-', '*', '/', '%'];
for (i = 0, j = assignOps.length; i < j; i++) {
t = assignOps[i];
assignOps[t] = tokens[t];
}
function defineGetter(obj, prop, fn, dontDelete, dontEnum) {
Object.defineProperty(obj, prop,
{ get: fn, configurable: !dontDelete, enumerable: !dontEnum });
}
function defineGetterSetter(obj, prop, getter, setter, dontDelete, dontEnum) {
Object.defineProperty(obj, prop, {
get: getter,
set: setter,
configurable: !dontDelete,
enumerable: !dontEnum
});
}
function defineMemoGetter(obj, prop, fn, dontDelete, dontEnum) {
Object.defineProperty(obj, prop, {
get: function() {
var val = fn();
defineProperty(obj, prop, val, dontDelete, true, dontEnum);
return val;
},
configurable: true,
enumerable: !dontEnum
});
}
function defineProperty(obj, prop, val, dontDelete, readOnly, dontEnum) {
Object.defineProperty(obj, prop,
{ value: val, writable: !readOnly, configurable: !dontDelete,
enumerable: !dontEnum });
}
// Returns true if fn is a native function. (Note: SpiderMonkey specific.)
function isNativeCode(fn) {
// Relies on the toString method to identify native code.
return ((typeof fn) === "function") && fn.toString().match(/\[native code\]/);
}
function getPropertyDescriptor(obj, name) {
while (obj) {
if (({}).hasOwnProperty.call(obj, name))
return Object.getOwnPropertyDescriptor(obj, name);
obj = Object.getPrototypeOf(obj);
}
}
};
exports.tokens = tokens;
exports.opTypeNames = opTypeNames;
exports.keywords = keywords;
exports.isStatementStartCode = isStatementStartCode;
exports.tokenIds = tokenIds;
exports.consts = consts;
exports.assignOps = assignOps;
exports.defineGetter = defineGetter;
exports.defineProperty = defineProperty;
exports.isNativeCode = isNativeCode;
exports.makePassthruHandler = makePassthruHandler;
exports.noPropFound = noPropFound;
exports.StringMap = StringMap;
exports.Stack = Stack;
function getPropertyNames(obj) {
var table = Object.create(null, {});
while (obj) {
var names = Object.getOwnPropertyNames(obj);
for (var i = 0, n = names.length; i < n; i++)
table[names[i]] = true;
obj = Object.getPrototypeOf(obj);
}
return Object.keys(table);
}
function getOwnProperties(obj) {
var map = {};
for (var name in Object.getOwnPropertyNames(obj))
map[name] = Object.getOwnPropertyDescriptor(obj, name);
return map;
}
function blacklistHandler(target, blacklist) {
var mask = Object.create(null, {});
var redirect = StringMap.create(blacklist).mapObject(function(name) { return mask; });
return mixinHandler(redirect, target);
}
function whitelistHandler(target, whitelist) {
var catchall = Object.create(null, {});
var redirect = StringMap.create(whitelist).mapObject(function(name) { return target; });
return mixinHandler(redirect, catchall);
}
function mirrorHandler(target, writable) {
var handler = makePassthruHandler(target);
var defineProperty = handler.defineProperty;
handler.defineProperty = function(name, desc) {
if (!desc.enumerable)
throw new Error("mirror property must be enumerable");
if (!desc.configurable)
throw new Error("mirror property must be configurable");
if (desc.writable !== writable)
throw new Error("mirror property must " + (writable ? "" : "not ") + "be writable");
defineProperty(name, desc);
};
handler.fix = function() { };
handler.getOwnPropertyDescriptor = handler.getPropertyDescriptor;
handler.getOwnPropertyNames = getPropertyNames.bind(handler, target);
handler.keys = handler.enumerate;
handler["delete"] = function() { return false; };
handler.hasOwn = handler.has;
return handler;
}
/*
* Mixin proxies break the single-inheritance model of prototypes, so
* the handler treats all properties as own-properties:
*
* X
* |
* +------------+------------+
* | O |
* | | |
* | O O O |
* | | | | |
* | O O O O |
* | | | | | |
* | O O O O O |
* | | | | | | |
* +-(*)--(w)--(x)--(y)--(z)-+
*/
function mixinHandler(redirect, catchall) {
function targetFor(name) {
return hasOwn(redirect, name) ? redirect[name] : catchall;
}
function getMuxPropertyDescriptor(name) {
var desc = getPropertyDescriptor(targetFor(name), name);
if (desc)
desc.configurable = true;
return desc;
}
function getMuxPropertyNames() {
var names1 = Object.getOwnPropertyNames(redirect).filter(function(name) {
return name in redirect[name];
});
var names2 = getPropertyNames(catchall).filter(function(name) {
return !hasOwn(redirect, name);
});
return names1.concat(names2);
}
function enumerateMux() {
var result = Object.getOwnPropertyNames(redirect).filter(function(name) {
return name in redirect[name];
});
for (name in catchall) {
if (!hasOwn(redirect, name))
result.push(name);
};
return result;
}
function hasMux(name) {
return name in targetFor(name);
}
return {
getOwnPropertyDescriptor: getMuxPropertyDescriptor,
getPropertyDescriptor: getMuxPropertyDescriptor,
getOwnPropertyNames: getMuxPropertyNames,
defineProperty: function(name, desc) {
Object.defineProperty(targetFor(name), name, desc);
},
"delete": function(name) {
var target = targetFor(name);
return delete target[name];
},
// FIXME: ha ha ha
fix: function() { },
has: hasMux,
hasOwn: hasMux,
get: function(receiver, name) {
var target = targetFor(name);
return target[name];
},
set: function(receiver, name, val) {
var target = targetFor(name);
target[name] = val;
return true;
},
enumerate: enumerateMux,
keys: enumerateMux
};
}
function makePassthruHandler(obj) {
// Handler copied from
// http://wiki.ecmascript.org/doku.php?id=harmony:proxies&s=proxy%20object#examplea_no-op_forwarding_proxy
return {
getOwnPropertyDescriptor: function(name) {
var desc = Object.getOwnPropertyDescriptor(obj, name);
// a trapping proxy's properties must always be configurable
desc.configurable = true;
return desc;
},
getPropertyDescriptor: function(name) {
var desc = getPropertyDescriptor(obj, name);
// a trapping proxy's properties must always be configurable
desc.configurable = true;
return desc;
},
getOwnPropertyNames: function() {
return Object.getOwnPropertyNames(obj);
},
defineProperty: function(name, desc) {
Object.defineProperty(obj, name, desc);
},
"delete": function(name) { return delete obj[name]; },
fix: function() {
if (Object.isFrozen(obj)) {
return getOwnProperties(obj);
}
// As long as obj is not frozen, the proxy won't allow itself to be fixed.
return undefined; // will cause a TypeError to be thrown
},
has: function(name) { return name in obj; },
hasOwn: function(name) { return ({}).hasOwnProperty.call(obj, name); },
get: function(receiver, name) { return obj[name]; },
// bad behavior when set fails in non-strict mode
set: function(receiver, name, val) { obj[name] = val; return true; },
enumerate: function() {
var result = [];
for (name in obj) { result.push(name); };
return result;
},
keys: function() { return Object.keys(obj); }
};
}
var hasOwnProperty = ({}).hasOwnProperty;
function hasOwn(obj, name) {
return hasOwnProperty.call(obj, name);
}
function StringMap(table, size) {
this.table = table || Object.create(null, {});
this.size = size || 0;
}
StringMap.create = function(table) {
var init = Object.create(null, {});
var size = 0;
var names = Object.getOwnPropertyNames(table);
for (var i = 0, n = names.length; i < n; i++) {
var name = names[i];
init[name] = table[name];
size++;
}
return new StringMap(init, size);
};
StringMap.prototype = {
has: function(x) { return hasOwnProperty.call(this.table, x); },
set: function(x, v) {
if (!hasOwnProperty.call(this.table, x))
this.size++;
this.table[x] = v;
},
get: function(x) { return this.table[x]; },
getDef: function(x, thunk) {
if (!hasOwnProperty.call(this.table, x)) {
this.size++;
this.table[x] = thunk();
}
return this.table[x];
},
forEach: function(f) {
var table = this.table;
for (var key in table)
f.call(this, key, table[key]);
},
map: function(f) {
var table1 = this.table;
var table2 = Object.create(null, {});
this.forEach(function(key, val) {
table2[key] = f.call(this, val, key);
});
return new StringMap(table2, this.size);
},
mapObject: function(f) {
var table1 = this.table;
var table2 = Object.create(null, {});
this.forEach(function(key, val) {
table2[key] = f.call(this, val, key);
});
return table2;
},
toObject: function() {
return this.mapObject(function(val) { return val; });
},
choose: function() {
return Object.getOwnPropertyNames(this.table)[0];
},
remove: function(x) {
if (hasOwnProperty.call(this.table, x)) {
this.size--;
delete this.table[x];
}
},
copy: function() {
var table = Object.create(null, {});
for (var key in this.table)
table[key] = this.table[key];
return new StringMap(table, this.size);
},
toString: function() { return "[object StringMap]" }
};
// an object-key table with poor asymptotics (replace with WeakMap when possible)
function ObjectMap(array) {
this.array = array || [];
}
function searchMap(map, key, found, notFound) {
var a = map.array;
for (var i = 0, n = a.length; i < n; i++) {
var pair = a[i];
if (pair.key === key)
return found(pair, i);
}
return notFound();
}
ObjectMap.prototype = {
has: function(x) {
return searchMap(this, x, function() { return true }, function() { return false });
},
set: function(x, v) {
var a = this.array;
searchMap(this, x,
function(pair) { pair.value = v },
function() { a.push({ key: x, value: v }) });
},
get: function(x) {
return searchMap(this, x,
function(pair) { return pair.value },
function() { return null });
},
getDef: function(x, thunk) {
var a = this.array;
return searchMap(this, x,
function(pair) { return pair.value },
function() {
var v = thunk();
a.push({ key: x, value: v });
return v;
});
},
forEach: function(f) {
var a = this.array;
for (var i = 0, n = a.length; i < n; i++) {
var pair = a[i];
f.call(this, pair.key, pair.value);
}
},
choose: function() {
return this.array[0].key;
},
get size() {
return this.array.length;
},
remove: function(x) {
var a = this.array;
searchMap(this, x,
function(pair, i) { a.splice(i, 1) },
function() { });
},
copy: function() {
return new ObjectMap(this.array.map(function(pair) {
return { key: pair.key, value: pair.value }
}));
},
clear: function() {
this.array = [];
},
toString: function() { return "[object ObjectMap]" }
};
// non-destructive stack
function Stack(elts) {
this.elts = elts || null;
}
Stack.prototype = {
push: function(x) {
return new Stack({ top: x, rest: this.elts });
},
top: function() {
if (!this.elts)
throw new Error("empty stack");
return this.elts.top;
},
isEmpty: function() {
return this.top === null;
},
find: function(test) {
for (var elts = this.elts; elts; elts = elts.rest) {
if (test(elts.top))
return elts.top;
}
return null;
},
has: function(x) {
return Boolean(this.find(function(elt) { return elt === x }));
},
forEach: function(f) {
for (var elts = this.elts; elts; elts = elts.rest) {
f(elts.top);
}
}
};
module.exports = {
tokens: tokens,
whitespace: whitespace,
opTypeNames: opTypeNames,
keywords: keywords,
isStatementStartCode: isStatementStartCode,
tokenIds: tokenIds,
consts: consts,
assignOps: assignOps,
defineGetter: defineGetter,
defineGetterSetter: defineGetterSetter,
defineMemoGetter: defineMemoGetter,
defineProperty: defineProperty,
isNativeCode: isNativeCode,
mirrorHandler: mirrorHandler,
mixinHandler: mixinHandler,
whitelistHandler: whitelistHandler,
blacklistHandler: blacklistHandler,
makePassthruHandler: makePassthruHandler,
StringMap: StringMap,
ObjectMap: ObjectMap,
Stack: Stack
};
});

View file

@ -47,416 +47,503 @@
* Lexical scanner.
*/
define(function(require, exports, module) {
define(function(require, exports, module) {
var definitions = require("ace/narcissus/jsdefs");
var definitions = require("ace/narcissus/jsdefs");
// Set constants in the local scope.
eval(definitions.consts);
// Set constants in the local scope.
eval(definitions.consts);
// Build up a trie of operator tokens.
var opTokens = {};
for (var op in definitions.opTypeNames) {
if (op === '\n' || op === '.')
continue;
// Banned keywords by language version
const blackLists = { 160: {}, 185: {}, harmony: {} };
blackLists[160][LET] = true;
blackLists[160][MODULE] = true;
blackLists[160][YIELD] = true;
blackLists[185][MODULE] = true;
var node = opTokens;
for (var i = 0; i < op.length; i++) {
var ch = op[i];
if (!(ch in node))
node[ch] = {};
node = node[ch];
node.op = op;
// Build up a trie of operator tokens.
var opTokens = {};
for (var op in definitions.opTypeNames) {
if (op === '\n' || op === '.')
continue;
var node = opTokens;
for (var i = 0; i < op.length; i++) {
var ch = op[i];
if (!(ch in node))
node[ch] = {};
node = node[ch];
node.op = op;
}
}
}
/*
* Tokenizer :: (source, filename, line number) -> Tokenizer
*/
function Tokenizer(s, f, l) {
this.cursor = 0;
this.source = String(s);
this.tokens = [];
this.tokenIndex = 0;
this.lookahead = 0;
this.scanNewlines = false;
this.unexpectedEOF = false;
this.filename = f || "";
this.lineno = l || 1;
}
Tokenizer.prototype = {
get done() {
// We need to set scanOperand to true here because the first thing
// might be a regexp.
return this.peek(true) === END;
},
get token() {
return this.tokens[this.tokenIndex];
},
match: function (tt, scanOperand) {
return this.get(scanOperand) === tt || this.unget();
},
mustMatch: function (tt) {
if (!this.match(tt)) {
throw this.newSyntaxError("Missing " +
definitions.tokens[tt].toLowerCase());
}
return this.token;
},
peek: function (scanOperand) {
var tt, next;
if (this.lookahead) {
next = this.tokens[(this.tokenIndex + this.lookahead) & 3];
tt = (this.scanNewlines && next.lineno !== this.lineno)
? NEWLINE
: next.type;
} else {
tt = this.get(scanOperand);
this.unget();
}
return tt;
},
peekOnSameLine: function (scanOperand) {
this.scanNewlines = true;
var tt = this.peek(scanOperand);
/*
* Tokenizer :: (source, filename, line number) -> Tokenizer
*/
function Tokenizer(s, f, l) {
this.cursor = 0;
this.source = String(s);
this.tokens = [];
this.tokenIndex = 0;
this.lookahead = 0;
this.scanNewlines = false;
return tt;
},
this.unexpectedEOF = false;
this.filename = f || "";
this.lineno = l || 1;
this.blackList = blackLists[Narcissus.options.version];
this.blockComments = null;
}
// Eat comments and whitespace.
skip: function () {
var input = this.source;
for (;;) {
var ch = input[this.cursor++];
var next = input[this.cursor];
if (ch === '\n' && !this.scanNewlines) {
this.lineno++;
} else if (ch === '/' && next === '*') {
this.cursor++;
for (;;) {
ch = input[this.cursor++];
if (ch === undefined)
throw this.newSyntaxError("Unterminated comment");
Tokenizer.prototype = {
get done() {
// We need to set scanOperand to true here because the first thing
// might be a regexp.
return this.peek(true) === END;
},
if (ch === '*') {
get token() {
return this.tokens[this.tokenIndex];
},
match: function (tt, scanOperand) {
return this.get(scanOperand) === tt || this.unget();
},
mustMatch: function (tt) {
if (!this.match(tt)) {
throw this.newSyntaxError("Missing " +
definitions.tokens[tt].toLowerCase());
}
return this.token;
},
peek: function (scanOperand) {
var tt, next;
if (this.lookahead) {
next = this.tokens[(this.tokenIndex + this.lookahead) & 3];
tt = (this.scanNewlines && next.lineno !== this.lineno)
? NEWLINE
: next.type;
} else {
tt = this.get(scanOperand);
this.unget();
}
return tt;
},
peekOnSameLine: function (scanOperand) {
this.scanNewlines = true;
var tt = this.peek(scanOperand);
this.scanNewlines = false;
return tt;
},
lastBlockComment: function() {
var length = this.blockComments.length;
return length ? this.blockComments[length - 1] : null;
},
// Eat comments and whitespace.
skip: function () {
var input = this.source;
this.blockComments = [];
for (;;) {
var ch = input[this.cursor++];
var next = input[this.cursor];
// handle \r, \r\n and (always preferable) \n
if (ch === '\r') {
// if the next character is \n, we don't care about this at all
if (next === '\n') continue;
// otherwise, we want to consider this as a newline
ch = '\n';
}
if (ch === '\n' && !this.scanNewlines) {
this.lineno++;
} else if (ch === '/' && next === '*') {
var commentStart = ++this.cursor;
for (;;) {
ch = input[this.cursor++];
if (ch === undefined)
throw this.newSyntaxError("Unterminated comment");
if (ch === '*') {
next = input[this.cursor];
if (next === '/') {
var commentEnd = this.cursor - 1;
this.cursor++;
break;
}
} else if (ch === '\n') {
this.lineno++;
}
}
this.blockComments.push(input.substring(commentStart, commentEnd));
} else if (ch === '/' && next === '/') {
this.cursor++;
for (;;) {
ch = input[this.cursor++];
next = input[this.cursor];
if (next === '/') {
this.cursor++;
if (ch === undefined)
return;
if (ch === '\r') {
// check for \r\n
if (next !== '\n') ch = '\n';
}
if (ch === '\n') {
if (this.scanNewlines) {
this.cursor--;
} else {
this.lineno++;
}
break;
}
} else if (ch === '\n') {
this.lineno++;
}
} else if (!(ch in definitions.whitespace)) {
this.cursor--;
return;
}
} else if (ch === '/' && next === '/') {
}
},
// Lex the exponential part of a number, if present. Return true iff an
// exponential part was found.
lexExponent: function() {
var input = this.source;
var next = input[this.cursor];
if (next === 'e' || next === 'E') {
this.cursor++;
for (;;) {
ch = input[this.cursor++];
if (ch === '+' || ch === '-')
ch = input[this.cursor++];
if (ch === undefined)
return;
if (ch === '\n') {
this.lineno++;
break;
}
}
} else if (ch !== ' ' && ch !== '\t') {
this.cursor--;
return;
}
}
},
if (ch < '0' || ch > '9')
throw this.newSyntaxError("Missing exponent");
// Lex the exponential part of a number, if present. Return true iff an
// exponential part was found.
lexExponent: function() {
var input = this.source;
var next = input[this.cursor];
if (next === 'e' || next === 'E') {
this.cursor++;
ch = input[this.cursor++];
if (ch === '+' || ch === '-')
ch = input[this.cursor++];
if (ch < '0' || ch > '9')
throw this.newSyntaxError("Missing exponent");
do {
ch = input[this.cursor++];
} while (ch >= '0' && ch <= '9');
this.cursor--;
return true;
}
return false;
},
lexZeroNumber: function (ch) {
var token = this.token, input = this.source;
token.type = NUMBER;
ch = input[this.cursor++];
if (ch === '.') {
do {
ch = input[this.cursor++];
} while (ch >= '0' && ch <= '9');
this.cursor--;
this.lexExponent();
token.value = parseFloat(token.start, this.cursor);
} else if (ch === 'x' || ch === 'X') {
do {
ch = input[this.cursor++];
} while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') ||
(ch >= 'A' && ch <= 'F'));
this.cursor--;
token.value = parseInt(input.substring(token.start, this.cursor));
} else if (ch >= '0' && ch <= '7') {
do {
ch = input[this.cursor++];
} while (ch >= '0' && ch <= '7');
this.cursor--;
token.value = parseInt(input.substring(token.start, this.cursor));
} else {
this.cursor--;
this.lexExponent(); // 0E1, &c.
token.value = 0;
}
},
lexNumber: function (ch) {
var token = this.token, input = this.source;
token.type = NUMBER;
var floating = false;
do {
ch = input[this.cursor++];
if (ch === '.' && !floating) {
floating = true;
ch = input[this.cursor++];
}
} while (ch >= '0' && ch <= '9');
this.cursor--;
var exponent = this.lexExponent();
floating = floating || exponent;
var str = input.substring(token.start, this.cursor);
token.value = floating ? parseFloat(str) : parseInt(str);
},
lexDot: function (ch) {
var token = this.token, input = this.source;
var next = input[this.cursor];
if (next >= '0' && next <= '9') {
do {
ch = input[this.cursor++];
} while (ch >= '0' && ch <= '9');
this.cursor--;
this.lexExponent();
token.type = NUMBER;
token.value = parseFloat(token.start, this.cursor);
} else {
token.type = DOT;
token.assignOp = null;
token.value = '.';
}
},
lexString: function (ch) {
var token = this.token, input = this.source;
token.type = STRING;
var hasEscapes = false;
var delim = ch;
if (input.length <= this.cursor)
throw this.newSyntaxError("Unterminated string literal");
while ((ch = input[this.cursor++]) !== delim) {
if (this.cursor == input.length)
throw this.newSyntaxError("Unterminated string literal");
if (ch === '\\') {
hasEscapes = true;
if (++this.cursor == input.length)
throw this.newSyntaxError("Unterminated string literal");
}
}
token.value = hasEscapes
? eval(input.substring(token.start, this.cursor))
: input.substring(token.start + 1, this.cursor - 1);
},
lexRegExp: function (ch) {
var token = this.token, input = this.source;
token.type = REGEXP;
do {
ch = input[this.cursor++];
if (ch === '\\') {
this.cursor++;
} else if (ch === '[') {
do {
if (ch === undefined)
throw this.newSyntaxError("Unterminated character class");
if (ch === '\\')
this.cursor++;
ch = input[this.cursor++];
} while (ch !== ']');
} else if (ch === undefined) {
throw this.newSyntaxError("Unterminated regex");
} while (ch >= '0' && ch <= '9');
this.cursor--;
return true;
}
} while (ch !== '/');
do {
return false;
},
lexZeroNumber: function (ch) {
var token = this.token, input = this.source;
token.type = NUMBER;
ch = input[this.cursor++];
} while (ch >= 'a' && ch <= 'z');
if (ch === '.') {
do {
ch = input[this.cursor++];
} while (ch >= '0' && ch <= '9');
this.cursor--;
this.cursor--;
this.lexExponent();
token.value = parseFloat(token.start, this.cursor);
} else if (ch === 'x' || ch === 'X') {
do {
ch = input[this.cursor++];
} while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') ||
(ch >= 'A' && ch <= 'F'));
this.cursor--;
token.value = eval(input.substring(token.start, this.cursor));
},
token.value = parseInt(input.substring(token.start, this.cursor));
} else if (ch >= '0' && ch <= '7') {
do {
ch = input[this.cursor++];
} while (ch >= '0' && ch <= '7');
this.cursor--;
lexOp: function (ch) {
var token = this.token, input = this.source;
token.value = parseInt(input.substring(token.start, this.cursor));
} else {
this.cursor--;
this.lexExponent(); // 0E1, &c.
token.value = 0;
}
},
// A bit ugly, but it seems wasteful to write a trie lookup routine
// for only 3 characters...
var node = opTokens[ch];
var next = input[this.cursor];
if (next in node) {
node = node[next];
this.cursor++;
next = input[this.cursor];
lexNumber: function (ch) {
var token = this.token, input = this.source;
token.type = NUMBER;
var floating = false;
do {
ch = input[this.cursor++];
if (ch === '.' && !floating) {
floating = true;
ch = input[this.cursor++];
}
} while (ch >= '0' && ch <= '9');
this.cursor--;
var exponent = this.lexExponent();
floating = floating || exponent;
var str = input.substring(token.start, this.cursor);
token.value = floating ? parseFloat(str) : parseInt(str);
},
lexDot: function (ch) {
var token = this.token, input = this.source;
var next = input[this.cursor];
if (next >= '0' && next <= '9') {
do {
ch = input[this.cursor++];
} while (ch >= '0' && ch <= '9');
this.cursor--;
this.lexExponent();
token.type = NUMBER;
token.value = parseFloat(token.start, this.cursor);
} else {
token.type = DOT;
token.assignOp = null;
token.value = '.';
}
},
lexString: function (ch) {
var token = this.token, input = this.source;
token.type = STRING;
var hasEscapes = false;
var delim = ch;
if (input.length <= this.cursor)
throw this.newSyntaxError("Unterminated string literal");
while ((ch = input[this.cursor++]) !== delim) {
if (this.cursor == input.length)
throw this.newSyntaxError("Unterminated string literal");
if (ch === '\\') {
hasEscapes = true;
if (++this.cursor == input.length)
throw this.newSyntaxError("Unterminated string literal");
}
}
token.value = hasEscapes
? eval(input.substring(token.start, this.cursor))
: input.substring(token.start + 1, this.cursor - 1);
},
lexRegExp: function (ch) {
var token = this.token, input = this.source;
token.type = REGEXP;
do {
ch = input[this.cursor++];
if (ch === '\\') {
this.cursor++;
} else if (ch === '[') {
do {
if (ch === undefined)
throw this.newSyntaxError("Unterminated character class");
if (ch === '\\')
this.cursor++;
ch = input[this.cursor++];
} while (ch !== ']');
} else if (ch === undefined) {
throw this.newSyntaxError("Unterminated regex");
}
} while (ch !== '/');
do {
ch = input[this.cursor++];
} while (ch >= 'a' && ch <= 'z');
this.cursor--;
token.value = eval(input.substring(token.start, this.cursor));
},
lexOp: function (ch) {
var token = this.token, input = this.source;
// A bit ugly, but it seems wasteful to write a trie lookup routine
// for only 3 characters...
var node = opTokens[ch];
var next = input[this.cursor];
if (next in node) {
node = node[next];
this.cursor++;
next = input[this.cursor];
if (next in node) {
node = node[next];
this.cursor++;
next = input[this.cursor];
}
}
}
var op = node.op;
if (definitions.assignOps[op] && input[this.cursor] === '=') {
this.cursor++;
token.type = ASSIGN;
token.assignOp = definitions.tokenIds[definitions.opTypeNames[op]];
op += '=';
} else {
token.type = definitions.tokenIds[definitions.opTypeNames[op]];
token.assignOp = null;
}
var op = node.op;
if (definitions.assignOps[op] && input[this.cursor] === '=') {
this.cursor++;
token.type = ASSIGN;
token.assignOp = definitions.tokenIds[definitions.opTypeNames[op]];
op += '=';
} else {
token.type = definitions.tokenIds[definitions.opTypeNames[op]];
token.assignOp = null;
}
token.value = op;
},
token.value = op;
},
// FIXME: Unicode escape sequences
// FIXME: Unicode identifiers
lexIdent: function (ch) {
var token = this.token, input = this.source;
// FIXME: Unicode escape sequences
lexIdent: function (ch) {
var token = this.token;
var id = ch;
do {
ch = input[this.cursor++];
} while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
(ch >= '0' && ch <= '9') || ch === '$' || ch === '_');
while ((ch = this.getValidIdentifierChar(false)) !== null) {
id += ch;
}
this.cursor--; // Put the non-word character back.
token.type = definitions.keywords[id] || IDENTIFIER;
if (token.type in this.blackList) {
// banned keyword, this is an identifier
token.type = IDENTIFIER;
}
token.value = id;
},
var id = input.substring(token.start, this.cursor);
token.type = definitions.keywords[id] || IDENTIFIER;
token.value = id;
},
/*
* Tokenizer.get :: void -> token type
*
* Consume input *only* if there is no lookahead.
* Dispatch to the appropriate lexing function depending on the input.
*/
get: function (scanOperand) {
var token;
while (this.lookahead) {
--this.lookahead;
this.tokenIndex = (this.tokenIndex + 1) & 3;
token = this.tokens[this.tokenIndex];
if (token.type !== NEWLINE || this.scanNewlines)
return token.type;
}
this.skip();
/*
* Tokenizer.get :: void -> token type
*
* Consume input *only* if there is no lookahead.
* Dispatch to the appropriate lexing function depending on the input.
*/
get: function (scanOperand) {
var token;
while (this.lookahead) {
--this.lookahead;
this.tokenIndex = (this.tokenIndex + 1) & 3;
token = this.tokens[this.tokenIndex];
if (token.type !== NEWLINE || this.scanNewlines)
return token.type;
}
if (!token)
this.tokens[this.tokenIndex] = token = {};
this.skip();
var input = this.source;
if (this.cursor >= input.length)
return token.type = END;
this.tokenIndex = (this.tokenIndex + 1) & 3;
token = this.tokens[this.tokenIndex];
if (!token)
this.tokens[this.tokenIndex] = token = {};
token.start = this.cursor;
token.lineno = this.lineno;
var input = this.source;
if (this.cursor === input.length)
return token.type = END;
var ich = this.getValidIdentifierChar(true);
var ch = (ich === null) ? input[this.cursor++] : null;
if (ich !== null) {
this.lexIdent(ich);
} else if (scanOperand && ch === '/') {
this.lexRegExp(ch);
} else if (ch in opTokens) {
this.lexOp(ch);
} else if (ch === '.') {
this.lexDot(ch);
} else if (ch >= '1' && ch <= '9') {
this.lexNumber(ch);
} else if (ch === '0') {
this.lexZeroNumber(ch);
} else if (ch === '"' || ch === "'") {
this.lexString(ch);
} else if (this.scanNewlines && (ch === '\n' || ch === '\r')) {
// if this was a \r, look for \r\n
if (ch === '\r' && input[this.cursor] === '\n') this.cursor++;
token.type = NEWLINE;
token.value = '\n';
this.lineno++;
} else {
throw this.newSyntaxError("Illegal token");
}
token.start = this.cursor;
token.lineno = this.lineno;
token.end = this.cursor;
return token.type;
},
var ch = input[this.cursor++];
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch === '$' || ch === '_') {
this.lexIdent(ch);
} else if (scanOperand && ch === '/') {
this.lexRegExp(ch);
} else if (ch in opTokens) {
this.lexOp(ch);
} else if (ch === '.') {
this.lexDot(ch);
} else if (ch >= '1' && ch <= '9') {
this.lexNumber(ch);
} else if (ch === '0') {
this.lexZeroNumber(ch);
} else if (ch === '"' || ch === "'") {
this.lexString(ch);
} else if (this.scanNewlines && ch === '\n') {
token.type = NEWLINE;
token.value = '\n';
this.lineno++;
} else {
throw this.newSyntaxError("Illegal token");
}
/*
* Tokenizer.unget :: void -> undefined
*
* Match depends on unget returning undefined.
*/
unget: function () {
if (++this.lookahead === 4) throw "PANIC: too much lookahead!";
this.tokenIndex = (this.tokenIndex - 1) & 3;
},
token.end = this.cursor;
return token.type;
},
newSyntaxError: function (m) {
m = (this.filename ? this.filename + ":" : "") + this.lineno + ": " + m;
var e = new SyntaxError(m, this.filename, this.lineno);
e.source = this.source;
e.cursor = this.lookahead
? this.tokens[(this.tokenIndex + this.lookahead) & 3].start
: this.cursor;
return e;
},
/*
* Tokenizer.unget :: void -> undefined
*
* Match depends on unget returning undefined.
*/
unget: function () {
if (++this.lookahead === 4) throw "PANIC: too much lookahead!";
this.tokenIndex = (this.tokenIndex - 1) & 3;
},
/* Gets a single valid identifier char from the input stream, or null
* if there is none.
* Since JavaScript provides no convenient way to determine if a
* character is in a particular Unicode category, we use
* metacircularity to accomplish this (oh yeaaaah!) */
getValidIdentifierChar: function(first) {
var input = this.source;
if (this.cursor >= input.length) return null;
var ch = input[this.cursor];
newSyntaxError: function (m) {
var e = new SyntaxError(m, this.filename, this.lineno);
e.source = this.source;
e.lineno = this.lineno;
e.cursor = this.lookahead
? this.tokens[(this.tokenIndex + this.lookahead) & 3].start
: this.cursor;
return e;
},
};
// first check for \u escapes
if (ch === '\\' && input[this.cursor+1] === 'u') {
// get the character value
try {
ch = String.fromCharCode(parseInt(
input.substring(this.cursor + 2, this.cursor + 6),
16));
} catch (ex) {
return null;
}
this.cursor += 5;
}
exports.Tokenizer = Tokenizer;
// check directly for ASCII
if (ch <= "\u007F") {
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch === '$' || ch === '_' ||
(!first && (ch >= '0' && ch <= '9'))) {
this.cursor++;
return ch;
}
return null;
}
// create an object to test this in
var x = {};
x["x"+ch] = true;
x[ch] = true;
// then use eval to determine if it's a valid character
var valid = false;
try {
valid = (Function("x", "return (x." + (first?"":"x") + ch + ");")(x) === true);
} catch (ex) {}
if (valid) this.cursor++;
return (valid ? ch : null);
},
};
});
return { Tokenizer: Tokenizer };
});

File diff suppressed because it is too large Load diff

View file

@ -290,6 +290,7 @@ var Range = function(startRow, startColumn, endRow, endColumn) {
session.documentToScreenPosition(this.start);
var screenPosEnd =
session.documentToScreenPosition(this.end);
return new Range(
screenPosStart.row, screenPosStart.column,
screenPosEnd.row, screenPosEnd.column

View file

@ -42,6 +42,7 @@ if (typeof process !== "undefined") {
define(function(require, exports, module) {
var Range = require("ace/range").Range;
var EditSession = require("ace/edit_session").EditSession;
var assert = require("ace/test/assertions");
module.exports = {
@ -165,6 +166,27 @@ module.exports = {
var range = new Range(2, 0, 2, 0);
assert.range(range.collapseRows(), 2, 0, 2, 0);
},
"test: to screen range" : function() {
var session = new EditSession([
"juhu",
"12\t\t34",
"ぁぁa",
"\t\t34",
]);
var range = new Range(0, 0, 0, 3);
assert.range(range.toScreenRange(session), 0, 0, 0, 3);
var range = new Range(1, 1, 1, 3);
assert.range(range.toScreenRange(session), 1, 1, 1, 4);
var range = new Range(2, 1, 2, 2);
assert.range(range.toScreenRange(session), 2, 2, 2, 4);
var range = new Range(3, 0, 3, 4);
assert.range(range.toScreenRange(session), 3, 0, 3, 10);
}
};

View file

@ -51,8 +51,11 @@ var ScrollBar = function(parent) {
parent.appendChild(this.element);
// in OSX lion the scrollbars appear to have no width. In this case resize
// the to show the scrollbar but still pretend that the scrollbar has a width
// of 0px
this.width = dom.scrollbarWidth();
this.element.style.width = this.width + "px";
this.element.style.width = (this.width || 15) + "px";
event.addListener(this.element, "scroll", this.onScroll.bind(this));
};

View file

@ -43,6 +43,13 @@ var lang = require("pilot/lang");
var EventEmitter = require("pilot/event_emitter").EventEmitter;
var Range = require("ace/range").Range;
/**
* Keeps cursor position and the text selection of an edit session.
*
* The row/columns used in the selection are in document coordinates
* representing ths coordinates as thez appear in the document
* before applying soft wrap and folding.
*/
var Selection = function(session) {
this.session = session;
this.doc = session.getDocument();
@ -56,7 +63,7 @@ var Selection = function(session) {
_self._dispatchEvent("changeCursor");
if (!_self.$isEmpty)
_self._dispatchEvent("changeSelection");
if (e.old.row == e.value.row)
if (!_self.$preventUpdateDesiredColumnOnChange && e.old.column != e.value.column)
_self.$updateDesiredColumn();
});
@ -297,7 +304,8 @@ var Selection = function(session) {
fold;
if (fold = this.session.getFoldAt(cursor.row, cursor.column, 1)) {
this.moveCursorTo(fold.end.row, fold.end.column);
} else if (this.selectionLead.column == this.doc.getLine(this.selectionLead.row).length) {
}
else if (this.selectionLead.column == this.doc.getLine(this.selectionLead.row).length) {
if (this.selectionLead.row < this.doc.getLength() - 1) {
this.moveCursorTo(this.selectionLead.row + 1, 0);
}
@ -318,25 +326,25 @@ var Selection = function(session) {
var screenRow = this.session.documentToScreenRow(row, column);
// Determ the doc-position of the first character at the screen line.
var firstColumnPosition =
this.session.screenToDocumentPosition(screenRow, 0);
var firstColumnPosition = this.session.screenToDocumentPosition(screenRow, 0);
// Determ the string "before" the cursor.
// Determ the line
var beforeCursor = this.session.getDisplayLine(
row, column,
firstColumnPosition.row, firstColumnPosition.column);
row, null,
firstColumnPosition.row, firstColumnPosition.column
);
//
var leadingSpace = beforeCursor.match(/^\s*/);
if (leadingSpace[0].length == 0
|| leadingSpace[0].length >= column - firstColumnPosition.column)
{
if (leadingSpace[0].length == column) {
this.moveCursorTo(
firstColumnPosition.row, firstColumnPosition.column);
} else {
firstColumnPosition.row, firstColumnPosition.column
);
}
else {
this.moveCursorTo(
firstColumnPosition.row,
firstColumnPosition.column + leadingSpace[0].length);
firstColumnPosition.column + leadingSpace[0].length
);
}
};
@ -434,7 +442,6 @@ var Selection = function(session) {
);
var screenCol = (chars == 0 && this.$desiredColumn) || screenPos.column;
var docPos = this.session.screenToDocumentPosition(screenPos.row + rows, screenCol);
this.moveCursorTo(docPos.row, docPos.column + chars, chars == 0);
};
@ -449,7 +456,11 @@ var Selection = function(session) {
row = fold.start.row;
column = fold.start.column;
}
this.$preventUpdateDesiredColumnOnChange = true;
this.selectionLead.setPosition(row, column);
this.$preventUpdateDesiredColumnOnChange = false;
if (!preventUpdateDesiredColumn)
this.$updateDesiredColumn(this.selectionLead.column);
};

View file

@ -144,8 +144,12 @@ module.exports = {
},
"test: moveCursor word left" : function() {
var session = new EditSession( ["ab",
" Juhu Kinners (abc, 12)", " cde"].join("\n"));
var session = new EditSession([
"ab",
" Juhu Kinners (abc, 12)",
" cde"
].join("\n"));
var selection = session.getSelection();
selection.moveCursorDown();
@ -183,6 +187,18 @@ module.exports = {
selection.moveCursorWordLeft();
assert.position(selection.getCursor(), 0, 2);
},
"test: moveCursor word left" : function() {
var session = new EditSession(" Fuß Füße");
var selection = session.getSelection();
selection.moveCursorTo(0, 9)
selection.moveCursorWordLeft();
assert.position(selection.getCursor(), 0, 5);
selection.moveCursorWordLeft();
assert.position(selection.getCursor(), 0, 4);
},
"test: select word left if cursor in word" : function() {
var session = new EditSession("Juhu Kinners");
@ -327,6 +343,106 @@ module.exports = {
// Move behind ||
selection.moveCursorWordLeft();
assert.position(selection.getCursor(), 0, 0);
},
"test: move cursor to line start should move cursor to end of the indentation first": function() {
var session = new EditSession("12\n Juhu\n12");
var selection = session.getSelection();
selection.moveCursorTo(1, 6);
selection.moveCursorLineStart();
assert.position(selection.getCursor(), 1, 4);
},
"test: move cursor to line start when the cursor is at the end of the indentation should move cursor to column 0": function() {
var session = new EditSession("12\n Juhu\n12");
var selection = session.getSelection();
selection.moveCursorTo(1, 4);
selection.moveCursorLineStart();
assert.position(selection.getCursor(), 1, 0);
},
"test: move cursor to line start when the cursor is at column 0 should move cursor to the end of the indentation": function() {
var session = new EditSession("12\n Juhu\n12");
var selection = session.getSelection();
selection.moveCursorTo(1, 0);
selection.moveCursorLineStart();
assert.position(selection.getCursor(), 1, 4);
},
// Eclipse style
"test: move cursor to line start when the cursor is before the initial indentation should move cursor to the end of the indentation": function() {
var session = new EditSession("12\n Juhu\n12");
var selection = session.getSelection();
selection.moveCursorTo(1, 2);
selection.moveCursorLineStart();
assert.position(selection.getCursor(), 1, 4);
},
"test go line up when in the middle of the first line should go to document start": function() {
var session = new EditSession("juhu kinners");
var selection = session.getSelection();
selection.moveCursorTo(0, 4);
selection.moveCursorUp();
assert.position(selection.getCursor(), 0, 0);
},
"test: (wrap) go line up when in the middle of the first line should go to document start": function() {
var session = new EditSession("juhu kinners");
session.setWrapLimitRange(5, 5);
session.adjustWrapLimit(80);
var selection = session.getSelection();
selection.moveCursorTo(0, 4);
selection.moveCursorUp();
assert.position(selection.getCursor(), 0, 0);
},
"test go line down when in the middle of the last line should go to document end": function() {
var session = new EditSession("juhu kinners");
var selection = session.getSelection();
selection.moveCursorTo(0, 4);
selection.moveCursorDown();
assert.position(selection.getCursor(), 0, 12);
},
"test (wrap) go line down when in the middle of the last line should go to document end": function() {
var session = new EditSession("juhu kinners");
session.setWrapLimitRange(8, 8);
session.adjustWrapLimit(80);
var selection = session.getSelection();
selection.moveCursorTo(0, 10);
selection.moveCursorDown();
assert.position(selection.getCursor(), 0, 12);
},
"test go line up twice and then once down when in the second should go back to the previous column": function() {
var session = new EditSession("juhu\nkinners");
var selection = session.getSelection();
selection.moveCursorTo(1, 4);
selection.moveCursorUp();
selection.moveCursorUp();
selection.moveCursorDown();
assert.position(selection.getCursor(), 1, 4);
}
};

View file

@ -39,6 +39,7 @@
define(function(require, exports, module) {
var oop = require("pilot/oop");
var dom = require("pilot/dom");
var lang = require("pilot/lang");
var EventEmitter = require("pilot/event_emitter").EventEmitter;
@ -71,12 +72,12 @@ var Split = function(container, theme, splits) {
oop.implement(this, EventEmitter);
this.$createEditor = function() {
var dom = document.createElement("div");
dom.className = this.$editorCSS;
dom.style = "position: absolute; top:0px; bottom:0px";
this.$container.appendChild(dom);
var el = document.createElement("div");
el.className = this.$editorCSS;
el.style.cssText = "position: absolute; top:0px; bottom:0px";
this.$container.appendChild(el);
var session = new EditSession("");
var editor = new Editor(new Renderer(dom, this.$theme));
var editor = new Editor(new Renderer(el, this.$theme));
editor.on("focus", function() {
this._emit("focus", editor);

View file

@ -1,7 +1,7 @@
define(function(require, exports, module) {
require("pilot/fixoldbrowsers");
var AsyncTest = require("asyncjs/test");
var AsyncTest = require("asyncjs").test;
var async = require("asyncjs");
var dom = require("pilot/dom");
@ -28,6 +28,7 @@ var tests = [
require("ace/mode/html_tokenizer_test"),
require("ace/mode/javascript_test"),
require("ace/mode/javascript_tokenizer_test"),
require("ace/mode/ruby_tokenizer_test"),
require("ace/mode/text_test"),
require("ace/mode/xml_test"),
require("ace/mode/xml_tokenizer_test")

85
lib/ace/test/benchmark.js Normal file
View file

@ -0,0 +1,85 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
if (typeof process !== "undefined") {
require("../../../support/paths");
}
define(function(require, exports, module) {
var assert = require("ace/test/assertions");
var EditSession = require("ace/edit_session").EditSession;
module.exports = {
setUp : function() {
this.start = Date.now();
},
tearDown : function() {
console.log("took: ", Date.now() - this.start + "ms");
},
"test: document to screen position": function() {
var s = new EditSession(Array(6000).join('someText\n'));
for (var i=0; i<6000; i++)
s.documentToScreenPosition(i, 0);
for (var i=0; i<6000; i++)
s.documentToScreenPosition(i, 0);
console.log(s.$rowCache.length);
},
"test: screen to document position": function() {
var s = new EditSession(Array(6000).join('someText\n'));
for (var i=0; i<6000; i++)
s.screenToDocumentPosition(i, 0);
for (var i=0; i<6000; i++)
s.documentToScreenPosition(i, 0);
console.log(s.$rowCache.length);
}
};
});
if (typeof module !== "undefined" && module === require.main) {
require("asyncjs").test.testcase(module.exports).exec();
}

View file

@ -0,0 +1,198 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var dom = require("pilot/dom");
var cssText = ".ace-crimson-editor .ace_editor {\
border: 2px solid rgb(159, 159, 159);\
}\
\
.ace-crimson-editor .ace_editor.ace_focus {\
border: 2px solid #327fbd;\
}\
\
.ace-crimson-editor .ace_gutter {\
width: 50px;\
background: #e8e8e8;\
color: #333;\
overflow : hidden;\
}\
\
.ace-crimson-editor .ace_gutter-layer {\
width: 100%;\
text-align: right;\
}\
\
.ace-crimson-editor .ace_gutter-layer .ace_gutter-cell {\
padding-right: 6px;\
}\
\
.ace-crimson-editor .ace_print_margin {\
width: 1px;\
background: #e8e8e8;\
}\
\
.ace-crimson-editor .ace_text-layer {\
cursor: text;\
color: rgb(64, 64, 64);\
}\
\
.ace-crimson-editor .ace_cursor {\
border-left: 2px solid black;\
}\
\
.ace-crimson-editor .ace_cursor.ace_overwrite {\
border-left: 0px;\
border-bottom: 1px solid black;\
}\
\
.ace-crimson-editor .ace_line .ace_invisible {\
color: rgb(191, 191, 191);\
}\
\
.ace-crimson-editor .ace_line .ace_identifier {\
color: black;\
}\
\
.ace-crimson-editor .ace_line .ace_keyword {\
color: blue;\
}\
\
.ace-crimson-editor .ace_line .ace_constant.ace_buildin {\
color: rgb(88, 72, 246);\
}\
\
.ace-crimson-editor .ace_line .ace_constant.ace_language {\
color: rgb(255, 156, 0);\
}\
\
.ace-crimson-editor .ace_line .ace_constant.ace_library {\
color: rgb(6, 150, 14);\
}\
\
.ace-crimson-editor .ace_line .ace_invalid {\
text-decoration: line-through;\
color: rgb(224, 0, 0);\
}\
\
.ace-crimson-editor .ace_line .ace_fold {\
background-color: #E4E4E4;\
border-radius: 3px;\
}\
\
.ace-crimson-editor .ace_line .ace_support.ace_function {\
color: rgb(192, 0, 0);\
}\
\
.ace-crimson-editor .ace_line .ace_support.ace_constant {\
color: rgb(6, 150, 14);\
}\
\
.ace-crimson-editor .ace_line .ace_support.ace_type,\
.ace-crimson-editor .ace_line .ace_support.ace_class {\
color: rgb(109, 121, 222);\
}\
\
.ace-crimson-editor .ace_line .ace_keyword.ace_operator {\
color: rgb(49, 132, 149);\
}\
\
.ace-crimson-editor .ace_line .ace_string {\
color: rgb(128, 0, 128);\
}\
\
.ace-crimson-editor .ace_line .ace_comment {\
color: rgb(76, 136, 107);\
}\
\
.ace-crimson-editor .ace_line .ace_comment.ace_doc {\
color: rgb(0, 102, 255);\
}\
\
.ace-crimson-editor .ace_line .ace_comment.ace_doc.ace_tag {\
color: rgb(128, 159, 191);\
}\
\
.ace-crimson-editor .ace_line .ace_constant.ace_numeric {\
color: rgb(0, 0, 64);\
}\
\
.ace-crimson-editor .ace_line .ace_variable {\
color: rgb(0, 64, 128);\
}\
\
.ace-crimson-editor .ace_line .ace_xml_pe {\
color: rgb(104, 104, 91);\
}\
\
.ace-crimson-editor .ace_marker-layer .ace_selection {\
background: rgb(181, 213, 255);\
}\
\
.ace-crimson-editor .ace_marker-layer .ace_step {\
background: rgb(252, 255, 0);\
}\
\
.ace-crimson-editor .ace_marker-layer .ace_stack {\
background: rgb(164, 229, 101);\
}\
\
.ace-crimson-editor .ace_marker-layer .ace_bracket {\
margin: -1px 0 0 -1px;\
border: 1px solid rgb(192, 192, 192);\
}\
\
.ace-crimson-editor .ace_marker-layer .ace_active_line {\
background: rgb(232, 242, 254);\
}\
\
.ace-crimson-editor .ace_marker-layer .ace_selected_word {\
background: rgb(250, 250, 255);\
border: 1px solid rgb(200, 200, 250);\
}\
\
.ace-crimson-editor .ace_string.ace_regex {\
color: rgb(192, 0, 192);\
}";
// Import CSS once.
dom.importCssString(cssText);
exports.cssClass = "ace-crimson-editor";
});

View file

@ -174,7 +174,7 @@ define(function(require, exports, module) {
}\
\
.ace-tm .ace_marker-layer .ace_active_line {\
background: rgb(232, 242, 254);\
background: rgba(0, 0, 0, 0.07);\
}\
\
.ace-tm .ace_marker-layer .ace_selected_word {\

View file

@ -69,7 +69,6 @@ var Tokenizer = function(rules) {
}
this.regExps[key] = new RegExp("(?:(" + ruleRegExps.join(")|(") + ")|(.))", "g");
}
};
@ -93,23 +92,26 @@ var Tokenizer = function(rules) {
while (match = re.exec(line)) {
var type = "text";
var rule = null;
var value = [match[0]];
for ( var i = 0; i < match.length-2; i++) {
for (var i = 0; i < match.length-2; i++) {
if (match[i + 1] !== undefined) {
var rule = state[mapping[i].rule];
rule = state[mapping[i].rule];
if (mapping[i].len > 1) {
value = match.slice(i+2, i+1+mapping[i].len);
}
// compute token type
if (typeof rule.token == "function")
type = rule.token.apply(this, value);
else
type = rule.token;
if (rule.next && rule.next !== currentState) {
currentState = rule.next;
var next = rule.next;
if (next && next !== currentState) {
currentState = next;
state = this.rules[currentState];
mapping = this.matchMappings[currentState];
lastIndex = re.lastIndex;
@ -120,26 +122,25 @@ var Tokenizer = function(rules) {
break;
}
};
if (typeof type == "string") {
if (typeof value != "string") {
if (value[0]) {
if (typeof type == "string") {
value = [value.join("")];
type = [type];
}
type = [type];
}
for ( var i = 0; i < value.length; i++) {
if (token.type !== type[i]) {
if (token.type) {
tokens.push(token);
}
for (var i = 0; i < value.length; i++) {
if ((!rule || rule.merge || type[i] === "text") && token.type === type[i]) {
token.value += value[i];
} else {
if (token.type) {
tokens.push(token);
}
token = {
type: type[i],
value: value[i]
token = {
type: type[i],
value: value[i]
}
}
} else {
token.value += value[i];
}
}

106
lib/ace/unicode.js Normal file
View file

@ -0,0 +1,106 @@
define(function(require, exports, module) {
/*
XRegExp Unicode plugin pack: Categories 1.0
(c) 2010 Steven Levithan
MIT License
<http://xregexp.com>
Uses the Unicode 5.2 character database
This package for the XRegExp Unicode plugin enables the following Unicode categories (aka properties):
L - Letter (the top-level Letter category is included in the Unicode plugin base script)
Ll - Lowercase letter
Lu - Uppercase letter
Lt - Titlecase letter
Lm - Modifier letter
Lo - Letter without case
M - Mark
Mn - Non-spacing mark
Mc - Spacing combining mark
Me - Enclosing mark
N - Number
Nd - Decimal digit
Nl - Letter number
No - Other number
P - Punctuation
Pd - Dash punctuation
Ps - Open punctuation
Pe - Close punctuation
Pi - Initial punctuation
Pf - Final punctuation
Pc - Connector punctuation
Po - Other punctuation
S - Symbol
Sm - Math symbol
Sc - Currency symbol
Sk - Modifier symbol
So - Other symbol
Z - Separator
Zs - Space separator
Zl - Line separator
Zp - Paragraph separator
C - Other
Cc - Control
Cf - Format
Co - Private use
Cs - Surrogate
Cn - Unassigned
Example usage:
\p{N}
\p{Cn}
*/
// will be populated by addUnicodePackage
exports.packages = {};
addUnicodePackage({
L: "0041-005A0061-007A00AA00B500BA00C0-00D600D8-00F600F8-02C102C6-02D102E0-02E402EC02EE0370-037403760377037A-037D03860388-038A038C038E-03A103A3-03F503F7-0481048A-05250531-055605590561-058705D0-05EA05F0-05F20621-064A066E066F0671-06D306D506E506E606EE06EF06FA-06FC06FF07100712-072F074D-07A507B107CA-07EA07F407F507FA0800-0815081A082408280904-0939093D09500958-0961097109720979-097F0985-098C098F09900993-09A809AA-09B009B209B6-09B909BD09CE09DC09DD09DF-09E109F009F10A05-0A0A0A0F0A100A13-0A280A2A-0A300A320A330A350A360A380A390A59-0A5C0A5E0A72-0A740A85-0A8D0A8F-0A910A93-0AA80AAA-0AB00AB20AB30AB5-0AB90ABD0AD00AE00AE10B05-0B0C0B0F0B100B13-0B280B2A-0B300B320B330B35-0B390B3D0B5C0B5D0B5F-0B610B710B830B85-0B8A0B8E-0B900B92-0B950B990B9A0B9C0B9E0B9F0BA30BA40BA8-0BAA0BAE-0BB90BD00C05-0C0C0C0E-0C100C12-0C280C2A-0C330C35-0C390C3D0C580C590C600C610C85-0C8C0C8E-0C900C92-0CA80CAA-0CB30CB5-0CB90CBD0CDE0CE00CE10D05-0D0C0D0E-0D100D12-0D280D2A-0D390D3D0D600D610D7A-0D7F0D85-0D960D9A-0DB10DB3-0DBB0DBD0DC0-0DC60E01-0E300E320E330E40-0E460E810E820E840E870E880E8A0E8D0E94-0E970E99-0E9F0EA1-0EA30EA50EA70EAA0EAB0EAD-0EB00EB20EB30EBD0EC0-0EC40EC60EDC0EDD0F000F40-0F470F49-0F6C0F88-0F8B1000-102A103F1050-1055105A-105D106110651066106E-10701075-1081108E10A0-10C510D0-10FA10FC1100-1248124A-124D1250-12561258125A-125D1260-1288128A-128D1290-12B012B2-12B512B8-12BE12C012C2-12C512C8-12D612D8-13101312-13151318-135A1380-138F13A0-13F41401-166C166F-167F1681-169A16A0-16EA1700-170C170E-17111720-17311740-17511760-176C176E-17701780-17B317D717DC1820-18771880-18A818AA18B0-18F51900-191C1950-196D1970-19741980-19AB19C1-19C71A00-1A161A20-1A541AA71B05-1B331B45-1B4B1B83-1BA01BAE1BAF1C00-1C231C4D-1C4F1C5A-1C7D1CE9-1CEC1CEE-1CF11D00-1DBF1E00-1F151F18-1F1D1F20-1F451F48-1F4D1F50-1F571F591F5B1F5D1F5F-1F7D1F80-1FB41FB6-1FBC1FBE1FC2-1FC41FC6-1FCC1FD0-1FD31FD6-1FDB1FE0-1FEC1FF2-1FF41FF6-1FFC2071207F2090-209421022107210A-211321152119-211D212421262128212A-212D212F-2139213C-213F2145-2149214E218321842C00-2C2E2C30-2C5E2C60-2CE42CEB-2CEE2D00-2D252D30-2D652D6F2D80-2D962DA0-2DA62DA8-2DAE2DB0-2DB62DB8-2DBE2DC0-2DC62DC8-2DCE2DD0-2DD62DD8-2DDE2E2F300530063031-3035303B303C3041-3096309D-309F30A1-30FA30FC-30FF3105-312D3131-318E31A0-31B731F0-31FF3400-4DB54E00-9FCBA000-A48CA4D0-A4FDA500-A60CA610-A61FA62AA62BA640-A65FA662-A66EA67F-A697A6A0-A6E5A717-A71FA722-A788A78BA78CA7FB-A801A803-A805A807-A80AA80C-A822A840-A873A882-A8B3A8F2-A8F7A8FBA90A-A925A930-A946A960-A97CA984-A9B2A9CFAA00-AA28AA40-AA42AA44-AA4BAA60-AA76AA7AAA80-AAAFAAB1AAB5AAB6AAB9-AABDAAC0AAC2AADB-AADDABC0-ABE2AC00-D7A3D7B0-D7C6D7CB-D7FBF900-FA2DFA30-FA6DFA70-FAD9FB00-FB06FB13-FB17FB1DFB1F-FB28FB2A-FB36FB38-FB3CFB3EFB40FB41FB43FB44FB46-FBB1FBD3-FD3DFD50-FD8FFD92-FDC7FDF0-FDFBFE70-FE74FE76-FEFCFF21-FF3AFF41-FF5AFF66-FFBEFFC2-FFC7FFCA-FFCFFFD2-FFD7FFDA-FFDC",
Ll: "0061-007A00AA00B500BA00DF-00F600F8-00FF01010103010501070109010B010D010F01110113011501170119011B011D011F01210123012501270129012B012D012F01310133013501370138013A013C013E014001420144014601480149014B014D014F01510153015501570159015B015D015F01610163016501670169016B016D016F0171017301750177017A017C017E-0180018301850188018C018D019201950199-019B019E01A101A301A501A801AA01AB01AD01B001B401B601B901BA01BD-01BF01C601C901CC01CE01D001D201D401D601D801DA01DC01DD01DF01E101E301E501E701E901EB01ED01EF01F001F301F501F901FB01FD01FF02010203020502070209020B020D020F02110213021502170219021B021D021F02210223022502270229022B022D022F02310233-0239023C023F0240024202470249024B024D024F-02930295-02AF037103730377037B-037D039003AC-03CE03D003D103D5-03D703D903DB03DD03DF03E103E303E503E703E903EB03ED03EF-03F303F503F803FB03FC0430-045F04610463046504670469046B046D046F04710473047504770479047B047D047F0481048B048D048F04910493049504970499049B049D049F04A104A304A504A704A904AB04AD04AF04B104B304B504B704B904BB04BD04BF04C204C404C604C804CA04CC04CE04CF04D104D304D504D704D904DB04DD04DF04E104E304E504E704E904EB04ED04EF04F104F304F504F704F904FB04FD04FF05010503050505070509050B050D050F05110513051505170519051B051D051F0521052305250561-05871D00-1D2B1D62-1D771D79-1D9A1E011E031E051E071E091E0B1E0D1E0F1E111E131E151E171E191E1B1E1D1E1F1E211E231E251E271E291E2B1E2D1E2F1E311E331E351E371E391E3B1E3D1E3F1E411E431E451E471E491E4B1E4D1E4F1E511E531E551E571E591E5B1E5D1E5F1E611E631E651E671E691E6B1E6D1E6F1E711E731E751E771E791E7B1E7D1E7F1E811E831E851E871E891E8B1E8D1E8F1E911E931E95-1E9D1E9F1EA11EA31EA51EA71EA91EAB1EAD1EAF1EB11EB31EB51EB71EB91EBB1EBD1EBF1EC11EC31EC51EC71EC91ECB1ECD1ECF1ED11ED31ED51ED71ED91EDB1EDD1EDF1EE11EE31EE51EE71EE91EEB1EED1EEF1EF11EF31EF51EF71EF91EFB1EFD1EFF-1F071F10-1F151F20-1F271F30-1F371F40-1F451F50-1F571F60-1F671F70-1F7D1F80-1F871F90-1F971FA0-1FA71FB0-1FB41FB61FB71FBE1FC2-1FC41FC61FC71FD0-1FD31FD61FD71FE0-1FE71FF2-1FF41FF61FF7210A210E210F2113212F21342139213C213D2146-2149214E21842C30-2C5E2C612C652C662C682C6A2C6C2C712C732C742C76-2C7C2C812C832C852C872C892C8B2C8D2C8F2C912C932C952C972C992C9B2C9D2C9F2CA12CA32CA52CA72CA92CAB2CAD2CAF2CB12CB32CB52CB72CB92CBB2CBD2CBF2CC12CC32CC52CC72CC92CCB2CCD2CCF2CD12CD32CD52CD72CD92CDB2CDD2CDF2CE12CE32CE42CEC2CEE2D00-2D25A641A643A645A647A649A64BA64DA64FA651A653A655A657A659A65BA65DA65FA663A665A667A669A66BA66DA681A683A685A687A689A68BA68DA68FA691A693A695A697A723A725A727A729A72BA72DA72F-A731A733A735A737A739A73BA73DA73FA741A743A745A747A749A74BA74DA74FA751A753A755A757A759A75BA75DA75FA761A763A765A767A769A76BA76DA76FA771-A778A77AA77CA77FA781A783A785A787A78CFB00-FB06FB13-FB17FF41-FF5A",
Lu: "0041-005A00C0-00D600D8-00DE01000102010401060108010A010C010E01100112011401160118011A011C011E01200122012401260128012A012C012E01300132013401360139013B013D013F0141014301450147014A014C014E01500152015401560158015A015C015E01600162016401660168016A016C016E017001720174017601780179017B017D018101820184018601870189-018B018E-0191019301940196-0198019C019D019F01A001A201A401A601A701A901AC01AE01AF01B1-01B301B501B701B801BC01C401C701CA01CD01CF01D101D301D501D701D901DB01DE01E001E201E401E601E801EA01EC01EE01F101F401F6-01F801FA01FC01FE02000202020402060208020A020C020E02100212021402160218021A021C021E02200222022402260228022A022C022E02300232023A023B023D023E02410243-02460248024A024C024E03700372037603860388-038A038C038E038F0391-03A103A3-03AB03CF03D2-03D403D803DA03DC03DE03E003E203E403E603E803EA03EC03EE03F403F703F903FA03FD-042F04600462046404660468046A046C046E04700472047404760478047A047C047E0480048A048C048E04900492049404960498049A049C049E04A004A204A404A604A804AA04AC04AE04B004B204B404B604B804BA04BC04BE04C004C104C304C504C704C904CB04CD04D004D204D404D604D804DA04DC04DE04E004E204E404E604E804EA04EC04EE04F004F204F404F604F804FA04FC04FE05000502050405060508050A050C050E05100512051405160518051A051C051E0520052205240531-055610A0-10C51E001E021E041E061E081E0A1E0C1E0E1E101E121E141E161E181E1A1E1C1E1E1E201E221E241E261E281E2A1E2C1E2E1E301E321E341E361E381E3A1E3C1E3E1E401E421E441E461E481E4A1E4C1E4E1E501E521E541E561E581E5A1E5C1E5E1E601E621E641E661E681E6A1E6C1E6E1E701E721E741E761E781E7A1E7C1E7E1E801E821E841E861E881E8A1E8C1E8E1E901E921E941E9E1EA01EA21EA41EA61EA81EAA1EAC1EAE1EB01EB21EB41EB61EB81EBA1EBC1EBE1EC01EC21EC41EC61EC81ECA1ECC1ECE1ED01ED21ED41ED61ED81EDA1EDC1EDE1EE01EE21EE41EE61EE81EEA1EEC1EEE1EF01EF21EF41EF61EF81EFA1EFC1EFE1F08-1F0F1F18-1F1D1F28-1F2F1F38-1F3F1F48-1F4D1F591F5B1F5D1F5F1F68-1F6F1FB8-1FBB1FC8-1FCB1FD8-1FDB1FE8-1FEC1FF8-1FFB21022107210B-210D2110-211221152119-211D212421262128212A-212D2130-2133213E213F214521832C00-2C2E2C602C62-2C642C672C692C6B2C6D-2C702C722C752C7E-2C802C822C842C862C882C8A2C8C2C8E2C902C922C942C962C982C9A2C9C2C9E2CA02CA22CA42CA62CA82CAA2CAC2CAE2CB02CB22CB42CB62CB82CBA2CBC2CBE2CC02CC22CC42CC62CC82CCA2CCC2CCE2CD02CD22CD42CD62CD82CDA2CDC2CDE2CE02CE22CEB2CEDA640A642A644A646A648A64AA64CA64EA650A652A654A656A658A65AA65CA65EA662A664A666A668A66AA66CA680A682A684A686A688A68AA68CA68EA690A692A694A696A722A724A726A728A72AA72CA72EA732A734A736A738A73AA73CA73EA740A742A744A746A748A74AA74CA74EA750A752A754A756A758A75AA75CA75EA760A762A764A766A768A76AA76CA76EA779A77BA77DA77EA780A782A784A786A78BFF21-FF3A",
Lt: "01C501C801CB01F21F88-1F8F1F98-1F9F1FA8-1FAF1FBC1FCC1FFC",
Lm: "02B0-02C102C6-02D102E0-02E402EC02EE0374037A0559064006E506E607F407F507FA081A0824082809710E460EC610FC17D718431AA71C78-1C7D1D2C-1D611D781D9B-1DBF2071207F2090-20942C7D2D6F2E2F30053031-3035303B309D309E30FC-30FEA015A4F8-A4FDA60CA67FA717-A71FA770A788A9CFAA70AADDFF70FF9EFF9F",
Lo: "01BB01C0-01C3029405D0-05EA05F0-05F20621-063F0641-064A066E066F0671-06D306D506EE06EF06FA-06FC06FF07100712-072F074D-07A507B107CA-07EA0800-08150904-0939093D09500958-096109720979-097F0985-098C098F09900993-09A809AA-09B009B209B6-09B909BD09CE09DC09DD09DF-09E109F009F10A05-0A0A0A0F0A100A13-0A280A2A-0A300A320A330A350A360A380A390A59-0A5C0A5E0A72-0A740A85-0A8D0A8F-0A910A93-0AA80AAA-0AB00AB20AB30AB5-0AB90ABD0AD00AE00AE10B05-0B0C0B0F0B100B13-0B280B2A-0B300B320B330B35-0B390B3D0B5C0B5D0B5F-0B610B710B830B85-0B8A0B8E-0B900B92-0B950B990B9A0B9C0B9E0B9F0BA30BA40BA8-0BAA0BAE-0BB90BD00C05-0C0C0C0E-0C100C12-0C280C2A-0C330C35-0C390C3D0C580C590C600C610C85-0C8C0C8E-0C900C92-0CA80CAA-0CB30CB5-0CB90CBD0CDE0CE00CE10D05-0D0C0D0E-0D100D12-0D280D2A-0D390D3D0D600D610D7A-0D7F0D85-0D960D9A-0DB10DB3-0DBB0DBD0DC0-0DC60E01-0E300E320E330E40-0E450E810E820E840E870E880E8A0E8D0E94-0E970E99-0E9F0EA1-0EA30EA50EA70EAA0EAB0EAD-0EB00EB20EB30EBD0EC0-0EC40EDC0EDD0F000F40-0F470F49-0F6C0F88-0F8B1000-102A103F1050-1055105A-105D106110651066106E-10701075-1081108E10D0-10FA1100-1248124A-124D1250-12561258125A-125D1260-1288128A-128D1290-12B012B2-12B512B8-12BE12C012C2-12C512C8-12D612D8-13101312-13151318-135A1380-138F13A0-13F41401-166C166F-167F1681-169A16A0-16EA1700-170C170E-17111720-17311740-17511760-176C176E-17701780-17B317DC1820-18421844-18771880-18A818AA18B0-18F51900-191C1950-196D1970-19741980-19AB19C1-19C71A00-1A161A20-1A541B05-1B331B45-1B4B1B83-1BA01BAE1BAF1C00-1C231C4D-1C4F1C5A-1C771CE9-1CEC1CEE-1CF12135-21382D30-2D652D80-2D962DA0-2DA62DA8-2DAE2DB0-2DB62DB8-2DBE2DC0-2DC62DC8-2DCE2DD0-2DD62DD8-2DDE3006303C3041-3096309F30A1-30FA30FF3105-312D3131-318E31A0-31B731F0-31FF3400-4DB54E00-9FCBA000-A014A016-A48CA4D0-A4F7A500-A60BA610-A61FA62AA62BA66EA6A0-A6E5A7FB-A801A803-A805A807-A80AA80C-A822A840-A873A882-A8B3A8F2-A8F7A8FBA90A-A925A930-A946A960-A97CA984-A9B2AA00-AA28AA40-AA42AA44-AA4BAA60-AA6FAA71-AA76AA7AAA80-AAAFAAB1AAB5AAB6AAB9-AABDAAC0AAC2AADBAADCABC0-ABE2AC00-D7A3D7B0-D7C6D7CB-D7FBF900-FA2DFA30-FA6DFA70-FAD9FB1DFB1F-FB28FB2A-FB36FB38-FB3CFB3EFB40FB41FB43FB44FB46-FBB1FBD3-FD3DFD50-FD8FFD92-FDC7FDF0-FDFBFE70-FE74FE76-FEFCFF66-FF6FFF71-FF9DFFA0-FFBEFFC2-FFC7FFCA-FFCFFFD2-FFD7FFDA-FFDC",
M: "0300-036F0483-04890591-05BD05BF05C105C205C405C505C70610-061A064B-065E067006D6-06DC06DE-06E406E706E806EA-06ED07110730-074A07A6-07B007EB-07F30816-0819081B-08230825-08270829-082D0900-0903093C093E-094E0951-0955096209630981-098309BC09BE-09C409C709C809CB-09CD09D709E209E30A01-0A030A3C0A3E-0A420A470A480A4B-0A4D0A510A700A710A750A81-0A830ABC0ABE-0AC50AC7-0AC90ACB-0ACD0AE20AE30B01-0B030B3C0B3E-0B440B470B480B4B-0B4D0B560B570B620B630B820BBE-0BC20BC6-0BC80BCA-0BCD0BD70C01-0C030C3E-0C440C46-0C480C4A-0C4D0C550C560C620C630C820C830CBC0CBE-0CC40CC6-0CC80CCA-0CCD0CD50CD60CE20CE30D020D030D3E-0D440D46-0D480D4A-0D4D0D570D620D630D820D830DCA0DCF-0DD40DD60DD8-0DDF0DF20DF30E310E34-0E3A0E47-0E4E0EB10EB4-0EB90EBB0EBC0EC8-0ECD0F180F190F350F370F390F3E0F3F0F71-0F840F860F870F90-0F970F99-0FBC0FC6102B-103E1056-1059105E-10601062-10641067-106D1071-10741082-108D108F109A-109D135F1712-17141732-1734175217531772177317B6-17D317DD180B-180D18A91920-192B1930-193B19B0-19C019C819C91A17-1A1B1A55-1A5E1A60-1A7C1A7F1B00-1B041B34-1B441B6B-1B731B80-1B821BA1-1BAA1C24-1C371CD0-1CD21CD4-1CE81CED1CF21DC0-1DE61DFD-1DFF20D0-20F02CEF-2CF12DE0-2DFF302A-302F3099309AA66F-A672A67CA67DA6F0A6F1A802A806A80BA823-A827A880A881A8B4-A8C4A8E0-A8F1A926-A92DA947-A953A980-A983A9B3-A9C0AA29-AA36AA43AA4CAA4DAA7BAAB0AAB2-AAB4AAB7AAB8AABEAABFAAC1ABE3-ABEAABECABEDFB1EFE00-FE0FFE20-FE26",
Mn: "0300-036F0483-04870591-05BD05BF05C105C205C405C505C70610-061A064B-065E067006D6-06DC06DF-06E406E706E806EA-06ED07110730-074A07A6-07B007EB-07F30816-0819081B-08230825-08270829-082D0900-0902093C0941-0948094D0951-095509620963098109BC09C1-09C409CD09E209E30A010A020A3C0A410A420A470A480A4B-0A4D0A510A700A710A750A810A820ABC0AC1-0AC50AC70AC80ACD0AE20AE30B010B3C0B3F0B41-0B440B4D0B560B620B630B820BC00BCD0C3E-0C400C46-0C480C4A-0C4D0C550C560C620C630CBC0CBF0CC60CCC0CCD0CE20CE30D41-0D440D4D0D620D630DCA0DD2-0DD40DD60E310E34-0E3A0E47-0E4E0EB10EB4-0EB90EBB0EBC0EC8-0ECD0F180F190F350F370F390F71-0F7E0F80-0F840F860F870F90-0F970F99-0FBC0FC6102D-10301032-10371039103A103D103E10581059105E-10601071-1074108210851086108D109D135F1712-17141732-1734175217531772177317B7-17BD17C617C9-17D317DD180B-180D18A91920-19221927192819321939-193B1A171A181A561A58-1A5E1A601A621A65-1A6C1A73-1A7C1A7F1B00-1B031B341B36-1B3A1B3C1B421B6B-1B731B801B811BA2-1BA51BA81BA91C2C-1C331C361C371CD0-1CD21CD4-1CE01CE2-1CE81CED1DC0-1DE61DFD-1DFF20D0-20DC20E120E5-20F02CEF-2CF12DE0-2DFF302A-302F3099309AA66FA67CA67DA6F0A6F1A802A806A80BA825A826A8C4A8E0-A8F1A926-A92DA947-A951A980-A982A9B3A9B6-A9B9A9BCAA29-AA2EAA31AA32AA35AA36AA43AA4CAAB0AAB2-AAB4AAB7AAB8AABEAABFAAC1ABE5ABE8ABEDFB1EFE00-FE0FFE20-FE26",
Mc: "0903093E-09400949-094C094E0982098309BE-09C009C709C809CB09CC09D70A030A3E-0A400A830ABE-0AC00AC90ACB0ACC0B020B030B3E0B400B470B480B4B0B4C0B570BBE0BBF0BC10BC20BC6-0BC80BCA-0BCC0BD70C01-0C030C41-0C440C820C830CBE0CC0-0CC40CC70CC80CCA0CCB0CD50CD60D020D030D3E-0D400D46-0D480D4A-0D4C0D570D820D830DCF-0DD10DD8-0DDF0DF20DF30F3E0F3F0F7F102B102C10311038103B103C105610571062-10641067-106D108310841087-108C108F109A-109C17B617BE-17C517C717C81923-19261929-192B193019311933-193819B0-19C019C819C91A19-1A1B1A551A571A611A631A641A6D-1A721B041B351B3B1B3D-1B411B431B441B821BA11BA61BA71BAA1C24-1C2B1C341C351CE11CF2A823A824A827A880A881A8B4-A8C3A952A953A983A9B4A9B5A9BAA9BBA9BD-A9C0AA2FAA30AA33AA34AA4DAA7BABE3ABE4ABE6ABE7ABE9ABEAABEC",
Me: "0488048906DE20DD-20E020E2-20E4A670-A672",
N: "0030-003900B200B300B900BC-00BE0660-066906F0-06F907C0-07C90966-096F09E6-09EF09F4-09F90A66-0A6F0AE6-0AEF0B66-0B6F0BE6-0BF20C66-0C6F0C78-0C7E0CE6-0CEF0D66-0D750E50-0E590ED0-0ED90F20-0F331040-10491090-10991369-137C16EE-16F017E0-17E917F0-17F91810-18191946-194F19D0-19DA1A80-1A891A90-1A991B50-1B591BB0-1BB91C40-1C491C50-1C5920702074-20792080-20892150-21822185-21892460-249B24EA-24FF2776-27932CFD30073021-30293038-303A3192-31953220-32293251-325F3280-328932B1-32BFA620-A629A6E6-A6EFA830-A835A8D0-A8D9A900-A909A9D0-A9D9AA50-AA59ABF0-ABF9FF10-FF19",
Nd: "0030-00390660-066906F0-06F907C0-07C90966-096F09E6-09EF0A66-0A6F0AE6-0AEF0B66-0B6F0BE6-0BEF0C66-0C6F0CE6-0CEF0D66-0D6F0E50-0E590ED0-0ED90F20-0F291040-10491090-109917E0-17E91810-18191946-194F19D0-19DA1A80-1A891A90-1A991B50-1B591BB0-1BB91C40-1C491C50-1C59A620-A629A8D0-A8D9A900-A909A9D0-A9D9AA50-AA59ABF0-ABF9FF10-FF19",
Nl: "16EE-16F02160-21822185-218830073021-30293038-303AA6E6-A6EF",
No: "00B200B300B900BC-00BE09F4-09F90BF0-0BF20C78-0C7E0D70-0D750F2A-0F331369-137C17F0-17F920702074-20792080-20892150-215F21892460-249B24EA-24FF2776-27932CFD3192-31953220-32293251-325F3280-328932B1-32BFA830-A835",
P: "0021-00230025-002A002C-002F003A003B003F0040005B-005D005F007B007D00A100AB00B700BB00BF037E0387055A-055F0589058A05BE05C005C305C605F305F40609060A060C060D061B061E061F066A-066D06D40700-070D07F7-07F90830-083E0964096509700DF40E4F0E5A0E5B0F04-0F120F3A-0F3D0F850FD0-0FD4104A-104F10FB1361-13681400166D166E169B169C16EB-16ED1735173617D4-17D617D8-17DA1800-180A1944194519DE19DF1A1E1A1F1AA0-1AA61AA8-1AAD1B5A-1B601C3B-1C3F1C7E1C7F1CD32010-20272030-20432045-20512053-205E207D207E208D208E2329232A2768-277527C527C627E6-27EF2983-299829D8-29DB29FC29FD2CF9-2CFC2CFE2CFF2E00-2E2E2E302E313001-30033008-30113014-301F3030303D30A030FBA4FEA4FFA60D-A60FA673A67EA6F2-A6F7A874-A877A8CEA8CFA8F8-A8FAA92EA92FA95FA9C1-A9CDA9DEA9DFAA5C-AA5FAADEAADFABEBFD3EFD3FFE10-FE19FE30-FE52FE54-FE61FE63FE68FE6AFE6BFF01-FF03FF05-FF0AFF0C-FF0FFF1AFF1BFF1FFF20FF3B-FF3DFF3FFF5BFF5DFF5F-FF65",
Pd: "002D058A05BE140018062010-20152E172E1A301C303030A0FE31FE32FE58FE63FF0D",
Ps: "0028005B007B0F3A0F3C169B201A201E2045207D208D23292768276A276C276E27702772277427C527E627E827EA27EC27EE2983298529872989298B298D298F299129932995299729D829DA29FC2E222E242E262E283008300A300C300E3010301430163018301A301DFD3EFE17FE35FE37FE39FE3BFE3DFE3FFE41FE43FE47FE59FE5BFE5DFF08FF3BFF5BFF5FFF62",
Pe: "0029005D007D0F3B0F3D169C2046207E208E232A2769276B276D276F27712773277527C627E727E927EB27ED27EF298429862988298A298C298E2990299229942996299829D929DB29FD2E232E252E272E293009300B300D300F3011301530173019301B301E301FFD3FFE18FE36FE38FE3AFE3CFE3EFE40FE42FE44FE48FE5AFE5CFE5EFF09FF3DFF5DFF60FF63",
Pi: "00AB2018201B201C201F20392E022E042E092E0C2E1C2E20",
Pf: "00BB2019201D203A2E032E052E0A2E0D2E1D2E21",
Pc: "005F203F20402054FE33FE34FE4D-FE4FFF3F",
Po: "0021-00230025-0027002A002C002E002F003A003B003F0040005C00A100B700BF037E0387055A-055F058905C005C305C605F305F40609060A060C060D061B061E061F066A-066D06D40700-070D07F7-07F90830-083E0964096509700DF40E4F0E5A0E5B0F04-0F120F850FD0-0FD4104A-104F10FB1361-1368166D166E16EB-16ED1735173617D4-17D617D8-17DA1800-18051807-180A1944194519DE19DF1A1E1A1F1AA0-1AA61AA8-1AAD1B5A-1B601C3B-1C3F1C7E1C7F1CD3201620172020-20272030-2038203B-203E2041-20432047-205120532055-205E2CF9-2CFC2CFE2CFF2E002E012E06-2E082E0B2E0E-2E162E182E192E1B2E1E2E1F2E2A-2E2E2E302E313001-3003303D30FBA4FEA4FFA60D-A60FA673A67EA6F2-A6F7A874-A877A8CEA8CFA8F8-A8FAA92EA92FA95FA9C1-A9CDA9DEA9DFAA5C-AA5FAADEAADFABEBFE10-FE16FE19FE30FE45FE46FE49-FE4CFE50-FE52FE54-FE57FE5F-FE61FE68FE6AFE6BFF01-FF03FF05-FF07FF0AFF0CFF0EFF0FFF1AFF1BFF1FFF20FF3CFF61FF64FF65",
S: "0024002B003C-003E005E0060007C007E00A2-00A900AC00AE-00B100B400B600B800D700F702C2-02C502D2-02DF02E5-02EB02ED02EF-02FF03750384038503F604820606-0608060B060E060F06E906FD06FE07F609F209F309FA09FB0AF10B700BF3-0BFA0C7F0CF10CF20D790E3F0F01-0F030F13-0F170F1A-0F1F0F340F360F380FBE-0FC50FC7-0FCC0FCE0FCF0FD5-0FD8109E109F13601390-139917DB194019E0-19FF1B61-1B6A1B74-1B7C1FBD1FBF-1FC11FCD-1FCF1FDD-1FDF1FED-1FEF1FFD1FFE20442052207A-207C208A-208C20A0-20B8210021012103-21062108210921142116-2118211E-2123212521272129212E213A213B2140-2144214A-214D214F2190-2328232B-23E82400-24262440-244A249C-24E92500-26CD26CF-26E126E326E8-26FF2701-27042706-2709270C-27272729-274B274D274F-27522756-275E2761-276727942798-27AF27B1-27BE27C0-27C427C7-27CA27CC27D0-27E527F0-29822999-29D729DC-29FB29FE-2B4C2B50-2B592CE5-2CEA2E80-2E992E9B-2EF32F00-2FD52FF0-2FFB300430123013302030363037303E303F309B309C319031913196-319F31C0-31E33200-321E322A-32503260-327F328A-32B032C0-32FE3300-33FF4DC0-4DFFA490-A4C6A700-A716A720A721A789A78AA828-A82BA836-A839AA77-AA79FB29FDFCFDFDFE62FE64-FE66FE69FF04FF0BFF1C-FF1EFF3EFF40FF5CFF5EFFE0-FFE6FFE8-FFEEFFFCFFFD",
Sm: "002B003C-003E007C007E00AC00B100D700F703F60606-060820442052207A-207C208A-208C2140-2144214B2190-2194219A219B21A021A321A621AE21CE21CF21D221D421F4-22FF2308-230B23202321237C239B-23B323DC-23E125B725C125F8-25FF266F27C0-27C427C7-27CA27CC27D0-27E527F0-27FF2900-29822999-29D729DC-29FB29FE-2AFF2B30-2B442B47-2B4CFB29FE62FE64-FE66FF0BFF1C-FF1EFF5CFF5EFFE2FFE9-FFEC",
Sc: "002400A2-00A5060B09F209F309FB0AF10BF90E3F17DB20A0-20B8A838FDFCFE69FF04FFE0FFE1FFE5FFE6",
Sk: "005E006000A800AF00B400B802C2-02C502D2-02DF02E5-02EB02ED02EF-02FF0375038403851FBD1FBF-1FC11FCD-1FCF1FDD-1FDF1FED-1FEF1FFD1FFE309B309CA700-A716A720A721A789A78AFF3EFF40FFE3",
So: "00A600A700A900AE00B000B60482060E060F06E906FD06FE07F609FA0B700BF3-0BF80BFA0C7F0CF10CF20D790F01-0F030F13-0F170F1A-0F1F0F340F360F380FBE-0FC50FC7-0FCC0FCE0FCF0FD5-0FD8109E109F13601390-1399194019E0-19FF1B61-1B6A1B74-1B7C210021012103-21062108210921142116-2118211E-2123212521272129212E213A213B214A214C214D214F2195-2199219C-219F21A121A221A421A521A7-21AD21AF-21CD21D021D121D321D5-21F32300-2307230C-231F2322-2328232B-237B237D-239A23B4-23DB23E2-23E82400-24262440-244A249C-24E92500-25B625B8-25C025C2-25F72600-266E2670-26CD26CF-26E126E326E8-26FF2701-27042706-2709270C-27272729-274B274D274F-27522756-275E2761-276727942798-27AF27B1-27BE2800-28FF2B00-2B2F2B452B462B50-2B592CE5-2CEA2E80-2E992E9B-2EF32F00-2FD52FF0-2FFB300430123013302030363037303E303F319031913196-319F31C0-31E33200-321E322A-32503260-327F328A-32B032C0-32FE3300-33FF4DC0-4DFFA490-A4C6A828-A82BA836A837A839AA77-AA79FDFDFFE4FFE8FFEDFFEEFFFCFFFD",
Z: "002000A01680180E2000-200A20282029202F205F3000",
Zs: "002000A01680180E2000-200A202F205F3000",
Zl: "2028",
Zp: "2029",
C: "0000-001F007F-009F00AD03780379037F-0383038B038D03A20526-05300557055805600588058B-059005C8-05CF05EB-05EF05F5-0605061C061D0620065F06DD070E070F074B074C07B2-07BF07FB-07FF082E082F083F-08FF093A093B094F095609570973-097809800984098D098E0991099209A909B109B3-09B509BA09BB09C509C609C909CA09CF-09D609D8-09DB09DE09E409E509FC-0A000A040A0B-0A0E0A110A120A290A310A340A370A3A0A3B0A3D0A43-0A460A490A4A0A4E-0A500A52-0A580A5D0A5F-0A650A76-0A800A840A8E0A920AA90AB10AB40ABA0ABB0AC60ACA0ACE0ACF0AD1-0ADF0AE40AE50AF00AF2-0B000B040B0D0B0E0B110B120B290B310B340B3A0B3B0B450B460B490B4A0B4E-0B550B58-0B5B0B5E0B640B650B72-0B810B840B8B-0B8D0B910B96-0B980B9B0B9D0BA0-0BA20BA5-0BA70BAB-0BAD0BBA-0BBD0BC3-0BC50BC90BCE0BCF0BD1-0BD60BD8-0BE50BFB-0C000C040C0D0C110C290C340C3A-0C3C0C450C490C4E-0C540C570C5A-0C5F0C640C650C70-0C770C800C810C840C8D0C910CA90CB40CBA0CBB0CC50CC90CCE-0CD40CD7-0CDD0CDF0CE40CE50CF00CF3-0D010D040D0D0D110D290D3A-0D3C0D450D490D4E-0D560D58-0D5F0D640D650D76-0D780D800D810D840D97-0D990DB20DBC0DBE0DBF0DC7-0DC90DCB-0DCE0DD50DD70DE0-0DF10DF5-0E000E3B-0E3E0E5C-0E800E830E850E860E890E8B0E8C0E8E-0E930E980EA00EA40EA60EA80EA90EAC0EBA0EBE0EBF0EC50EC70ECE0ECF0EDA0EDB0EDE-0EFF0F480F6D-0F700F8C-0F8F0F980FBD0FCD0FD9-0FFF10C6-10CF10FD-10FF1249124E124F12571259125E125F1289128E128F12B112B612B712BF12C112C612C712D7131113161317135B-135E137D-137F139A-139F13F5-13FF169D-169F16F1-16FF170D1715-171F1737-173F1754-175F176D17711774-177F17B417B517DE17DF17EA-17EF17FA-17FF180F181A-181F1878-187F18AB-18AF18F6-18FF191D-191F192C-192F193C-193F1941-1943196E196F1975-197F19AC-19AF19CA-19CF19DB-19DD1A1C1A1D1A5F1A7D1A7E1A8A-1A8F1A9A-1A9F1AAE-1AFF1B4C-1B4F1B7D-1B7F1BAB-1BAD1BBA-1BFF1C38-1C3A1C4A-1C4C1C80-1CCF1CF3-1CFF1DE7-1DFC1F161F171F1E1F1F1F461F471F4E1F4F1F581F5A1F5C1F5E1F7E1F7F1FB51FC51FD41FD51FDC1FF01FF11FF51FFF200B-200F202A-202E2060-206F20722073208F2095-209F20B9-20CF20F1-20FF218A-218F23E9-23FF2427-243F244B-245F26CE26E226E4-26E727002705270A270B2728274C274E2753-2755275F27602795-279727B027BF27CB27CD-27CF2B4D-2B4F2B5A-2BFF2C2F2C5F2CF2-2CF82D26-2D2F2D66-2D6E2D70-2D7F2D97-2D9F2DA72DAF2DB72DBF2DC72DCF2DD72DDF2E32-2E7F2E9A2EF4-2EFF2FD6-2FEF2FFC-2FFF3040309730983100-3104312E-3130318F31B8-31BF31E4-31EF321F32FF4DB6-4DBF9FCC-9FFFA48D-A48FA4C7-A4CFA62C-A63FA660A661A674-A67BA698-A69FA6F8-A6FFA78D-A7FAA82C-A82FA83A-A83FA878-A87FA8C5-A8CDA8DA-A8DFA8FC-A8FFA954-A95EA97D-A97FA9CEA9DA-A9DDA9E0-A9FFAA37-AA3FAA4EAA4FAA5AAA5BAA7C-AA7FAAC3-AADAAAE0-ABBFABEEABEFABFA-ABFFD7A4-D7AFD7C7-D7CAD7FC-F8FFFA2EFA2FFA6EFA6FFADA-FAFFFB07-FB12FB18-FB1CFB37FB3DFB3FFB42FB45FBB2-FBD2FD40-FD4FFD90FD91FDC8-FDEFFDFEFDFFFE1A-FE1FFE27-FE2FFE53FE67FE6C-FE6FFE75FEFD-FF00FFBF-FFC1FFC8FFC9FFD0FFD1FFD8FFD9FFDD-FFDFFFE7FFEF-FFFBFFFEFFFF",
Cc: "0000-001F007F-009F",
Cf: "00AD0600-060306DD070F17B417B5200B-200F202A-202E2060-2064206A-206FFEFFFFF9-FFFB",
Co: "E000-F8FF",
Cs: "D800-DFFF",
Cn: "03780379037F-0383038B038D03A20526-05300557055805600588058B-059005C8-05CF05EB-05EF05F5-05FF06040605061C061D0620065F070E074B074C07B2-07BF07FB-07FF082E082F083F-08FF093A093B094F095609570973-097809800984098D098E0991099209A909B109B3-09B509BA09BB09C509C609C909CA09CF-09D609D8-09DB09DE09E409E509FC-0A000A040A0B-0A0E0A110A120A290A310A340A370A3A0A3B0A3D0A43-0A460A490A4A0A4E-0A500A52-0A580A5D0A5F-0A650A76-0A800A840A8E0A920AA90AB10AB40ABA0ABB0AC60ACA0ACE0ACF0AD1-0ADF0AE40AE50AF00AF2-0B000B040B0D0B0E0B110B120B290B310B340B3A0B3B0B450B460B490B4A0B4E-0B550B58-0B5B0B5E0B640B650B72-0B810B840B8B-0B8D0B910B96-0B980B9B0B9D0BA0-0BA20BA5-0BA70BAB-0BAD0BBA-0BBD0BC3-0BC50BC90BCE0BCF0BD1-0BD60BD8-0BE50BFB-0C000C040C0D0C110C290C340C3A-0C3C0C450C490C4E-0C540C570C5A-0C5F0C640C650C70-0C770C800C810C840C8D0C910CA90CB40CBA0CBB0CC50CC90CCE-0CD40CD7-0CDD0CDF0CE40CE50CF00CF3-0D010D040D0D0D110D290D3A-0D3C0D450D490D4E-0D560D58-0D5F0D640D650D76-0D780D800D810D840D97-0D990DB20DBC0DBE0DBF0DC7-0DC90DCB-0DCE0DD50DD70DE0-0DF10DF5-0E000E3B-0E3E0E5C-0E800E830E850E860E890E8B0E8C0E8E-0E930E980EA00EA40EA60EA80EA90EAC0EBA0EBE0EBF0EC50EC70ECE0ECF0EDA0EDB0EDE-0EFF0F480F6D-0F700F8C-0F8F0F980FBD0FCD0FD9-0FFF10C6-10CF10FD-10FF1249124E124F12571259125E125F1289128E128F12B112B612B712BF12C112C612C712D7131113161317135B-135E137D-137F139A-139F13F5-13FF169D-169F16F1-16FF170D1715-171F1737-173F1754-175F176D17711774-177F17DE17DF17EA-17EF17FA-17FF180F181A-181F1878-187F18AB-18AF18F6-18FF191D-191F192C-192F193C-193F1941-1943196E196F1975-197F19AC-19AF19CA-19CF19DB-19DD1A1C1A1D1A5F1A7D1A7E1A8A-1A8F1A9A-1A9F1AAE-1AFF1B4C-1B4F1B7D-1B7F1BAB-1BAD1BBA-1BFF1C38-1C3A1C4A-1C4C1C80-1CCF1CF3-1CFF1DE7-1DFC1F161F171F1E1F1F1F461F471F4E1F4F1F581F5A1F5C1F5E1F7E1F7F1FB51FC51FD41FD51FDC1FF01FF11FF51FFF2065-206920722073208F2095-209F20B9-20CF20F1-20FF218A-218F23E9-23FF2427-243F244B-245F26CE26E226E4-26E727002705270A270B2728274C274E2753-2755275F27602795-279727B027BF27CB27CD-27CF2B4D-2B4F2B5A-2BFF2C2F2C5F2CF2-2CF82D26-2D2F2D66-2D6E2D70-2D7F2D97-2D9F2DA72DAF2DB72DBF2DC72DCF2DD72DDF2E32-2E7F2E9A2EF4-2EFF2FD6-2FEF2FFC-2FFF3040309730983100-3104312E-3130318F31B8-31BF31E4-31EF321F32FF4DB6-4DBF9FCC-9FFFA48D-A48FA4C7-A4CFA62C-A63FA660A661A674-A67BA698-A69FA6F8-A6FFA78D-A7FAA82C-A82FA83A-A83FA878-A87FA8C5-A8CDA8DA-A8DFA8FC-A8FFA954-A95EA97D-A97FA9CEA9DA-A9DDA9E0-A9FFAA37-AA3FAA4EAA4FAA5AAA5BAA7C-AA7FAAC3-AADAAAE0-ABBFABEEABEFABFA-ABFFD7A4-D7AFD7C7-D7CAD7FC-D7FFFA2EFA2FFA6EFA6FFADA-FAFFFB07-FB12FB18-FB1CFB37FB3DFB3FFB42FB45FBB2-FBD2FD40-FD4FFD90FD91FDC8-FDEFFDFEFDFFFE1A-FE1FFE27-FE2FFE53FE67FE6C-FE6FFE75FEFDFEFEFF00FFBF-FFC1FFC8FFC9FFD0FFD1FFD8FFD9FFDD-FFDFFFE7FFEF-FFF8FFFEFFFF"
});
function addUnicodePackage (pack) {
var codePoint = /\w{4}/g;
for (var name in pack)
exports.packages[name] = pack[name].replace(codePoint, "\\u$&");
};
});

View file

@ -121,6 +121,20 @@ var VirtualRenderer = function(container, theme) {
scrollerWidth: 0
};
this.layerConfig = {
width : 1,
padding : 0,
firstRow : 0,
firstRowScreen: 0,
lastRow : 0,
lineHeight : 1,
characterWidth : 1,
minHeight : 1,
maxHeight : 1,
offset : 0,
height : 1
};
this.$loop = new RenderLoop(this.$renderChanges.bind(this));
this.$loop.schedule(this.CHANGE_FULL);
@ -332,39 +346,36 @@ var VirtualRenderer = function(container, theme) {
return;
var bounds = this.content.getBoundingClientRect();
var offset = (this.layerConfig && this.layerConfig.offset) || 0;
var offset = this.layerConfig.offset;
textarea.style.left = (bounds.left + pos.left + this.$padding) + "px";
textarea.style.top = (bounds.top + pos.top - this.scrollTop + offset) + "px";
};
this.getFirstVisibleRow = function() {
return (this.layerConfig || {}).firstRow || 0;
return this.layerConfig.firstRow;
};
this.getFirstFullyVisibleRow = function(){
if (!this.layerConfig)
return 0;
this.getFirstFullyVisibleRow = function() {
return this.layerConfig.firstRow + (this.layerConfig.offset === 0 ? 0 : 1);
};
this.getLastFullyVisibleRow = function() {
if (!this.layerConfig)
return 0;
var flint = Math.floor((this.layerConfig.height + this.layerConfig.offset) / this.layerConfig.lineHeight);
return this.layerConfig.firstRow - 1 + flint;
};
this.getLastVisibleRow = function() {
return (this.layerConfig || {}).lastRow || 0;
return this.layerConfig.lastRow;
};
this.$padding = null;
this.setPadding = function(padding) {
this.$padding = padding;
this.content.style.padding = "0 " + padding + "px";
this.$textLayer.setPadding(padding);
this.$cursorLayer.setPadding(padding);
this.$markerFront.setPadding(padding);
this.$markerBack.setPadding(padding);
this.$loop.schedule(this.CHANGE_FULL);
this.$updatePrintMargin();
};
@ -395,8 +406,7 @@ var VirtualRenderer = function(container, theme) {
return;
// text, scrolling and resize changes can cause the view port size to change
if (!this.layerConfig ||
changes & this.CHANGE_FULL ||
if (changes & this.CHANGE_FULL ||
changes & this.CHANGE_SIZE ||
changes & this.CHANGE_TEXT ||
changes & this.CHANGE_LINES ||
@ -469,7 +479,7 @@ var VirtualRenderer = function(container, theme) {
var minHeight = this.$size.scrollerHeight + this.lineHeight;
var longestLine = this.$getLongestLine();
var widthChanged = !this.layerConfig ? true : (this.layerConfig.width != longestLine);
var widthChanged = this.layerConfig.width != longestLine;
var horizScroll = this.$horizScrollAlwaysVisible || this.$size.scrollerWidth - longestLine < 0;
var horizScrollChanged = this.$horizScroll !== horizScroll;
@ -570,7 +580,7 @@ var VirtualRenderer = function(container, theme) {
if (this.$textLayer.showInvisibles)
charCount += 1;
return Math.max(this.$size.scrollerWidth - this.$padding * 2, Math.round(charCount * this.characterWidth));
return Math.max(this.$size.scrollerWidth, Math.round(charCount * this.characterWidth));
};
this.updateFrontMarkers = function() {

View file

@ -1,5 +1,5 @@
define(function(require, exports, module) {
/*
/*!
* JSHint, by JSHint Community.
*
* Licensed under the same slightly modified MIT license that JSLint is.
@ -152,7 +152,8 @@ define(function(require, exports, module) {
*/
/*jshint
evil: true, nomen: false, onevar: false, regexp: false, strict: true, boss: true
evil: true, nomen: false, onevar: false, regexp: false, strict: true, boss: true,
undef: true, maxlen: 100
*/
/*members "\b", "\t", "\n", "\f", "\r", "!=", "!==", "\"", "%", "(begin)",
@ -186,13 +187,14 @@ define(function(require, exports, module) {
close, closed, closure, comment, condition, confirm, console, constructor,
content, couch, create, css, curly, d, data, datalist, dd, debug, decodeURI,
decodeURIComponent, defaultStatus, defineClass, deserialize, devel, document,
edition, else, emit, encodeURI, encodeURIComponent, entityify, eqeqeq, eqnull,
errors, es5, escape, eval, event, evidence, evil, ex, exception, exec, exps,
expr, exports, FileReader, first, floor, focus, forin, fragment, frames, from,
fromCharCode, fud, funct, function, functions, g, gc, getComputedStyle, getRow,
GLOBAL, global, globals, globalstrict, hasOwnProperty, help, history, i, id,
identifier, immed, implieds, include, indent, indexOf, init, ins, instanceOf,
isAlpha, isApplicationRunning, isArray, isDigit, isFinite, isNaN, join, jshint,
dojo, dijit, dojox, define, edition, else, emit, encodeURI, encodeURIComponent,
entityify, eqeqeq, eqnull, errors, es5, escape, eval, event, evidence, evil,
ex, exception, exec, exps, expr, exports, FileReader, first, floor, focus,
forin, fragment, frames, from, fromCharCode, fud, funct, function, functions,
g, gc, getComputedStyle, getRow, GLOBAL, global, globals, globalstrict,
hasOwnProperty, help, history, i, id, identifier, immed, implieds, include,
indent, indexOf, init, ins, instanceOf, isAlpha, isApplicationRunning, isArray,
isDigit, isFinite, isNaN, iterator, join, jshint,
JSHINT, json, jquery, jQuery, keys, label, labelled, last, lastsemic, laxbreak,
latedef, lbp, led, left, length, line, load, loadClass, localStorage, location,
log, loopfunc, m, match, maxerr, maxlen, member,message, meta, module, moveBy,
@ -200,10 +202,10 @@ define(function(require, exports, module) {
nonew, nud, onbeforeunload, onblur, onerror, onevar, onfocus, onload, onresize,
onunload, open, openDatabase, openURL, opener, opera, outer, param, parent,
parseFloat, parseInt, passfail, plusplus, predef, print, process, prompt,
prototype, prototypejs, push, quit, range, raw, reach, reason, regexp,
proto, prototype, prototypejs, push, quit, range, raw, reach, reason, regexp,
readFile, readUrl, regexdash, removeEventListener, replace, report, require,
reserved, resizeBy, resizeTo, resolvePath, resumeUpdates, respond, rhino, right,
runCommand, scroll, screen, scrollBy, scrollTo, scrollbar, search, seal, send,
runCommand, scroll, screen, scripturl, scrollBy, scrollTo, scrollbar, search, seal, send,
serialize, setInterval, setTimeout, shift, slice, sort,spawn, split, stack,
status, start, strict, sub, substr, supernew, shadow, supplant, sum, sync,
test, toLowerCase, toString, toUpperCase, toint32, token, top, trailing, type,
@ -247,9 +249,10 @@ var JSHINT = (function () {
boss : true, // if advanced usage of assignments should be allowed
browser : true, // if the standard browser globals should be predefined
couch : true, // if CouchDB globals should be predefined
curly : true, // if curly braces around blocks should be required (even in if/for/while)
curly : true, // if curly braces around all blocks should be required
debug : true, // if debugger statements should be allowed
devel : true, // if logging globals should be predefined (console, alert, etc.)
dojo : true, // if Dojo Toolkit globals should be predefined
eqeqeq : true, // if === should be required
eqnull : true, // if == null comparisons should be tolerated
es5 : true, // if ES5 syntax should be allowed
@ -258,6 +261,7 @@ var JSHINT = (function () {
forin : true, // if for in statements must filter
globalstrict: true, // if global "use strict"; should be allowed (also enables 'strict')
immed : true, // if immediate invocations must be wrapped in parens
iterator : true, // if the `__iterator__` property should be disallowed
jquery : true, // if jQuery globals should be predefined
latedef : true, // if the use before definition should not be tolerated
laxbreak : true, // if line breaks should not be checked
@ -272,18 +276,22 @@ var JSHINT = (function () {
onevar : true, // if only one var statement per function should be allowed
passfail : true, // if the scan should stop on first error
plusplus : true, // if increment/decrement should not be allowed
proto : true, // if the `__proto__` property should be disallowed
prototypejs : true, // if Prototype and Scriptaculous globals should be predefined
regexdash : true, // if unescaped last dash (-) inside brackets should be tolerated
regexp : true, // if the . should not be allowed in regexp literals
rhino : true, // if the Rhino environment globals should be predefined
undef : true, // if variables should be declared before used
scripturl : true, // if script-targeted URLs should be tolerated
shadow : true, // if variable shadowing should be tolerated
strict : true, // require the "use strict"; pragma
sub : true, // if all forms of subscript notation are tolerated
supernew : true, // if `new function () { ... };` and `new Object;` should be tolerated
supernew : true, // if `new function () { ... };` and `new Object;`
// should be tolerated
trailing : true, // if trailing whitespace rules apply
white : true, // if strict whitespace rules apply
wsh : true // if the Windows Scripting Host environment globals should be predefined
wsh : true // if the Windows Scripting Host environment globals should
// be predefined
},
// browser contains a set of global names which are commonly provided by a
@ -375,12 +383,20 @@ var JSHINT = (function () {
},
devel = {
alert : false,
confirm : false,
console : false,
Debug : false,
opera : false,
prompt : false
alert : false,
confirm : false,
console : false,
Debug : false,
opera : false,
prompt : false
},
dojo = {
dojo : false,
dijit : false,
dojox : false,
define : false,
"require" : false
},
escapes = {
@ -617,27 +633,38 @@ var JSHINT = (function () {
VBArray : true,
WSH : true,
WScript : true
},
};
// Regular expressions. Some of these are stupidly long.
// Regular expressions. Some of these are stupidly long.
var ax, cx, tx, nx, nxg, lx, ix, jx, ft;
(function () {
/*jshint maxlen:300 */
// unsafe comment or string
ax = /@cc|<\/?|script|\]\s*\]|<\s*!|&lt/i,
// unsafe characters that are silently deleted by one or more browsers
cx = /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/,
// token
tx = /^\s*([(){}\[.,:;'"~\?\]#@]|==?=?|\/(\*(jshint|jslint|members?|global)?|=|\/)?|\*[\/=]?|\+(?:=|\++)?|-(?:=|-+)?|%=?|&[&=]?|\|[|=]?|>>?>?=?|<([\/=!]|\!(\[|--)?|<=?)?|\^=?|\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\.[0-9]*)?([eE][+\-]?[0-9]+)?)/,
// characters in strings that need escapement
nx = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/,
nxg = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
// star slash
lx = /\*\/|\/\*/,
// identifier
ix = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/,
// javascript url
jx = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i,
// catches /* falls through */ comments
ft = /^\s*\/\*\s*falls\sthrough\s*\*\/\s*$/;
// unsafe comment or string
ax = /@cc|<\/?|script|\]\s*\]|<\s*!|&lt/i;
// unsafe characters that are silently deleted by one or more browsers
cx = /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/;
// token
tx = /^\s*([(){}\[.,:;'"~\?\]#@]|==?=?|\/(\*(jshint|jslint|members?|global)?|=|\/)?|\*[\/=]?|\+(?:=|\++)?|-(?:=|-+)?|%=?|&[&=]?|\|[|=]?|>>?>?=?|<([\/=!]|\!(\[|--)?|<=?)?|\^=?|\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\.[0-9]*)?([eE][+\-]?[0-9]+)?)/;
// characters in strings that need escapement
nx = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/;
nxg = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
// star slash
lx = /\*\/|\/\*/;
// identifier
ix = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/;
// javascript url
jx = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i;
// catches /* falls through */ comments
ft = /^\s*\/\*\s*falls\sthrough\s*\*\/\s*$/;
}());
function F() {} // Used by Object.create
@ -760,6 +787,9 @@ var JSHINT = (function () {
if (option.devel)
combine(predefined, devel);
if (option.dojo)
combine(predefined, dojo);
if (option.browser)
combine(predefined, browser);
@ -875,7 +905,7 @@ var JSHINT = (function () {
// Check for trailing whitespaces
tw = s.search(/\s+$/);
if (option.trailing && ~tw)
if (option.trailing && ~tw && !~s.search(/^\s+$/))
warningAt("Trailing whitespace.", line, tw);
return true;
@ -895,17 +925,19 @@ var JSHINT = (function () {
}
t = Object.create(t);
if (type === '(string)' || type === '(range)') {
if (jx.test(value)) {
if (!option.scripturl && jx.test(value)) {
warningAt("Script URL.", line, from);
}
}
if (type === '(identifier)') {
t.identifier = true;
if (value === '__iterator__' || value === '__proto__') {
errorAt("Reserved name '{a}'.",
if (value === '__proto__' && !option.proto) {
warningAt("The '{a}' property is deprecated.",
line, from, value);
} else if (option.nomen &&
(value.charAt(0) === '_' ||
} else if (value === '__iterator__' && !option.iterator) {
warningAt("'{a}' is only available in JavaScript 1.7.",
line, from, value);
} else if (option.nomen && (value.charAt(0) === '_' ||
value.charAt(value.length - 1) === '_')) {
warningAt("Unexpected {a} in '{b}'.", line, from,
"dangling '_'", value);
@ -2141,12 +2173,14 @@ loop: for (;;) {
if (!t.block) {
if (!option.expr && (!r || !r.exps)) {
warning("Expected an assignment or function call and instead saw an expression.", token);
warning("Expected an assignment or function call and instead saw an expression.",
token);
} else if (option.nonew && r.id === '(' && r.left.id === 'new') {
warning("Do not use 'new' for side effects.");
}
if (nexttoken.id !== ';') {
if (!option.asi && !(option.lastsemic && nexttoken.id == '}' && nexttoken.line == token.line)) {
if (!option.asi && !(option.lastsemic && nexttoken.id == '}' &&
nexttoken.line == token.line)) {
warningAt("Missing semicolon.", token.line, token.from + token.value.length);
}
} else {
@ -2509,7 +2543,10 @@ loop: for (;;) {
});
relation('===');
relation('!=', function (left, right) {
if (option.eqeqeq) {
var eqnull = option.eqnull &&
(left.value == 'null' || right.value == 'null');
if (!eqnull && option.eqeqeq) {
warning("Expected '{a}' and instead saw '{b}'.",
this, '!==', '!=');
} else if (isPoorRelation(left)) {
@ -2536,7 +2573,7 @@ loop: for (;;) {
if (left && right && left.id === '(string)' && right.id === '(string)') {
left.value += right.value;
left.character = right.character;
if (jx.test(left.value)) {
if (!option.scripturl && jx.test(left.value)) {
warning("JavaScript URL.", left);
}
return left;
@ -2637,7 +2674,8 @@ loop: for (;;) {
if (c.id !== 'function') {
i = c.value.substr(0, 1);
if (option.newcap && (i < 'A' || i > 'Z')) {
warning("A constructor name should start with an uppercase letter.", token);
warning("A constructor name should start with "+
"an uppercase letter.", token);
}
}
}
@ -3043,8 +3081,9 @@ loop: for (;;) {
blockstmt('function', function () {
if (inblock) {
warning(
"Function declarations should not be placed in blocks. Use a function expression or move the statement to the top of the outer function.", token);
warning("Function declarations should not be placed in blocks. " +
"Use a function expression or move the statement to the top of " +
"the outer function.", token);
}
var i = identifier();
@ -3318,7 +3357,8 @@ loop: for (;;) {
s = block(true, true);
if (option.forin && (s.length > 1 || typeof s[0] !== 'object' ||
s[0].value !== 'if')) {
warning("The body of a for in should be wrapped in an if statement to filter unwanted properties from the prototype.", this);
warning("The body of a for in should be wrapped in an if statement to filter " +
"unwanted properties from the prototype.", this);
}
funct['(breakage)'] -= 1;
funct['(loopage)'] -= 1;
@ -3487,8 +3527,10 @@ loop: for (;;) {
if (o[nexttoken.value] === true) {
warning("Duplicate key '{a}'.",
nexttoken, nexttoken.value);
} else if (nexttoken.value === '__proto__') {
warning("Stupid key '{a}'.",
} else if ((nexttoken.value === '__proto__' &&
!option.proto) || (nexttoken.value === '__iterator__' &&
!option.iterator)) {
warning("The '{a}' key may produce unexpected results.",
nexttoken, nexttoken.value);
} else {
o[nexttoken.value] = true;
@ -3574,7 +3616,7 @@ loop: for (;;) {
} else if (typeof a === 'object') {
k = Object.keys(a);
for (i = 0; i < k.length; i += 1) {
predefined[k[i]] = !!a[k];
predefined[k[i]] = !!a[k[i]];
}
}
}
@ -3871,5 +3913,5 @@ loop: for (;;) {
// Make JSHINT a Node module, if possible.
if (typeof exports == 'object' && exports)
exports.JSHINT = JSHINT;
});

View file

@ -49,13 +49,15 @@ var WorkerClient = function(topLevelNamespaces, packagedJs, module, classname) {
var worker = this.$worker = new Worker(base + packagedJs);
}
else {
var workerUrl = require.nameToUrl("ace/worker/worker", null, "_");
var workerUrl = this.$normalizePath(require.nameToUrl("ace/worker/worker", null, "_"));
var worker = this.$worker = new Worker(workerUrl);
var tlns = {};
for (var i=0; i<topLevelNamespaces.length; i++) {
var ns = topLevelNamespaces[i];
tlns[ns] = require.nameToUrl(ns, null, "_").replace(/.js$/, "");
var path = this.$normalizePath(require.nameToUrl(ns, null, "_").replace(/.js$/, ""));
tlns[ns] = path;
}
}
@ -100,20 +102,31 @@ var WorkerClient = function(topLevelNamespaces, packagedJs, module, classname) {
oop.implement(this, EventEmitter);
this.$normalizePath = function(path) {
if (!path.match(/^\w+:/))
path = location.protocol + "//" + location.host + location.pathname.replace(/\/.*?$/, "/") + "/" + path;
return path;
};
this.$guessBasePath = function() {
if (require.aceBaseUrl)
return require.aceBaseUrl;
var scripts = document.getElementsByTagName("script");
for (var i=0; i<scripts.length; i++) {
var src = scripts[i].src || scripts[i].getAttribute("src");
var script = scripts[i];
var base = script.getAttribute("data-ace-base");
if (base)
return base.replace(/\/*$/, "/");
var src = script.src || script.getAttribute("src");
if (!src) {
continue;
}
var m = src.match(/^(?:(.*\/)ace\.js|(.*\/)ace-uncompressed\.js)(?:\?|$)/);
if (m) {
if (m)
return m[1] || m[2];
}
}
return "";
};