minor adjustment to readme
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / inquirer / lib / utils / screen-manager.js
1 'use strict';
2 var _ = {
3   last: require('lodash/last'),
4   flatten: require('lodash/flatten'),
5 };
6 var util = require('./readline');
7 var cliWidth = require('cli-width');
8 var stripAnsi = require('strip-ansi');
9 var stringWidth = require('string-width');
10
11 function height(content) {
12   return content.split('\n').length;
13 }
14
15 function lastLine(content) {
16   return _.last(content.split('\n'));
17 }
18
19 class ScreenManager {
20   constructor(rl) {
21     // These variables are keeping information to allow correct prompt re-rendering
22     this.height = 0;
23     this.extraLinesUnderPrompt = 0;
24
25     this.rl = rl;
26   }
27
28   render(content, bottomContent) {
29     this.rl.output.unmute();
30     this.clean(this.extraLinesUnderPrompt);
31
32     /**
33      * Write message to screen and setPrompt to control backspace
34      */
35
36     var promptLine = lastLine(content);
37     var rawPromptLine = stripAnsi(promptLine);
38
39     // Remove the rl.line from our prompt. We can't rely on the content of
40     // rl.line (mainly because of the password prompt), so just rely on it's
41     // length.
42     var prompt = rawPromptLine;
43     if (this.rl.line.length) {
44       prompt = prompt.slice(0, -this.rl.line.length);
45     }
46
47     this.rl.setPrompt(prompt);
48
49     // SetPrompt will change cursor position, now we can get correct value
50     var cursorPos = this.rl._getCursorPos();
51     var width = this.normalizedCliWidth();
52
53     content = this.forceLineReturn(content, width);
54     if (bottomContent) {
55       bottomContent = this.forceLineReturn(bottomContent, width);
56     }
57
58     // Manually insert an extra line if we're at the end of the line.
59     // This prevent the cursor from appearing at the beginning of the
60     // current line.
61     if (rawPromptLine.length % width === 0) {
62       content += '\n';
63     }
64
65     var fullContent = content + (bottomContent ? '\n' + bottomContent : '');
66     this.rl.output.write(fullContent);
67
68     /**
69      * Re-adjust the cursor at the correct position.
70      */
71
72     // We need to consider parts of the prompt under the cursor as part of the bottom
73     // content in order to correctly cleanup and re-render.
74     var promptLineUpDiff = Math.floor(rawPromptLine.length / width) - cursorPos.rows;
75     var bottomContentHeight =
76       promptLineUpDiff + (bottomContent ? height(bottomContent) : 0);
77     if (bottomContentHeight > 0) {
78       util.up(this.rl, bottomContentHeight);
79     }
80
81     // Reset cursor at the beginning of the line
82     util.left(this.rl, stringWidth(lastLine(fullContent)));
83
84     // Adjust cursor on the right
85     if (cursorPos.cols > 0) {
86       util.right(this.rl, cursorPos.cols);
87     }
88
89     /**
90      * Set up state for next re-rendering
91      */
92     this.extraLinesUnderPrompt = bottomContentHeight;
93     this.height = height(fullContent);
94
95     this.rl.output.mute();
96   }
97
98   clean(extraLines) {
99     if (extraLines > 0) {
100       util.down(this.rl, extraLines);
101     }
102
103     util.clearLine(this.rl, this.height);
104   }
105
106   done() {
107     this.rl.setPrompt('');
108     this.rl.output.unmute();
109     this.rl.output.write('\n');
110   }
111
112   releaseCursor() {
113     if (this.extraLinesUnderPrompt > 0) {
114       util.down(this.rl, this.extraLinesUnderPrompt);
115     }
116   }
117
118   normalizedCliWidth() {
119     var width = cliWidth({
120       defaultWidth: 80,
121       output: this.rl.output,
122     });
123     return width;
124   }
125
126   breakLines(lines, width) {
127     // Break lines who're longer than the cli width so we can normalize the natural line
128     // returns behavior across terminals.
129     width = width || this.normalizedCliWidth();
130     var regex = new RegExp('(?:(?:\\033[[0-9;]*m)*.?){1,' + width + '}', 'g');
131     return lines.map((line) => {
132       var chunk = line.match(regex);
133       // Last match is always empty
134       chunk.pop();
135       return chunk || '';
136     });
137   }
138
139   forceLineReturn(content, width) {
140     width = width || this.normalizedCliWidth();
141     return _.flatten(this.breakLines(content.split('\n'), width)).join('\n');
142   }
143 }
144
145 module.exports = ScreenManager;