diff --git a/lib/ace/background_tokenizer.js b/lib/ace/background_tokenizer.js index 28d11994409..3bb97e49a4d 100644 --- a/lib/ace/background_tokenizer.js +++ b/lib/ace/background_tokenizer.js @@ -227,7 +227,7 @@ var BackgroundTokenizer = function(tokenizer, editor) { var state = this.states[row - 1]; if (line.length > MAX_LINE_LENGTH) { - var overflow = {value: line.substr(MAX_LINE_LENGTH), type: "text"}; + var overflow = {value: line.substring(MAX_LINE_LENGTH), type: "text"}; line = line.slice(0, MAX_LINE_LENGTH); } var data = this.tokenizer.getLineTokens(line, state); diff --git a/lib/ace/document.js b/lib/ace/document.js index 4d4d757d516..f4801ad5acb 100644 --- a/lib/ace/document.js +++ b/lib/ace/document.js @@ -35,6 +35,7 @@ var oop = require("./lib/oop"); var EventEmitter = require("./lib/event_emitter").EventEmitter; var Range = require("./range").Range; var Anchor = require("./anchor").Anchor; +var unicode = require("./unicode"); /** * Contains the text of the document. Document can be attached to several [[EditSession `EditSession`]]s. @@ -76,7 +77,7 @@ 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.remove(new Range(0, 0, len, unicode.length(this.getLine(len-1)))); this.insert({row: 0, column:0}, text); }; @@ -231,13 +232,12 @@ var Document = function(text) { **/ this.getTextRange = function(range) { if (range.start.row == range.end.row) { - return this.$lines[range.start.row].substring(range.start.column, - range.end.column); + return unicode.substring(this.$lines[range.start.row], range.start.column, range.end.column); } else { var lines = this.getLines(range.start.row+1, range.end.row-1); - lines.unshift((this.$lines[range.start.row] || "").substring(range.start.column)); - lines.push((this.$lines[range.end.row] || "").substring(0, range.end.column)); + lines.unshift(unicode.substring(this.$lines[range.start.row] || "", range.start.column)); + lines.push(unicode.substring(this.$lines[range.end.row] || "", 0, range.end.column)); return lines.join(this.getNewLineCharacter()); } }; @@ -246,7 +246,7 @@ var Document = function(text) { var length = this.getLength(); if (position.row >= length) { position.row = Math.max(0, length - 1); - position.column = this.getLine(length-1).length; + position.column = unicode.length(this.getLine(length-1)); } return position; }; @@ -359,8 +359,8 @@ var Document = function(text) { position = this.$clipPosition(position); 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, line.length)); + this.$lines[position.row] = unicode.substring(line, 0, position.column); + this.$lines.splice(position.row + 1, 0, unicode.substring(line, position.column)); var end = { row : position.row + 1, @@ -393,12 +393,12 @@ var Document = function(text) { var line = this.$lines[position.row] || ""; - this.$lines[position.row] = line.substring(0, position.column) + text - + line.substring(position.column); + this.$lines[position.row] = unicode.substring(line, 0, position.column) + text + + unicode.substring(line, position.column); var end = { row : position.row, - column : position.column + text.length + column : position.column + unicode.length(text) }; var delta = { @@ -440,7 +440,7 @@ var Document = function(text) { this.removeLines(firstFullRow, lastFullRow); if (firstFullRow != firstRow) { - this.removeInLine(firstRow, range.start.column, this.getLine(firstRow).length); + this.removeInLine(firstRow, range.start.column, unicode.length(this.getLine(firstRow))); this.removeNewLine(range.start.row); } } @@ -465,8 +465,8 @@ var Document = function(text) { var range = new Range(row, startColumn, row, endColumn); var line = this.getLine(row); - var removed = line.substring(startColumn, endColumn); - var newLine = line.substring(0, startColumn) + line.substring(endColumn, line.length); + var removed = unicode.substring(line, startColumn, endColumn); + var newLine = unicode.substring(line, 0, startColumn) + unicode.substring(line, endColumn); this.$lines.splice(row, 1, newLine); var delta = { @@ -509,7 +509,7 @@ var Document = function(text) { var firstLine = this.getLine(row); var secondLine = this.getLine(row+1); - var range = new Range(row, firstLine.length, row+1, 0); + var range = new Range(row, unicode.length(firstLine), row+1, 0); var line = firstLine + secondLine; this.$lines.splice(row, 2, line); diff --git a/lib/ace/edit_session.js b/lib/ace/edit_session.js index ae16984b604..5accbb60ac9 100644 --- a/lib/ace/edit_session.js +++ b/lib/ace/edit_session.js @@ -42,6 +42,7 @@ var Range = require("./range").Range; var Document = require("./document").Document; var BackgroundTokenizer = require("./background_tokenizer").BackgroundTokenizer; var SearchHighlight = require("./search_highlight").SearchHighlight; +var unicode = require("./unicode"); /** * @@ -360,10 +361,10 @@ var EditSession = function(text, mode) { var token, c = 0; if (column == null) { i = tokens.length - 1; - c = this.getLine(row).length; + c = unicode.length(this.getLine(row)); } else { for (var i = 0; i < tokens.length; i++) { - c += tokens[i].value.length; + c += unicode.length(tokens[i].value); if (c >= column) break; } @@ -372,7 +373,7 @@ var EditSession = function(text, mode) { if (!token) return null; token.index = i; - token.start = c - token.value.length; + token.start = c - unicode.length(token.value); return token; }; @@ -796,14 +797,14 @@ var EditSession = function(text, mode) { var inToken = false; if (column > 0) - inToken = !!line.charAt(column - 1).match(this.tokenRe); + inToken = !!unicode.charAt(line, column - 1).match(this.tokenRe); if (!inToken) - inToken = !!line.charAt(column).match(this.tokenRe); + inToken = !!unicode.charAt(line, column).match(this.tokenRe); if (inToken) var re = this.tokenRe; - else if (/^\s+$/.test(line.slice(column-1, column+1))) + else if (/^\s+$/.test(unicode.substring(line, column-1, column+1))) var re = /\s/; else var re = this.nonTokenRe; @@ -813,12 +814,12 @@ var EditSession = function(text, mode) { do { start--; } - while (start >= 0 && line.charAt(start).match(re)); + while (start >= 0 && unicode.charAt(line, start).match(re)); start++; } var end = column; - while (end < line.length && line.charAt(end).match(re)) { + while (end < unicode.length(line) && unicode.charAt(line, end).match(re)) { end++; } @@ -836,7 +837,7 @@ var EditSession = function(text, mode) { var wordRange = this.getWordRange(row, column); var line = this.getLine(wordRange.end.row); - while (line.charAt(wordRange.end.column).match(/[ \t]/)) { + while (unicode.charAt(line, wordRange.end.column).match(/[ \t]/)) { wordRange.end.column += 1; } return wordRange; @@ -1380,7 +1381,7 @@ var EditSession = function(text, mode) { // front of the chosen point of insertion. if (!fromRange.isMultiLine() && fromRange.start.row == toRow && fromRange.end.column < toColumn) - toColumn -= text.length; + toColumn -= unicode.length(text); if (fromRange.isMultiLine() && fromRange.end.row < toRow) { var lines = this.doc.$split(text); @@ -1432,9 +1433,9 @@ var EditSession = function(text, mode) { deleteRange.start.row = i; deleteRange.end.row = i; for (var j = 0; j < size; ++j) - if (line.charAt(j) != ' ') + if (unicode.charAt(line, j) != ' ') break; - if (j < size && line.charAt(j) == '\t') { + if (j < size && unicode.charAt(line, j) == '\t') { deleteRange.start.column = j; deleteRange.end.column = j + 1; } else { @@ -1507,7 +1508,7 @@ var EditSession = function(text, mode) { this.$clipColumnToRow = function(row, column) { if (column < 0) return 0; - return Math.min(this.doc.getLine(row).length, column); + return Math.min(unicode.length(this.doc.getLine(row)), column); }; @@ -1521,9 +1522,9 @@ var EditSession = function(text, mode) { var len = this.doc.getLength(); if (row >= len) { row = len - 1; - column = this.doc.getLine(len-1).length; + column = unicode.length(this.doc.getLine(len-1)); } else { - column = Math.min(this.doc.getLine(row).length, column); + column = Math.min(unicode.length(this.doc.getLine(row)), column); } } @@ -1547,7 +1548,7 @@ var EditSession = function(text, mode) { var len = this.doc.getLength() - 1; if (range.end.row > len) { range.end.row = len; - range.end.column = this.doc.getLine(len).length; + range.end.column = unicode.length(this.doc.getLine(len)); } else { range.end.column = this.$clipColumnToRow( range.end.row, @@ -1834,13 +1835,13 @@ var EditSession = function(text, mode) { } } else { walkTokens = this.$getDisplayTokens( - lines[row].substring(lastColumn, column), + unicode.substring(lines[row], lastColumn, column), tokens.length); } tokens = tokens.concat(walkTokens); }.bind(this), foldLine.end.row, - lines[foldLine.end.row].length + 1 + unicode.length(lines[foldLine.end.row]) + 1 ); // Remove spaces/tabs from the back of the token array. while (tokens.length != 0 && tokens[tokens.length - 1] >= SPACE) @@ -1994,6 +1995,20 @@ var EditSession = function(text, mode) { for (var i = 0; i < str.length; i++) { var c = str.charCodeAt(i); + + var part = c & 0xfc00; + if (part == 0xdc00) + return null; + else if (part != 0xd800); + else if (++i == str.length) + return null; + else { + var next = str.charCodeAt(i); + if ((next & 0xfc00) != 0xdc00) + return null; + c = 0x10000 | (c & 0x03ff) << 10 | next & 0x03ff; + } + // Tab if (c == 9) { tabSize = this.getScreenTabSize(arr.length + offset); @@ -2038,9 +2053,23 @@ var EditSession = function(text, mode) { maxScreenColumn = Infinity; screenColumn = screenColumn || 0; - var c, column; - for (column = 0; column < str.length; column++) { - c = str.charCodeAt(column); + var c, column = 0; + for (var i = 0; i < str.length; i++, column++) { + c = str.charCodeAt(i); + + var part = c & 0xfc00; + if (part == 0xdc00) + return null; + else if (part != 0xd800); + else if (++i == str.length) + return null; + else { + var next = str.charCodeAt(i); + if ((next & 0xfc00) != 0xdc00) + return null; + c = 0x10000 | (c & 0x03ff) << 10 | next & 0x03ff; + } + // tab if (c == 9) { screenColumn += this.getScreenTabSize(screenColumn); @@ -2204,7 +2233,7 @@ var EditSession = function(text, mode) { // clip at the end of the document return { row: maxRow, - column: this.getLine(maxRow).length + column: unicode.length(this.getLine(maxRow)) } } else { line = this.getLine(docRow); @@ -2217,7 +2246,7 @@ var EditSession = function(text, mode) { column = splits[screenRow - row]; if(screenRow > row && splits.length) { docColumn = splits[screenRow - row - 1] || splits[splits.length - 1]; - line = line.substring(docColumn); + line = unicode.substring(line, docColumn); } } } @@ -2311,19 +2340,19 @@ var EditSession = function(text, mode) { textLine = this.getFoldDisplayLine(foldLine, docRow, docColumn); foldStartRow = foldLine.start.row; } else { - textLine = this.getLine(docRow).substring(0, docColumn); + textLine = unicode.substring(this.getLine(docRow), 0, docColumn); foldStartRow = docRow; } // Clamp textLine if in wrapMode. if (this.$useWrapMode) { var wrapRow = this.$wrapData[foldStartRow]; var screenRowOffset = 0; - while (textLine.length >= wrapRow[screenRowOffset]) { + while (unicode.length(textLine) >= wrapRow[screenRowOffset]) { screenRow ++; screenRowOffset++; } - textLine = textLine.substring( - wrapRow[screenRowOffset - 1] || 0, textLine.length + textLine = unicode.substring(textLine, + wrapRow[screenRowOffset - 1] || 0, unicode.length(textLine) ); } diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 8a0340193ce..59dc0afd4ae 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -46,6 +46,7 @@ var Range = require("./range").Range; var EventEmitter = require("./lib/event_emitter").EventEmitter; var CommandManager = require("./commands/command_manager").CommandManager; var defaultCommands = require("./commands/default_commands").commands; +var unicode = require("./unicode"); /** * @@ -534,16 +535,16 @@ var Editor = function(renderer, session) { var startOuter = selection.start.column - 1; var endOuter = selection.end.column + 1; var line = session.getLine(selection.start.row); - var lineCols = line.length; - var needle = line.substring(Math.max(startOuter, 0), - Math.min(endOuter, lineCols)); + var lineCols = unicode.length(line); + var needle = unicode.substring(line, Math.max(startOuter, 0), + Math.min(endOuter, lineCols)); // Make sure the outer characters are not part of the word. if ((startOuter >= 0 && /^[\w\d]/.test(needle)) || (endOuter <= lineCols && /[\w\d]$/.test(needle))) return; - needle = line.substring(selection.start.column, selection.end.column); + needle = unicode.substring(line, selection.start.column, selection.end.column); if (!/^[\w\d]+$/.test(needle)) return; @@ -686,7 +687,7 @@ var Editor = function(renderer, session) { } else if (this.session.getOverwrite()) { var range = new Range.fromPoints(cursor, cursor); - range.end.column += text.length; + range.end.column += unicode.length(text); this.session.remove(range); } @@ -716,7 +717,7 @@ var Editor = function(renderer, session) { // possibly doing the indent before inserting the text // if (cursor.row !== end.row) { if (session.getDocument().isNewLine(text)) { - var lineIndent = mode.getNextLineIndent(lineState, line.slice(0, cursor.column), session.getTabString()); + var lineIndent = mode.getNextLineIndent(lineState, unicode.substring(line, 0, cursor.column), session.getTabString()); this.moveCursorTo(cursor.row+1, 0); @@ -727,10 +728,10 @@ var Editor = function(renderer, session) { var indent = 0; line = session.getLine(row); - for (var i = 0; i < line.length; ++i) - if (line.charAt(i) == '\t') + for (var i = 0, e = unicode.length(line); i < e; ++i) + if (unicode.charAt(line, i) == '\t') indent += size; - else if (line.charAt(i) == ' ') + else if (unicode.charAt(line, i) == ' ') indent += 1; else break; @@ -742,10 +743,10 @@ var Editor = function(renderer, session) { var outdent = minIndent; line = session.getLine(row); - for (var i = 0; i < line.length && outdent > 0; ++i) - if (line.charAt(i) == '\t') + for (var i = 0, e = unicode.length(line); i < e && outdent > 0; ++i) + if (unicode.charAt(line, i) == '\t') outdent -= size; - else if (line.charAt(i) == ' ') + else if (unicode.charAt(line, i) == ' ') outdent -= 1; session.remove(new Range(row, 0, row, i)); } @@ -1195,12 +1196,12 @@ var Editor = function(renderer, session) { var line = this.session.getLine(cursor.row); var swap, range; - if (column < line.length) { - swap = line.charAt(column) + line.charAt(column-1); + if (column < unicode.length(line)) { + swap = unicode.charAt(line, column) + unicode.charAt(line, column-1); range = new Range(cursor.row, column-1, cursor.row, column+1); } else { - swap = line.charAt(column-1) + line.charAt(column-2); + swap = unicode.charAt(line, column-1) + unicode.charAt(line, column-2); range = new Range(cursor.row, column-2, cursor.row, column); } this.session.replace(range, swap); @@ -1293,7 +1294,7 @@ var Editor = function(renderer, session) { var line = session.getLine(i); deleteRange.start.row = i; deleteRange.end.row = i; - deleteRange.end.column = line.length; + deleteRange.end.column = unicode.length(line); session.replace(deleteRange, lines[i-rows.first]); } }; @@ -1319,11 +1320,13 @@ var Editor = function(renderer, session) { var s = this.session.getLine(row) while(_numberRx.lastIndex < column - 1 ){ var m = _numberRx.exec(s) - if(m.index <= column && m.index+m[0].length >= column){ + var start = unicode.unit2point(s, [m.index])[0] + var end = start + unicode.length(m[0]) + if(start <= column && end >= column){ var number = { value: m[0], - start: m.index, - end: m.index+m[0].length + start: start, + end: end } return number @@ -1353,7 +1356,7 @@ var Editor = function(renderer, session) { // if number found if (nr) { var fp = nr.value.indexOf(".") >= 0 ? nr.start + nr.value.indexOf(".") + 1 : nr.end; - var decimals = nr.start + nr.value.length - fp; + var decimals = nr.start + unicode.length(nr.value) - fp; var t = parseFloat(nr.value); t *= Math.pow(10, decimals); @@ -1374,7 +1377,7 @@ var Editor = function(renderer, session) { this.session.replace(replaceRange, nnr); //reposition the cursor - this.moveCursorTo(row, Math.max(nr.start +1, column + nnr.length - nr.value.length)); + this.moveCursorTo(row, Math.max(nr.start +1, column + unicode.length(nnr) - unicode.length(nr.value))); } } @@ -1391,8 +1394,8 @@ var Editor = function(renderer, session) { range = new Range(rows.first, 0, rows.last+1, 0); else range = new Range( - rows.first-1, this.session.getLine(rows.first-1).length, - rows.last, this.session.getLine(rows.last).length + rows.first-1, unicode.length(this.session.getLine(rows.first-1)), + rows.last, unicode.length(this.session.getLine(rows.last)) ); this.session.remove(range); this.clearSelection(); diff --git a/lib/ace/multi_select.js b/lib/ace/multi_select.js index e1ecd80c29a..69141eeb9ec 100644 --- a/lib/ace/multi_select.js +++ b/lib/ace/multi_select.js @@ -720,7 +720,7 @@ var Editor = require("./editor").Editor; var spaceOffsets = ranges.map(function(r) { var p = r.cursor; var line = session.getLine(p.row); - var spaceOffset = line.substr(p.column).search(/\S/g); + var spaceOffset = line.substring(p.column).search(/\S/g); if (spaceOffset == -1) spaceOffset = 0; diff --git a/lib/ace/search.js b/lib/ace/search.js index 3e90b95d856..2fb7e4de85d 100644 --- a/lib/ace/search.js +++ b/lib/ace/search.js @@ -34,6 +34,7 @@ define(function(require, exports, module) { var lang = require("./lib/lang"); var oop = require("./lib/oop"); var Range = require("./range").Range; +var unicode = require("./unicode"); /** * @class Search @@ -359,7 +360,7 @@ var Search = function() { } : function(callback) { var row = start.row; - var line = session.getLine(row).substr(start.column); + var line = session.getLine(row).substring(start.column); if (callback(line, row, start.column)) return; diff --git a/lib/ace/selection.js b/lib/ace/selection.js index 71a17f34578..75939b7de2d 100644 --- a/lib/ace/selection.js +++ b/lib/ace/selection.js @@ -35,6 +35,7 @@ var oop = require("./lib/oop"); var lang = require("./lib/lang"); var EventEmitter = require("./lib/event_emitter").EventEmitter; var Range = require("./range").Range; +var unicode = require("./unicode"); /** * @@ -235,7 +236,7 @@ var Selection = function(session) { this.selectAll = function() { var lastRow = this.doc.getLength() - 1; this.setSelectionAnchor(0, 0); - this.moveCursorTo(lastRow, this.doc.getLine(lastRow).length); + this.moveCursorTo(lastRow, unicode.length(this.doc.getLine(lastRow))); }; /** @@ -417,7 +418,7 @@ var Selection = function(session) { rowEnd = rowStart; } if (excludeLastChar) - return new Range(rowStart, 0, rowEnd, this.session.getLine(rowEnd).length); + return new Range(rowStart, 0, rowEnd, unicode.length(this.session.getLine(rowEnd))); else return new Range(rowStart, 0, rowEnd + 1, 0); }; @@ -458,12 +459,12 @@ var Selection = function(session) { } else if (cursor.column == 0) { // cursor is a line (start if (cursor.row > 0) { - this.moveCursorTo(cursor.row - 1, this.doc.getLine(cursor.row - 1).length); + this.moveCursorTo(cursor.row - 1, unicode.length(this.doc.getLine(cursor.row - 1))); } } else { var tabSize = this.session.getTabSize(); - if (this.session.isTabStop(cursor) && this.doc.getLine(cursor.row).slice(cursor.column-tabSize, cursor.column).split(" ").length-1 == tabSize) + if (this.session.isTabStop(cursor) && unicode.substring(this.doc.getLine(cursor.row), cursor.column-tabSize, cursor.column).split(" ").length-1 == tabSize) this.moveCursorBy(0, -tabSize); else this.moveCursorBy(0, -1); @@ -480,7 +481,7 @@ var Selection = function(session) { if (fold = this.session.getFoldAt(cursor.row, cursor.column, 1)) { this.moveCursorTo(fold.end.row, fold.end.column); } - else if (this.lead.column == this.doc.getLine(this.lead.row).length) { + else if (this.lead.column == unicode.length(this.doc.getLine(this.lead.row))) { if (this.lead.row < this.doc.getLength() - 1) { this.moveCursorTo(this.lead.row + 1, 0); } @@ -488,7 +489,7 @@ var Selection = function(session) { else { var tabSize = this.session.getTabSize(); var cursor = this.lead; - if (this.session.isTabStop(cursor) && this.doc.getLine(cursor.row).slice(cursor.column, cursor.column+tabSize).split(" ").length-1 == tabSize) + if (this.session.isTabStop(cursor) && unicode.substring(this.doc.getLine(cursor.row), cursor.column, cursor.column+tabSize).split(" ").length-1 == tabSize) this.moveCursorBy(0, tabSize); else this.moveCursorBy(0, 1); @@ -514,7 +515,7 @@ var Selection = function(session) { ); var leadingSpace = beforeCursor.match(/^\s*/); - if (leadingSpace[0].length == column) { + if (unicode.length(leadingSpace[0]) == column) { this.moveCursorTo( firstColumnPosition.row, firstColumnPosition.column ); @@ -522,7 +523,7 @@ var Selection = function(session) { else { this.moveCursorTo( firstColumnPosition.row, - firstColumnPosition.column + leadingSpace[0].length + firstColumnPosition.column + unicode.length(leadingSpace[0]) ); } }; @@ -536,7 +537,7 @@ var Selection = function(session) { var lineEnd = this.session.getDocumentLastRowColumnPosition(lead.row, lead.column); if (this.lead.column == lineEnd.column) { var line = this.session.getLine(lineEnd.row); - if (lineEnd.column == line.length) { + if (lineEnd.column == unicode.length(line)) { var textEnd = line.search(/\s+$/); if (textEnd > 0) lineEnd.column = textEnd; @@ -552,7 +553,7 @@ var Selection = function(session) { **/ this.moveCursorFileEnd = function() { var row = this.doc.getLength() - 1; - var column = this.doc.getLine(row).length; + var column = unicode.length(this.doc.getLine(row)); this.moveCursorTo(row, column); }; @@ -572,7 +573,7 @@ var Selection = function(session) { var row = this.lead.row; var column = this.lead.column; var line = this.doc.getLine(row); - var rightOfCursor = line.substring(column); + var rightOfCursor = unicode.substring(line, column); var match; this.session.nonTokenRe.lastIndex = 0; @@ -589,12 +590,12 @@ var Selection = function(session) { if (match = this.session.nonTokenRe.exec(rightOfCursor)) { column += this.session.nonTokenRe.lastIndex; this.session.nonTokenRe.lastIndex = 0; - rightOfCursor = line.substring(column); + rightOfCursor = unicode.substring(line, column); } // if at line end proceed with next line - if (column >= line.length) { - this.moveCursorTo(row, line.length); + if (column >= unicode.length(line)) { + this.moveCursorTo(row, unicode.length(line)); this.moveCursorRight(); if (row < this.doc.getLength() - 1) this.moveCursorWordRight(); @@ -627,7 +628,7 @@ var Selection = function(session) { var str = this.session.getFoldStringAt(row, column, -1); if (str == null) { - str = this.doc.getLine(row).substring(0, column) + str = unicode.substring(this.doc.getLine(row), 0, column) } var leftOfCursor = lang.stringReverse(str); @@ -638,7 +639,7 @@ var Selection = function(session) { // skip whitespace if (match = this.session.nonTokenRe.exec(leftOfCursor)) { column -= this.session.nonTokenRe.lastIndex; - leftOfCursor = leftOfCursor.slice(this.session.nonTokenRe.lastIndex); + leftOfCursor = unicode.substring(leftOfCursor, this.session.nonTokenRe.lastIndex); this.session.nonTokenRe.lastIndex = 0; } @@ -700,13 +701,13 @@ var Selection = function(session) { var row = this.lead.row; var column = this.lead.column; var line = this.doc.getLine(row); - var rightOfCursor = line.substring(column); + var rightOfCursor = unicode.substring(line, column); var fold = this.session.getFoldAt(row, column, 1); if (fold) return this.moveCursorTo(fold.end.row, fold.end.column); - if (column == line.length) { + if (column == unicode.length(line)) { var l = this.doc.getLength(); do { row++; @@ -731,14 +732,14 @@ var Selection = function(session) { if (fold = this.session.getFoldAt(row, column, -1)) return this.moveCursorTo(fold.start.row, fold.start.column); - var line = this.session.getLine(row).substring(0, column); + var line = unicode.substring(this.session.getLine(row), 0, column); if (column == 0) { do { row--; line = this.doc.getLine(row); } while (row > 0 && /^\s*$/.test(line)) - column = line.length; + column = unicode.length(line); if (!/\s+$/.test(line)) line = "" } diff --git a/lib/ace/unicode.js b/lib/ace/unicode.js index 5c291744643..ff743ac46ae 100644 --- a/lib/ace/unicode.js +++ b/lib/ace/unicode.js @@ -104,4 +104,71 @@ function addUnicodePackage (pack) { exports.packages[name] = pack[name].replace(codePoint, "\\u$&"); }; +exports.adjust = function(mode, string, after) { + var before = after.slice(); + var offset = 0, index = 0; + + var check = function() { + var from = mode ? index : offset; + var to = mode ? offset : index; + + for (var o = 0, l = after.length; o != l; ++o) + if (before[o] == from) { + before[o] = null; + after[o] = to; + } + }; + + for (var e = string.length; index != e; ++index) { + check(); + + var unit = string.charCodeAt(index); + var part = unit & 0xfc00; + + if (part == 0xdc00) + return null; + else if (part != 0xd800); + else if (++index == e) + return null; + else { + var next = string.charCodeAt(index); + if ((next & 0xfc00) != 0xdc00) + return null; + } + + ++offset; + } + + check(); + return after; +}; + +exports.point2unit = function(string, offsets) { + return exports.adjust(false, string, offsets); +}; + +exports.unit2point = function(string, offsets) { + return exports.adjust(true, string, offsets); +}; + +exports.length = function(string) { + return exports.unit2point(string, [string.length])[0]; +}; + +exports.substring = function(string, start, stop) { + var range = exports.point2unit(string, [start, stop]); + return string.substring(range[0], range[1]); +}; + +exports.substr = function(string, start, length) { + var stop; + if (typeof length !== "undefined") + stop = start + length; + return exports.substring(string, start, stop); +}; + +exports.charAt = function(string, offset) { + return exports.substring(string, offset, offset + 1); +}; + });