readline: use StringDecoder for decoding "normal" data
authorNathan Rajlich <nathan@tootallnate.net>
Fri, 6 Apr 2012 21:33:58 +0000 (14:33 -0700)
committerNathan Rajlich <nathan@tootallnate.net>
Fri, 6 Apr 2012 23:13:40 +0000 (16:13 -0700)
The fix from #3059 was not handling multi-byte utf8 data properly.

lib/readline.js
test/simple/test-readline-interface.js

index 7da3ce75d6b084108aa38990f88f5d8cf0952bd7..6fb5e9fd6743e3f5e708f91951a592e2904923b7 100644 (file)
@@ -93,6 +93,8 @@ function Interface(input, output, completer, terminal) {
     input.on('end', function() {
       self.emit('end');
     });
+    var StringDecoder = require('string_decoder').StringDecoder; // lazy load
+    this._decoder = new StringDecoder('utf8');
 
   } else {
 
@@ -264,22 +266,27 @@ Interface.prototype.write = function(d, key) {
   this.terminal ? this._ttyWrite(d, key) : this._normalWrite(d, key);
 };
 
-// telnet on windows sends every single keystroke seperately, so we need
-// to buffer them and only fire the 'line' event when a \n is sent
-Interface.prototype._line_buffer = '';
-
 Interface.prototype._normalWrite = function(b) {
   if (b === undefined) {
     return;
   }
-  this._line_buffer += b.toString();
-  if (this._line_buffer.indexOf('\n') !== -1) {
-    var lines = this._line_buffer.split('\n');
+  var string = this._decoder.write(b);
+  if (this._line_buffer) {
+    string = this._line_buffer + string;
+    this._line_buffer = null;
+  }
+  if (string.indexOf('\n') !== -1) {
+    // got one or more newlines; process into "line" events
+    var lines = string.split('\n');
     // either '' or (concievably) the unfinished portion of the next line
-    this._line_buffer = lines.pop();
+    string = lines.pop();
+    this._line_buffer = string;
     lines.forEach(function(line) {
       this._onLine(line + '\n');
     }, this);
+  } else if (string) {
+    // no newlines this time, save what we have for next time
+    this._line_buffer = string;
   }
 };
 
index fc8d4f2fe422be53cde7f01628bcea94011c946c..986fa1f47813aef1604a648642941ef797158e51 100644 (file)
@@ -104,3 +104,19 @@ rli.on('line', function(line) {
 });
 fi.emit('data', expectedLines.join(''));
 assert.equal(callCount, expectedLines.length - 1);
+
+// sending a multi-byte utf8 char over multiple writes
+var buf = Buffer('☮', 'utf8');
+fi = new FakeInput();
+rli = new readline.Interface(fi, {});
+callCount = 0;
+rli.on('line', function(line) {
+  callCount++;
+  assert.equal(line, buf.toString('utf8') + '\n');
+});
+[].forEach.call(buf, function(i) {
+  fi.emit('data', Buffer([i]));
+});
+assert.equal(callCount, 0);
+fi.emit('data', '\n');
+assert.equal(callCount, 1);