blob: 058d1868496cc800b9d7a536694e5a82a510b11f (
plain)
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
|
const ansi = require('./ansi')
const unic = require('./unichars')
module.exports = class Flushable {
// A writable that can be used to collect chunks of data before writing
// them.
constructor(writable, shouldCompress = false) {
this.target = writable
// Use the magical ANSI self-made compression method that probably
// doesn't *quite* work but should drastically decrease write size?
this.shouldCompress = shouldCompress
// Whether or not to show compression statistics (original written size
// and ANSI-interpreted compressed size) in the output of flush.
this.shouldShowCompressionStatistics = false
// Use resizeScreen if you plan on using the ANSI compressor!
this.screenLines = 24
this.screenCols = 80
this.lastFrame = undefined
this.ended = false
this.paused = false
this.requestedFlush = false
this.chunks = []
}
resizeScreen({lines, cols}) {
this.screenLines = lines
this.screenCols = cols
this.clearLastFrame()
}
clearLastFrame() {
this.lastFrame = undefined
}
write(what) {
this.chunks.push(what)
}
flush() {
// If we're paused, we don't want to write, but we will keep a note that a
// flush was requested for when we unpause.
if (this.paused) {
this.requestedFlush = true
return
}
// Don't write if we've ended.
if (this.ended) {
return
}
// End if the target is destroyed.
// Yes, this relies on the target having a destroyed property
// Don't worry, it'll still work if there is no destroyed property though
// (I think)
if (this.target.destroyed) {
this.end()
return
}
let toWrite = this.chunks.join('')
if (this.shouldCompress) {
toWrite = this.compress(toWrite)
}
try {
this.target.write(toWrite)
} catch(err) {
console.error('Flushable write error (ending):', err.message)
this.end()
}
this.chunks = []
}
pause() {
this.paused = true
}
resume() {
this.paused = false
if (this.requestedFlush) {
this.flush()
}
}
end() {
this.ended = true
}
compress(toWrite) {
// TODO: customize screen size
const output = ansi.interpret(
toWrite, this.screenLines, this.screenCols, this.lastFrame
)
let { screen } = output
this.lastFrame = output
if (this.shouldShowCompressionStatistics) {
let msg = this.lastInterpretMessage
if (screen.length > 0 || !this.lastInterpretMessage) {
const pcSaved = Math.round(1000 - (1000 / toWrite.length * screen.length)) / 10
const kbSaved = Math.round((toWrite.length - screen.length) / 100) / 10
msg = this.lastInterpretMessage = (
'(ANSI-interpret: ' +
`${toWrite.length} -> ${screen.length} ${pcSaved}% / ${kbSaved} KB saved)`
)
}
screen += '\x1b[H\x1b[0m'
screen += msg + unic.BOX_H_DOUBLE.repeat(this.screenCols - msg.length)
this.lastFrame.oldLastChar.attributes = []
}
return screen
}
}
|