summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKrzysztof Chrapka <chrapka.k@gmail.com>2013-06-04 17:01:14 +0200
committerBen Noordhuis <info@bnoordhuis.nl>2013-06-17 16:19:12 +0200
commitffcd8b94c2111dcc72425ce0fbc48826ca8ba9ac (patch)
tree06b42c27e03eb0bcdf9709fafa60100655fff451
parent212e9cd8c9b10da3c471638ca9b0f8ebef2a67bb (diff)
downloadnode-ffcd8b94c2111dcc72425ce0fbc48826ca8ba9ac.tar.gz
readline: strip ctrl chars for prompt width calc
Use regular expression to strip vt ansi escape codes from display when calulating prompt display width and cursor position Fixes #3860 and #5628.
-rw-r--r--lib/readline.js23
-rw-r--r--test/simple/test-readline-interface.js10
2 files changed, 29 insertions, 4 deletions
diff --git a/lib/readline.js b/lib/readline.js
index af025b8ef..79b886946 100644
--- a/lib/readline.js
+++ b/lib/readline.js
@@ -557,6 +557,7 @@ Interface.prototype._getDisplayPos = function(str) {
var offset = 0;
var col = this.columns;
var code;
+ str = stripVTControlCharacters(str);
for (var i = 0, len = str.length; i < len; i++) {
code = codePointAt(str, i);
if (code >= 0x10000) { // surrogates
@@ -581,7 +582,7 @@ Interface.prototype._getDisplayPos = function(str) {
Interface.prototype._getCursorPos = function() {
var columns = this.columns;
var strBeforeCursor = this._prompt + this.line.substring(0, this.cursor);
- var dispPos = this._getDisplayPos(strBeforeCursor);
+ var dispPos = this._getDisplayPos(stripVTControlCharacters(strBeforeCursor));
var cols = dispPos.cols;
var rows = dispPos.rows;
// If the cursor is on a full-width character which steps over the line,
@@ -921,9 +922,11 @@ exports.emitKeypressEvents = emitKeypressEvents;
*/
// Regexes used for ansi escape code splitting
-var metaKeyCodeRe = /^(?:\x1b)([a-zA-Z0-9])$/;
-var functionKeyCodeRe =
- /^(?:\x1b+)(O|N|\[|\[\[)(?:(\d+)(?:;(\d+))?([~^$])|(?:1;)?(\d+)?([a-zA-Z]))/;
+var metaKeyCodeReAnywhere = /(?:\x1b)([a-zA-Z0-9])/;
+var metaKeyCodeRe = new RegExp('^' + metaKeyCodeReAnywhere.source + '$');
+var functionKeyCodeReAnywhere =
+ /(?:\x1b+)(O|N|\[|\[\[)(?:(\d+)(?:;(\d+))?([~^$])|(?:1;)?(\d+)?([a-zA-Z]))/;
+var functionKeyCodeRe = new RegExp('^' + functionKeyCodeReAnywhere.source);
function emitKey(stream, s) {
var ch,
@@ -1207,6 +1210,7 @@ exports.clearScreenDown = clearScreenDown;
function getStringWidth(str) {
var width = 0;
+ str = stripVTControlCharacters(str);
for (var i = 0, len = str.length; i < len; i++) {
var code = codePointAt(str, i);
if (code >= 0x10000) { // surrogates
@@ -1289,3 +1293,14 @@ function codePointAt(str, index) {
return code;
}
exports.codePointAt = codePointAt;
+
+
+/**
+ * Tries to remove all VT control characters. Use to estimate displayed
+ * string width. May be buggy due to not running a real state machine
+ */
+function stripVTControlCharacters(str) {
+ str = str.replace(new RegExp(functionKeyCodeReAnywhere.source, 'g'), '');
+ return str.replace(new RegExp(metaKeyCodeReAnywhere.source, 'g'), '');
+}
+exports.stripVTControlCharacters = stripVTControlCharacters;
diff --git a/test/simple/test-readline-interface.js b/test/simple/test-readline-interface.js
index d0bc494c2..8b7c9a08b 100644
--- a/test/simple/test-readline-interface.js
+++ b/test/simple/test-readline-interface.js
@@ -192,6 +192,16 @@ FakeInput.prototype.end = function() {};
assert.equal(readline.getStringWidth('안녕하세요'), 10);
assert.equal(readline.getStringWidth('A\ud83c\ude00BC'), 5); // surrogate
+ // check if vt control chars are stripped
+ assert.equal(readline.stripVTControlCharacters('\u001b[31m> \u001b[39m'), '> ');
+ assert.equal(readline.stripVTControlCharacters('\u001b[31m> \u001b[39m> '), '> > ');
+ assert.equal(readline.stripVTControlCharacters('\u001b[31m\u001b[39m'), '');
+ assert.equal(readline.stripVTControlCharacters('> '), '> ');
+ assert.equal(readline.getStringWidth('\u001b[31m> \u001b[39m'), 2);
+ assert.equal(readline.getStringWidth('\u001b[31m> \u001b[39m> '), 4);
+ assert.equal(readline.getStringWidth('\u001b[31m\u001b[39m'), 0);
+ assert.equal(readline.getStringWidth('> '), 2);
+
assert.deepEqual(fi.listeners('end'), []);
assert.deepEqual(fi.listeners(terminal ? 'keypress' : 'data'), []);
});