File size: 3,558 Bytes
1070765
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
const _readline = require('readline');

// low-level terminal interactions
class Terminal{

    constructor(outputStream){
        this.stream = outputStream;

        // default: line wrapping enabled
        this.linewrap = true;

        // current, relative y position
        this.dy = 0;
    }

    // save cursor position + settings
    cursorSave(){
        if (!this.stream.isTTY){
            return;
        }

        // save position
        this.stream.write('\x1B7');
    }

    // restore last cursor position + settings
    cursorRestore(){
        if (!this.stream.isTTY){
            return;
        }

        // restore cursor
        this.stream.write('\x1B8');
    }

    // show/hide cursor
    cursor(enabled){
        if (!this.stream.isTTY){
            return;
        }

        if (enabled){
            this.stream.write('\x1B[?25h');
        }else{
            this.stream.write('\x1B[?25l');
        }
    }

    // change cursor positionn
    cursorTo(x=null, y=null){
        if (!this.stream.isTTY){
            return;
        }

        // move cursor absolute
        _readline.cursorTo(this.stream, x, y);
    }

    // change relative cursor position
    cursorRelative(dx=null, dy=null){
        if (!this.stream.isTTY){
            return;
        }

        // store current position
        this.dy = this.dy + dy;
        
        // move cursor relative
        _readline.moveCursor(this.stream, dx, dy);
    }

    // relative reset
    cursorRelativeReset(){
        if (!this.stream.isTTY){
            return;
        }

        // move cursor to initial line
        _readline.moveCursor(this.stream, 0, -this.dy);

        // first char
        _readline.cursorTo(this.stream, 0, null);

        // reset counter
        this.dy = 0;
    }

    // clear to the right from cursor
    clearRight(){
        if (!this.stream.isTTY){
            return;
        }

        _readline.clearLine(this.stream, 1);
    }

    // clear the full line
    clearLine(){
        if (!this.stream.isTTY){
            return;
        }

        _readline.clearLine(this.stream, 0);
    }

    // clear everyting beyond the current line
    clearBottom(){
        if (!this.stream.isTTY){
            return;
        }

        _readline.clearScreenDown(this.stream);
    }

    // add new line; increment counter
    newline(){
        this.stream.write('\n');
        this.dy++;
    }

    // write content to output stream
    // @TODO use string-width to strip length
    write(s, rawWrite=false){
        // line wrapping enabled ? trim output
        // this is just a fallback mechanism in case user enabled line-wrapping via options or set it to auto
        if (this.linewrap === true && rawWrite === false){
            this.stream.write(s.substr(0, this.getWidth()));

        // standard behaviour with disabled linewrapping
        }else{
            this.stream.write(s);
        }
    }

    // control line wrapping
    lineWrapping(enabled){
        if (!this.stream.isTTY){
            return;
        }

        // store state
        this.linewrap = enabled;
        if (enabled){
            this.stream.write('\x1B[?7h');
        }else{
            this.stream.write('\x1B[?7l');
        }
    }

    // tty environment ?
    isTTY(){
        return (this.stream.isTTY === true);
    }

    // get terminal width
    getWidth(){
        // set max width to 80 in tty-mode and 200 in notty-mode
        return this.stream.columns || (this.stream.isTTY ? 80 : 200);
    }
}

module.exports = Terminal;