process.on('SIGWINCH', function() {
var winSize = output.getWindowSize();
exports.columns = winSize[0];
+
+ // FIXME: when #2922 will be approved, change this to
+ // output.on('resize', ...
+ self._refreshLine();
});
}
}
if (this.line.length === 0) return '';
this.history.unshift(this.line);
- this.line = '';
this.historyIndex = -1;
- this.cursor = 0;
-
// Only store so many
if (this.history.length > kHistorySize) this.history.pop();
Interface.prototype._refreshLine = function() {
+ var columns = this.columns;
+
+ // line length
+ var line = this._prompt + this.line;
+ var lineLength = line.length;
+ var lineCols = lineLength % columns;
+ var lineRows = (lineLength - lineCols) / columns;
+
+ // cursor position
+ var cursorPos = this._getCursorPos();
+
+ // first move to the bottom of the current line, based on cursor pos
+ var prevRows = this.prevRows || 0;
+ if (prevRows > 0) {
+ this.output.moveCursor(0, -prevRows);
+ }
+
// Cursor to left edge.
this.output.cursorTo(0);
+ // erase data
+ this.output.clearScreenDown();
// Write the prompt and the current buffer content.
- this.output.write(this._prompt);
- this.output.write(this.line);
+ this.output.write(line);
- // Erase to right.
- this.output.clearLine(1);
+ // Force terminal to allocate a new line
+ if (lineCols === 0) {
+ this.output.write(" ");
+ }
// Move cursor to original position.
- this.output.cursorTo(this._promptLength + this.cursor);
+ this.output.cursorTo(cursorPos.cols);
+
+ var diff = lineRows - cursorPos.rows;
+ if (diff > 0) {
+ this.output.moveCursor(0, -diff);
+ }
+
+ this.prevRows = cursorPos.rows;
};
this.line += c;
this.cursor += c.length;
this.output.write(c);
+
+ // a hack to get the line refreshed if it's needed
+ this._moveCursor(0);
}
};
if (this.cursor > 0) {
var leading = this.line.slice(0, this.cursor);
var match = leading.match(/([^\w\s]+|\w+|)\s*$/);
- this.cursor -= match[0].length;
- this._refreshLine();
+ this._moveCursor(-match[0].length);
}
};
if (this.cursor < this.line.length) {
var trailing = this.line.slice(this.cursor);
var match = trailing.match(/^(\s+|\W+|\w+)\s*/);
- this.cursor += match[0].length;
- this._refreshLine();
+ this._moveCursor(match[0].length);
}
};
};
+Interface.prototype.clearLine = function() {
+ this._moveCursor(+Infinity);
+ this.output.write('\r\n');
+ this.line = '';
+ this.cursor = 0;
+ this.prevRows = 0;
+};
+
+
Interface.prototype._line = function() {
var line = this._addHistory();
- this.output.write('\r\n');
+ this.clearLine();
this._onLine(line);
};
};
+// Returns current cursor's position and line
+Interface.prototype._getCursorPos = function() {
+ var columns = this.columns;
+ var cursorPos = this.cursor + this._promptLength;
+ var cols = cursorPos % columns;
+ var rows = (cursorPos - cols) / columns;
+ return {cols: cols, rows: rows};
+};
+
+
+// This function moves cursor dx places to the right
+// (-dx for left) and refreshes the line if it is needed
+Interface.prototype._moveCursor = function(dx) {
+ var oldcursor = this.cursor;
+ var oldPos = this._getCursorPos();
+ this.cursor += dx;
+
+ // bounds check
+ if (this.cursor < 0) this.cursor = 0;
+ if (this.cursor > this.line.length) this.cursor = this.line.length;
+
+ var newPos = this._getCursorPos();
+
+ // check if cursors are in the same line
+ if (oldPos.rows == newPos.rows && newPos.cols != 0) {
+ this.output.moveCursor(this.cursor - oldcursor, 0);
+ this.prevRows = newPos.rows;
+ } else {
+ this._refreshLine();
+ }
+};
+
+
// handle a write from the tty
Interface.prototype._ttyWrite = function(s, key) {
var next_word, next_non_word, previous_word, previous_non_word;
break;
case 'a': // go to the start of the line
- this.cursor = 0;
- this._refreshLine();
+ this._moveCursor(-Infinity);
break;
case 'e': // go to the end of the line
- this.cursor = this.line.length;
- this._refreshLine();
+ this._moveCursor(+Infinity);
break;
case 'b': // back one character
- if (this.cursor > 0) {
- this.cursor--;
- this._refreshLine();
- }
+ this._moveCursor(-1);
break;
case 'f': // forward one character
- if (this.cursor != this.line.length) {
- this.cursor++;
- this._refreshLine();
- }
+ this._moveCursor(+1);
break;
case 'n': // next history item
break;
case 'left':
- if (this.cursor > 0) {
- this.cursor--;
- this.output.moveCursor(-1, 0);
- }
+ this._moveCursor(-1);
break;
case 'right':
- if (this.cursor != this.line.length) {
- this.cursor++;
- this.output.moveCursor(1, 0);
- }
+ this._moveCursor(+1);
break;
case 'home':
- this.cursor = 0;
- this._refreshLine();
+ this._moveCursor(-Infinity);
break;
case 'end':
- this.cursor = this.line.length;
- this._refreshLine();
+ this._moveCursor(+Infinity);
break;
case 'up':