diff --git a/lib/ace/document.js b/lib/ace/document.js index c5c99b4e..4bc170c2 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -57,8 +57,8 @@ var Document = function(text) { this.setValue = function(text) { var len = this.getLength(); - this.remove(new Range(0, 0, len, this.getLine(len-1).length)); - this.insertLines(0, this.$split(text)); + this.remove(new Range(0, 0, len, this.getLine(len-1).length)); + this.insert({row: 0, column:0}, text); }; this.getValue = function() { @@ -262,14 +262,20 @@ var Document = function(text) { var firstRow = range.start.row; var lastRow = range.end.row; - if (range.isMultiLine()) { - - // TODO removeInLine can be optimized away! - this.removeInLine(lastRow, 0, range.end.column); - if (lastRow - firstRow >= 2) - this.removeLines(firstRow + 1, lastRow - 1); - this.removeInLine(firstRow, range.start.column, this.$lines[firstRow].length); - this.removeNewLine(range.start.row); + if (range.isMultiLine()) { + var firstFullRow = range.start.column == 0 ? firstRow : firstRow + 1; + var lastFullRow = lastRow - 1; + + if (range.end.column > 0) + this.removeInLine(lastRow, 0, range.end.column); + + if (lastFullRow >= firstFullRow) + this.removeLines(firstFullRow, lastFullRow); + + if (firstFullRow != firstRow) { + this.removeInLine(firstRow, range.start.column, this.$lines[firstRow].length); + this.removeNewLine(range.start.row); + } } else { this.removeInLine(firstRow, range.start.column, range.end.column); diff --git a/lib/ace/test/document_test.js b/lib/ace/test/document_test.js index 5441893a..cdc78732 100644 --- a/lib/ace/test/document_test.js +++ b/lib/ace/test/document_test.js @@ -37,7 +37,6 @@ * ***** END LICENSE BLOCK ***** */ var Document = require("../document").Document, - EditSession = require("../edit_session").EditSession, Range = require("../range").Range, assert = require("./assertions"), async = require("asyncjs"); @@ -280,89 +279,19 @@ var Test = { doc.replace(new Range(0, 0, 2, 1), ["4", "5", "6"].join("\n")); assert.equal(["4", "5", "6"].join("\n"), doc.getValue()); }, - - "test: wrapLine split function" : function() { - var splits; - var computeWrapSplits = EditSession.prototype.$computeWrapSplits; - var c = 0; - - function computeAndAssert(line, assertEqual, wrapLimit, tabSize) { - wrapLimit = wrapLimit || 12; - tabSize = tabSize || 4; - splits = computeWrapSplits.call(EditSession.prototype, line, wrapLimit, tabSize); - console.log("String:", line, "Result:", splits, "Expected:", assertEqual); - assert.ok(splits.length == assertEqual.length); - for (var i = 0; i < splits.length; i++) { - assert.ok(splits[i] == assertEqual[i]); - } - } - - // Basic splitting. - computeAndAssert("foo bar foo bar", [ 12 ]); - computeAndAssert("foo bar f bar", [ 12 ]); - computeAndAssert("foo bar f r", [ 14 ]); - computeAndAssert("foo bar foo bar foo bara foo", [12, 25]); - - // Don't split if there is only whitespaces/tabs at the end of the line. - computeAndAssert("foo foo foo \t \t", [ ]); - - // If there is no space to split, force split. - computeAndAssert("foooooooooooooo", [ 12 ]); - computeAndAssert("fooooooooooooooooooooooooooo", [12, 24]); - computeAndAssert("foo bar fooooooooooobooooooo", [8, 20]); - - // Basic splitting + tabs. - computeAndAssert("foo \t\tbar", [ 6 ]); - computeAndAssert("foo \t \tbar", [ 7 ]); - - // Ignore spaces/tabs at beginning of split. - computeAndAssert("foo \t \t \t \t bar", [ 14 ]); - - // Test wrapping for asian characters. - computeAndAssert("ぁぁ", [1], 2); - computeAndAssert(" ぁぁ", [1, 2], 2); - computeAndAssert(" ぁ\tぁ", [1, 3], 2); - computeAndAssert(" ぁぁ\tぁ", [1, 4], 4); - }, - - "test: documentToScreen": function() { - var tabSize = 4; - var wrapLimit = 12; - var session = new EditSession(["foo bar foo bar"]); - session.setUseWrapMode(true); - session.setWrapLimit(12); - - assert.position(session.documentToScreenPosition(0, 11), 0, 11); - assert.position(session.documentToScreenPosition(0, 12), 1, 0); - - session = new EditSession(["ぁぁa"]); - session.setUseWrapMode(true); - session.setWrapLimit(2); - assert.position(session.documentToScreenPosition(0, 1), 1, 0); - assert.position(session.documentToScreenPosition(0, 2), 2, 0); - assert.position(session.documentToScreenPosition(0, 4), 2, 1); - }, - - "test: screenToDocument": function() { - var tabSize = 4; - var wrapLimit = 12; - var session = new EditSession(["foo bar foo bar"]); - session.setUseWrapMode(true); - session.setWrapLimit(12); - - assert.position(session.screenToDocumentPosition(1, 0), 0, 12); - assert.position(session.screenToDocumentPosition(0, 11), 0, 11); - // Check if the position is clamped the right way. - assert.position(session.screenToDocumentPosition(0, 12), 0, 11); - assert.position(session.screenToDocumentPosition(0, 20), 0, 11); - - session = new EditSession(["ぁ a"]); - session.setUseWrapMode(true); - assert.position(session.screenToDocumentPosition(0, 1), 0, 0); - assert.position(session.screenToDocumentPosition(0, 2), 0, 1); - assert.position(session.screenToDocumentPosition(0, 3), 0, 2); - assert.position(session.screenToDocumentPosition(0, 4), 0, 3); - assert.position(session.screenToDocumentPosition(0, 5), 0, 3); + + "test: set value": function() { + var doc = new Document("1"); + assert.equal("1", doc.getValue()); + + doc.setValue(doc.getValue()); + assert.equal("1", doc.getValue()); + + var doc = new Document("1\n2"); + assert.equal("1\n2", doc.getValue()); + + doc.setValue(doc.getValue()); + assert.equal("1\n2", doc.getValue()); } }; diff --git a/lib/ace/test/edit_session_test.js b/lib/ace/test/edit_session_test.js index cce711ae..8153fab2 100644 --- a/lib/ace/test/edit_session_test.js +++ b/lib/ace/test/edit_session_test.js @@ -153,7 +153,7 @@ var Test = { assert.equal(session.documentToScreenColumn(0, 13), 15); }, - "test: convert document to scrren coordinates with leading tabs": function() { + "test: convert document to screen coordinates with leading tabs": function() { var session = new EditSession("\t\t123"); session.setTabSize(4); @@ -162,6 +162,24 @@ var Test = { assert.equal(session.documentToScreenColumn(0, 2), 8); assert.equal(session.documentToScreenColumn(0, 3), 9); }, + + "test: documentToScreen with soft wrap and multibyte characters": function() { + var tabSize = 4; + var wrapLimit = 12; + var session = new EditSession(["foo bar foo bar"]); + session.setUseWrapMode(true); + session.setWrapLimit(12); + + assert.position(session.documentToScreenPosition(0, 11), 0, 11); + assert.position(session.documentToScreenPosition(0, 12), 1, 0); + + session = new EditSession(["ぁぁa"]); + session.setUseWrapMode(true); + session.setWrapLimit(2); + assert.position(session.documentToScreenPosition(0, 1), 1, 0); + assert.position(session.documentToScreenPosition(0, 2), 2, 0); + assert.position(session.documentToScreenPosition(0, 4), 2, 1); + }, "test: convert screen to document coordinates" : function() { var session = new EditSession("01234\t567890\t1234"); @@ -177,6 +195,72 @@ var Test = { assert.equal(session.screenToDocumentColumn(0, 15), 12); assert.equal(session.screenToDocumentColumn(0, 19), 13); }, + + "test: screenToDocument with soft wrap and multi byte characters": function() { + var tabSize = 4; + var wrapLimit = 12; + var session = new EditSession(["foo bar foo bar"]); + session.setUseWrapMode(true); + session.setWrapLimit(12); + + assert.position(session.screenToDocumentPosition(1, 0), 0, 12); + assert.position(session.screenToDocumentPosition(0, 11), 0, 11); + // Check if the position is clamped the right way. + assert.position(session.screenToDocumentPosition(0, 12), 0, 11); + assert.position(session.screenToDocumentPosition(0, 20), 0, 11); + + session = new EditSession(["ぁ a"]); + session.setUseWrapMode(true); + assert.position(session.screenToDocumentPosition(0, 1), 0, 0); + assert.position(session.screenToDocumentPosition(0, 2), 0, 1); + assert.position(session.screenToDocumentPosition(0, 3), 0, 2); + assert.position(session.screenToDocumentPosition(0, 4), 0, 3); + assert.position(session.screenToDocumentPosition(0, 5), 0, 3); + }, + + "test: wrapLine split function" : function() { + var splits; + var computeWrapSplits = EditSession.prototype.$computeWrapSplits; + var c = 0; + + function computeAndAssert(line, assertEqual, wrapLimit, tabSize) { + wrapLimit = wrapLimit || 12; + tabSize = tabSize || 4; + splits = computeWrapSplits.call(EditSession.prototype, line, wrapLimit, tabSize); + console.log("String:", line, "Result:", splits, "Expected:", assertEqual); + assert.ok(splits.length == assertEqual.length); + for (var i = 0; i < splits.length; i++) { + assert.ok(splits[i] == assertEqual[i]); + } + } + + // Basic splitting. + computeAndAssert("foo bar foo bar", [ 12 ]); + computeAndAssert("foo bar f bar", [ 12 ]); + computeAndAssert("foo bar f r", [ 14 ]); + computeAndAssert("foo bar foo bar foo bara foo", [12, 25]); + + // Don't split if there is only whitespaces/tabs at the end of the line. + computeAndAssert("foo foo foo \t \t", [ ]); + + // If there is no space to split, force split. + computeAndAssert("foooooooooooooo", [ 12 ]); + computeAndAssert("fooooooooooooooooooooooooooo", [12, 24]); + computeAndAssert("foo bar fooooooooooobooooooo", [8, 20]); + + // Basic splitting + tabs. + computeAndAssert("foo \t\tbar", [ 6 ]); + computeAndAssert("foo \t \tbar", [ 7 ]); + + // Ignore spaces/tabs at beginning of split. + computeAndAssert("foo \t \t \t \t bar", [ 14 ]); + + // Test wrapping for asian characters. + computeAndAssert("ぁぁ", [1], 2); + computeAndAssert(" ぁぁ", [1, 2], 2); + computeAndAssert(" ぁ\tぁ", [1, 3], 2); + computeAndAssert(" ぁぁ\tぁ", [1, 4], 4); + }, "test: insert text in multiple rows": function() { var session = new EditSession(["12", "", "abcd"]); diff --git a/lib/ace/test/mockrenderer.js b/lib/ace/test/mockrenderer.js index b076cc78..eefbd08f 100644 --- a/lib/ace/test/mockrenderer.js +++ b/lib/ace/test/mockrenderer.js @@ -71,6 +71,13 @@ MockRenderer.prototype.getMouseEventTarget = function() { return this.container; }; +MockRenderer.prototype.getTextAreaContainer = function() { + return this.container; +}; + +MockRenderer.prototype.moveTextAreaToCursor = function() { +}; + MockRenderer.prototype.setSession = function(session) { this.session = session; };