This commit is contained in:
Sergi Mansilla 2011-11-03 00:12:20 +01:00
commit e02b43d9c0
136 changed files with 1074 additions and 582 deletions

View file

@ -365,4 +365,33 @@ canon.addCommand({
exec: function(env, args, request) { env.editor.transposeLetters(); }
});
canon.addCommand({
name: "fold",
bindKey: bindKey("Alt-L", "Alt-L"),
exec: function(env) {
env.editor.session.toggleFold(false);
}
});
canon.addCommand({
name: "unfold",
bindKey: bindKey("Alt-Shift-L", "Alt-Shift-L"),
exec: function(env) {
env.editor.session.toggleFold(true);
}
});
canon.addCommand({
name: "foldall",
bindKey: bindKey("Alt-Shift-0", "Alt-Shift-0"),
exec: function(env) {
env.editor.session.foldAll();
}
});
canon.addCommand({
name: "unfoldall",
bindKey: bindKey("Alt-Shift-0", "Alt-Shift-0"),
exec: function(env) {
env.editor.session.unFoldAll();
}
});
});

View file

@ -91,7 +91,7 @@ var EditSession = function(text, mode) {
this.doc = doc;
doc.on("change", this.onChange.bind(this));
this.on("changeFold", this.onChangeFold.bind(this));
if (this.bgTokenizer) {
this.bgTokenizer.setDocument(this.getDocument());
this.bgTokenizer.start(0);
@ -136,7 +136,7 @@ var EditSession = function(text, mode) {
folds: removedFolds
});
}
this.$informUndoManager.schedule();
}
@ -148,7 +148,7 @@ var EditSession = function(text, mode) {
this.doc.setValue(text);
this.selection.moveCursorTo(0, 0);
this.selection.clearSelection();
this.$resetRowCache(0);
this.$deltas = [];
this.$deltasDoc = [];
@ -173,6 +173,27 @@ var EditSession = function(text, mode) {
return this.bgTokenizer.getTokens(firstRow, lastRow);
};
this.getTokenAt = function(row, column) {
var tokens = this.bgTokenizer.getTokens(row, row)[0].tokens;
var token, c = 0;
if (column == null) {
i = tokens.length - 1;
c = this.getLine(row).length;
} else {
for (var i = 0; i < tokens.length; i++) {
c += tokens[i].value.length;
if (c >= column)
break;
}
}
token = tokens[i];
if (!token)
return null;
token.index = i;
token.start = c - token.value.length;
return token;
};
this.setUndoManager = function(undoManager) {
this.$undoManager = undoManager;
this.$resetRowCache(0);
@ -187,7 +208,7 @@ var EditSession = function(text, mode) {
var self = this;
this.$syncInformUndoManager = function() {
self.$informUndoManager.cancel();
if (self.$deltasFold.length) {
self.$deltas.push({
group: "fold",
@ -195,7 +216,7 @@ var EditSession = function(text, mode) {
});
self.$deltasFold = [];
}
if (self.$deltasDoc.length) {
self.$deltas.push({
group: "doc",
@ -203,14 +224,14 @@ var EditSession = function(text, mode) {
});
self.$deltasDoc = [];
}
if (self.$deltas.length > 0) {
undoManager.execute({
action: "aceupdate",
args: [self.$deltas, self]
});
}
self.$deltas = [];
}
this.$informUndoManager =
@ -479,7 +500,7 @@ var EditSession = function(text, mode) {
this.bgTokenizer.setDocument(this.getDocument());
this.bgTokenizer.start(0);
this.tokenRe = mode.tokenRe;
this.nonTokenRe = mode.nonTokenRe;
@ -894,7 +915,7 @@ var EditSession = function(text, mode) {
this.$clipRowToDocument = function(row) {
return Math.max(0, Math.min(row, this.doc.getLength()-1));
};
this.$clipPositionToDocument = function(row, column) {
column = Math.max(0, column);
@ -910,7 +931,7 @@ var EditSession = function(text, mode) {
column = Math.min(this.doc.getLine(row).length, column);
}
}
return {
row: row,
column: column
@ -1176,6 +1197,7 @@ var EditSession = function(text, mode) {
CHAR_EXT = 2,
PLACEHOLDER_START = 3,
PLACEHOLDER_BODY = 4,
PUNCTUATION = 9,
SPACE = 10,
TAB = 11,
TAB_SPACE = 12;
@ -1219,7 +1241,7 @@ var EditSession = function(text, mode) {
// a split is simple.
if (tokens[split] >= SPACE) {
// Include all following spaces + tabs in this split as well.
while (tokens[split] >= SPACE) {
while (tokens[split] >= SPACE) {
split ++;
}
addSplit(split);
@ -1274,16 +1296,17 @@ var EditSession = function(text, mode) {
}
// === ELSE ===
// Search for the first non space/tab/placeholder token backwards.
for (split; split != lastSplit - 1; split--) {
if (tokens[split] >= PLACEHOLDER_START) {
split++;
break;
}
// Search for the first non space/tab/placeholder/punctuation token backwards.
var minSplit = Math.max(split - 10, lastSplit - 1);
while (split > minSplit && tokens[split] < PLACEHOLDER_START) {
split --;
}
while (split > minSplit && tokens[split] == PUNCTUATION) {
split --;
}
// If we found one, then add the split.
if (split > lastSplit) {
addSplit(split);
if (split > minSplit) {
addSplit(++split);
continue;
}
@ -1291,7 +1314,7 @@ var EditSession = function(text, mode) {
split = lastSplit + wrapLimit;
// The split is inside of a CHAR or CHAR_EXT token and no space
// around -> force a split.
addSplit(lastSplit + wrapLimit);
addSplit(split);
}
return splits;
}
@ -1317,11 +1340,13 @@ var EditSession = function(text, mode) {
}
}
// Space
else if(c == 32) {
else if (c == 32) {
arr.push(SPACE);
} else if((c > 39 && c < 48) || (c > 57 && c < 64)) {
arr.push(PUNCTUATION);
}
// full width characters
else if (isFullWidth(c)) {
else if (c >= 0x1100 && isFullWidth(c)) {
arr.push(CHAR, CHAR_EXT);
} else {
arr.push(CHAR);
@ -1357,7 +1382,7 @@ var EditSession = function(text, mode) {
screenColumn += this.getScreenTabSize(screenColumn);
}
// full width characters
else if (isFullWidth(c)) {
else if (c >= 0x1100 && isFullWidth(c)) {
screenColumn += 2;
} else {
screenColumn += 1;
@ -1433,7 +1458,7 @@ var EditSession = function(text, mode) {
column: 0
}
}
var line;
var docRow = 0;
var docColumn = 0;
@ -1453,11 +1478,11 @@ var EditSession = function(text, mode) {
}
}
var doCache = !rowCache.length || i == rowCache.length;
// clamp row before clamping column, for selection on last line
var maxRow = this.getLength() - 1;
var foldLine = this.getNextFold(docRow);
var foldLine = this.getNextFoldLine(docRow);
var foldStart = foldLine ? foldLine.start.row : Infinity;
while (row <= screenRow) {
@ -1469,7 +1494,7 @@ var EditSession = function(text, mode) {
docRow++;
if (docRow > foldStart) {
docRow = foldLine.end.row+1;
foldLine = this.getNextFold(docRow);
foldLine = this.getNextFoldLine(docRow, foldLine);
foldStart = foldLine ? foldLine.start.row : Infinity;
}
}
@ -1521,7 +1546,7 @@ var EditSession = function(text, mode) {
if (foldLine) {
return foldLine.idxToPosition(docColumn);
}
return {
row: docRow,
column: docColumn
@ -1532,12 +1557,12 @@ var EditSession = function(text, mode) {
// Normalize the passed in arguments.
if (typeof docColumn === "undefined")
var pos = this.$clipPositionToDocument(docRow.row, docRow.column);
else
else
pos = this.$clipPositionToDocument(docRow, docColumn);
docRow = pos.row;
docColumn = pos.column;
var LL = this.$rowCache.length;
var wrapData;
@ -1579,7 +1604,7 @@ var EditSession = function(text, mode) {
}
var doCache = !rowCache.length || i == rowCache.length;
var foldLine = this.getNextFold(row);
var foldLine = this.getNextFoldLine(row);
var foldStart = foldLine ?foldLine.start.row :Infinity;
while (row < docRow) {
@ -1587,7 +1612,7 @@ var EditSession = function(text, mode) {
rowEnd = foldLine.end.row + 1;
if (rowEnd > docRow)
break;
foldLine = this.getNextFold(rowEnd);
foldLine = this.getNextFoldLine(rowEnd, foldLine);
foldStart = foldLine ?foldLine.start.row :Infinity;
}
else {
@ -1596,7 +1621,7 @@ var EditSession = function(text, mode) {
screenRow += this.getRowLength(row);
row = rowEnd;
if (doCache) {
rowCache.push({
docRow: row,
@ -1713,4 +1738,4 @@ var EditSession = function(text, mode) {
require("ace/edit_session/folding").Folding.call(EditSession.prototype);
exports.EditSession = EditSession;
});
});

View file

@ -52,7 +52,7 @@ function Folding() {
var foldLine = this.getFoldLine(row);
if (!foldLine)
return null;
var folds = foldLine.folds;
for (var i = 0; i < folds.length; i++) {
var fold = folds[i];
@ -134,7 +134,7 @@ function Folding() {
var foldLine = foldLine || this.getFoldLine(row);
if (!foldLine)
return null;
var lastFold = {
end: { column: 0 }
};
@ -183,7 +183,7 @@ function Folding() {
}
// returns the fold which starts after or contains docRow
this.getNextFold = function(docRow, startFoldLine) {
this.getNextFoldLine = function(docRow, startFoldLine) {
var foldData = this.$foldData, ans;
var i = 0;
if (startFoldLine)
@ -251,7 +251,7 @@ function Folding() {
var startColumn = fold.start.column;
var endRow = fold.end.row;
var endColumn = fold.end.column;
// --- Some checking ---
if (fold.placeholder.length < 2)
throw "Placeholder has to be at least 2 characters";
@ -489,8 +489,85 @@ function Folding() {
return fd;
};
}
this.toggleFold = function(tryToUnfold) {
var selection = this.selection;
var range = selection.getRange();
if (range.isEmpty()) {
var cursor = range.start
var fold = this.getFoldAt(cursor.row, cursor.column);
var bracketPos, column;
if (fold) {
this.expandFold(fold);
return;
} else if (bracketPos = this.findMatchingBracket(cursor)) {
if (range.comparePoint(bracketPos) == 1) {
range.end = bracketPos;
} else {
range.start = bracketPos;
range.start.column++;
range.end.column--;
}
} else if (bracketPos = this.findMatchingBracket({row: cursor.row, column: cursor.column + 1})) {
if (range.comparePoint(bracketPos) == 1)
range.end = bracketPos;
else
range.start = bracketPos;
range.start.column++;
} else {
var token = this.getTokenAt(cursor.row, cursor.column);
if (token && /^comment|string/.test(token.type)) {
var startRow = cursor.row;
var endRow = cursor.row;
var t = token;
while ((t = this.getTokenAt(startRow - 1)) && t.type == token.type) {
startRow --;
token = t;
}
range.start.row = startRow;
range.start.column = token.start + 2;
while ((t = this.getTokenAt(endRow + 1, 0)) && t.type == token.type) {
endRow ++;
token = t;
}
range.end.row = endRow;
range.end.column = token.start + token.value.length - 1;
}
}
} else {
var folds = this.getFoldsInRange(range);
if (tryToUnfold && folds.length) {
this.expandFolds(folds);
return;
} else if (folds.length == 1 ) {
fold = folds[0];
}
}
if (!fold)
fold = this.getFoldAt(range.start.row, range.start.column);
if (fold && fold.range.toString() == range.toString()){
this.expandFold(fold);
return
}
var placeholder = "...";
if (!range.isMultiLine()) {
placeholder = this.getTextRange(range);
if(placeholder.length < 4)
return;
placeholder = placeholder.trim().substring(0, 2) + ".."
}
this.addFold(placeholder, range);
};
}
exports.Folding = Folding;
});

View file

@ -346,6 +346,11 @@ module.exports = {
computeAndAssert(" ぁぁ", [1, 2], 2);
computeAndAssert(" ぁ\tぁ", [1, 3], 2);
computeAndAssert(" ぁぁ\tぁ", [1, 4], 4);
// Test wrapping for punctuation.
computeAndAssert(" ab.c;ef++", [1, 3, 5, 7, 8], 2);
computeAndAssert(" a.b", [1, 2, 3], 1);
computeAndAssert("#>>", [1, 2], 1);
},
"test get longest line" : function() {

View file

@ -792,7 +792,7 @@ var Editor =function(renderer, session) {
indentString = lang.stringRepeat(" ", count);
} else
indentString = "\t";
return this.onTextInput(indentString);
return this.onTextInput(indentString, true);
}
};

View file

@ -420,7 +420,7 @@ module.exports = {
var editor = new Editor(new MockRenderer(), session);
editor.moveCursorTo(1, 1);
editor.removeLeft();
editor.remove("left");
assert.equal(session.toString(), "123\n56");
},
@ -429,7 +429,7 @@ module.exports = {
var editor = new Editor(new MockRenderer(), session);
editor.moveCursorTo(1, 0);
editor.removeLeft();
editor.remove("left");
assert.equal(session.toString(), "123456");
},
@ -440,7 +440,7 @@ module.exports = {
var editor = new Editor(new MockRenderer(), session);
editor.moveCursorTo(1, 8);
editor.removeLeft();
editor.remove("left");
assert.equal(session.toString(), "123\n 456");
},

22
lib/ace/ext/static.css Normal file
View file

@ -0,0 +1,22 @@
.ace_editor {
font-family: 'Monaco', 'Menlo', 'Droid Sans Mono', 'Courier New', monospace;
font-size: 12px;
}
.ace_editor .ace_gutter {
width: 25px !important;
display: block;
float: left;
text-align: right;
padding: 0 3px 0 0;
margin-right: 3px;
}
.ace-row { clear: both; }
*.ace_gutter-cell {
-moz-user-select: -moz-none;
-khtml-user-select: none;
-webkit-user-select: none;
user-select: none;
}

View file

@ -0,0 +1,95 @@
/* vim:ts=4:sts=4:sw=4:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Jan Jongboom <fabian AT ajax DOT org>
* Fabian Jakobs <fabian AT ajax DOT org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var EditSession = require("ace/edit_session").EditSession;
var TextLayer = require("ace/layer/text").Text;
var baseStyles = require("ace/requirejs/text!ace/ext/static.css");
/** Transforms a given input code snippet into HTML using the given mode
*
* @param {string} input Code snippet
* @param {mode} mode Mode loaded from /ace/mode (use 'ServerSideHiglighter.getMode')
* @param {string} r Code snippet
* @returns {object} An object containing: html, css
*/
exports.render = function(input, mode, theme) {
var session = new EditSession("");
session.setMode(mode);
session.setUseWorker(false);
var textLayer = new TextLayer(document.createElement("div"));
textLayer.setSession(session);
textLayer.config = {
characterWidth: 10,
lineHeight: 20
};
session.setValue(input);
var stringBuilder = [];
var length = session.getLength();
var tokens = session.getTokens(0, length - 1);
for(var ix = 0; ix < length; ix++) {
var lineTokens = tokens[ix].tokens;
stringBuilder.push("<div class='ace-row'>");
stringBuilder.push("<span class='ace_gutter ace_gutter-cell' unselectable='on'>" + (ix+1) + "</span>");
textLayer.$renderLine(stringBuilder, 0, lineTokens, true);
stringBuilder.push("</div>");
}
// let's prepare the whole html
var html = "<div class=':cssClass'>\
<div class='ace_editor ace_scroller ace_text-layer'>\
:code\
</div>\
</div>".replace(/:cssClass/, theme.cssClass).replace(/:code/, stringBuilder.join(""));
textLayer.destroy();
return {
css: baseStyles + theme.cssText,
html: html
};
};
});

View file

@ -0,0 +1,74 @@
if (typeof process !== "undefined") {
require("../../../support/paths");
require("ace/test/mockdom");
}
var assert = require("assert");
var highlighter = require("./static_highlight");
var JavaScriptMode = require("ace/mode/javascript").Mode;
// Execution ORDER: test.setUpSuite, setUp, testFn, tearDown, test.tearDownSuite
module.exports = {
timeout: 10000,
"test simple snippet": function(next) {
var theme = require("ace/theme/tomorrow");
var snippet = "/** this is a function\n\
*\n\
*/\n\
function hello (a, b, c) {\n\
console.log(a * b + c + 'sup?');\n\
}";
var mode = new JavaScriptMode();
var isError = false, result;
try {
result = highlighter.render(snippet, mode, theme);
}
catch (e) {
console.log(e);
isError = true;
}
// todo: write something more meaningful
assert.equal(isError, false);
next();
},
"test css from theme is used": function(next) {
var theme = require("ace/theme/tomorrow");
var snippet = "/** this is a function\n\
*\n\
*/\n\
function hello (a, b, c) {\n\
console.log(a * b + c + 'sup?');\n\
}";
var mode = new JavaScriptMode();
var isError = false, result;
result = highlighter.render(snippet, mode, theme);
assert.equal(result.css, theme.cssText);
next();
},
"test theme classname should be in output html": function (next) {
var theme = require("ace/theme/tomorrow");
var snippet = "/** this is a function\n\
*\n\
*/\n\
function hello (a, b, c) {\n\
console.log(a * b + c + 'sup?');\n\
}";
var mode = new JavaScriptMode();
var isError = false, result;
result = highlighter.render(snippet, mode, theme);
assert.equal(!!result.html.match(/<div class='ace-tomorrow'>/), true);
next();
}
};
!module.parent && require("asyncjs").test.testcase(module.exports).exec();

View file

@ -93,8 +93,8 @@ var vimStates = {
},
vimcommand("(k|up)", "golineup"),
vimcommand("(j|down)", "golinedown"),
vimcommand("(l|right)", "golineright"),
vimcommand("(h|left)", "golineleft"),
vimcommand("(l|right)", "gotoright"),
vimcommand("(h|left)", "gotoleft"),
{
key: "shift-g",
exec: "gotoend"

View file

@ -103,13 +103,13 @@ var Gutter = function(parentEl) {
var html = [];
var i = config.firstRow;
var lastRow = config.lastRow;
var fold = this.session.getNextFold(i);
var fold = this.session.getNextFoldLine(i);
var foldStart = fold ? fold.start.row : Infinity;
while (true) {
if(i > foldStart) {
i = fold.end.row + 1;
fold = this.session.getNextFold(i);
fold = this.session.getNextFoldLine(i, fold);
foldStart = fold ?fold.start.row :Infinity;
}
if(i > lastRow)

View file

@ -23,6 +23,7 @@
* Fabian Jakobs <fabian AT ajax DOT org>
* Julian Viereck <julian DOT viereck AT gmail DOT com>
* Mihai Sucan <mihai.sucan@gmail.com>
* Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -121,8 +122,8 @@ var Text = function(parentEl) {
// Note: characterWidth can be a float!
measureNode.innerHTML = lang.stringRepeat("Xy", n);
if (document.body) {
document.body.appendChild(measureNode);
if (this.element.ownerDocument.body) {
this.element.ownerDocument.body.appendChild(measureNode);
} else {
var container = this.element.parentNode;
while (!dom.hasCssClass(container, "ace_editor"))
@ -257,15 +258,15 @@ var Text = function(parentEl) {
};
this.$renderLinesFragment = function(config, firstRow, lastRow) {
var fragment = document.createDocumentFragment(),
var fragment = this.element.ownerDocument.createDocumentFragment(),
row = firstRow,
fold = this.session.getNextFold(row),
fold = this.session.getNextFoldLine(row),
foldStart = fold ?fold.start.row :Infinity;
while (true) {
if(row > foldStart) {
row = fold.end.row+1;
fold = this.session.getNextFold(row);
fold = this.session.getNextFoldLine(row, fold);
foldStart = fold ?fold.start.row :Infinity;
}
if(row > lastRow)
@ -306,13 +307,13 @@ var Text = function(parentEl) {
var firstRow = config.firstRow, lastRow = config.lastRow;
var row = firstRow,
fold = this.session.getNextFold(row),
fold = this.session.getNextFoldLine(row),
foldStart = fold ?fold.start.row :Infinity;
while (true) {
if(row > foldStart) {
row = fold.end.row+1;
fold = this.session.getNextFold(row);
fold = this.session.getNextFoldLine(row, fold);
foldStart = fold ?fold.start.row :Infinity;
}
if(row > lastRow)

View file

@ -93,7 +93,7 @@ module.exports = {
assert.equal(
stringBuilder.join(""),
"<span class='ace_cjk ace_invisible' style='width:20px'>" + this.textLayer.SPACE_CHAR + "</span>"
+ "<span class='ace_invisible'>&para;</span>"
+ "<span class='ace_invisible'>\xB6</span>"
);
}
};

View file

@ -54,7 +54,7 @@ define(function(require, exports, module) {
var keywords = lang.arrayToMap((
"this|throw|then|try|typeof|super|switch|return|break|by)|continue|" +
"catch|class|in|instanceof|is|isnt|if|else|extends|for|forown|" +
"finally|function|while|when|new|not|delete|debugger|do|loop|of|off|" +
"finally|function|while|when|new|no|not|delete|debugger|do|loop|of|off|" +
"or|on|unless|until|and|yes").split("|")
);

View file

@ -78,9 +78,9 @@ module.exports = {
var tokens = this.tokenizer.getLineTokens("{()}", "start").tokens;
assert.equal(3, tokens.length);
assert.equal("lparen", tokens[0].type);
assert.equal("paren.lparen", tokens[0].type);
assert.equal("text", tokens[1].type);
assert.equal("rparen", tokens[2].type);
assert.equal("paren.rparen", tokens[2].type);
},
"test for last rule in ruleset to catch capturing group bugs" : function() {

View file

@ -95,20 +95,20 @@ module.exports = {
var tokens = this.tokenizer.getLineTokens(line, "start").tokens;
assert.equal(7, tokens.length);
assert.equal("lparen", tokens[0].type);
assert.equal("lparen", tokens[1].type);
assert.equal("lparen", tokens[2].type);
assert.equal("paren.lparen", tokens[0].type);
assert.equal("paren.lparen", tokens[1].type);
assert.equal("paren.lparen", tokens[2].type);
assert.equal("text", tokens[3].type);
assert.equal("rparen", tokens[4].type);
assert.equal("rparen", tokens[5].type);
assert.equal("rparen", tokens[6].type);
assert.equal("paren.rparen", tokens[4].type);
assert.equal("paren.rparen", tokens[5].type);
assert.equal("paren.rparen", tokens[6].type);
},
"test for last rule in ruleset to catch capturing group bugs" : function() {
var tokens = this.tokenizer.getLineTokens("}", "start").tokens;
assert.equal(1, tokens.length);
assert.equal("rparen", tokens[0].type);
assert.equal("paren.rparen", tokens[0].type);
},
"test tokenize arithmetic expression which looks like a regexp": function() {
@ -160,7 +160,7 @@ module.exports = {
"test // is not a regexp": function() {
var tokens = this.tokenizer.getLineTokens("{ // 123", "start").tokens;
assert.equal(3, tokens.length);
assert.equal("lparen", tokens[0].type);
assert.equal("paren.lparen", tokens[0].type);
assert.equal("text", tokens[1].type);
assert.equal("comment", tokens[2].type);
}

View file

@ -206,13 +206,12 @@ var Mode = function() {
for (var key in behaviours) {
if (behaviours[key][action]) {
var ret = behaviours[key][action].apply(this, arguments);
if (ret !== false) {
if (ret) {
return ret;
}
}
}
}
return false;
}
}).call(Mode.prototype);

View file

@ -126,18 +126,18 @@ function DefaultHandlers(editor) {
mousePageY = event.getDocumentY(e);
};
var onMouseSelectionEnd = function() {
var onMouseSelectionEnd = function(e) {
clearInterval(timerId);
if (state == STATE_UNKNOWN)
onStartSelect(pos);
else if (state == STATE_DRAG)
onMouseDragSelectionEnd();
onMouseDragSelectionEnd(e);
_self.$clickSelection = null;
state = STATE_UNKNOWN;
};
var onMouseDragSelectionEnd = function() {
var onMouseDragSelectionEnd = function(e) {
dom.removeCssClass(editor.container, "ace_dragging");
editor.session.removeMarker(dragSelectionMarker);
@ -157,7 +157,12 @@ function DefaultHandlers(editor) {
}
editor.clearSelection();
var newRange = editor.moveText(dragRange, dragCursor);
if (e && (e.ctrlKey || e.altKey)) {
var session = editor.session;
var newRange = session.insert(dragCursor, session.getTextRange(dragRange));
} else {
var newRange = editor.moveText(dragRange, dragCursor);
}
if (!newRange) {
dragCursor = null;
return;

View file

@ -102,9 +102,12 @@ var Range = function(startRow, startColumn, endRow, endColumn) {
}
}
this.comparePoint = function(p) {
return this.compare(p.row, p.column);
}
this.containsRange = function(range) {
var cmp = this.compareRange(range);
return (cmp == -1 || cmp == 0 || cmp == 1);
return this.comparePoint(range.start) == 0 && this.comparePoint(range.end) == 0;
}
this.isEnd = function(row, column) {

View file

@ -20,6 +20,7 @@
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -39,10 +40,11 @@ define(function(require, exports, module) {
var event = require("pilot/event");
var RenderLoop = function(onRender) {
var RenderLoop = function(onRender, window) {
this.onRender = onRender;
this.pending = false;
this.changes = 0;
this.setTimeoutZero = this.setTimeoutZero.bind(window);
};
(function() {
@ -70,31 +72,31 @@ var RenderLoop = function(onRender) {
window.msRequestAnimationFrame;
if (this.setTimeoutZero) {
this.setTimeoutZero = this.setTimeoutZero.bind(window)
this.setTimeoutZero = this.setTimeoutZero;
} else if (window.postMessage) {
this.messageName = "zero-timeout-message";
this.setTimeoutZero = (function(messageName, attached, listener) {
return function setTimeoutZero(callback) {
// Set up listener if not listening already.
if (!attached) {
event.addListener(this, "message", function(e) {
if (listener && e.data == messageName) {
event.stopPropagation(e);
listener();
}
});
attached = true;
}
this.setTimeoutZero = function(callback) {
if (!this.attached) {
var _self = this;
event.addListener(window, "message", function(e) {
if (_self.callback && e.data == _self.messageName) {
event.stopPropagation(e);
_self.callback();
}
});
this.attached = true;
}
this.callback = callback;
window.postMessage(this.messageName, "*");
}
listener = callback;
this.postMessage(messageName, "*");
};
})("zero-timeout-message", false, null);
} else {
this.setTimeoutZero = function(callback) {
setTimeout(callback, 0);
this.setTimeout(callback, 0);
}
}

View file

@ -20,6 +20,7 @@
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -56,7 +57,7 @@ var ScrollBar = function(parent) {
// of 0px
// in Firefox 6+ scrollbar is hidden if element has the same width as scrollbar
// make element a little bit wider to retain scrollbar when page is zoomed
this.width = dom.scrollbarWidth();
this.width = dom.scrollbarWidth(parent.ownerDocument);
this.element.style.width = (this.width || 15) + 5 + "px";
event.addListener(this.element, "scroll", this.onScroll.bind(this));

View file

@ -89,20 +89,28 @@ Search.SELECTION = 2;
};
this.findAll = function(session) {
if (!this.$options.needle)
var options = this.$options;
if (!options.needle)
return [];
if (this.$options.backwards) {
if (options.backwards) {
var iterator = this.$backwardMatchIterator(session);
} else {
iterator = this.$forwardMatchIterator(session);
}
var ignoreCursor = !options.start && options.wrap && options.scope == Search.ALL;
if (ignoreCursor)
options.start = {row: 0, column: 0};
var ranges = [];
iterator.forEach(function(range) {
ranges.push(range);
});
if (ignoreCursor)
options.start = null;
return ranges;
};
@ -213,8 +221,8 @@ Search.SELECTION = 2;
this.$forwardLineIterator = function(session) {
var searchSelection = this.$options.scope == Search.SELECTION;
var range = session.getSelection().getRange();
var start = session.getSelection().getCursor();
var range = this.$options.range || session.getSelection().getRange();
var start = this.$options.start || session.getSelection().getCursor();
var firstRow = searchSelection ? range.start.row : 0;
var firstColumn = searchSelection ? range.start.column : 0;
@ -275,8 +283,8 @@ Search.SELECTION = 2;
this.$backwardLineIterator = function(session) {
var searchSelection = this.$options.scope == Search.SELECTION;
var range = session.getSelection().getRange();
var start = searchSelection ? range.end : range.start;
var range = this.$options.range || session.getSelection().getRange();
var start = this.$options.start || session.getSelection().getCursor();
var firstRow = searchSelection ? range.start.row : 0;
var firstColumn = searchSelection ? range.start.column : 0;

View file

@ -348,6 +348,24 @@ module.exports = {
assert.equal(search.replace("ab12", "$$"), "$");
},
"test: find all using regular expresion containing $" : function() {
var session = new EditSession(["a", " b", "c ", "d"]);
var search = new Search().set({
needle: "[ ]+$",
regExp: true,
wrap: true,
scope: Search.ALL
});
session.getSelection().moveCursorTo(1, 2);
var ranges = search.findAll(session);
assert.equal(ranges.length, 1);
assert.position(ranges[0].start, 2, 1);
assert.position(ranges[0].end, 2, 2);
},
"test: find all matches in a line" : function() {
var session = new EditSession("foo bar foo baz foobar foo");
@ -362,12 +380,12 @@ module.exports = {
var ranges = search.findAll(session);
assert.equal(ranges.length, 3);
assert.position(ranges[0].start, 0, 8);
assert.position(ranges[0].end, 0, 11);
assert.position(ranges[1].start, 0, 23);
assert.position(ranges[1].end, 0, 26);
assert.position(ranges[2].start, 0, 0);
assert.position(ranges[2].end, 0, 3);
assert.position(ranges[0].start, 0, 0);
assert.position(ranges[0].end, 0, 3);
assert.position(ranges[1].start, 0, 8);
assert.position(ranges[1].end, 0, 11);
assert.position(ranges[2].start, 0, 23);
assert.position(ranges[2].end, 0, 26);
},
"test: find all matches in a line backwards" : function() {
@ -385,12 +403,12 @@ module.exports = {
var ranges = search.findAll(session);
assert.equal(ranges.length, 3);
assert.position(ranges[0].start, 0, 8);
assert.position(ranges[0].end, 0, 11);
assert.position(ranges[1].start, 0, 0);
assert.position(ranges[1].end, 0, 3);
assert.position(ranges[2].start, 0, 23);
assert.position(ranges[2].end, 0, 26);
assert.position(ranges[0].start, 0, 23);
assert.position(ranges[0].end, 0, 26);
assert.position(ranges[1].start, 0, 8);
assert.position(ranges[1].end, 0, 11);
assert.position(ranges[2].start, 0, 0);
assert.position(ranges[2].end, 0, 3);
},
};

View file

@ -123,7 +123,7 @@ var Selection = function(session) {
};
var anchor = this.getSelectionAnchor();
var lead = this.getSelectionLead();
var lead = this.getSelectionLead();
var isBackwards = this.isBackwards();
@ -440,9 +440,26 @@ var Selection = function(session) {
this.selectionLead.row,
this.selectionLead.column
);
var screenCol = (chars == 0 && this.$desiredColumn) || screenPos.column;
var screenCol = (chars === 0 && this.$desiredColumn) || screenPos.column;
// so here is the deal. First checkout what the content of ur current and ur target line is
var currentLine = (this.session.getLines(screenPos.row, screenPos.row) || [""])[0],
targetLine = (this.session.getLines(screenPos.row + rows, screenPos.row + rows) || [""])[0];
// if you are at the EOL of your current line, and your targetline is all whitespace
if (currentLine && targetLine &&
currentLine.length === screenPos.column && targetLine.match(/^\s*$/)) {
// set the new column to the EOL of the target line
screenCol = this.session.getTabString(targetLine).length;
// update the chars so we are sure that the desired column will be updated
chars = 1;
};
var docPos = this.session.screenToDocumentPosition(screenPos.row + rows, screenCol);
this.moveCursorTo(docPos.row, docPos.column + chars, chars == 0);
// move the cursor and update the desired column
this.moveCursorTo(docPos.row, docPos.column + chars, chars === 0);
};
this.moveCursorToPosition = function(position) {

View file

@ -442,6 +442,42 @@ module.exports = {
selection.moveCursorUp();
selection.moveCursorDown();
assert.position(selection.getCursor(), 1, 4);
},
"test (keyboard navigation) when curLine is EOL and targetLine is all whitespace new column should be targetLine's EOL": function() {
var session = new EditSession("function (a) {\n\
\n\
}");
var selection = session.getSelection();
selection.moveCursorTo(2, 1);
selection.moveCursorUp();
assert.position(selection.getCursor(), 1, 4);
},
"test (keyboard navigation) when curLine is not EOL and targetLine is all whitespace new column should be current column": function() {
var session = new EditSession("function (a) {\n\
\n\
}");
var selection = session.getSelection();
selection.moveCursorTo(2, 0);
selection.moveCursorUp();
assert.position(selection.getCursor(), 1, 0);
},
"test (keyboard navigation) when curLine is EOL and targetLine is shorter dan current column, new column should be targetLine's EOL": function() {
var session = new EditSession("function (a) {\n\
\n\
}");
var selection = session.getSelection();
selection.moveCursorTo(0, 14);
selection.moveCursorDown();
assert.position(selection.getCursor(), 1, 4);
}
};

View file

@ -161,4 +161,8 @@ MockRenderer.prototype.textToScreenCoordinates = function() {
}
};
MockRenderer.prototype.adjustWrapLimit = function () {
};
});

View file

@ -27,8 +27,7 @@
var require = {
paths: {
ace: "../",
cockpit: "../../../../support/cockpit/lib/cockpit",
pilot: "../../../../support/pilot/lib/pilot"
pilot: "../../../support/pilot/lib/pilot"
},
packages : [{
name: "asyncjs",
@ -41,7 +40,7 @@
}]
};
</script>
<script src="../../../demo/require.js" data-main="all_browser" type="text/javascript" charset="utf-8"></script>
<script src="../../../demo/kitchen-sink/require.js" data-main="all_browser" type="text/javascript" charset="utf-8"></script>
</body>

View file

@ -37,9 +37,8 @@
define(function(require, exports, module) {
var dom = require("pilot/dom");
var cssText = ".ace-clouds .ace_editor {\
exports.cssClass = "ace-clouds";
exports.cssText = ".ace-clouds .ace_editor {\
border: 2px solid rgb(159, 159, 159);\
}\
\
@ -252,8 +251,4 @@ define(function(require, exports, module) {
\
}";
// import CSS once
dom.importCssString(cssText);
exports.cssClass = "ace-clouds";
});
});

View file

@ -37,9 +37,8 @@
define(function(require, exports, module) {
var dom = require("pilot/dom");
var cssText = ".ace-clouds-midnight .ace_editor {\
exports.cssClass = "ace-clouds-midnight";
exports.cssText = ".ace-clouds-midnight .ace_editor {\
border: 2px solid rgb(159, 159, 159);\
}\
\
@ -253,8 +252,4 @@ background-color:#E92E2E;\
\
}";
// import CSS once
dom.importCssString(cssText);
exports.cssClass = "ace-clouds-midnight";
});
});

View file

@ -37,9 +37,8 @@
define(function(require, exports, module) {
var dom = require("pilot/dom");
var cssText = ".ace-cobalt .ace_editor {\
exports.cssClass = "ace-cobalt";
exports.cssText = ".ace-cobalt .ace_editor {\
border: 2px solid rgb(159, 159, 159);\
}\
\
@ -255,8 +254,4 @@ background-color:#001221;\
\
}";
// import CSS once
dom.importCssString(cssText);
exports.cssClass = "ace-cobalt";
});
});

View file

@ -37,9 +37,7 @@
define(function(require, exports, module) {
var dom = require("pilot/dom");
var cssText = ".ace-crimson-editor .ace_editor {\
exports.cssText = ".ace-crimson-editor .ace_editor {\
border: 2px solid rgb(159, 159, 159);\
}\
\
@ -195,8 +193,6 @@ define(function(require, exports, module) {
color: rgb(192, 0, 192);\
}";
// Import CSS once.
dom.importCssString(cssText);
exports.cssClass = "ace-crimson-editor";
exports.cssClass = "ace-crimson-editor";
});

View file

@ -37,9 +37,7 @@
define(function(require, exports, module) {
var dom = require("pilot/dom");
var cssText = ".ace-dawn .ace_editor {\
exports.cssText = ".ace-dawn .ace_editor {\
border: 2px solid rgb(159, 159, 159);\
}\
\
@ -258,8 +256,6 @@ color:#5A525F;\
\
}";
// import CSS once
dom.importCssString(cssText);
exports.cssClass = "ace-dawn";
exports.cssClass = "ace-dawn";
});
});

View file

@ -37,9 +37,7 @@
define(function(require, exports, module) {
var dom = require("pilot/dom");
var cssText = ".ace-eclipse .ace_editor {\
exports.cssText = ".ace-eclipse .ace_editor {\
border: 2px solid rgb(159, 159, 159);\
}\
\
@ -143,8 +141,6 @@ define(function(require, exports, module) {
background: rgb(232, 242, 254);\
}";
// import CSS once
dom.importCssString(cssText);
exports.cssClass = "ace-eclipse";
exports.cssClass = "ace-eclipse";
});

View file

@ -37,9 +37,7 @@
define(function(require, exports, module) {
var dom = require("pilot/dom");
var cssText = ".ace-idle-fingers .ace_editor {\
exports.cssText = ".ace-idle-fingers .ace_editor {\
border: 2px solid rgb(159, 159, 159);\
}\
\
@ -255,8 +253,6 @@ color:#BC9458;\
background-color:#FFF980; \
}";
// import CSS once
dom.importCssString(cssText);
exports.cssClass = "ace-idle-fingers";
exports.cssClass = "ace-idle-fingers";
});
});

View file

@ -37,9 +37,7 @@
define(function(require, exports, module) {
var dom = require("pilot/dom");
var cssText = ".ace-kr-theme .ace_editor {\
exports.cssText = ".ace-kr-theme .ace_editor {\
border: 2px solid rgb(159, 159, 159);\
}\
\
@ -254,8 +252,6 @@ color:#706D5B;\
\
}";
// import CSS once
dom.importCssString(cssText);
exports.cssClass = "ace-kr-theme";
exports.cssClass = "ace-kr-theme";
});
});

View file

@ -37,9 +37,7 @@
define(function(require, exports, module) {
var dom = require("pilot/dom");
var cssText = ".ace-merbivore .ace_editor {\
exports.cssText = ".ace-merbivore .ace_editor {\
border: 2px solid rgb(159, 159, 159);\
}\
\
@ -246,8 +244,6 @@ background-color:#990000;\
\
}";
// import CSS once
dom.importCssString(cssText);
exports.cssClass = "ace-merbivore";
exports.cssClass = "ace-merbivore";
});
});

View file

@ -37,9 +37,7 @@
define(function(require, exports, module) {
var dom = require("pilot/dom");
var cssText = ".ace-merbivore-soft .ace_editor {\
exports.cssText = ".ace-merbivore-soft .ace_editor {\
border: 2px solid rgb(159, 159, 159);\
}\
\
@ -246,8 +244,6 @@ background-color:#FE3838;\
\
}";
// import CSS once
dom.importCssString(cssText);
exports.cssClass = "ace-merbivore-soft";
exports.cssClass = "ace-merbivore-soft";
});
});

View file

@ -37,9 +37,7 @@
define(function(require, exports, module) {
var dom = require("pilot/dom");
var cssText = ".ace-mono-industrial .ace_editor {\
exports.cssText = ".ace-mono-industrial .ace_editor {\
border: 2px solid rgb(159, 159, 159);\
}\
\
@ -254,8 +252,6 @@ background-color:#151C19;\
\
}";
// import CSS once
dom.importCssString(cssText);
exports.cssClass = "ace-mono-industrial";
exports.cssClass = "ace-mono-industrial";
});
});

View file

@ -37,9 +37,7 @@
define(function(require, exports, module) {
var dom = require("pilot/dom");
var cssText = ".ace-monokai .ace_editor {\
exports.cssText = ".ace-monokai .ace_editor {\
border: 2px solid rgb(159, 159, 159);\
}\
\
@ -254,8 +252,6 @@ background-color:#AE81FF;\
\
}";
// import CSS once
dom.importCssString(cssText);
exports.cssClass = "ace-monokai";
exports.cssClass = "ace-monokai";
});
});

View file

@ -37,9 +37,7 @@
define(function(require, exports, module) {
var dom = require("pilot/dom");
var cssText = ".ace-pastel-on-dark .ace_editor {\
exports.cssText = ".ace-pastel-on-dark .ace_editor {\
border: 2px solid rgb(159, 159, 159);\
}\
\
@ -195,8 +193,6 @@ color:#D2A8A1;\
color:#494949;\
}";
// import CSS once
dom.importCssString(cssText);
exports.cssClass = "ace-pastel-on-dark";
exports.cssClass = "ace-pastel-on-dark";
});

View file

@ -37,9 +37,7 @@
define(function(require, exports, module) {
var dom = require("pilot/dom");
var cssText = ".ace-solarized-dark .ace_editor {\
exports.cssText = ".ace-solarized-dark .ace_editor {\
border: 2px solid rgb(159, 159, 159);\
}\
\
@ -253,8 +251,6 @@ color:#657B83;\
\
}";
// import CSS once
dom.importCssString(cssText);
exports.cssClass = "ace-solarized-dark";
exports.cssClass = "ace-solarized-dark";
});
});

View file

@ -37,9 +37,7 @@
define(function(require, exports, module) {
var dom = require("pilot/dom");
var cssText = ".ace-solarized-light .ace_editor {\
exports.cssText = ".ace-solarized-light .ace_editor {\
border: 2px solid rgb(159, 159, 159);\
}\
\
@ -252,8 +250,6 @@ define(function(require, exports, module) {
\
}";
// import CSS once
dom.importCssString(cssText);
exports.cssClass = "ace-solarized-light";
exports.cssClass = "ace-solarized-light";
});
});

View file

@ -37,9 +37,9 @@
define(function(require, exports, module) {
var dom = require("pilot/dom");
var cssText = ".ace-tm .ace_editor {\
exports.cssClass = "ace-tm";
exports.cssText = ".ace-tm .ace_editor {\
border: 2px solid rgb(159, 159, 159);\
}\
\
@ -206,8 +206,4 @@ define(function(require, exports, module) {
color: rgb(255, 0, 0)\
}";
// import CSS once
dom.importCssString(cssText);
exports.cssClass = "ace-tm";
});

View file

@ -37,9 +37,7 @@
define(function(require, exports, module) {
var dom = require("pilot/dom");
var cssText = ".ace-tomorrow .ace_editor {\
exports.cssText = ".ace-tomorrow .ace_editor {\
border: 2px solid rgb(159, 159, 159);\
}\
\
@ -254,8 +252,5 @@ background-color:#8959A8;\
\
}";
// import CSS once
dom.importCssString(cssText);
exports.cssClass = "ace-tomorrow";
});

View file

@ -37,9 +37,8 @@
define(function(require, exports, module) {
var dom = require("pilot/dom");
var cssText = ".ace-twilight .ace_editor {\
exports.cssClass = "ace-twilight";
exports.cssText = ".ace-twilight .ace_editor {\
border: 2px solid rgb(159, 159, 159);\
}\
\
@ -256,8 +255,4 @@ color:#5F5A60;\
\
}";
// import CSS once
dom.importCssString(cssText);
exports.cssClass = "ace-twilight";
});
});

View file

@ -37,9 +37,7 @@
define(function(require, exports, module) {
var dom = require("pilot/dom");
var cssText = ".ace-vibrant-ink .ace_editor {\
exports.cssText = ".ace-vibrant-ink .ace_editor {\
border: 2px solid rgb(159, 159, 159);\
}\
\
@ -255,8 +253,6 @@ color:#99CC99;\
\
}";
// import CSS once
dom.importCssString(cssText);
exports.cssClass = "ace-vibrant-ink";
exports.cssClass = "ace-vibrant-ink";
});
});

View file

@ -53,11 +53,11 @@ var RenderLoop = require("ace/renderloop").RenderLoop;
var EventEmitter = require("pilot/event_emitter").EventEmitter;
var editorCss = require("ace/requirejs/text!ace/css/editor.css");
// import CSS once
dom.importCssString(editorCss);
var VirtualRenderer = function(container, theme) {
this.container = container;
// Imports CSS once per DOM document ('ace_editor' serves as an identifier).
dom.importCssString(editorCss, "ace_editor", container.ownerDocument);
dom.addCssClass(this.container, "ace_editor");
this.setTheme(theme);
@ -135,7 +135,10 @@ var VirtualRenderer = function(container, theme) {
height : 1
};
this.$loop = new RenderLoop(this.$renderChanges.bind(this));
this.$loop = new RenderLoop(
this.$renderChanges.bind(this),
this.container.ownerDocument.defaultView
);
this.$loop.schedule(this.CHANGE_FULL);
this.setPadding(4);
@ -800,6 +803,12 @@ var VirtualRenderer = function(container, theme) {
}
function afterLoad(theme) {
dom.importCssString(
theme.cssText,
theme.cssClass,
_self.container.ownerDocument
);
if (_self.$theme)
dom.removeCssClass(_self.container, _self.$theme);