diff --git a/demo/startup.js b/demo/startup.js index d0f3db5f..6caf3f4c 100644 --- a/demo/startup.js +++ b/demo/startup.js @@ -283,6 +283,8 @@ exports.launch = function(env) { return event.preventDefault(e); }); + + window.env = env; }; }); diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index 9245b32d..9e907b3d 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -764,14 +764,14 @@ var EditSession = function(text, mode) { addSplit(split); } else { // Search for the first non space/tab token. - for (split; split != lastSplit; split--) { + for (split; split != lastSplit - 1; split--) { if (tokens[split] >= SPACE) { split++; break; } } // If we found one, then add the split. - if (split != lastSplit) { + if (split > lastSplit) { addSplit(split); } // No space or tab around? Well, force a split then. @@ -953,7 +953,7 @@ var EditSession = function(text, mode) { docRow = row; row = 0; docColumn = 0; - line = this.getLine(docRow).split("\t"); + line = this.getLine(docRow); } else { var wrapData = this.$wrapData, linesCount = this.getLength(); @@ -968,22 +968,42 @@ var EditSession = function(text, mode) { }; } docColumn = wrapData[docRow][row - 1] || 0; - line = this.getLine(docRow).substring(docColumn).split("\t"); + line = this.getLine(docRow).substring(docColumn); } var tabSize = this.getTabSize(); - for (var i=0; i= len + tabSize) { - remaining -= (len + tabSize); - docColumn += (len + 1); - } - else if (remaining > len){ - docColumn += len; - break; - } - else { - docColumn += remaining; + for(var i = 0; i < line.length; i++) { + var c = line.charCodeAt(i); + + if (remaining > 0) { + docColumn += 1; + // tab + if (c == 9) { + if (remaining >= tabSize) { + remaining -= tabSize; + } else { + remaining = 0; + docColumn -= 1; + } + } + // CJK characters + else if ( + c >= 0x3040 && c <= 0x309F || // Hiragana + c >= 0x30A0 && c <= 0x30FF || // Katakana + c >= 0x4E00 && c <= 0x9FFF || // Single CJK ideographs + c >= 0xF900 && c <= 0xFAFF || + c >= 0x3400 && c <= 0x4DBF + ) { + if (remaining >= 2) { + remaining -= 2; + } else { + remaining = 0; + docColumn -= 1; + } + } else { + remaining -= 1; + } + } else { break; } } @@ -1065,7 +1085,7 @@ var EditSession = function(text, mode) { if (!this.$useWrapMode) { str = this.getLine(row).substring(0, column); - column += (str.split("\t").length - 1) * (tabSize - 1); + column = this.$getStringScreenWidth(str); return { row: row, column: column @@ -1085,11 +1105,10 @@ var EditSession = function(text, mode) { var rowData = this.$documentToScreenRow(row, column); screenRow = rowData[0]; screenRowOffset = rowData[1]; - screenColumn = column - (wrapRowData[screenRowOffset - 1] || 0); str = this.getLine(row).substring( wrapRowData[screenRowOffset - 1] || 0, column); - screenColumn += (str.split("\t").length - 1) * (tabSize - 1); + screenColumn = this.$getStringScreenWidth(str); return { row: screenRow, diff --git a/lib/ace/test/document_test.js b/lib/ace/test/document_test.js index 49e5f7eb..5441893a 100644 --- a/lib/ace/test/document_test.js +++ b/lib/ace/test/document_test.js @@ -283,14 +283,14 @@ var Test = { "test: wrapLine split function" : function() { var splits; - var tabSize = 4; - var wrapLimit = 12; var computeWrapSplits = EditSession.prototype.$computeWrapSplits; var c = 0; - function computeAndAssert(line, assertEqual) { + 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); + 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]); @@ -317,6 +317,12 @@ var Test = { // 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() { @@ -328,6 +334,13 @@ var Test = { 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() { @@ -342,6 +355,14 @@ var Test = { // 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); } };