move source files into ace folder
This commit is contained in:
parent
41e4b133ba
commit
5fd3cd3f20
25 changed files with 24 additions and 24 deletions
|
|
@ -40,30 +40,30 @@
|
|||
<link rel="stylesheet" href="../css/editor.css" type="text/css" charset="utf-8">
|
||||
<link rel="stylesheet" href="../css/tm.css" type="text/css" charset="utf-8">
|
||||
|
||||
<script src="../src/ace.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/mode/Text.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/mode/JavaScript.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/mode/JavaScriptHighlightRules.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/mode/Html.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/mode/HtmlHighlightRules.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/mode/Css.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/mode/CssHighlightRules.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/mode/Xml.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/mode/XmlHighlightRules.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/MEventEmitter.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/Selection.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/Document.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/Tokenizer.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/BackgroundTokenizer.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/layer/Cursor.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/layer/Gutter.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/layer/Text.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/layer/Marker.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/ScrollBar.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/TextInput.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/KeyBinding.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/Editor.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/VirtualRenderer.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/ace/ace.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/ace/mode/Text.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/ace/mode/JavaScript.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/ace/mode/JavaScriptHighlightRules.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/ace/mode/Html.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/ace/mode/HtmlHighlightRules.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/ace/mode/Css.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/ace/mode/CssHighlightRules.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/ace/mode/Xml.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/ace/mode/XmlHighlightRules.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/ace/MEventEmitter.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/ace/Selection.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/ace/Document.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/ace/Tokenizer.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/ace/BackgroundTokenizer.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/ace/layer/Cursor.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/ace/layer/Gutter.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/ace/layer/Text.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/ace/layer/Marker.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/ace/ScrollBar.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/ace/TextInput.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/ace/KeyBinding.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/ace/Editor.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../src/ace/VirtualRenderer.js" type="text/javascript" charset="utf-8"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
|
|
|||
107
src/ace/BackgroundTokenizer.js
Normal file
107
src/ace/BackgroundTokenizer.js
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
ace.provide("ace.BackgroundTokenizer");
|
||||
|
||||
ace.BackgroundTokenizer = function(tokenizer) {
|
||||
this.running = false;
|
||||
this.textLines = [];
|
||||
this.lines = [];
|
||||
this.currentLine = 0;
|
||||
this.tokenizer = tokenizer;
|
||||
|
||||
var self = this;
|
||||
this.$worker = function() {
|
||||
if (!self.running) { return; }
|
||||
|
||||
var workerStart = new Date();
|
||||
var startLine = self.currentLine;
|
||||
var textLines = self.textLines;
|
||||
|
||||
var processedLines = 0;
|
||||
|
||||
while (self.currentLine < textLines.length) {
|
||||
var line = textLines[self.currentLine];
|
||||
|
||||
var state = self.currentLine == 0 ? "start"
|
||||
: self.lines[self.currentLine - 1].state;
|
||||
self.lines[self.currentLine] = self.tokenizer.getLineTokens(line, state);
|
||||
|
||||
// only check every 30 lines
|
||||
processedLines += 1;
|
||||
if ((processedLines % 30 == 0) && (new Date() - workerStart) > 20) {
|
||||
self.fireUpdateEvent(startLine, self.currentLine);
|
||||
return setTimeout(self.$worker, 10);
|
||||
}
|
||||
|
||||
self.currentLine++;
|
||||
}
|
||||
|
||||
self.running = false;
|
||||
|
||||
self.fireUpdateEvent(startLine, textLines.length - 1);
|
||||
};
|
||||
|
||||
this.$initEvents();
|
||||
};
|
||||
|
||||
(function(){
|
||||
|
||||
ace.implement(this, ace.MEventEmitter);
|
||||
|
||||
this.setTokenizer = function(tokenizer) {
|
||||
this.tokenizer = tokenizer;
|
||||
this.lines = [];
|
||||
|
||||
this.start(0);
|
||||
};
|
||||
|
||||
this.setLines = function(textLines) {
|
||||
this.textLines = textLines;
|
||||
this.lines = [];
|
||||
|
||||
this.stop();
|
||||
};
|
||||
|
||||
this.fireUpdateEvent = function(firstRow, lastRow) {
|
||||
var data = {
|
||||
first: firstRow,
|
||||
last: lastRow
|
||||
};
|
||||
this.$dispatchEvent("update", {data: data});
|
||||
};
|
||||
|
||||
this.start = function(startRow) {
|
||||
this.currentLine = Math.min(startRow || 0, this.currentLine,
|
||||
this.textLines.length);
|
||||
|
||||
this.lines.splice(this.currentLine, this.lines.length);
|
||||
|
||||
if (!this.running) {
|
||||
clearTimeout(this.running);
|
||||
// pretty long delay to prevent the tokenizer from interfering with the user
|
||||
this.running = setTimeout(this.$worker, 200);
|
||||
}
|
||||
};
|
||||
|
||||
this.stop = function() {
|
||||
this.running = false;
|
||||
};
|
||||
|
||||
this.getTokens = function(row) {
|
||||
return this.$tokenizeRow(row).tokens;
|
||||
};
|
||||
|
||||
this.getState = function(row) {
|
||||
return this.$tokenizeRow(row).state;
|
||||
};
|
||||
|
||||
this.$tokenizeRow = function(row) {
|
||||
if (!this.lines[row]) {
|
||||
var state = "start";
|
||||
if (row > 0 && this.lines[row - 1]) {
|
||||
state = this.lines[row - 1].state;
|
||||
}
|
||||
this.lines[row] = this.tokenizer.getLineTokens(this.textLines[row] || "", state);
|
||||
}
|
||||
return this.lines[row];
|
||||
};
|
||||
|
||||
}).call(ace.BackgroundTokenizer.prototype);
|
||||
393
src/ace/Document.js
Normal file
393
src/ace/Document.js
Normal file
|
|
@ -0,0 +1,393 @@
|
|||
ace.provide("ace.Document");
|
||||
|
||||
ace.Document = function(text, mode) {
|
||||
this.$initEvents();
|
||||
|
||||
this.lines = this.$split(text);
|
||||
this.modified = true;
|
||||
this.selection = new ace.Selection(this);
|
||||
|
||||
this.listeners = [];
|
||||
if (mode) {
|
||||
this.setMode(mode);
|
||||
}
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
ace.implement(this, ace.MEventEmitter);
|
||||
|
||||
this.$split = function(text) {
|
||||
return text.split(/\r\n|\r|\n/);
|
||||
};
|
||||
|
||||
this.toString = function() {
|
||||
return this.lines.join("\n");
|
||||
};
|
||||
|
||||
this.getSelection = function() {
|
||||
return this.selection;
|
||||
};
|
||||
|
||||
this.fireChangeEvent = function(firstRow, lastRow) {
|
||||
var data = {
|
||||
firstRow: firstRow,
|
||||
lastRow: lastRow
|
||||
};
|
||||
this.$dispatchEvent("change", { data: data});
|
||||
};
|
||||
|
||||
this.getTabString = function() {
|
||||
if (this.getUseSoftTabs()) {
|
||||
return new Array(this.getTabSize()+1).join(" ");
|
||||
} else {
|
||||
return "\t";
|
||||
}
|
||||
};
|
||||
|
||||
this.$useSoftTabs = false;
|
||||
this.setUseSoftTabs = function(useSoftTabs) {
|
||||
if (this.$useSoftTabs === useSoftTabs) return;
|
||||
|
||||
this.$useSoftTabs = useSoftTabs;
|
||||
};
|
||||
|
||||
this.getUseSoftTabs = function() {
|
||||
return this.$useSoftTabs;
|
||||
};
|
||||
|
||||
this.$tabSize = 4;
|
||||
this.setTabSize = function(tabSize) {
|
||||
if (this.$tabSize === tabSize) return;
|
||||
|
||||
this.$tabSize = tabSize;
|
||||
this.$dispatchEvent("changeTabSize");
|
||||
};
|
||||
|
||||
this.getTabSize = function() {
|
||||
return this.$tabSize;
|
||||
};
|
||||
|
||||
this.$mode = null;
|
||||
this.setMode = function(mode) {
|
||||
if (this.$mode === mode) return;
|
||||
|
||||
this.$mode = mode;
|
||||
this.$dispatchEvent("changeMode");
|
||||
};
|
||||
|
||||
this.getMode = function() {
|
||||
if (!this.$mode) {
|
||||
this.$mode = new ace.mode.Text();
|
||||
}
|
||||
return this.$mode;
|
||||
};
|
||||
|
||||
this.$scrollTop = 0;
|
||||
this.setScrollTopRow = function(scrollTopRow) {
|
||||
if (this.$scrollTop === scrollTopRow) return;
|
||||
|
||||
this.$scrollTop = scrollTopRow;
|
||||
this.$dispatchEvent("changeScrollTop");
|
||||
};
|
||||
|
||||
this.getScrollTopRow = function() {
|
||||
return this.$scrollTop;
|
||||
};
|
||||
|
||||
this.getWidth = function() {
|
||||
if (this.modified) {
|
||||
this.modified = false;
|
||||
|
||||
var lines = this.lines;
|
||||
var longestLine = 0;
|
||||
for ( var i = 0; i < lines.length; i++) {
|
||||
longestLine = Math.max(longestLine, lines[i].length);
|
||||
}
|
||||
this.width = longestLine;
|
||||
}
|
||||
return this.width;
|
||||
};
|
||||
|
||||
this.getLine = function(row) {
|
||||
return this.lines[row] || "";
|
||||
};
|
||||
|
||||
this.getLength = function() {
|
||||
return this.lines.length;
|
||||
};
|
||||
|
||||
this.getTextRange = function(range) {
|
||||
if (range.start.row == range.end.row) {
|
||||
return this.lines[range.start.row].substring(range.start.column,
|
||||
range.end.column);
|
||||
}
|
||||
else {
|
||||
var lines = [];
|
||||
lines.push(this.lines[range.start.row].substring(range.start.column));
|
||||
lines.push.apply(lines, this.getLines(range.start.row+1, range.end.row-1));
|
||||
lines.push(this.lines[range.end.row].substring(0, range.end.column));
|
||||
return lines.join("\n");
|
||||
}
|
||||
};
|
||||
|
||||
this.getLines = function(firstRow, lastRow) {
|
||||
return this.lines.slice(firstRow, lastRow+1);
|
||||
};
|
||||
|
||||
this.findMatchingBracket = function(position) {
|
||||
if (position.column == 0) return null;
|
||||
|
||||
var charBeforeCursor = this.getLine(position.row).charAt(position.column-1);
|
||||
if (charBeforeCursor == "") return null;
|
||||
|
||||
var match = charBeforeCursor.match(/([\(\[\{])|([\)\]\}])/);
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (match[1]) {
|
||||
return this.$findClosingBracket(match[1], position);
|
||||
} else {
|
||||
return this.$findOpeningBracket(match[2], position);
|
||||
}
|
||||
};
|
||||
|
||||
this.$brackets = {
|
||||
")": "(",
|
||||
"(": ")",
|
||||
"]": "[",
|
||||
"[": "]",
|
||||
"{": "}",
|
||||
"}": "{"
|
||||
};
|
||||
|
||||
this.$findOpeningBracket = function(bracket, position) {
|
||||
var openBracket = this.$brackets[bracket];
|
||||
|
||||
var column = position.column - 2;
|
||||
var row = position.row;
|
||||
var depth = 1;
|
||||
|
||||
var line = this.getLine(row);
|
||||
|
||||
while (true) {
|
||||
while(column >= 0) {
|
||||
var char = line.charAt(column);
|
||||
if (char == openBracket) {
|
||||
depth -= 1;
|
||||
if (depth == 0) {
|
||||
return {row: row, column: column};
|
||||
}
|
||||
}
|
||||
else if (char == bracket) {
|
||||
depth +=1;
|
||||
}
|
||||
column -= 1;
|
||||
}
|
||||
row -=1;
|
||||
if (row < 0) break;
|
||||
|
||||
var line = this.getLine(row);
|
||||
var column = line.length-1;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
this.$findClosingBracket = function(bracket, position) {
|
||||
var closingBracket = this.$brackets[bracket];
|
||||
|
||||
var column = position.column;
|
||||
var row = position.row;
|
||||
var depth = 1;
|
||||
|
||||
var line = this.getLine(row);
|
||||
var lineCount = this.getLength();
|
||||
|
||||
while (true) {
|
||||
while(column < line.length) {
|
||||
var char = line.charAt(column);
|
||||
if (char == closingBracket) {
|
||||
depth -= 1;
|
||||
if (depth == 0) {
|
||||
return {row: row, column: column};
|
||||
}
|
||||
}
|
||||
else if (char == bracket) {
|
||||
depth +=1;
|
||||
}
|
||||
column += 1;
|
||||
}
|
||||
row +=1;
|
||||
if (row >= lineCount) break;
|
||||
|
||||
var line = this.getLine(row);
|
||||
var column = 0;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
this.insert = function(position, text) {
|
||||
var end = this.$insert(position, text);
|
||||
this.fireChangeEvent(position.row, position.row == end.row ? position.row
|
||||
: undefined);
|
||||
return end;
|
||||
};
|
||||
|
||||
this.$insertLines = function(row, lines) {
|
||||
var args = [row, 0];
|
||||
args.push.apply(args, lines);
|
||||
this.lines.splice.apply(this.lines, args);
|
||||
},
|
||||
|
||||
this.$insert = function(position, text) {
|
||||
this.modified = true;
|
||||
|
||||
var newLines = this.$split(text);
|
||||
|
||||
if (this.$isNewLine(text)) {
|
||||
var line = this.lines[position.row] || "";
|
||||
this.lines[position.row] = line.substring(0, position.column);
|
||||
this.lines.splice(position.row + 1, 0, line.substring(position.column));
|
||||
|
||||
return {
|
||||
row : position.row + 1,
|
||||
column : 0
|
||||
};
|
||||
}
|
||||
else if (newLines.length == 1) {
|
||||
var line = this.lines[position.row] || "";
|
||||
this.lines[position.row] = line.substring(0, position.column) + text
|
||||
+ line.substring(position.column);
|
||||
|
||||
return {
|
||||
row : position.row,
|
||||
column : position.column + text.length
|
||||
};
|
||||
}
|
||||
else {
|
||||
var line = this.lines[position.row] || "";
|
||||
|
||||
this.lines[position.row] = line.substring(0, position.column)
|
||||
+ newLines[0];
|
||||
this.lines[position.row + 1] = newLines[newLines.length - 1]
|
||||
+ line.substring(position.column);
|
||||
|
||||
if (newLines.length > 2) {
|
||||
this.$insertLines(position.row + 1, newLines.slice(1, -1));
|
||||
}
|
||||
|
||||
return {
|
||||
row : position.row + newLines.length - 1,
|
||||
column : newLines[newLines.length - 1].length
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
this.$isNewLine = function(text) {
|
||||
return (text == "\r\n" || text == "\r" || text == "\n");
|
||||
};
|
||||
|
||||
this.remove = function(range) {
|
||||
this.$remove(range);
|
||||
|
||||
this.fireChangeEvent(range.start.row,
|
||||
range.end.row == range.start.row ? range.start.row
|
||||
: undefined);
|
||||
return range.start;
|
||||
};
|
||||
|
||||
this.$remove = function(range) {
|
||||
this.modified = true;
|
||||
|
||||
var firstRow = range.start.row;
|
||||
var lastRow = range.end.row;
|
||||
|
||||
var row = this.lines[firstRow].substring(0, range.start.column)
|
||||
+ this.lines[lastRow].substring(range.end.column);
|
||||
|
||||
this.lines.splice(firstRow, lastRow - firstRow + 1, row);
|
||||
|
||||
return range.start;
|
||||
};
|
||||
|
||||
this.replace = function(range, text) {
|
||||
this.$remove(range);
|
||||
if (text) {
|
||||
var end = this.$insert(range.start, text);
|
||||
}
|
||||
else {
|
||||
end = range.start;
|
||||
}
|
||||
|
||||
var lastRemoved = range.end.column == 0 ? range.end.column - 1
|
||||
: range.end.column;
|
||||
this.fireChangeEvent(range.start.row, lastRemoved == end.row ? lastRemoved
|
||||
: undefined);
|
||||
|
||||
return end;
|
||||
};
|
||||
|
||||
this.indentRows = function(range, indentString) {
|
||||
for (var i=range.start.row; i<= range.end.row; i++) {
|
||||
this.lines[i] = indentString + this.getLine(i);
|
||||
}
|
||||
this.fireChangeEvent(range.start.row, range.end.row);
|
||||
return indentString.length;
|
||||
};
|
||||
|
||||
this.outdentRows = function(range, indentString) {
|
||||
outdentLength = indentString.length;
|
||||
|
||||
for (var i=range.start.row; i<= range.end.row; i++) {
|
||||
if (this.getLine(i).substr(0, outdentLength) !== indentString) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (var i=range.start.row; i<= range.end.row; i++) {
|
||||
this.lines[i] = this.getLine(i).substring(outdentLength);
|
||||
}
|
||||
|
||||
this.fireChangeEvent(range.start.row, range.end.row);
|
||||
return -outdentLength;
|
||||
};
|
||||
|
||||
this.moveLinesUp = function(firstRow, lastRow) {
|
||||
if (firstRow <= 0) return 0;
|
||||
|
||||
var removed = this.lines.splice(firstRow, lastRow-firstRow+1);
|
||||
this.$insertLines(firstRow-1, removed);
|
||||
|
||||
this.fireChangeEvent(firstRow-1, lastRow);
|
||||
return -1;
|
||||
};
|
||||
|
||||
this.moveLinesDown = function(firstRow, lastRow) {
|
||||
if (lastRow >= this.lines.length-1) return 0;
|
||||
|
||||
var removed = this.lines.splice(firstRow, lastRow-firstRow+1);
|
||||
this.$insertLines(firstRow+1, removed);
|
||||
|
||||
this.fireChangeEvent(firstRow, lastRow+1);
|
||||
return 1;
|
||||
};
|
||||
|
||||
this.duplicateLines = function(firstRow, lastRow) {
|
||||
var firstRow = this.$clipRowToDocument(firstRow);
|
||||
var lastRow = this.$clipRowToDocument(lastRow);
|
||||
|
||||
var lines = this.getLines(firstRow, lastRow);
|
||||
this.$insertLines(firstRow, lines);
|
||||
|
||||
var addedRows = lastRow - firstRow + 1;
|
||||
this.fireChangeEvent(firstRow, lastRow+addedRows);
|
||||
|
||||
return addedRows;
|
||||
};
|
||||
|
||||
this.$clipRowToDocument = function(row) {
|
||||
return Math.max(0, Math.min(row, this.lines.length-1));
|
||||
};
|
||||
|
||||
}).call(ace.Document.prototype);
|
||||
661
src/ace/Editor.js
Normal file
661
src/ace/Editor.js
Normal file
|
|
@ -0,0 +1,661 @@
|
|||
ace.provide("ace.Editor");
|
||||
|
||||
ace.Editor = function(renderer, doc) {
|
||||
var container = renderer.getContainerElement();
|
||||
this.container = container;
|
||||
this.renderer = renderer;
|
||||
|
||||
this.textInput = new ace.TextInput(container, this);
|
||||
new ace.KeyBinding(container, this);
|
||||
var self = this;
|
||||
ace.addListener(container, "mousedown", function(e) {
|
||||
self.focus();
|
||||
return ace.preventDefault(e);
|
||||
});
|
||||
|
||||
var mouseTarget = renderer.getMouseEventTarget();
|
||||
ace.addListener(mouseTarget, "mousedown", ace.bind(this.onMouseDown, this));
|
||||
ace.addListener(mouseTarget, "dblclick", ace.bind(this.onMouseDoubleClick, this));
|
||||
ace.addTripleClickListener(mouseTarget, ace.bind(this.onMouseTripleClick, this));
|
||||
ace.addMouseWheelListener(mouseTarget, ace.bind(this.onMouseWheel, this));
|
||||
|
||||
this.$selectionMarker = null;
|
||||
this.$highlightLineMarker = null;
|
||||
this.$blockScrolling = false;
|
||||
|
||||
this.setDocument(doc || new ace.Document(""));
|
||||
};
|
||||
|
||||
(function(){
|
||||
|
||||
this.setDocument = function(doc) {
|
||||
if (this.doc == doc) return;
|
||||
|
||||
if (this.doc) {
|
||||
this.doc.removeEventListener("change", this.$onDocumentChange);
|
||||
this.doc.removeEventListener("changeMode", this.$onDocumentModeChange);
|
||||
this.doc.removeEventListener("changeTabSize", this.$onDocumentChangeTabSize);
|
||||
|
||||
var selection = this.doc.getSelection();
|
||||
this.selection.removeEventListener("changeCursor", this.$onCursorChange);
|
||||
this.selection.removeEventListener("changeSelection", this.$onSelectionChange);
|
||||
|
||||
this.doc.setScrollTopRow(this.renderer.getScrollTopRow());
|
||||
}
|
||||
|
||||
this.doc = doc;
|
||||
|
||||
this.$onDocumentChange = ace.bind(this.onDocumentChange, this);
|
||||
doc.addEventListener("change", this.$onDocumentChange);
|
||||
this.renderer.setDocument(doc);
|
||||
|
||||
this.$onDocumentModeChange = ace.bind(this.onDocumentModeChange, this);
|
||||
doc.addEventListener("changeMode", this.$onDocumentModeChange);
|
||||
|
||||
this.$onDocumentChangeTabSize = ace.bind(this.renderer.draw, this.renderer);
|
||||
doc.addEventListener("changeTabSize", this.$onDocumentChangeTabSize);
|
||||
|
||||
this.selection = doc.getSelection();
|
||||
|
||||
this.$onCursorChange = ace.bind(this.onCursorChange, this);
|
||||
this.selection.addEventListener("changeCursor", this.$onCursorChange);
|
||||
|
||||
this.$onSelectionChange = ace.bind(this.onSelectionChange, this);
|
||||
this.selection.addEventListener("changeSelection", this.$onSelectionChange);
|
||||
|
||||
this.onDocumentModeChange();
|
||||
this.bgTokenizer.setLines(this.doc.lines);
|
||||
|
||||
this.renderer.draw();
|
||||
this.onCursorChange();
|
||||
this.onSelectionChange();
|
||||
this.renderer.scrollToRow(doc.getScrollTopRow());
|
||||
};
|
||||
|
||||
this.getDocument = function() {
|
||||
return this.doc;
|
||||
};
|
||||
|
||||
this.getSelection = function() {
|
||||
return this.selection;
|
||||
};
|
||||
|
||||
this.resize = function() {
|
||||
this.renderer.onResize();
|
||||
};
|
||||
|
||||
this.$highlightBrackets = function() {
|
||||
if (this.$bracketHighlight) {
|
||||
this.renderer.removeMarker(this.$bracketHighlight);
|
||||
this.$bracketHighlight = null;
|
||||
}
|
||||
|
||||
if (this.$highlightPending) {
|
||||
return;
|
||||
}
|
||||
|
||||
// perform highlight async to not block the browser during navigation
|
||||
var self = this;
|
||||
this.$highlightPending = true;
|
||||
setTimeout(function() {
|
||||
self.$highlightPending = false;
|
||||
|
||||
var pos = self.doc.findMatchingBracket(self.getCursorPosition());
|
||||
if (pos) {
|
||||
range = {
|
||||
start: pos,
|
||||
end: {
|
||||
row: pos.row,
|
||||
column: pos.column+1
|
||||
}
|
||||
};
|
||||
self.$bracketHighlight = self.renderer.addMarker(range, "bracket");
|
||||
}
|
||||
}, 10);
|
||||
};
|
||||
|
||||
this.focus = function() {
|
||||
this.textInput.focus();
|
||||
};
|
||||
|
||||
this.blur = function() {
|
||||
this.textInput.blur();
|
||||
};
|
||||
|
||||
this.onFocus = function() {
|
||||
this.renderer.showCursor();
|
||||
this.renderer.visualizeFocus();
|
||||
};
|
||||
|
||||
this.onBlur = function() {
|
||||
this.renderer.hideCursor();
|
||||
this.renderer.visualizeBlur();
|
||||
};
|
||||
|
||||
this.onDocumentChange = function(e) {
|
||||
var data = e.data;
|
||||
this.bgTokenizer.start(data.firstRow);
|
||||
this.renderer.updateLines(data.firstRow, data.lastRow);
|
||||
};
|
||||
|
||||
this.onTokenizerUpdate = function(e) {
|
||||
var rows = e.data;
|
||||
this.renderer.updateLines(rows.first, rows.last);
|
||||
};
|
||||
|
||||
this.onCursorChange = function() {
|
||||
this.$highlightBrackets();
|
||||
this.renderer.updateCursor(this.getCursorPosition());
|
||||
|
||||
if (!this.$blockScrolling) {
|
||||
this.renderer.scrollCursorIntoView();
|
||||
}
|
||||
this.$updateHighlightActiveLine();
|
||||
};
|
||||
|
||||
this.$updateHighlightActiveLine = function() {
|
||||
if (this.$highlightLineMarker) {
|
||||
this.renderer.removeMarker(this.$highlightLineMarker);
|
||||
}
|
||||
this.$highlightLineMarker = null;
|
||||
|
||||
if (this.getHighlightActiveLine() && !this.selection.isMultiLine()) {
|
||||
var cursor = this.getCursorPosition();
|
||||
var range = {
|
||||
start: {
|
||||
row: cursor.row,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
row: cursor.row+1,
|
||||
column: 0
|
||||
}
|
||||
};
|
||||
this.$highlightLineMarker = this.renderer.addMarker(range, "active_line", "line");
|
||||
}
|
||||
};
|
||||
|
||||
this.onSelectionChange = function() {
|
||||
if (this.$selectionMarker) {
|
||||
this.renderer.removeMarker(this.$selectionMarker);
|
||||
}
|
||||
this.$selectionMarker = null;
|
||||
|
||||
if (!this.selection.isEmpty()) {
|
||||
var range = this.selection.getRange();
|
||||
var style = this.getSelectionStyle();
|
||||
this.$selectionMarker = this.renderer.addMarker(range, "selection", style);
|
||||
}
|
||||
|
||||
this.onCursorChange();
|
||||
};
|
||||
|
||||
this.onDocumentModeChange = function() {
|
||||
var mode = this.doc.getMode();
|
||||
|
||||
this.mode = mode;
|
||||
var tokenizer = mode.getTokenizer();
|
||||
|
||||
if (!this.bgTokenizer) {
|
||||
var onUpdate = ace.bind(this.onTokenizerUpdate, this);
|
||||
this.bgTokenizer = new ace.BackgroundTokenizer(tokenizer);
|
||||
this.bgTokenizer.addEventListener("update", onUpdate);
|
||||
} else {
|
||||
this.bgTokenizer.setTokenizer(tokenizer);
|
||||
}
|
||||
|
||||
this.renderer.setTokenizer(this.bgTokenizer);
|
||||
this.renderer.draw();
|
||||
};
|
||||
|
||||
|
||||
this.onMouseDown = function(e) {
|
||||
var pageX = ace.getDocumentX(e);
|
||||
var pageY = ace.getDocumentY(e);
|
||||
|
||||
var pos = this.renderer.screenToTextCoordinates(pageX, pageY);
|
||||
this.moveCursorToPosition(pos);
|
||||
this.selection.setSelectionAnchor(pos.row, pos.column);
|
||||
this.renderer.scrollCursorIntoView();
|
||||
|
||||
var _self = this;
|
||||
var mousePageX, mousePageY;
|
||||
|
||||
var onMouseSelection = function(e) {
|
||||
mousePageX = ace.getDocumentX(e);
|
||||
mousePageY = ace.getDocumentY(e);
|
||||
};
|
||||
|
||||
var onMouseSelectionEnd = function() {
|
||||
clearInterval(timerId);
|
||||
};
|
||||
|
||||
var onSelectionInterval = function() {
|
||||
if (mousePageX === undefined || mousePageY === undefined)
|
||||
return;
|
||||
|
||||
selectionLead = _self.renderer.screenToTextCoordinates(mousePageX,
|
||||
mousePageY);
|
||||
|
||||
_self.selection.selectToPosition(selectionLead);
|
||||
_self.renderer.scrollCursorIntoView();
|
||||
};
|
||||
|
||||
ace.capture(this.container, onMouseSelection, onMouseSelectionEnd);
|
||||
var timerId = setInterval(onSelectionInterval, 20);
|
||||
|
||||
return ace.preventDefault(e);
|
||||
};
|
||||
|
||||
this.onMouseDoubleClick = function(e) {
|
||||
this.selection.selectWord();
|
||||
};
|
||||
|
||||
this.onMouseTripleClick = function(e) {
|
||||
this.selection.selectLine();
|
||||
};
|
||||
|
||||
this.onMouseWheel = function(e) {
|
||||
var delta = e.wheel;
|
||||
this.renderer.scrollToY(this.renderer.getScrollTop() - (delta * 15));
|
||||
return ace.preventDefault(e);
|
||||
};
|
||||
|
||||
this.getCopyText = function() {
|
||||
if (!this.selection.isEmpty()) {
|
||||
return this.doc.getTextRange(this.getSelectionRange());
|
||||
}
|
||||
else {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
this.onCut = function() {
|
||||
if (this.$readOnly)
|
||||
return;
|
||||
|
||||
if (!this.selection.isEmpty()) {
|
||||
this.moveCursorToPosition(this.doc.remove(this.getSelectionRange()));
|
||||
this.clearSelection();
|
||||
}
|
||||
};
|
||||
|
||||
this.onTextInput = function(text) {
|
||||
if (this.$readOnly)
|
||||
return;
|
||||
|
||||
var cursor = this.getCursorPosition();
|
||||
|
||||
text = text.replace("\t", this.doc.getTabString());
|
||||
|
||||
if (!this.selection.isEmpty()) {
|
||||
var end = this.doc.replace(this.getSelectionRange(), text);
|
||||
this.clearSelection();
|
||||
}
|
||||
else {
|
||||
var end = this.doc.insert(cursor, text);
|
||||
}
|
||||
|
||||
// multi line insert
|
||||
var row = cursor.row;
|
||||
if (row !== end.row) {
|
||||
var line = this.doc.getLine(row);
|
||||
var lineState = this.bgTokenizer.getState(row);
|
||||
var indent = this.mode.getNextLineIndent(line, lineState, this.doc.getTabString());
|
||||
if (indent) {
|
||||
var indentRange = {
|
||||
start: {
|
||||
row: row+1,
|
||||
column: 0
|
||||
},
|
||||
end : end
|
||||
};
|
||||
end.column += this.doc.indentRows(indentRange, indent);
|
||||
}
|
||||
}
|
||||
|
||||
this.moveCursorToPosition(end);
|
||||
this.renderer.scrollCursorIntoView();
|
||||
};
|
||||
|
||||
this.$selectionStyle = "line";
|
||||
this.setSelectionStyle = function(style) {
|
||||
if (this.$selectionStyle == style) return;
|
||||
|
||||
this.$selectionStyle = style;
|
||||
this.onSelectionChange();
|
||||
};
|
||||
|
||||
this.getSelectionStyle = function() {
|
||||
return this.$selectionStyle;
|
||||
};
|
||||
|
||||
this.$highlightActiveLine = true;
|
||||
this.setHighlightActiveLine = function(shouldHighlight) {
|
||||
if (this.$highlightActiveLine == shouldHighlight) return;
|
||||
|
||||
this.$highlightActiveLine = shouldHighlight;
|
||||
this.$updateHighlightActiveLine();
|
||||
};
|
||||
|
||||
this.getHighlightActiveLine = function() {
|
||||
return this.$highlightActiveLine;
|
||||
};
|
||||
|
||||
this.$showInvisibles = true;
|
||||
this.setShowInvisibles = function(showInvisibles) {
|
||||
showInvisibles = !!showInvisibles;
|
||||
if (this.$showInvisibles == showInvisibles) return;
|
||||
|
||||
this.$showInvisibles = showInvisibles;
|
||||
this.renderer.setShowInvisibles(showInvisibles);
|
||||
this.renderer.draw();
|
||||
};
|
||||
|
||||
this.getShowInvisibles = function() {
|
||||
return this.showInvisibles;
|
||||
};
|
||||
|
||||
this.$readOnly = false;
|
||||
this.setReadOnly = function(readOnly) {
|
||||
this.$readOnly = readOnly;
|
||||
};
|
||||
|
||||
this.getReadOnly = function() {
|
||||
return this.readOnly;
|
||||
};
|
||||
|
||||
this.removeRight = function() {
|
||||
if (this.$readOnly)
|
||||
return;
|
||||
|
||||
if (this.selection.isEmpty()) {
|
||||
this.selection.selectRight();
|
||||
}
|
||||
this.moveCursorToPosition(this.doc.remove(this.getSelectionRange()));
|
||||
this.clearSelection();
|
||||
};
|
||||
|
||||
this.removeLeft = function() {
|
||||
if (this.$readOnly)
|
||||
return;
|
||||
|
||||
if (this.selection.isEmpty()) {
|
||||
this.selection.selectLeft();
|
||||
}
|
||||
this.moveCursorToPosition(this.doc.remove(this.getSelectionRange()));
|
||||
this.clearSelection();
|
||||
};
|
||||
|
||||
this.blockIndent = function(indentString) {
|
||||
if (this.$readOnly)
|
||||
return;
|
||||
|
||||
var indentString = indentString || this.doc.getTabString();
|
||||
var addedColumns = this.doc.indentRows(this.getSelectionRange(), indentString);
|
||||
|
||||
this.selection.shiftSelection(addedColumns);
|
||||
};
|
||||
|
||||
this.blockOutdent = function(indentString) {
|
||||
if (this.$readOnly)
|
||||
return;
|
||||
|
||||
var indentString = indentString || this.doc.getTabString();
|
||||
var addedColumns = this.doc.outdentRows(this.getSelectionRange(), indentString);
|
||||
|
||||
this.selection.shiftSelection(addedColumns);
|
||||
};
|
||||
|
||||
this.toggleCommentLines = function() {
|
||||
if (this.$readOnly)
|
||||
return;
|
||||
|
||||
var rows = this.$getSelectedRows();
|
||||
|
||||
var range = {
|
||||
start: {
|
||||
row: rows.first,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
row: rows.last,
|
||||
column: 0
|
||||
}
|
||||
};
|
||||
var state = this.bgTokenizer.getState(this.getCursorPosition().row);
|
||||
var addedColumns = this.mode.toggleCommentLines(this.doc, range, state);
|
||||
|
||||
this.selection.shiftSelection(addedColumns);
|
||||
};
|
||||
|
||||
this.removeLines = function() {
|
||||
if (this.$readOnly)
|
||||
return;
|
||||
|
||||
var rows = this.$getSelectedRows();
|
||||
this.selection.setSelectionAnchor(rows.last+1, 0);
|
||||
this.selection.selectTo(rows.first, 0);
|
||||
|
||||
this.doc.remove(this.getSelectionRange());
|
||||
this.clearSelection();
|
||||
};
|
||||
|
||||
this.moveLinesDown = function() {
|
||||
if (this.$readOnly)
|
||||
return;
|
||||
|
||||
this.$moveLines(function(firstRow, lastRow) {
|
||||
return this.doc.moveLinesDown(firstRow, lastRow);
|
||||
});
|
||||
};
|
||||
|
||||
this.moveLinesUp = function() {
|
||||
if (this.$readOnly)
|
||||
return;
|
||||
|
||||
this.$moveLines(function(firstRow, lastRow) {
|
||||
return this.doc.moveLinesUp(firstRow, lastRow);
|
||||
});
|
||||
};
|
||||
|
||||
this.copyLinesUp = function() {
|
||||
if (this.$readOnly)
|
||||
return;
|
||||
|
||||
this.$moveLines(function(firstRow, lastRow) {
|
||||
this.doc.duplicateLines(firstRow, lastRow);
|
||||
return 0;
|
||||
});
|
||||
};
|
||||
|
||||
this.copyLinesDown = function() {
|
||||
if (this.$readOnly)
|
||||
return;
|
||||
|
||||
this.$moveLines(function(firstRow, lastRow) {
|
||||
return this.doc.duplicateLines(firstRow, lastRow);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
this.$moveLines = function(mover) {
|
||||
var rows = this.$getSelectedRows();
|
||||
|
||||
var linesMoved = mover.call(this, rows.first, rows.last);
|
||||
|
||||
var selection = this.selection;
|
||||
selection.setSelectionAnchor(rows.last+linesMoved+1, 0);
|
||||
selection.$moveSelection(function() {
|
||||
selection.moveCursorTo(rows.first+linesMoved, 0);
|
||||
});
|
||||
};
|
||||
|
||||
this.$getSelectedRows = function() {
|
||||
var range = this.getSelectionRange();
|
||||
var firstRow = range.start.row;
|
||||
var lastRow = range.end.row;
|
||||
if (range.end.column == 0 && (range.start.row !== range.end.row)) {
|
||||
lastRow -= 1;
|
||||
}
|
||||
|
||||
return {
|
||||
first: firstRow,
|
||||
last: lastRow
|
||||
};
|
||||
};
|
||||
|
||||
this.onCompositionStart = function() {
|
||||
this.renderer.showComposition(this.getCursorPosition());
|
||||
this.onTextInput(" ");
|
||||
};
|
||||
|
||||
this.onCompositionUpdate = function(text) {
|
||||
this.renderer.setCompositionText(text);
|
||||
};
|
||||
|
||||
this.onCompositionEnd = function() {
|
||||
this.renderer.hideComposition();
|
||||
this.removeLeft();
|
||||
};
|
||||
|
||||
|
||||
this.getFirstVisibleRow = function() {
|
||||
return this.renderer.getFirstVisibleRow();
|
||||
};
|
||||
|
||||
this.getLastVisibleRow = function() {
|
||||
return this.renderer.getLastVisibleRow();
|
||||
};
|
||||
|
||||
this.isRowVisible = function(row) {
|
||||
return (row >= this.getFirstVisibleRow() && row <= this.getLastVisibleRow());
|
||||
};
|
||||
|
||||
this.getVisibleRowCount = function() {
|
||||
return this.getLastVisibleRow() - this.getFirstVisibleRow() + 1;
|
||||
};
|
||||
|
||||
this.getPageDownRow = function() {
|
||||
return this.renderer.getLastVisibleRow() - 1;
|
||||
};
|
||||
|
||||
this.getPageUpRow = function() {
|
||||
var firstRow = this.renderer.getFirstVisibleRow();
|
||||
var lastRow = this.renderer.getLastVisibleRow();
|
||||
|
||||
return firstRow - (lastRow - firstRow) + 1;
|
||||
};
|
||||
|
||||
|
||||
this.scrollPageDown = function() {
|
||||
this.scrollToRow(this.getPageDownRow());
|
||||
};
|
||||
|
||||
this.scrollPageUp = function() {
|
||||
this.renderer.scrollToRow(this.getPageUpRow());
|
||||
};
|
||||
|
||||
this.scrollToRow = function(row) {
|
||||
this.renderer.scrollToRow(row);
|
||||
};
|
||||
|
||||
|
||||
this.getCursorPosition = function() {
|
||||
return this.selection.getCursor();
|
||||
};
|
||||
|
||||
this.getSelectionRange = function() {
|
||||
return this.selection.getRange();
|
||||
};
|
||||
|
||||
this.clearSelection = function() {
|
||||
this.selection.clearSelection();
|
||||
};
|
||||
|
||||
this.moveCursorTo = function(row, column) {
|
||||
this.selection.moveCursorTo(row, column);
|
||||
};
|
||||
|
||||
this.moveCursorToPosition = function(pos) {
|
||||
this.selection.moveCursorToPosition(pos);
|
||||
};
|
||||
|
||||
|
||||
this.gotoLine = function(lineNumber) {
|
||||
this.$blockScrolling = true;
|
||||
this.moveCursorTo(lineNumber-1, 0);
|
||||
this.$blockScrolling = false;
|
||||
|
||||
if (!this.isRowVisible(this.getCursorPosition().row)) {
|
||||
this.scrollToRow(lineNumber - 1 - Math.floor(this.getVisibleRowCount() / 2));
|
||||
}
|
||||
},
|
||||
|
||||
this.navigateTo = function(row, column) {
|
||||
this.clearSelection();
|
||||
this.moveCursorTo(row, column);
|
||||
};
|
||||
|
||||
this.navigateUp = function() {
|
||||
this.clearSelection();
|
||||
this.selection.moveCursorUp();
|
||||
};
|
||||
|
||||
this.navigateDown = function() {
|
||||
this.clearSelection();
|
||||
this.selection.moveCursorDown();
|
||||
};
|
||||
|
||||
this.navigateLeft = function() {
|
||||
if (!this.selection.isEmpty()) {
|
||||
var selectionStart = this.getSelectionRange().start;
|
||||
this.moveCursorToPosition(selectionStart);
|
||||
}
|
||||
else {
|
||||
this.selection.moveCursorLeft();
|
||||
}
|
||||
this.clearSelection();
|
||||
};
|
||||
|
||||
this.navigateRight = function() {
|
||||
if (!this.selection.isEmpty()) {
|
||||
var selectionEnd = this.getSelectionRange().end;
|
||||
this.moveCursorToPosition(selectionEnd);
|
||||
}
|
||||
else {
|
||||
this.selection.moveCursorRight();
|
||||
}
|
||||
this.clearSelection();
|
||||
};
|
||||
|
||||
this.navigateLineStart = function() {
|
||||
this.clearSelection();
|
||||
this.selection.moveCursorLineStart();
|
||||
};
|
||||
|
||||
this.navigateLineEnd = function() {
|
||||
this.clearSelection();
|
||||
this.selection.moveCursorLineEnd();
|
||||
};
|
||||
|
||||
this.navigateFileEnd = function() {
|
||||
this.clearSelection();
|
||||
this.selection.moveCursorFileEnd();
|
||||
};
|
||||
|
||||
this.navigateFileStart = function() {
|
||||
this.clearSelection();
|
||||
this.selection.moveCursorFileStart();
|
||||
};
|
||||
|
||||
this.navigateWordRight = function() {
|
||||
this.clearSelection();
|
||||
this.selection.moveCursorWordRight();
|
||||
};
|
||||
|
||||
this.navigateWordLeft = function() {
|
||||
this.clearSelection();
|
||||
this.selection.moveCursorWordLeft();
|
||||
};
|
||||
}).call(ace.Editor.prototype);
|
||||
202
src/ace/KeyBinding.js
Normal file
202
src/ace/KeyBinding.js
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
ace.provide("ace.KeyBinding");
|
||||
|
||||
ace.KeyBinding = function(element, editor) {
|
||||
|
||||
var keys = this.keys;
|
||||
|
||||
ace.addListener(element, "keydown", function(e) {
|
||||
var key = e.keyCode;
|
||||
var selection = editor.getSelection();
|
||||
|
||||
switch (key) {
|
||||
case keys.A:
|
||||
if (e.metaKey) {
|
||||
selection.selectAll();
|
||||
return ace.stopEvent(e);
|
||||
}
|
||||
break;
|
||||
|
||||
case keys.D:
|
||||
if (e.metaKey) {
|
||||
editor.removeLines();
|
||||
return ace.stopEvent(e);
|
||||
}
|
||||
break;
|
||||
|
||||
case keys.L:
|
||||
if (e.metaKey) {
|
||||
var line = parseInt(prompt("Enter line number:"));
|
||||
if (!isNaN(line)) {
|
||||
editor.gotoLine(line);
|
||||
return ace.stopEvent(e);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case keys["7"]:
|
||||
if (e.metaKey) {
|
||||
editor.toggleCommentLines();
|
||||
return ace.stopEvent(e);
|
||||
};
|
||||
break;
|
||||
|
||||
case keys.UP:
|
||||
if (e.altKey && e.metaKey ) {
|
||||
editor.copyLinesUp();
|
||||
}
|
||||
else if (e.altKey) {
|
||||
editor.moveLinesUp();
|
||||
}
|
||||
else if (e.metaKey && e.shiftKey) {
|
||||
selection.selectFileStart();
|
||||
}
|
||||
else if (e.metaKey) {
|
||||
editor.navigateFileStart();
|
||||
}
|
||||
else if (e.shiftKey) {
|
||||
selection.selectUp();
|
||||
}
|
||||
else {
|
||||
editor.navigateUp();
|
||||
}
|
||||
return ace.stopEvent(e);
|
||||
|
||||
case keys.DOWN:
|
||||
if (e.altKey && e.metaKey ) {
|
||||
editor.copyLinesDown();
|
||||
}
|
||||
else if (e.altKey) {
|
||||
editor.moveLinesDown();
|
||||
}
|
||||
else if (e.metaKey && e.shiftKey) {
|
||||
selection.selectFileEnd();
|
||||
}
|
||||
else if (e.metaKey) {
|
||||
editor.navigateFileEnd();
|
||||
}
|
||||
else if (e.shiftKey) {
|
||||
selection.selectDown();
|
||||
}
|
||||
else {
|
||||
editor.navigateDown();
|
||||
}
|
||||
return ace.stopEvent(e);
|
||||
|
||||
case keys.LEFT:
|
||||
if (e.altKey && e.shiftKey) {
|
||||
selection.selectWordLeft();
|
||||
}
|
||||
else if (e.altKey) {
|
||||
editor.navigateWordLeft();
|
||||
}
|
||||
else if (e.metaKey && e.shiftKey) {
|
||||
selection.selectLineStart();
|
||||
}
|
||||
else if (e.metaKey) {
|
||||
editor.navigateLineStart();
|
||||
}
|
||||
else if (e.shiftKey) {
|
||||
selection.selectLeft();
|
||||
}
|
||||
else {
|
||||
editor.navigateLeft();
|
||||
}
|
||||
return ace.stopEvent(e);
|
||||
|
||||
case keys.RIGHT:
|
||||
if (e.altKey && e.shiftKey) {
|
||||
selection.selectWordRight();
|
||||
}
|
||||
else if (e.altKey) {
|
||||
editor.navigateWordRight();
|
||||
}
|
||||
else if (e.metaKey && e.shiftKey) {
|
||||
selection.selectLineEnd();
|
||||
}
|
||||
else if (e.metaKey) {
|
||||
editor.navigateLineEnd();
|
||||
}
|
||||
else if (e.shiftKey) {
|
||||
selection.selectRight();
|
||||
}
|
||||
else {
|
||||
editor.navigateRight();
|
||||
}
|
||||
return ace.stopEvent(e);
|
||||
|
||||
case keys.PAGEDOWN:
|
||||
if (e.shiftKey) {
|
||||
selection.selectPageDown();
|
||||
}
|
||||
else {
|
||||
editor.scrollPageDown();
|
||||
}
|
||||
return ace.stopEvent(e);
|
||||
|
||||
case keys.PAGEUP:
|
||||
if (e.shiftKey) {
|
||||
selection.selectPageUp();
|
||||
}
|
||||
else {
|
||||
editor.scrollPageUp();
|
||||
}
|
||||
return ace.stopEvent(e);
|
||||
|
||||
case keys.POS1:
|
||||
if (e.shiftKey) {
|
||||
selection.selectLineStart();
|
||||
}
|
||||
else {
|
||||
editor.navigateLineStart();
|
||||
}
|
||||
return ace.stopEvent(e);
|
||||
|
||||
case keys.END:
|
||||
if (e.shiftKey) {
|
||||
selection.selectLineEnd();
|
||||
}
|
||||
else {
|
||||
editor.navigateLineEnd();
|
||||
}
|
||||
return ace.stopEvent(e);
|
||||
|
||||
case keys.DELETE:
|
||||
editor.removeRight();
|
||||
return ace.stopEvent(e);
|
||||
|
||||
case keys.BACKSPACE:
|
||||
editor.removeLeft();
|
||||
return ace.stopEvent(e);
|
||||
|
||||
case keys.TAB:
|
||||
if (e.shiftKey) {
|
||||
editor.blockOutdent();
|
||||
} else if (selection.isMultiLine()) {
|
||||
editor.blockIndent();
|
||||
} else {
|
||||
editor.onTextInput("\t");
|
||||
}
|
||||
return ace.stopEvent(e);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
(function() {
|
||||
this.keys = {
|
||||
UP : 38,
|
||||
RIGHT : 39,
|
||||
DOWN : 40,
|
||||
LEFT : 37,
|
||||
PAGEUP : 33,
|
||||
PAGEDOWN : 34,
|
||||
POS1 : 36,
|
||||
END : 35,
|
||||
DELETE : 46,
|
||||
BACKSPACE : 8,
|
||||
TAB : 9,
|
||||
A : 65,
|
||||
D: 68,
|
||||
L: 76,
|
||||
"7": 55
|
||||
};
|
||||
}).call(ace.KeyBinding.prototype);
|
||||
41
src/ace/MEventEmitter.js
Normal file
41
src/ace/MEventEmitter.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
ace.provide("ace.MEventEmitter");
|
||||
|
||||
ace.MEventEmitter = function() {
|
||||
|
||||
this.$initEvents = function() {
|
||||
this.$eventRegistry = {};
|
||||
};
|
||||
|
||||
this.$dispatchEvent = function(eventName, e) {
|
||||
var listeners = this.$eventRegistry[eventName];
|
||||
if (!listeners || !listeners.length) return;
|
||||
|
||||
var e = e || {};
|
||||
e.type = eventName;
|
||||
|
||||
for (var i=0; i<listeners.length; i++) {
|
||||
listeners[i](e);
|
||||
}
|
||||
};
|
||||
|
||||
this.addEventListener = function(eventName, callback) {
|
||||
var listeners = this.$eventRegistry[eventName];
|
||||
if (!listeners) {
|
||||
var listeners = this.$eventRegistry[eventName] = [];
|
||||
}
|
||||
if (ace.arrayIndexOf(listeners, callback) == -1) {
|
||||
listeners.push(callback);
|
||||
}
|
||||
};
|
||||
|
||||
this.removeEventListener = function(eventName, callback) {
|
||||
var listeners = this.$eventRegistry[eventName];
|
||||
if (!listeners) {
|
||||
return;
|
||||
}
|
||||
var index = ace.arrayIndexOf(listeners, callback);
|
||||
if (index !== -1) {
|
||||
listeners.splice(index, 1);
|
||||
}
|
||||
};
|
||||
};
|
||||
44
src/ace/ScrollBar.js
Normal file
44
src/ace/ScrollBar.js
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
ace.provide("ace.ScrollBar");
|
||||
|
||||
ace.ScrollBar = function(parent) {
|
||||
this.$initEvents();
|
||||
|
||||
this.element = document.createElement("div");
|
||||
this.element.className = "sb";
|
||||
|
||||
this.inner = document.createElement("div");
|
||||
this.element.appendChild(this.inner);
|
||||
|
||||
parent.appendChild(this.element);
|
||||
|
||||
this.width = ace.scrollbarWidth();
|
||||
this.element.style.width = this.width;
|
||||
|
||||
ace.addListener(this.element, "scroll", ace.bind(this.onScroll, this));
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
ace.implement(this, ace.MEventEmitter);
|
||||
|
||||
this.onScroll = function() {
|
||||
this.$dispatchEvent("scroll", {data: this.element.scrollTop});
|
||||
};
|
||||
|
||||
this.getWidth = function() {
|
||||
return this.width;
|
||||
};
|
||||
|
||||
this.setHeight = function(height) {
|
||||
this.element.style.height = Math.max(0, height - this.width) + "px";
|
||||
};
|
||||
|
||||
this.setInnerHeight = function(height) {
|
||||
this.inner.style.height = height + "px";
|
||||
};
|
||||
|
||||
this.setScrollTop = function(scrollTop) {
|
||||
this.element.scrollTop = scrollTop;
|
||||
};
|
||||
|
||||
}).call(ace.ScrollBar.prototype);
|
||||
394
src/ace/Selection.js
Normal file
394
src/ace/Selection.js
Normal file
|
|
@ -0,0 +1,394 @@
|
|||
ace.provide("ace.Selection");
|
||||
|
||||
ace.Selection = function(doc) {
|
||||
this.doc = doc;
|
||||
|
||||
this.$initEvents();
|
||||
|
||||
this.clearSelection();
|
||||
this.selectionLead = {
|
||||
row: 0,
|
||||
column: 0
|
||||
};
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
ace.implement(this, ace.MEventEmitter);
|
||||
|
||||
this.isEmpty = function() {
|
||||
return (this.selectionAnchor == null);
|
||||
};
|
||||
|
||||
this.isMultiLine = function() {
|
||||
if (this.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var range = this.getRange();
|
||||
return (range.start.row !== range.end.row);
|
||||
};
|
||||
|
||||
this.getCursor = function() {
|
||||
return this.selectionLead;
|
||||
};
|
||||
|
||||
this.setSelectionAnchor = function(row, column) {
|
||||
this.clearSelection();
|
||||
|
||||
this.selectionAnchor = this.$clipPositionToDocument(row, column);
|
||||
};
|
||||
|
||||
this.getSelectionAnchor = function() {
|
||||
if (this.selectionAnchor) {
|
||||
return this.$clone(this.selectionAnchor);
|
||||
} else {
|
||||
return this.$clone(this.selectionLead);
|
||||
}
|
||||
};
|
||||
|
||||
this.getSelectionLead = function() {
|
||||
return this.$clone(this.selectionLead);
|
||||
};
|
||||
|
||||
this.shiftSelection = function(columns) {
|
||||
if (this.isEmpty()) {
|
||||
this.moveCursorTo(this.selectionLead.row, this.selectionLead.column + columns);
|
||||
return;
|
||||
};
|
||||
|
||||
var anchor = this.getSelectionAnchor();
|
||||
var lead = this.getSelectionLead();
|
||||
|
||||
this.setSelectionAnchor(anchor.row, anchor.column + columns);
|
||||
this.$moveSelection(function() {
|
||||
this.moveCursorTo(lead.row, lead.column + columns);
|
||||
});
|
||||
};
|
||||
|
||||
this.getRange = function() {
|
||||
var anchor = this.selectionAnchor || this.selectionLead;
|
||||
var lead = this.selectionLead;
|
||||
|
||||
if (anchor.row > lead.row
|
||||
|| (anchor.row == lead.row && anchor.column > lead.column)) {
|
||||
return {
|
||||
start : lead,
|
||||
end : anchor
|
||||
};
|
||||
}
|
||||
else {
|
||||
return {
|
||||
start : anchor,
|
||||
end : lead
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
this.clearSelection = function() {
|
||||
if (this.selectionAnchor) {
|
||||
this.selectionAnchor = null;
|
||||
this.$dispatchEvent("changeSelection", {});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.selectAll = function() {
|
||||
var lastRow = this.doc.getLength() - 1;
|
||||
this.setSelectionAnchor(lastRow, this.doc.getLine(lastRow).length);
|
||||
|
||||
this.$moveSelection(function() {
|
||||
this.moveCursorTo(0, 0);
|
||||
});
|
||||
};
|
||||
|
||||
this.$moveSelection = function(mover) {
|
||||
var changed = false;
|
||||
|
||||
if (!this.selectionAnchor) {
|
||||
changed = true;
|
||||
this.selectionAnchor = this.$clone(this.selectionLead);
|
||||
}
|
||||
|
||||
var cursor = this.$clone(this.selectionLead);
|
||||
mover.call(this);
|
||||
|
||||
if (cursor.row !== this.selectionLead.row || cursor.column !== this.selectionLead.column) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
this.$dispatchEvent("changeSelection", {});
|
||||
};
|
||||
|
||||
this.selectTo = function(row, column) {
|
||||
this.$moveSelection(function() {
|
||||
this.moveCursorTo(row, column);
|
||||
});
|
||||
};
|
||||
|
||||
this.selectToPosition = function(pos) {
|
||||
this.$moveSelection(function() {
|
||||
this.moveCursorToPosition(pos);
|
||||
});
|
||||
};
|
||||
|
||||
this.selectUp = function() {
|
||||
this.$moveSelection(this.moveCursorUp);
|
||||
};
|
||||
|
||||
this.selectDown = function() {
|
||||
this.$moveSelection(this.moveCursorDown);
|
||||
};
|
||||
|
||||
this.selectRight = function() {
|
||||
this.$moveSelection(this.moveCursorRight);
|
||||
};
|
||||
|
||||
this.selectLeft = function() {
|
||||
this.$moveSelection(this.moveCursorLeft);
|
||||
};
|
||||
|
||||
this.selectLineStart = function() {
|
||||
this.$moveSelection(this.moveCursorLineStart);
|
||||
};
|
||||
|
||||
this.selectLineEnd = function() {
|
||||
this.$moveSelection(this.moveCursorLineEnd);
|
||||
};
|
||||
|
||||
this.selectPageDown = function() {
|
||||
var row = this.getPageDownRow() + Math.floor(this.getVisibleRowCount() / 2);
|
||||
|
||||
this.scrollPageDown();
|
||||
|
||||
this.$moveSelection(function() {
|
||||
this.moveCursorTo(row, this.selectionLead.column);
|
||||
});
|
||||
};
|
||||
|
||||
this.selectPageUp = function() {
|
||||
var visibleRows = this.getLastVisibleRow() - this.getFirstVisibleRow();
|
||||
var row = this.getPageUpRow() + Math.round(visibleRows / 2);
|
||||
|
||||
this.scrollPageUp();
|
||||
|
||||
this.$moveSelection(function() {
|
||||
this.moveCursorTo(row, this.selectionLead.column);
|
||||
});
|
||||
};
|
||||
|
||||
this.selectFileEnd = function() {
|
||||
this.$moveSelection(this.moveCursorFileEnd);
|
||||
};
|
||||
|
||||
this.selectFileStart = function() {
|
||||
this.$moveSelection(this.moveCursorFileStart);
|
||||
};
|
||||
|
||||
this.tokenRe = /^[\w\d]+/g;
|
||||
this.nonTokenRe = /^[^\w\d]+/g;
|
||||
|
||||
this.selectWordRight = function() {
|
||||
this.$moveSelection(this.moveCursorWordRight);
|
||||
};
|
||||
|
||||
this.selectWordLeft = function() {
|
||||
this.$moveSelection(this.moveCursorWordLeft);
|
||||
};
|
||||
|
||||
this.selectWord = function() {
|
||||
var cursor = this.selectionLead;
|
||||
|
||||
var line = this.doc.getLine(cursor.row);
|
||||
var column = cursor.column;
|
||||
|
||||
var inToken = false;
|
||||
if (column > 0) {
|
||||
inToken = !!line.charAt(column - 1).match(this.tokenRe);
|
||||
}
|
||||
|
||||
if (!inToken) {
|
||||
inToken = !!line.charAt(column).match(this.tokenRe);
|
||||
}
|
||||
|
||||
var re = inToken ? this.tokenRe : this.nonTokenRe;
|
||||
|
||||
var start = column;
|
||||
if (start > 0) {
|
||||
do {
|
||||
start--;
|
||||
}
|
||||
while (start >= 0 && line.charAt(start).match(re));
|
||||
start++;
|
||||
}
|
||||
|
||||
var end = column;
|
||||
while (end < line.length && line.charAt(end).match(re)) {
|
||||
end++;
|
||||
}
|
||||
|
||||
this.setSelectionAnchor(cursor.row, start);
|
||||
this.$moveSelection(function() {
|
||||
this.moveCursorTo(cursor.row, end);
|
||||
});
|
||||
};
|
||||
|
||||
this.selectLine = function() {
|
||||
this.setSelectionAnchor(this.selectionLead.row, 0);
|
||||
this.$moveSelection(function() {
|
||||
this.moveCursorTo(this.selectionLead.row + 1, 0);
|
||||
});
|
||||
};
|
||||
|
||||
this.moveCursorUp = function() {
|
||||
this.moveCursorBy(-1, 0);
|
||||
};
|
||||
|
||||
this.moveCursorDown = function() {
|
||||
this.moveCursorBy(1, 0);
|
||||
};
|
||||
|
||||
this.moveCursorLeft = function() {
|
||||
if (this.selectionLead.column == 0) {
|
||||
if (this.selectionLead.row > 0) {
|
||||
this.moveCursorTo(this.selectionLead.row - 1, this.doc
|
||||
.getLine(this.selectionLead.row - 1).length);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.moveCursorBy(0, -1);
|
||||
}
|
||||
};
|
||||
|
||||
this.moveCursorRight = function() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.moveCursorBy(0, 1);
|
||||
}
|
||||
};
|
||||
|
||||
this.moveCursorLineStart = function() {
|
||||
this.moveCursorTo(this.selectionLead.row, 0);
|
||||
};
|
||||
|
||||
this.moveCursorLineEnd = function() {
|
||||
this.moveCursorTo(this.selectionLead.row,
|
||||
this.doc.getLine(this.selectionLead.row).length);
|
||||
};
|
||||
|
||||
this.moveCursorFileEnd = function() {
|
||||
var row = this.doc.getLength() - 1;
|
||||
var column = this.doc.getLine(row).length;
|
||||
this.moveCursorTo(row, column);
|
||||
};
|
||||
|
||||
this.moveCursorFileStart = function() {
|
||||
this.moveCursorTo(0, 0);
|
||||
};
|
||||
|
||||
this.moveCursorWordRight = function() {
|
||||
var row = this.selectionLead.row;
|
||||
var column = this.selectionLead.column;
|
||||
var line = this.doc.getLine(row);
|
||||
var rightOfCursor = line.substring(column);
|
||||
|
||||
var match;
|
||||
this.nonTokenRe.lastIndex = 0;
|
||||
this.tokenRe.lastIndex = 0;
|
||||
|
||||
if (column == line.length) {
|
||||
this.moveCursorRight();
|
||||
return;
|
||||
}
|
||||
else if (match = this.nonTokenRe.exec(rightOfCursor)) {
|
||||
column += this.nonTokenRe.lastIndex;
|
||||
this.nonTokenRe.lastIndex = 0;
|
||||
}
|
||||
else if (match = this.tokenRe.exec(rightOfCursor)) {
|
||||
column += this.tokenRe.lastIndex;
|
||||
this.tokenRe.lastIndex = 0;
|
||||
}
|
||||
|
||||
this.moveCursorTo(row, column);
|
||||
};
|
||||
|
||||
this.moveCursorWordLeft = function() {
|
||||
var row = this.selectionLead.row;
|
||||
var column = this.selectionLead.column;
|
||||
var line = this.doc.getLine(row);
|
||||
var leftOfCursor = ace.stringReverse(line.substring(0, column));
|
||||
|
||||
var match;
|
||||
this.nonTokenRe.lastIndex = 0;
|
||||
this.tokenRe.lastIndex = 0;
|
||||
|
||||
if (column == 0) {
|
||||
this.moveCursorLeft();
|
||||
return;
|
||||
}
|
||||
else if (match = this.nonTokenRe.exec(leftOfCursor)) {
|
||||
column -= this.nonTokenRe.lastIndex;
|
||||
this.nonTokenRe.lastIndex = 0;
|
||||
}
|
||||
else if (match = this.tokenRe.exec(leftOfCursor)) {
|
||||
column -= this.tokenRe.lastIndex;
|
||||
this.tokenRe.lastIndex = 0;
|
||||
}
|
||||
|
||||
this.moveCursorTo(row, column);
|
||||
};
|
||||
|
||||
this.moveCursorBy = function(rows, chars) {
|
||||
this.moveCursorTo(this.selectionLead.row + rows, this.selectionLead.column + chars);
|
||||
};
|
||||
|
||||
|
||||
this.moveCursorToPosition = function(position) {
|
||||
this.moveCursorTo(position.row, position.column);
|
||||
};
|
||||
|
||||
this.moveCursorTo = function(row, column) {
|
||||
var cursor = this.$clipPositionToDocument(row, column);
|
||||
|
||||
if (cursor.row !== this.selectionLead.row || cursor.column !== this.selectionLead.column) {
|
||||
this.selectionLead = cursor;
|
||||
this.$dispatchEvent("changeCursor", { data: this.getCursor() });
|
||||
}
|
||||
};
|
||||
|
||||
this.moveCursorUp = function() {
|
||||
this.moveCursorBy(-1, 0);
|
||||
};
|
||||
|
||||
this.$clipPositionToDocument = function(row, column) {
|
||||
var pos = {};
|
||||
|
||||
if (row >= this.doc.getLength()) {
|
||||
pos.row = this.doc.getLength() - 1;
|
||||
pos.column = this.doc.getLine(pos.row).length;
|
||||
}
|
||||
else if (row < 0) {
|
||||
pos.row = 0;
|
||||
pos.column = 0;
|
||||
}
|
||||
else {
|
||||
pos.row = row;
|
||||
pos.column = Math.min(this.doc.getLine(pos.row).length,
|
||||
Math.max(0, column));
|
||||
}
|
||||
return pos;
|
||||
};
|
||||
|
||||
this.$clone = function(pos) {
|
||||
return {
|
||||
row: pos.row,
|
||||
column: pos.column
|
||||
};
|
||||
};
|
||||
|
||||
}).call(ace.Selection.prototype);
|
||||
83
src/ace/TextInput.js
Normal file
83
src/ace/TextInput.js
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
ace.provide("ace.TextInput");
|
||||
|
||||
ace.TextInput = function(parentNode, host) {
|
||||
|
||||
var text = document.createElement("textarea");
|
||||
var style = text.style;
|
||||
style.position = "absolute";
|
||||
style.left = "-10000px";
|
||||
style.top = "-10000px";
|
||||
parentNode.appendChild(text);
|
||||
|
||||
var inCompostion = false;
|
||||
|
||||
var onTextInput = function(e) {
|
||||
setTimeout(function() {
|
||||
if (!inCompostion) {
|
||||
if (text.value)
|
||||
host.onTextInput(text.value);
|
||||
text.value = "";
|
||||
}
|
||||
}, 0);
|
||||
};
|
||||
|
||||
var onCompositionStart = function(e) {
|
||||
inCompostion = true;
|
||||
|
||||
if (text.value)
|
||||
host.onTextInput(text.value);
|
||||
text.value = "";
|
||||
|
||||
host.onCompositionStart();
|
||||
setTimeout(onCompositionUpdate, 0);
|
||||
};
|
||||
|
||||
var onCompositionUpdate = function() {
|
||||
host.onCompositionUpdate(text.value);
|
||||
};
|
||||
|
||||
var onCompositionEnd = function() {
|
||||
inCompostion = false;
|
||||
host.onCompositionEnd();
|
||||
onTextInput();
|
||||
};
|
||||
|
||||
var onCopy = function() {
|
||||
text.value = host.getCopyText();
|
||||
text.select();
|
||||
};
|
||||
|
||||
var onCut = function() {
|
||||
text.value = host.getCopyText();
|
||||
host.onCut();
|
||||
text.select();
|
||||
};
|
||||
|
||||
ace.addListener(text, "keypress", onTextInput);
|
||||
ace.addListener(text, "textInput", onTextInput);
|
||||
ace.addListener(text, "paste", onTextInput);
|
||||
ace.addListener(text, "propertychange", onTextInput);
|
||||
|
||||
ace.addListener(text, "copy", onCopy);
|
||||
ace.addListener(text, "cut", onCut);
|
||||
|
||||
ace.addListener(text, "compositionstart", onCompositionStart);
|
||||
ace.addListener(text, "compositionupdate", onCompositionUpdate);
|
||||
ace.addListener(text, "compositionend", onCompositionEnd);
|
||||
|
||||
ace.addListener(text, "blur", function() {
|
||||
host.onBlur();
|
||||
});
|
||||
|
||||
ace.addListener(text, "focus", function() {
|
||||
host.onFocus();
|
||||
});
|
||||
|
||||
this.focus = function() {
|
||||
text.focus();
|
||||
};
|
||||
|
||||
this.blur = function() {
|
||||
text.blur();
|
||||
};
|
||||
};
|
||||
92
src/ace/Tokenizer.js
Normal file
92
src/ace/Tokenizer.js
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
ace.provide("ace.Tokenizer");
|
||||
|
||||
ace.Tokenizer = function(rules) {
|
||||
this.rules = rules;
|
||||
|
||||
this.regExps = {};
|
||||
for ( var key in this.rules) {
|
||||
var state = this.rules[key];
|
||||
var ruleRegExps = [];
|
||||
|
||||
for ( var i = 0; i < state.length; i++) {
|
||||
ruleRegExps.push(state[i].regex);
|
||||
};
|
||||
|
||||
this.regExps[key] = new RegExp("(?:(" + ruleRegExps.join(")|(")
|
||||
+ ")|(.))", "g");
|
||||
}
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
this.getLineTokens = function(line, startState) {
|
||||
var currentState = startState;
|
||||
var state = this.rules[currentState];
|
||||
var re = this.regExps[currentState];
|
||||
re.lastIndex = 0;
|
||||
|
||||
var match, tokens = [];
|
||||
|
||||
var lastIndex = 0;
|
||||
|
||||
var token = {
|
||||
type: null,
|
||||
value: ""
|
||||
};
|
||||
|
||||
while (match = re.exec(line)) {
|
||||
var type = "text";
|
||||
var value = match[0];
|
||||
|
||||
if (re.lastIndex == lastIndex) { throw new Error("tokenizer error"); }
|
||||
lastIndex = re.lastIndex;
|
||||
|
||||
window.LOG && jstestdriver.console.log(currentState, match);
|
||||
|
||||
for ( var i = 0; i < state.length; i++) {
|
||||
if (match[i + 1]) {
|
||||
if (typeof state[i].token == "function") {
|
||||
type = state[i].token(match[0]);
|
||||
}
|
||||
else {
|
||||
type = state[i].token;
|
||||
}
|
||||
|
||||
if (state[i].next && state[i].next !== currentState) {
|
||||
currentState = state[i].next;
|
||||
var state = this.rules[currentState];
|
||||
var lastIndex = re.lastIndex;
|
||||
|
||||
var re = this.regExps[currentState];
|
||||
re.lastIndex = lastIndex;
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
if (token.type !== type) {
|
||||
if (token.type) {
|
||||
tokens.push(token);
|
||||
}
|
||||
token = {
|
||||
type: type,
|
||||
value: value
|
||||
};
|
||||
} else {
|
||||
token.value += value;
|
||||
}
|
||||
};
|
||||
|
||||
if (token.type) {
|
||||
tokens.push(token);
|
||||
}
|
||||
|
||||
window.LOG && jstestdriver.console.log(tokens, currentState);
|
||||
|
||||
return {
|
||||
tokens : tokens,
|
||||
state : currentState
|
||||
};
|
||||
};
|
||||
|
||||
}).call(ace.Tokenizer.prototype);
|
||||
318
src/ace/VirtualRenderer.js
Normal file
318
src/ace/VirtualRenderer.js
Normal file
|
|
@ -0,0 +1,318 @@
|
|||
ace.provide("ace.VirtualRenderer");
|
||||
|
||||
ace.VirtualRenderer = function(container) {
|
||||
this.container = container;
|
||||
ace.addCssClass(this.container, "editor");
|
||||
|
||||
this.scroller = document.createElement("div");
|
||||
this.scroller.className = "scroller";
|
||||
this.container.appendChild(this.scroller);
|
||||
|
||||
this.gutter = document.createElement("div");
|
||||
this.gutter.className = "gutter";
|
||||
this.container.appendChild(this.gutter);
|
||||
|
||||
this.gutterLayer = new ace.layer.Gutter(this.gutter);
|
||||
this.markerLayer = new ace.layer.Marker(this.scroller);
|
||||
|
||||
var textLayer = this.textLayer = new ace.layer.Text(this.scroller);
|
||||
this.canvas = textLayer.element;
|
||||
|
||||
this.characterWidth = textLayer.getCharacterWidth();
|
||||
this.lineHeight = textLayer.getLineHeight();
|
||||
|
||||
this.cursorLayer = new ace.layer.Cursor(this.scroller);
|
||||
|
||||
this.layers = [ this.markerLayer, textLayer, this.cursorLayer ];
|
||||
|
||||
this.scrollBar = new ace.ScrollBar(container);
|
||||
this.scrollBar.addEventListener("scroll", ace.bind(this.onScroll, this));
|
||||
|
||||
this.scrollTop = 0;
|
||||
|
||||
this.cursorPos = {
|
||||
row : 0,
|
||||
column : 0
|
||||
};
|
||||
|
||||
this.onResize();
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
this.setDocument = function(doc) {
|
||||
this.lines = doc.lines;
|
||||
this.doc = doc;
|
||||
this.markerLayer.setDocument(doc);
|
||||
this.textLayer.setDocument(doc);
|
||||
};
|
||||
|
||||
this.setTokenizer = function(tokenizer) {
|
||||
this.textLayer.setTokenizer(tokenizer);
|
||||
};
|
||||
|
||||
this.$showInvisibles = true;
|
||||
this.setShowInvisibles = function(showInvisibles) {
|
||||
this.$showInvisibles = showInvisibles;
|
||||
this.textLayer.setShowInvisibles(showInvisibles);
|
||||
};
|
||||
|
||||
this.getContainerElement = function() {
|
||||
return this.container;
|
||||
};
|
||||
|
||||
this.getMouseEventTarget = function() {
|
||||
return this.scroller;
|
||||
};
|
||||
|
||||
this.getFirstVisibleRow = function() {
|
||||
return this.layerConfig.firstRow || 0;
|
||||
};
|
||||
|
||||
this.getLastVisibleRow = function() {
|
||||
return this.layerConfig.lastRow || 0;
|
||||
};
|
||||
|
||||
this.onResize = function()
|
||||
{
|
||||
var height = ace.getInnerHeight(this.container);
|
||||
this.gutter.style.height = height + "px";
|
||||
this.scroller.style.height = height + "px";
|
||||
this.scrollBar.setHeight(height);
|
||||
|
||||
var width = ace.getInnerWidth(this.container);
|
||||
var gutterWidth = this.gutter.offsetWidth;
|
||||
this.scroller.style.left = gutterWidth + "px";
|
||||
this.scroller.style.width = Math.max(0, width - gutterWidth - this.scrollBar.getWidth()) + "px";
|
||||
|
||||
if (this.doc) {
|
||||
this.$updateScrollBar();
|
||||
this.scrollToY(this.getScrollTop());
|
||||
this.draw();
|
||||
}
|
||||
};
|
||||
|
||||
this.onScroll = function(e) {
|
||||
this.scrollToY(e.data);
|
||||
};
|
||||
|
||||
this.$updateScrollBar = function() {
|
||||
this.scrollBar.setInnerHeight(this.doc.getLength() * this.lineHeight);
|
||||
this.scrollBar.setScrollTop(this.scrollTop);
|
||||
};
|
||||
|
||||
this.updateLines = function(firstRow, lastRow) {
|
||||
var layerConfig = this.layerConfig;
|
||||
|
||||
if (firstRow > layerConfig.lastRow + 1) { return; }
|
||||
if (lastRow < layerConfig.firstRow) { return; }
|
||||
|
||||
// if the last row is unknown -> redraw everything
|
||||
if (lastRow === undefined) {
|
||||
this.draw();
|
||||
return;
|
||||
}
|
||||
|
||||
// else update only the changed rows
|
||||
this.textLayer.updateLines(layerConfig, firstRow, lastRow);
|
||||
};
|
||||
|
||||
this.draw = function() {
|
||||
var lines = this.lines;
|
||||
|
||||
var offset = this.scrollTop % this.lineHeight;
|
||||
var minHeight = this.scroller.clientHeight + offset;
|
||||
|
||||
var charCount = this.doc.getWidth();
|
||||
if (this.$showInvisibles)
|
||||
charCount += 1;
|
||||
var longestLine = Math.max(this.scroller.clientWidth, Math.round(charCount * this.characterWidth));
|
||||
|
||||
var lineCount = Math.ceil(minHeight / this.lineHeight);
|
||||
var firstRow = Math.round((this.scrollTop - offset) / this.lineHeight);
|
||||
var lastRow = Math.min(lines.length, firstRow + lineCount) - 1;
|
||||
|
||||
var layerConfig = this.layerConfig = {
|
||||
width : longestLine,
|
||||
firstRow : firstRow,
|
||||
lastRow : lastRow,
|
||||
lineHeight : this.lineHeight,
|
||||
characterWidth : this.characterWidth
|
||||
};
|
||||
|
||||
for ( var i = 0; i < this.layers.length; i++) {
|
||||
var layer = this.layers[i];
|
||||
|
||||
var style = layer.element.style;
|
||||
style.marginTop = (-offset) + "px";
|
||||
style.height = minHeight + "px";
|
||||
style.width = longestLine + "px";
|
||||
|
||||
layer.update(layerConfig);
|
||||
};
|
||||
|
||||
this.gutterLayer.element.style.marginTop = (-offset) + "px";
|
||||
this.gutterLayer.element.style.height = minHeight + "px";
|
||||
this.gutterLayer.update(layerConfig);
|
||||
|
||||
this.$updateScrollBar();
|
||||
};
|
||||
|
||||
this.addMarker = function(range, clazz, type) {
|
||||
range.start = this.$documentToScreenPosition(range.start);
|
||||
range.end = this.$documentToScreenPosition(range.end);
|
||||
return this.markerLayer.addMarker(range, clazz, type);
|
||||
};
|
||||
|
||||
this.removeMarker = function(markerId) {
|
||||
this.markerLayer.removeMarker(markerId);
|
||||
};
|
||||
|
||||
this.updateCursor = function(position) {
|
||||
this.cursorLayer.setCursor(this.$documentToScreenPosition(position));
|
||||
this.cursorLayer.update(this.layerConfig);
|
||||
};
|
||||
|
||||
this.$documentToScreenPosition = function(pos) {
|
||||
return {
|
||||
row: pos.row,
|
||||
column: this.$documentToScreenColumn(pos.row, pos.column)
|
||||
};
|
||||
};
|
||||
|
||||
this.$documentToScreenColumn = function(row, docColumn) {
|
||||
var tabSize = this.doc.getTabSize();
|
||||
|
||||
var screenColumn = 0;
|
||||
var remaining = docColumn;
|
||||
|
||||
var line = this.doc.getLine(row).split(/\t/g);
|
||||
for (var i=0; i<line.length; i++) {
|
||||
var len = line[i].length;
|
||||
if (remaining > len) {
|
||||
remaining -= (len + 1);
|
||||
screenColumn += len + tabSize;
|
||||
}
|
||||
else {
|
||||
screenColumn += remaining;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return screenColumn;
|
||||
};
|
||||
|
||||
this.$screenToDocumentColumn = function(row, screenColumn) {
|
||||
var tabSize = this.doc.getTabSize();
|
||||
|
||||
var docColumn = 0;
|
||||
var remaining = screenColumn;
|
||||
|
||||
var line = this.doc.getLine(row).split(/\t/g);
|
||||
for (var i=0; i<line.length; i++) {
|
||||
var len = line[i].length;
|
||||
if (remaining >= len + tabSize) {
|
||||
remaining -= (len + tabSize);
|
||||
docColumn += (len + 1);
|
||||
}
|
||||
else if (remaining > len){
|
||||
docColumn += len;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
docColumn += remaining;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return docColumn;
|
||||
};
|
||||
|
||||
this.hideCursor = function() {
|
||||
this.cursorLayer.hideCursor();
|
||||
};
|
||||
|
||||
this.showCursor = function() {
|
||||
this.cursorLayer.showCursor();
|
||||
};
|
||||
|
||||
this.scrollCursorIntoView = function() {
|
||||
var pos = this.cursorLayer.getPixelPosition();
|
||||
|
||||
var left = pos.left;
|
||||
var top = pos.top;
|
||||
|
||||
if (this.getScrollTop() > top) {
|
||||
this.scrollToY(top);
|
||||
}
|
||||
|
||||
if (this.getScrollTop() + this.scroller.clientHeight < top
|
||||
+ this.lineHeight) {
|
||||
this.scrollToY(top + this.lineHeight - this.scroller.clientHeight);
|
||||
}
|
||||
|
||||
if (this.scroller.scrollLeft > left) {
|
||||
this.scroller.scrollLeft = left;
|
||||
}
|
||||
|
||||
if (this.scroller.scrollLeft + this.scroller.clientWidth < left
|
||||
+ this.characterWidth) {
|
||||
this.scroller.scrollLeft = Math.round(left + this.characterWidth
|
||||
- this.scroller.clientWidth);
|
||||
}
|
||||
},
|
||||
|
||||
this.getScrollTop = function() {
|
||||
return this.scrollTop;
|
||||
};
|
||||
|
||||
this.getScrollTopRow = function() {
|
||||
return this.scrollTop / this.lineHeight;
|
||||
};
|
||||
|
||||
this.scrollToRow = function(row) {
|
||||
this.scrollToY(row * this.lineHeight);
|
||||
};
|
||||
|
||||
this.scrollToY = function(scrollTop) {
|
||||
var maxHeight = this.lines.length * this.lineHeight
|
||||
- this.scroller.clientHeight;
|
||||
var scrollTop = Math.max(0, Math.min(maxHeight, scrollTop));
|
||||
|
||||
if (this.scrollTop !== scrollTop) {
|
||||
this.scrollTop = scrollTop;
|
||||
this.$updateScrollBar();
|
||||
this.draw();
|
||||
}
|
||||
};
|
||||
|
||||
this.screenToTextCoordinates = function(pageX, pageY) {
|
||||
var canvasPos = this.scroller.getBoundingClientRect();
|
||||
|
||||
var col = Math.floor((pageX + this.scroller.scrollLeft - canvasPos.left)
|
||||
/ this.characterWidth);
|
||||
var row = Math.floor((pageY + this.scrollTop - canvasPos.top)
|
||||
/ this.lineHeight);
|
||||
|
||||
return {
|
||||
row : row,
|
||||
column : this.$screenToDocumentColumn(row, col)
|
||||
};
|
||||
};
|
||||
|
||||
this.visualizeFocus = function() {
|
||||
ace.addCssClass(this.container, "focus");
|
||||
};
|
||||
|
||||
this.visualizeBlur = function() {
|
||||
ace.removeCssClass(this.container, "focus");
|
||||
};
|
||||
|
||||
this.showComposition = function(position) {
|
||||
};
|
||||
|
||||
this.setCompositionText = function(text) {
|
||||
};
|
||||
|
||||
this.hideComposition = function() {
|
||||
};
|
||||
|
||||
}).call(ace.VirtualRenderer.prototype);
|
||||
275
src/ace/ace.js
Normal file
275
src/ace/ace.js
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
if (!window.ace)
|
||||
ace = {};
|
||||
|
||||
ace.provide = function(namespace) {
|
||||
var parts = namespace.split(".");
|
||||
var obj = window;
|
||||
for (var i=0; i<parts.length; i++) {
|
||||
var part = parts[i];
|
||||
if (!obj[part]) {
|
||||
obj[part] = {};
|
||||
}
|
||||
obj = obj[part];
|
||||
}
|
||||
};
|
||||
|
||||
ace.inherits = function(ctor, superCtor) {
|
||||
var tempCtor = function() {};
|
||||
tempCtor.prototype = superCtor.prototype;
|
||||
ctor.super_ = superCtor.prototype;
|
||||
ctor.prototype = new tempCtor();
|
||||
ctor.prototype.constructor = ctor;
|
||||
};
|
||||
|
||||
ace.implement = function(proto, mixin) {
|
||||
mixin.call(proto);
|
||||
};
|
||||
|
||||
ace.addListener = function(elem, type, callback) {
|
||||
if (elem.addEventListener) {
|
||||
return elem.addEventListener(type, callback, false);
|
||||
}
|
||||
if (elem.attachEvent) {
|
||||
var wrapper = function() {
|
||||
callback(window.event);
|
||||
};
|
||||
callback.$$wrapper = wrapper;
|
||||
elem.attachEvent("on" + type, wrapper);
|
||||
}
|
||||
};
|
||||
|
||||
ace.removeListener = function(elem, type, callback) {
|
||||
if (elem.removeEventListener) {
|
||||
return elem.removeEventListener(type, callback, false);
|
||||
}
|
||||
if (elem.detachEvent) {
|
||||
elem.detachEvent("on" + type, callback.$$wrapper || callback);
|
||||
}
|
||||
};
|
||||
|
||||
ace.setText = function(elem, text) {
|
||||
if (elem.innerText !== undefined) {
|
||||
elem.innerText = text;
|
||||
}
|
||||
if (elem.textContent !== undefined) {
|
||||
elem.textContent = text;
|
||||
}
|
||||
};
|
||||
|
||||
ace.stopEvent = function(e) {
|
||||
ace.stopPropagation(e);
|
||||
ace.preventDefault(e);
|
||||
return false;
|
||||
};
|
||||
|
||||
ace.stopPropagation = function(e) {
|
||||
if (e.stopPropagation)
|
||||
e.stopPropagation();
|
||||
else
|
||||
e.cancelBubble = true;
|
||||
};
|
||||
|
||||
ace.preventDefault = function(e) {
|
||||
if (e.preventDefault)
|
||||
e.preventDefault();
|
||||
else
|
||||
e.returnValue = false;
|
||||
};
|
||||
|
||||
|
||||
ace.hasCssClass = function(el, name) {
|
||||
var classes = el.className.split(/\s*/g);
|
||||
return ace.arrayIndexOf(classes, name) !== -1;
|
||||
};
|
||||
|
||||
|
||||
ace.addCssClass = function(el, name) {
|
||||
if (!ace.hasCssClass(el, name)) {
|
||||
el.className += " " + name;
|
||||
}
|
||||
};
|
||||
|
||||
ace.removeCssClass = function(el, name) {
|
||||
var classes = el.className.split(/\s+/g);
|
||||
while (true) {
|
||||
var index = ace.arrayIndexOf(classes, name);
|
||||
if (index == -1) {
|
||||
break;
|
||||
}
|
||||
classes.splice(index, 1);
|
||||
}
|
||||
el.className = classes.join(" ");
|
||||
};
|
||||
|
||||
ace.getInnerWidth = function(element) {
|
||||
return (parseInt(ace.computedStyle(element, "paddingLeft"))
|
||||
+ parseInt(ace.computedStyle(element, "paddingRight")) + element.clientWidth);
|
||||
};
|
||||
|
||||
ace.getInnerHeight = function(element) {
|
||||
return (parseInt(ace.computedStyle(element, "paddingTop"))
|
||||
+ parseInt(ace.computedStyle(element, "paddingBottom")) + element.clientHeight);
|
||||
};
|
||||
|
||||
ace.computedStyle = function(element, style) {
|
||||
if (window.getComputedStyle) {
|
||||
return (window.getComputedStyle(element, null))[style];
|
||||
}
|
||||
else {
|
||||
return element.currentStyle[style];
|
||||
}
|
||||
};
|
||||
|
||||
ace.scrollbarWidth = function() {
|
||||
|
||||
var inner = document.createElement('p');
|
||||
inner.style.width = "100%";
|
||||
inner.style.height = "200px";
|
||||
|
||||
var outer = document.createElement("div");
|
||||
var style = outer.style;
|
||||
|
||||
style.position = "absolute";
|
||||
style.left = "-10000px";
|
||||
style.overflow = "hidden";
|
||||
style.width = "200px";
|
||||
style.height = "150px";
|
||||
|
||||
outer.appendChild(inner);
|
||||
document.body.appendChild(outer);
|
||||
var noScrollbar = inner.offsetWidth;
|
||||
|
||||
style.overflow = "scroll";
|
||||
var withScrollbar = inner.offsetWidth;
|
||||
|
||||
if (noScrollbar == withScrollbar) {
|
||||
withScrollbar = outer.clientWidth;
|
||||
}
|
||||
|
||||
document.body.removeChild(outer);
|
||||
|
||||
return noScrollbar-withScrollbar;
|
||||
};
|
||||
|
||||
ace.stringReverse = function(string) {
|
||||
return string.split("").reverse().join("");
|
||||
};
|
||||
|
||||
if (Array.prototype.indexOf) {
|
||||
ace.arrayIndexOf = function(array, searchElement) {
|
||||
return array.indexOf(searchElement);
|
||||
};
|
||||
}
|
||||
else {
|
||||
ace.arrayIndexOf = function(array, searchElement) {
|
||||
for (var i=0; i<array.length; i++) {
|
||||
if (array[i] == searchElement) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
}
|
||||
|
||||
ace.bind = function(fcn, context) {
|
||||
return function() {
|
||||
return fcn.apply(context, arguments);
|
||||
};
|
||||
};
|
||||
|
||||
ace.getDocumentX = function(event) {
|
||||
if (event.clientX) {
|
||||
var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
|
||||
return event.clientX + scrollLeft;
|
||||
} else {
|
||||
return event.pageX;
|
||||
}
|
||||
};
|
||||
|
||||
ace.getDocumentY = function(event) {
|
||||
if (event.clientY) {
|
||||
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
|
||||
return event.clientY + scrollTop;
|
||||
} else {
|
||||
return event.pageX;
|
||||
}
|
||||
};
|
||||
|
||||
if (document.documentElement.setCapture) {
|
||||
ace.capture = function(el, eventHandler, releaseCaptureHandler) {
|
||||
function onMouseMove(e) {
|
||||
eventHandler(e);
|
||||
return ace.stopPropagation(e);
|
||||
}
|
||||
|
||||
function onReleaseCapture(e) {
|
||||
eventHandler && eventHandler(e);
|
||||
releaseCaptureHandler && releaseCaptureHandler();
|
||||
|
||||
ace.removeListener(el, "mousemove", eventHandler);
|
||||
ace.removeListener(el, "mouseup", onReleaseCapture);
|
||||
ace.removeListener(el, "losecapture", onReleaseCapture);
|
||||
|
||||
el.releaseCapture();
|
||||
}
|
||||
|
||||
ace.addListener(el, "mousemove", eventHandler);
|
||||
ace.addListener(el, "mouseup", onReleaseCapture);
|
||||
ace.addListener(el, "losecapture", onReleaseCapture);
|
||||
el.setCapture();
|
||||
};
|
||||
}
|
||||
else {
|
||||
ace.capture = function(el, eventHandler, releaseCaptureHandler) {
|
||||
function onMouseMove(e) {
|
||||
eventHandler(e);
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
function onMouseUp(e) {
|
||||
eventHandler && eventHandler(e);
|
||||
releaseCaptureHandler && releaseCaptureHandler();
|
||||
|
||||
document.removeEventListener("mousemove", onMouseMove, true);
|
||||
document.removeEventListener("mouseup", onMouseUp, true);
|
||||
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
document.addEventListener("mousemove", onMouseMove, true);
|
||||
document.addEventListener("mouseup", onMouseUp, true);
|
||||
};
|
||||
}
|
||||
|
||||
ace.addMouseWheelListener = function(el, callback) {
|
||||
var listener = function(e) {
|
||||
e.wheel = (e.wheelDelta) ? e.wheelDelta / 120
|
||||
: -(e.detail || 0) / 3;
|
||||
callback(e);
|
||||
};
|
||||
ace.addListener(el, "DOMMouseScroll", listener);
|
||||
ace.addListener(el, "mousewheel", listener);
|
||||
};
|
||||
|
||||
ace.autoremoveListener = function(el, type, callback, timeout) {
|
||||
var listener = function(e) {
|
||||
clearTimeout(timeoutId);
|
||||
remove();
|
||||
callback(e);
|
||||
};
|
||||
|
||||
var remove = function() {
|
||||
ace.removeListener(el, type, listener);
|
||||
};
|
||||
|
||||
ace.addListener(el, type, listener);
|
||||
var timeoutId = setTimeout(remove, timeout);
|
||||
};
|
||||
|
||||
ace.addTripleClickListener = function(el, callback) {
|
||||
ace.addListener(el, "mousedown", function() {
|
||||
ace.autoremoveListener(el, "mousedown", function() {
|
||||
ace.autoremoveListener(el, "mousedown", callback, 300);
|
||||
}, 300);
|
||||
});
|
||||
};
|
||||
85
src/ace/layer/Cursor.js
Normal file
85
src/ace/layer/Cursor.js
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
ace.provide("ace.layer.Cursor");
|
||||
|
||||
ace.layer.Cursor = function(parentEl) {
|
||||
this.element = document.createElement("div");
|
||||
this.element.className = "layer cursor-layer";
|
||||
parentEl.appendChild(this.element);
|
||||
|
||||
this.cursor = document.createElement("div");
|
||||
this.cursor.className = "cursor";
|
||||
|
||||
this.isVisible = false;
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
this.setCursor = function(position) {
|
||||
this.position = {
|
||||
row : position.row,
|
||||
column : position.column
|
||||
};
|
||||
};
|
||||
|
||||
this.hideCursor = function() {
|
||||
this.isVisible = false;
|
||||
if (this.cursor.parentNode) {
|
||||
this.cursor.parentNode.removeChild(this.cursor);
|
||||
}
|
||||
clearInterval(this.blinkId);
|
||||
};
|
||||
|
||||
this.showCursor = function() {
|
||||
this.isVisible = true;
|
||||
this.element.appendChild(this.cursor);
|
||||
|
||||
var cursor = this.cursor;
|
||||
cursor.style.visibility = "visible";
|
||||
this.restartTimer();
|
||||
};
|
||||
|
||||
this.restartTimer = function() {
|
||||
clearInterval(this.blinkId);
|
||||
if (!this.isVisible) {
|
||||
return;
|
||||
}
|
||||
|
||||
var cursor = this.cursor;
|
||||
this.blinkId = setInterval(function() {
|
||||
cursor.style.visibility = "hidden";
|
||||
setTimeout(function() {
|
||||
cursor.style.visibility = "visible";
|
||||
}, 400);
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
this.getPixelPosition = function() {
|
||||
return this.pixelPos || {
|
||||
left : 0,
|
||||
top : 0
|
||||
};
|
||||
};
|
||||
|
||||
this.update = function(config) {
|
||||
if (!this.position)
|
||||
return;
|
||||
|
||||
var cursorLeft = Math.round(this.position.column * config.characterWidth);
|
||||
var cursorTop = this.position.row * config.lineHeight;
|
||||
|
||||
this.pixelPos = {
|
||||
left : cursorLeft,
|
||||
top : cursorTop
|
||||
};
|
||||
|
||||
this.cursor.style.left = cursorLeft + "px";
|
||||
this.cursor.style.top = (cursorTop - (config.firstRow * config.lineHeight))
|
||||
+ "px";
|
||||
this.cursor.style.height = config.lineHeight + "px";
|
||||
|
||||
if (this.isVisible) {
|
||||
this.element.appendChild(this.cursor);
|
||||
}
|
||||
this.restartTimer();
|
||||
};
|
||||
|
||||
}).call(ace.layer.Cursor.prototype);
|
||||
22
src/ace/layer/Gutter.js
Normal file
22
src/ace/layer/Gutter.js
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
ace.provide("ace.layer.Gutter");
|
||||
|
||||
ace.layer.Gutter = function(parentEl) {
|
||||
this.element = document.createElement("div");
|
||||
this.element.className = "layer gutter-layer";
|
||||
parentEl.appendChild(this.element);
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
this.update = function(config) {
|
||||
var html = [];
|
||||
for ( var i = config.firstRow; i <= config.lastRow; i++) {
|
||||
html.push("<div class='gutter-cell' style='height:" + config.lineHeight
|
||||
+ "px;'>", (i+1), "</div>");
|
||||
html.push("</div>");
|
||||
}
|
||||
|
||||
this.element.innerHTML = html.join("");
|
||||
};
|
||||
|
||||
}).call(ace.layer.Gutter.prototype);
|
||||
165
src/ace/layer/Marker.js
Normal file
165
src/ace/layer/Marker.js
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
ace.provide("ace.layer.Marker");
|
||||
|
||||
ace.layer.Marker = function(parentEl) {
|
||||
this.element = document.createElement("div");
|
||||
this.element.className = "layer marker-layer";
|
||||
parentEl.appendChild(this.element);
|
||||
|
||||
this.markers = {};
|
||||
this.$markerId = 1;
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
this.setDocument = function(doc) {
|
||||
this.doc = doc;
|
||||
};
|
||||
|
||||
this.addMarker = function(range, clazz, type) {
|
||||
var id = this.$markerId++;
|
||||
this.markers[id] = {
|
||||
range : range,
|
||||
type : type || "line",
|
||||
clazz : clazz
|
||||
};
|
||||
|
||||
this.update();
|
||||
return id;
|
||||
};
|
||||
|
||||
this.removeMarker = function(markerId) {
|
||||
var marker = this.markers[markerId];
|
||||
if (marker) {
|
||||
delete (this.markers[markerId]);
|
||||
this.update();
|
||||
}
|
||||
};
|
||||
|
||||
this.update = function(config) {
|
||||
var config = config || this.config;
|
||||
if (!config)
|
||||
return;
|
||||
|
||||
this.config = config;
|
||||
|
||||
var html = [];
|
||||
for ( var key in this.markers) {
|
||||
var marker = this.markers[key];
|
||||
var range = {
|
||||
start: marker.range.start,
|
||||
end: marker.range.end
|
||||
};
|
||||
|
||||
// clip
|
||||
if (range.start.row > config.lastRow) continue;
|
||||
if (range.end.row < config.firstRow) continue;
|
||||
|
||||
if (range.end.row > config.lastRow) {
|
||||
range.end = {
|
||||
row: config.lastRow+1,
|
||||
column: 0
|
||||
};
|
||||
}
|
||||
|
||||
if (range.start.row < config.firstRow) {
|
||||
range.start = {
|
||||
row: config.firstRow,
|
||||
column: 0
|
||||
};
|
||||
}
|
||||
|
||||
if (range.start.row !== range.end.row) {
|
||||
if (marker.type == "text") {
|
||||
this.drawTextMarker(html, range, marker.clazz, config);
|
||||
} else {
|
||||
this.drawMultiLineMarker(html, range, marker.clazz, config);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.drawSingleLineMarker(html, range, marker.clazz, config);
|
||||
}
|
||||
}
|
||||
this.element.innerHTML = html.join("");
|
||||
};
|
||||
|
||||
this.drawTextMarker = function(stringBuilder, range, clazz, layerConfig) {
|
||||
|
||||
// selection start
|
||||
var row = range.start.row;
|
||||
var lineRange = { start: {}, end: {}};
|
||||
|
||||
lineRange.start.row = row;
|
||||
lineRange.start.column = range.start.column;
|
||||
lineRange.end.row = row;
|
||||
lineRange.end.column = this.doc.getLine(row).length;
|
||||
this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig);
|
||||
|
||||
// selection end
|
||||
var row = range.end.row;
|
||||
lineRange.start.row = row;
|
||||
lineRange.start.column = 0;
|
||||
lineRange.end.row = row;
|
||||
lineRange.end.column = range.end.column;
|
||||
this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig);
|
||||
|
||||
for (var row = range.start.row + 1; row < range.end.row; row++) {
|
||||
lineRange.start.row = row;
|
||||
lineRange.end.row = row;
|
||||
lineRange.end.column = this.doc.getLine(row).length;
|
||||
this.drawSingleLineMarker(stringBuilder, lineRange, clazz, layerConfig);
|
||||
}
|
||||
};
|
||||
|
||||
this.drawMultiLineMarker = function(stringBuilder, range, clazz, layerConfig) {
|
||||
|
||||
var height = layerConfig.lineHeight;
|
||||
var width = Math.round(layerConfig.width - (range.start.column * layerConfig.characterWidth));
|
||||
var top = (range.start.row - layerConfig.firstRow) * layerConfig.lineHeight;
|
||||
var left = Math.round(range.start.column * layerConfig.characterWidth);
|
||||
|
||||
stringBuilder.push(
|
||||
"<div class='", clazz, "' style='",
|
||||
"height:", height, "px;",
|
||||
"width:", width, "px;",
|
||||
"top:", top, "px;",
|
||||
"left:", left, "px;'></div>"
|
||||
);
|
||||
|
||||
var top = (range.end.row - layerConfig.firstRow) * layerConfig.lineHeight;
|
||||
var width = Math.round(range.end.column * layerConfig.characterWidth);
|
||||
|
||||
stringBuilder.push(
|
||||
"<div class='", clazz, "' style='",
|
||||
"height:", height, "px;",
|
||||
"top:", top, "px;",
|
||||
"width:", width, "px;'></div>"
|
||||
);
|
||||
|
||||
for (var row = range.start.row + 1; row < range.end.row; row++) {
|
||||
var top = (row - layerConfig.firstRow) * layerConfig.lineHeight;
|
||||
stringBuilder.push(
|
||||
"<div class='", clazz, "' style='",
|
||||
"height:", height, "px;",
|
||||
"width:", layerConfig.width, "px;",
|
||||
"top:", top, "px;'></div>"
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
this.drawSingleLineMarker = function(stringBuilder, range, clazz, layerConfig) {
|
||||
|
||||
var height = layerConfig.lineHeight;
|
||||
var width = Math.round((range.end.column - range.start.column) * layerConfig.characterWidth);
|
||||
var top = (range.start.row - layerConfig.firstRow) * layerConfig.lineHeight;
|
||||
var left = Math.round(range.start.column * layerConfig.characterWidth);
|
||||
|
||||
stringBuilder.push(
|
||||
"<div class='", clazz, "' style='",
|
||||
"height:", height, "px;",
|
||||
"width:", width, "px;",
|
||||
"top:", top, "px;",
|
||||
"left:", left,"px;'></div>"
|
||||
);
|
||||
};
|
||||
|
||||
}).call(ace.layer.Marker.prototype);
|
||||
133
src/ace/layer/Text.js
Normal file
133
src/ace/layer/Text.js
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
ace.provide("ace.layer.Text");
|
||||
|
||||
ace.layer.Text = function(parentEl) {
|
||||
this.element = document.createElement("div");
|
||||
this.element.className = "layer text-layer";
|
||||
parentEl.appendChild(this.element);
|
||||
|
||||
this.$measureSizes();
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
// this.EOF_CHAR = "¶";
|
||||
this.EOF_CHAR = "¶";
|
||||
this.EOL_CHAR = "¬";
|
||||
// this.TAB_CHAR = "‣";
|
||||
this.TAB_CHAR = "→";
|
||||
|
||||
this.setTokenizer = function(tokenizer) {
|
||||
this.tokenizer = tokenizer;
|
||||
};
|
||||
|
||||
this.getLineHeight = function() {
|
||||
return this.lineHeight;
|
||||
};
|
||||
|
||||
this.getCharacterWidth = function() {
|
||||
return this.characterWidth;
|
||||
};
|
||||
|
||||
this.$measureSizes = function() {
|
||||
var measureNode = document.createElement("div");
|
||||
var style = measureNode.style;
|
||||
style.width = style.height = "auto";
|
||||
style.left = style.top = "-1000px";
|
||||
style.visibility = "hidden";
|
||||
style.position = "absolute";
|
||||
style.overflow = "visible";
|
||||
|
||||
measureNode.innerHTML = new Array(1000).join("Xy");
|
||||
this.element.appendChild(measureNode);
|
||||
|
||||
// in FF 3.6 monospace fonts can have a fixed sub pixel width.
|
||||
// that's why we have to measure many characters
|
||||
// Note: characterWidth can be a float!
|
||||
this.lineHeight = measureNode.offsetHeight;
|
||||
this.characterWidth = measureNode.offsetWidth / 2000;
|
||||
|
||||
this.element.removeChild(measureNode);
|
||||
};
|
||||
|
||||
this.setDocument = function(doc) {
|
||||
this.doc = doc;
|
||||
};
|
||||
|
||||
this.$showInvisibles = true;
|
||||
this.setShowInvisibles = function(showInvisibles) {
|
||||
this.$showInvisibles = showInvisibles;
|
||||
};
|
||||
|
||||
this.$computeTabString = function() {
|
||||
var tabSize = this.doc.getTabSize();
|
||||
if (this.$showInvisibles) {
|
||||
var halfTab = (tabSize) / 2;
|
||||
this.$tabString = "<span class='invisible'>"
|
||||
+ new Array(Math.floor(halfTab)).join(" ")
|
||||
+ this.TAB_CHAR
|
||||
+ new Array(Math.ceil(halfTab)+1).join(" ")
|
||||
+ "</span>";
|
||||
} else {
|
||||
this.$tabString = new Array(tabSize+1).join(" ");
|
||||
}
|
||||
};
|
||||
|
||||
this.updateLines = function(layerConfig, firstRow, lastRow) {
|
||||
this.$computeTabString();
|
||||
|
||||
var first = Math.max(firstRow, layerConfig.firstRow);
|
||||
var last = Math.min(lastRow, layerConfig.lastRow);
|
||||
|
||||
var lineElements = this.element.childNodes;
|
||||
|
||||
for ( var i = first; i <= last; i++) {
|
||||
var html = [];
|
||||
this.renderLine(html, i);
|
||||
|
||||
var lineElement = lineElements[i - layerConfig.firstRow];
|
||||
lineElement.innerHTML = html.join("");
|
||||
};
|
||||
};
|
||||
|
||||
this.update = function(config) {
|
||||
this.$computeTabString();
|
||||
|
||||
var html = [];
|
||||
for ( var i = config.firstRow; i <= config.lastRow; i++) {
|
||||
html.push("<div class='line' style='height:" + this.lineHeight + "px;", "width:",
|
||||
config.width, "px'>");
|
||||
this.renderLine(html, i), html.push("</div>");
|
||||
}
|
||||
|
||||
this.element.innerHTML = html.join("");
|
||||
};
|
||||
|
||||
this.renderLine = function(stringBuilder, row) {
|
||||
var tokens = this.tokenizer.getTokens(row);
|
||||
for ( var i = 0; i < tokens.length; i++) {
|
||||
var token = tokens[i];
|
||||
|
||||
var output = token.value
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/[\v\f \u00a0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000]/g, " ")
|
||||
.replace(/\t/g, this.$tabString);
|
||||
|
||||
if (token.type !== "text") {
|
||||
stringBuilder.push("<span class='", token.type, "'>", output, "</span>");
|
||||
}
|
||||
else {
|
||||
stringBuilder.push(output);
|
||||
}
|
||||
};
|
||||
|
||||
if (this.$showInvisibles) {
|
||||
if (row !== this.doc.getLength() - 1) {
|
||||
stringBuilder.push("<span class='invisible'>" + this.EOL_CHAR + "</span>");
|
||||
} else {
|
||||
stringBuilder.push("<span class='invisible'>" + this.EOF_CHAR + "</span>");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}).call(ace.layer.Text.prototype);
|
||||
27
src/ace/mode/Css.js
Normal file
27
src/ace/mode/Css.js
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
ace.provide("ace.mode.Css");
|
||||
|
||||
ace.mode.Css = function() {
|
||||
this.$tokenizer = new ace.Tokenizer(new ace.mode.CssHighlightRules().getRules());
|
||||
};
|
||||
ace.inherits(ace.mode.Css, ace.mode.Text);
|
||||
|
||||
(function() {
|
||||
|
||||
this.getNextLineIndent = function(line, state, tab) {
|
||||
var indent = this.$getIndent(line);
|
||||
|
||||
// ignore braces in comments
|
||||
var tokens = this.$tokenizer.getLineTokens(line, state).tokens;
|
||||
if (tokens.length && tokens[tokens.length-1].type == "comment") {
|
||||
return indent;
|
||||
}
|
||||
|
||||
var match = line.match(/^.*\{\s*$/);
|
||||
if (match) {
|
||||
indent += tab;
|
||||
}
|
||||
|
||||
return indent;
|
||||
};
|
||||
|
||||
}).call(ace.mode.Css.prototype);
|
||||
184
src/ace/mode/CssHighlightRules.js
Normal file
184
src/ace/mode/CssHighlightRules.js
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
ace.provide("ace.mode.CssHighlightRules");
|
||||
|
||||
ace.mode.CssHighlightRules = function() {
|
||||
|
||||
var properties = {
|
||||
"width": 1,
|
||||
"height": 1,
|
||||
"top": 1,
|
||||
"left": 1,
|
||||
"right": 1,
|
||||
"bottom": 1,
|
||||
"overflow": 1,
|
||||
"overflow-x": 1,
|
||||
"overflow-y": 1,
|
||||
"background": 1,
|
||||
"font": 1,
|
||||
"font-style": 1,
|
||||
"font-family": 1,
|
||||
"font-size": 1,
|
||||
"text-align": 1,
|
||||
"white-space": 1,
|
||||
"color": 1,
|
||||
"z-index": 1,
|
||||
"position": 1,
|
||||
"cursor": 1,
|
||||
"box-sizing": 1,
|
||||
"-webkit-box-sizing": 1,
|
||||
"-moz-box-sizing": 1,
|
||||
"margin": 1,
|
||||
"padding": 1,
|
||||
"padding-top": 1,
|
||||
"padding-right": 1,
|
||||
"padding-bottom": 1,
|
||||
"padding-left": 1,
|
||||
"border": 1,
|
||||
"border-top": 1,
|
||||
"border-right": 1,
|
||||
"border-left": 1,
|
||||
"border-bottom": 1
|
||||
};
|
||||
|
||||
var functions = {
|
||||
"rgb": 1,
|
||||
"rgba": 1
|
||||
};
|
||||
|
||||
var constants = {
|
||||
"absolute": 1,
|
||||
"relative": 1,
|
||||
"fixed": 1,
|
||||
"solid": 1,
|
||||
"hidden": 1,
|
||||
"scroll": 1,
|
||||
"no-wrap": 1
|
||||
};
|
||||
|
||||
// regexp must not have capturing parentheses. Use (?:) instead.
|
||||
// regexps are ordered -> the first match is used
|
||||
|
||||
var numRe = "\\-?(?:(?:[0-9]+)|(?:[0-9]*\\.[0-9]+))";
|
||||
|
||||
function ic(str) {
|
||||
var re = [];
|
||||
var chars = str.split("");
|
||||
for (var i=0; i<chars.length; i++) {
|
||||
re.push(
|
||||
"[",
|
||||
chars[i].toLowerCase(),
|
||||
chars[i].toUpperCase(),
|
||||
"]"
|
||||
);
|
||||
}
|
||||
return re.join("");
|
||||
}
|
||||
|
||||
this.$rules = {
|
||||
"start" : [ {
|
||||
token : "comment", // multi line comment
|
||||
regex : "\\/\\*",
|
||||
next : "comment"
|
||||
}, {
|
||||
token : "string", // single line
|
||||
regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]'
|
||||
}, {
|
||||
token : "string", // single line
|
||||
regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
|
||||
}, {
|
||||
token : "number",
|
||||
regex : numRe + ic("em")
|
||||
}, {
|
||||
token : "number",
|
||||
regex : numRe + ic("ex")
|
||||
}, {
|
||||
token : "number",
|
||||
regex : numRe + ic("px")
|
||||
}, {
|
||||
token : "number",
|
||||
regex : numRe + ic("cm")
|
||||
}, {
|
||||
token : "number",
|
||||
regex : numRe + ic("mm")
|
||||
}, {
|
||||
token : "number",
|
||||
regex : numRe + ic("in")
|
||||
}, {
|
||||
token : "number",
|
||||
regex : numRe + ic("pt")
|
||||
}, {
|
||||
token : "number",
|
||||
regex : numRe + ic("pc")
|
||||
}, {
|
||||
token : "number",
|
||||
regex : numRe + ic("deg")
|
||||
}, {
|
||||
token : "number",
|
||||
regex : numRe + ic("rad")
|
||||
}, {
|
||||
token : "number",
|
||||
regex : numRe + ic("grad")
|
||||
}, {
|
||||
token : "number",
|
||||
regex : numRe + ic("ms")
|
||||
}, {
|
||||
token : "number",
|
||||
regex : numRe + ic("s")
|
||||
}, {
|
||||
token : "number",
|
||||
regex : numRe + ic("hz")
|
||||
}, {
|
||||
token : "number",
|
||||
regex : numRe + ic("khz")
|
||||
}, {
|
||||
token : "number",
|
||||
regex : numRe + "%"
|
||||
}, {
|
||||
token : "number",
|
||||
regex : numRe
|
||||
}, {
|
||||
token : "number", // hex6 color
|
||||
regex : "#[a-fA-F0-9]{6}"
|
||||
}, {
|
||||
token : "number", // hex3 color
|
||||
regex : "#[a-fA-F0-9]{3}"
|
||||
}, {
|
||||
token : "lparen",
|
||||
regex : "\{"
|
||||
}, {
|
||||
token : "rparen",
|
||||
regex : "\}"
|
||||
}, {
|
||||
token : function(value) {
|
||||
if (properties[value.toLowerCase()]) {
|
||||
return "buildin-constant";
|
||||
}
|
||||
else if (functions[value.toLowerCase()]) {
|
||||
return "buildin-function";
|
||||
}
|
||||
else if (constants[value.toLowerCase()]) {
|
||||
return "library-constant";
|
||||
}
|
||||
else {
|
||||
return "identifier";
|
||||
}
|
||||
},
|
||||
regex : "\\-?[a-zA-Z_][a-zA-Z0-9_\\-]*"
|
||||
}],
|
||||
"comment" : [{
|
||||
token : "comment", // closing comment
|
||||
regex : ".*?\\*\\/",
|
||||
next : "start"
|
||||
}, {
|
||||
token : "comment", // comment spanning whole line
|
||||
regex : ".+"
|
||||
}]
|
||||
};
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
this.getRules = function() {
|
||||
return this.$rules;
|
||||
};
|
||||
|
||||
}).call(ace.mode.CssHighlightRules.prototype);
|
||||
41
src/ace/mode/Html.js
Normal file
41
src/ace/mode/Html.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
ace.provide("ace.mode.Html");
|
||||
|
||||
ace.mode.Html = function() {
|
||||
this.$tokenizer = new ace.Tokenizer(new ace.mode.HtmlHighlightRules().getRules());
|
||||
|
||||
this.$js = new ace.mode.JavaScript();
|
||||
this.$css = new ace.mode.Css();
|
||||
};
|
||||
ace.inherits(ace.mode.Html, ace.mode.Text);
|
||||
|
||||
(function() {
|
||||
|
||||
this.toggleCommentLines = function(doc, range, state) {
|
||||
var split = state.split("js-");
|
||||
if (!split[0] && split[1]) {
|
||||
return this.$js.toggleCommentLines(doc, range, state);
|
||||
}
|
||||
|
||||
var split = state.split("css-");
|
||||
if (!split[0] && split[1]) {
|
||||
return this.$css.toggleCommentLines(doc, range, state);
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
this.getNextLineIndent = function(line, state, tab) {
|
||||
var split = state.split("js-");
|
||||
if (!split[0] && split[1]) {
|
||||
return this.$js.getNextLineIndent(line, split[1], tab);
|
||||
}
|
||||
|
||||
var split = state.split("css-");
|
||||
if (!split[0] && split[1]) {
|
||||
return this.$css.getNextLineIndent(line, split[1], tab);
|
||||
}
|
||||
|
||||
return "";
|
||||
};
|
||||
|
||||
}).call(ace.mode.Html.prototype);
|
||||
152
src/ace/mode/HtmlHighlightRules.js
Normal file
152
src/ace/mode/HtmlHighlightRules.js
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
ace.provide("ace.mode.HtmlHighlightRules");
|
||||
|
||||
ace.mode.HtmlHighlightRules = function() {
|
||||
|
||||
// regexp must not have capturing parentheses
|
||||
// regexps are ordered -> the first match is used
|
||||
|
||||
this.$rules = {
|
||||
start : [ {
|
||||
token : "text",
|
||||
regex : "<\\!\\[CDATA\\[",
|
||||
next : "cdata"
|
||||
}, {
|
||||
token : "xml_pe",
|
||||
regex : "<\\?.*?\\?>"
|
||||
}, {
|
||||
token : "comment",
|
||||
regex : "<\\!--",
|
||||
next : "comment"
|
||||
}, {
|
||||
token : "text",
|
||||
regex : "<(?=\s*script)",
|
||||
next : "script"
|
||||
}, {
|
||||
token : "text",
|
||||
regex : "<(?=\s*style)",
|
||||
next : "css"
|
||||
}, {
|
||||
token : "text", // opening tag
|
||||
regex : "<\\/?",
|
||||
next : "tag"
|
||||
}, {
|
||||
token : "text",
|
||||
regex : "\\s+"
|
||||
}, {
|
||||
token : "text",
|
||||
regex : "[^<]+"
|
||||
} ],
|
||||
|
||||
script : [ {
|
||||
token : "text",
|
||||
regex : ">",
|
||||
next : "js-start"
|
||||
}, {
|
||||
token : "keyword",
|
||||
regex : "[-_a-zA-Z0-9:]+"
|
||||
}, {
|
||||
token : "text",
|
||||
regex : "\\s+"
|
||||
}, {
|
||||
token : "string",
|
||||
regex : '".*?"'
|
||||
}, {
|
||||
token : "string",
|
||||
regex : "'.*?'"
|
||||
} ],
|
||||
|
||||
css : [ {
|
||||
token : "text",
|
||||
regex : ">",
|
||||
next : "css-start"
|
||||
}, {
|
||||
token : "keyword",
|
||||
regex : "[-_a-zA-Z0-9:]+"
|
||||
}, {
|
||||
token : "text",
|
||||
regex : "\\s+"
|
||||
}, {
|
||||
token : "string",
|
||||
regex : '".*?"'
|
||||
}, {
|
||||
token : "string",
|
||||
regex : "'.*?'"
|
||||
} ],
|
||||
|
||||
tag : [ {
|
||||
token : "text",
|
||||
regex : ">",
|
||||
next : "start"
|
||||
}, {
|
||||
token : "keyword",
|
||||
regex : "[-_a-zA-Z0-9:]+"
|
||||
}, {
|
||||
token : "text",
|
||||
regex : "\\s+"
|
||||
}, {
|
||||
token : "string",
|
||||
regex : '".*?"'
|
||||
}, {
|
||||
token : "string",
|
||||
regex : "'.*?'"
|
||||
} ],
|
||||
|
||||
cdata : [ {
|
||||
token : "text",
|
||||
regex : "\\]\\]>",
|
||||
next : "start"
|
||||
}, {
|
||||
token : "text",
|
||||
regex : "\\s+"
|
||||
}, {
|
||||
token : "text",
|
||||
regex : ".+"
|
||||
} ],
|
||||
|
||||
comment : [ {
|
||||
token : "comment",
|
||||
regex : ".*?-->",
|
||||
next : "start"
|
||||
}, {
|
||||
token : "comment",
|
||||
regex : ".+"
|
||||
} ]
|
||||
};
|
||||
|
||||
var jsRules = new ace.mode.JavaScriptHighlightRules().getRules();
|
||||
this.$addRules(jsRules, "js-");
|
||||
this.$rules["js-start"].unshift({
|
||||
token: "text",
|
||||
regex: "<\\/(?=script)",
|
||||
next: "tag"
|
||||
});
|
||||
|
||||
var cssRules = new ace.mode.CssHighlightRules().getRules();
|
||||
this.$addRules(cssRules, "css-");
|
||||
this.$rules["css-start"].unshift({
|
||||
token: "text",
|
||||
regex: "<\\/(?=style)",
|
||||
next: "tag"
|
||||
});
|
||||
};
|
||||
|
||||
(function() {
|
||||
|
||||
this.$addRules = function(rules, prefix) {
|
||||
for (var key in rules) {
|
||||
var state = rules[key];
|
||||
for (var i=0; i<state.length; i++) {
|
||||
var rule = state[i];
|
||||
if (rule.next) {
|
||||
rule.next = prefix + rule.next;
|
||||
}
|
||||
}
|
||||
this.$rules[prefix + key] = state;
|
||||
}
|
||||
};
|
||||
|
||||
this.getRules = function() {
|
||||
return this.$rules;
|
||||
};
|
||||
|
||||
}).call(ace.mode.HtmlHighlightRules.prototype);
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue