| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 |
- 'use strict';
- var _ = require('lodash');
- var util = require('./readline');
- var readline = require('readline');
- var cliWidth = require('cli-width');
- var stripAnsi = require('strip-ansi');
- var ScreenManager = module.exports = function (rl) {
- // These variables are keeping information to allow correct prompt re-rendering
- this.height = 0;
- this.extraLinesUnderPrompt = 0;
- this.rl = rl;
- };
- ScreenManager.prototype.render = function (content, opt) {
- opt = _.extend({ cursor: 0 }, opt || {});
- var cursorPos = this.rl._getCursorPos();
- this.rl.output.unmute();
- this.clean(this.extraLinesUnderPrompt);
- /**
- * Write message to screen and setPrompt to control backspace
- */
- var lines = content.split(/\n/);
- var promptLine = lines[lines.length - 1 - opt.cursor];
- var rawPromptLine = stripAnsi(promptLine);
- // Remove the rl.line from our prompt. We can't rely on the content of
- // rl.line (mainly because of the password prompt), so just rely on it's
- // length.
- var prompt = promptLine;
- if (this.rl.line.length) {
- prompt = prompt.slice(0, -this.rl.line.length);
- }
- this.rl.setPrompt(prompt);
- var rawPrompt = stripAnsi(prompt);
- // Manually insert an extra line if we're at the end of the line.
- // This prevent the cursor from appearing at the beginning of the
- // current line.
- if (rawPromptLine.length === cliWidth()) {
- lines.splice(lines.length, 0, ' ');
- }
- this.rl.output.write(lines.join('\n'));
- /**
- * Re-adjust the cursor at the correct position.
- */
- var breakedLines = breakLines(lines);
- var actualLines = _.flatten(breakedLines);
- var promptLineUpDiff = Math.floor(rawPromptLine.length / cliWidth()) - cursorPos.rows;
- if (opt.cursor + promptLineUpDiff > 0) {
- util.up(this.rl, opt.cursor + promptLineUpDiff);
- }
- // Reset cursor at the beginning of the line
- util.left(this.rl, stripAnsi(_.last(actualLines)).length);
- var rightPos = cursorPos.cols;
- if (cursorPos.rows === 0) {
- rightPos = Math.max(rightPos, rawPrompt.length);
- }
- // rightPos should never be further than the total line content size.
- // If we changed the prompt and reset the rl.line, we want to reset our
- // cursor at the beginning of the prompt.
- if (rightPos > rawPromptLine.length && !this.rl.line) {
- rightPos = rawPrompt.length;
- }
- util.right(this.rl, rightPos);
- /**
- * Set up state for next re-rendering
- */
- var bottomSection = breakedLines.slice(breakedLines.length - opt.cursor - promptLineUpDiff);
- this.extraLinesUnderPrompt = _.flatten(bottomSection).length;
- this.height = actualLines.length;
- this.rl.output.mute();
- };
- ScreenManager.prototype.clean = function (extraLines) {
- if (extraLines > 0) {
- util.down(this.rl, extraLines);
- }
- util.clearLine(this.rl, this.height);
- };
- ScreenManager.prototype.done = function () {
- this.rl.setPrompt('');
- this.rl.output.unmute();
- this.rl.output.write('\n');
- };
- function breakLines(lines) {
- // Break lines who're longuer than the cli width so we can gracefully handle line
- // returns.
- var regex = new RegExp('.{1,' + cliWidth() + '}', 'g');
- return lines.map(function (line) {
- return stripAnsi(line).match(regex);
- });
- }
|