@socketsecurity/cli-with-sentry 0.14.137 → 0.14.138

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/dist/blessed/LICENSE +20 -0
  2. package/dist/blessed/lib/alias.js +519 -0
  3. package/dist/blessed/lib/blessed.js +32 -0
  4. package/dist/blessed/lib/colors.js +490 -0
  5. package/dist/blessed/lib/events.js +195 -0
  6. package/dist/blessed/lib/gpmclient.js +245 -0
  7. package/dist/blessed/lib/helpers.js +170 -0
  8. package/dist/blessed/lib/keys.js +512 -0
  9. package/dist/blessed/lib/program.js +4530 -0
  10. package/dist/blessed/lib/tput.js +3111 -0
  11. package/dist/blessed/lib/unicode.js +912 -0
  12. package/dist/blessed/lib/widget.js +60 -0
  13. package/dist/blessed/lib/widgets/ansiimage.js +173 -0
  14. package/dist/blessed/lib/widgets/bigtext.js +170 -0
  15. package/dist/blessed/lib/widgets/box.js +34 -0
  16. package/dist/blessed/lib/widgets/button.js +62 -0
  17. package/dist/blessed/lib/widgets/checkbox.js +95 -0
  18. package/dist/blessed/lib/widgets/element.js +2871 -0
  19. package/dist/blessed/lib/widgets/filemanager.js +223 -0
  20. package/dist/blessed/lib/widgets/form.js +301 -0
  21. package/dist/blessed/lib/widgets/image.js +71 -0
  22. package/dist/blessed/lib/widgets/input.js +34 -0
  23. package/dist/blessed/lib/widgets/layout.js +249 -0
  24. package/dist/blessed/lib/widgets/line.js +59 -0
  25. package/dist/blessed/lib/widgets/list.js +652 -0
  26. package/dist/blessed/lib/widgets/listbar.js +452 -0
  27. package/dist/blessed/lib/widgets/listtable.js +265 -0
  28. package/dist/blessed/lib/widgets/loading.js +88 -0
  29. package/dist/blessed/lib/widgets/log.js +82 -0
  30. package/dist/blessed/lib/widgets/message.js +145 -0
  31. package/dist/blessed/lib/widgets/node.js +314 -0
  32. package/dist/blessed/lib/widgets/overlayimage.js +794 -0
  33. package/dist/blessed/lib/widgets/progressbar.js +166 -0
  34. package/dist/blessed/lib/widgets/prompt.js +127 -0
  35. package/dist/blessed/lib/widgets/question.js +129 -0
  36. package/dist/blessed/lib/widgets/radiobutton.js +62 -0
  37. package/dist/blessed/lib/widgets/radioset.js +36 -0
  38. package/dist/blessed/lib/widgets/screen.js +2485 -0
  39. package/dist/blessed/lib/widgets/scrollablebox.js +415 -0
  40. package/dist/blessed/lib/widgets/scrollabletext.js +35 -0
  41. package/dist/blessed/lib/widgets/table.js +383 -0
  42. package/dist/blessed/lib/widgets/terminal.js +452 -0
  43. package/dist/blessed/lib/widgets/text.js +35 -0
  44. package/dist/blessed/lib/widgets/textarea.js +376 -0
  45. package/dist/blessed/lib/widgets/textbox.js +79 -0
  46. package/dist/blessed/lib/widgets/video.js +130 -0
  47. package/dist/blessed/usr/fonts/AUTHORS +1 -0
  48. package/dist/blessed/usr/fonts/LICENSE +94 -0
  49. package/dist/blessed/usr/fonts/README +340 -0
  50. package/dist/blessed/usr/fonts/ter-u14b.json +17826 -0
  51. package/dist/blessed/usr/fonts/ter-u14n.json +17826 -0
  52. package/dist/blessed/usr/linux +0 -0
  53. package/dist/blessed/usr/windows-ansi +0 -0
  54. package/dist/blessed/usr/xterm +0 -0
  55. package/dist/blessed/usr/xterm-256color +0 -0
  56. package/dist/blessed/usr/xterm.termcap +243 -0
  57. package/dist/blessed/usr/xterm.terminfo +1977 -0
  58. package/dist/blessed/vendor/tng.js +1876 -0
  59. package/dist/blessed-contrib/LICENSE.md +21 -0
  60. package/dist/blessed-contrib/lib/layout/carousel.js +82 -0
  61. package/dist/blessed-contrib/lib/layout/grid.js +46 -0
  62. package/dist/blessed-contrib/lib/server-utils.js +83 -0
  63. package/dist/blessed-contrib/lib/utils.js +73 -0
  64. package/dist/blessed-contrib/lib/widget/canvas.js +52 -0
  65. package/dist/blessed-contrib/lib/widget/charts/bar.js +99 -0
  66. package/dist/blessed-contrib/lib/widget/charts/line.js +311 -0
  67. package/dist/blessed-contrib/lib/widget/charts/stacked-bar.js +245 -0
  68. package/dist/blessed-contrib/lib/widget/donut.js +183 -0
  69. package/dist/blessed-contrib/lib/widget/gauge-list.js +111 -0
  70. package/dist/blessed-contrib/lib/widget/gauge.js +127 -0
  71. package/dist/blessed-contrib/lib/widget/lcd.js +497 -0
  72. package/dist/blessed-contrib/lib/widget/log.js +32 -0
  73. package/dist/blessed-contrib/lib/widget/map.js +97 -0
  74. package/dist/blessed-contrib/lib/widget/markdown.js +68 -0
  75. package/dist/blessed-contrib/lib/widget/picture.js +61 -0
  76. package/dist/blessed-contrib/lib/widget/sparkline.js +66 -0
  77. package/dist/blessed-contrib/lib/widget/table.js +141 -0
  78. package/dist/blessed-contrib/lib/widget/tree.js +179 -0
  79. package/dist/blessed-contrib/node_modules/ansi-regex/index.js +6 -0
  80. package/dist/blessed-contrib/node_modules/ansi-regex/license +21 -0
  81. package/dist/blessed-contrib/node_modules/ansi-regex/package.json +64 -0
  82. package/dist/blessed-contrib/node_modules/ansi-regex/readme.md +39 -0
  83. package/dist/blessed-contrib/node_modules/ansi-styles/index.js +67 -0
  84. package/dist/blessed-contrib/node_modules/ansi-styles/license +21 -0
  85. package/dist/blessed-contrib/node_modules/ansi-styles/package.json +50 -0
  86. package/dist/blessed-contrib/node_modules/ansi-styles/readme.md +86 -0
  87. package/dist/blessed-contrib/node_modules/chalk/index.js +118 -0
  88. package/dist/blessed-contrib/node_modules/chalk/license +21 -0
  89. package/dist/blessed-contrib/node_modules/chalk/package.json +70 -0
  90. package/dist/blessed-contrib/node_modules/chalk/readme.md +213 -0
  91. package/dist/blessed-contrib/node_modules/escape-string-regexp/index.js +13 -0
  92. package/dist/blessed-contrib/node_modules/escape-string-regexp/license +21 -0
  93. package/dist/blessed-contrib/node_modules/escape-string-regexp/package.json +41 -0
  94. package/dist/blessed-contrib/node_modules/escape-string-regexp/readme.md +27 -0
  95. package/dist/blessed-contrib/node_modules/strip-ansi/index.js +8 -0
  96. package/dist/blessed-contrib/node_modules/strip-ansi/license +21 -0
  97. package/dist/blessed-contrib/node_modules/strip-ansi/package.json +57 -0
  98. package/dist/blessed-contrib/node_modules/strip-ansi/readme.md +33 -0
  99. package/dist/blessed-contrib/node_modules/supports-color/index.js +52 -0
  100. package/dist/blessed-contrib/node_modules/supports-color/license +21 -0
  101. package/dist/blessed-contrib/node_modules/supports-color/package.json +49 -0
  102. package/dist/blessed-contrib/node_modules/supports-color/readme.md +36 -0
  103. package/dist/cli.js +9 -8
  104. package/dist/cli.js.map +1 -1
  105. package/dist/instrument-with-sentry.js +2 -2
  106. package/dist/instrument-with-sentry.js.map +1 -1
  107. package/dist/shadow-npm-inject.js +2 -2
  108. package/dist/shadow-npm-inject.js.map +1 -1
  109. package/package.json +4 -4
@@ -0,0 +1,2871 @@
1
+ /**
2
+ * element.js - base element for blessed
3
+ * Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
4
+ * https://github.com/chjj/blessed
5
+ */
6
+
7
+ /**
8
+ * Modules
9
+ */
10
+
11
+ const assert = require('node:assert')
12
+
13
+ const colors = require('../colors'),
14
+ unicode = require('../unicode')
15
+
16
+ const nextTick = global.setImmediate || process.nextTick.bind(process)
17
+
18
+ const helpers = require('../helpers')
19
+
20
+ const Node = require('./node')
21
+
22
+ /**
23
+ * Element
24
+ */
25
+
26
+ function Element(options) {
27
+ const self = this
28
+
29
+ if (!(this instanceof Node)) {
30
+ return new Element(options)
31
+ }
32
+
33
+ options = options || {}
34
+
35
+ // Workaround to get a `scrollable` option.
36
+ if (options.scrollable && !this._ignore && this.type !== 'scrollable-box') {
37
+ const ScrollableBox = require('./scrollablebox')
38
+ Object.getOwnPropertyNames(ScrollableBox.prototype).forEach(function (key) {
39
+ if (key === 'type') {
40
+ return
41
+ }
42
+ Object.defineProperty(
43
+ this,
44
+ key,
45
+ Object.getOwnPropertyDescriptor(ScrollableBox.prototype, key)
46
+ )
47
+ }, this)
48
+ this._ignore = true
49
+ ScrollableBox.call(this, options)
50
+ delete this._ignore
51
+ return this
52
+ }
53
+
54
+ Node.call(this, options)
55
+
56
+ this.name = options.name
57
+
58
+ options.position = options.position || {
59
+ left: options.left,
60
+ right: options.right,
61
+ top: options.top,
62
+ bottom: options.bottom,
63
+ width: options.width,
64
+ height: options.height
65
+ }
66
+
67
+ if (
68
+ options.position.width === 'shrink' ||
69
+ options.position.height === 'shrink'
70
+ ) {
71
+ if (options.position.width === 'shrink') {
72
+ delete options.position.width
73
+ }
74
+ if (options.position.height === 'shrink') {
75
+ delete options.position.height
76
+ }
77
+ options.shrink = true
78
+ }
79
+
80
+ this.position = options.position
81
+
82
+ this.noOverflow = options.noOverflow
83
+ this.dockBorders = options.dockBorders
84
+ this.shadow = options.shadow
85
+
86
+ this.style = options.style
87
+
88
+ if (!this.style) {
89
+ this.style = {}
90
+ this.style.fg = options.fg
91
+ this.style.bg = options.bg
92
+ this.style.bold = options.bold
93
+ this.style.underline = options.underline
94
+ this.style.blink = options.blink
95
+ this.style.inverse = options.inverse
96
+ this.style.invisible = options.invisible
97
+ this.style.transparent = options.transparent
98
+ }
99
+
100
+ this.hidden = options.hidden || false
101
+ this.fixed = options.fixed || false
102
+ this.align = options.align || 'left'
103
+ this.valign = options.valign || 'top'
104
+ this.wrap = options.wrap !== false
105
+ this.shrink = options.shrink
106
+ this.fixed = options.fixed
107
+ this.ch = options.ch || ' '
108
+
109
+ if (typeof options.padding === 'number' || !options.padding) {
110
+ options.padding = {
111
+ left: options.padding,
112
+ top: options.padding,
113
+ right: options.padding,
114
+ bottom: options.padding
115
+ }
116
+ }
117
+
118
+ this.padding = {
119
+ left: options.padding.left || 0,
120
+ top: options.padding.top || 0,
121
+ right: options.padding.right || 0,
122
+ bottom: options.padding.bottom || 0
123
+ }
124
+
125
+ this.border = options.border
126
+ if (this.border) {
127
+ if (typeof this.border === 'string') {
128
+ this.border = { type: this.border }
129
+ }
130
+ this.border.type = this.border.type || 'bg'
131
+ if (this.border.type === 'ascii') {
132
+ this.border.type = 'line'
133
+ }
134
+ this.border.ch = this.border.ch || ' '
135
+ this.style.border = this.style.border || this.border.style
136
+ if (!this.style.border) {
137
+ this.style.border = {}
138
+ this.style.border.fg = this.border.fg
139
+ this.style.border.bg = this.border.bg
140
+ }
141
+ //this.border.style = this.style.border;
142
+ if (this.border.left == null) {
143
+ this.border.left = true
144
+ }
145
+ if (this.border.top == null) {
146
+ this.border.top = true
147
+ }
148
+ if (this.border.right == null) {
149
+ this.border.right = true
150
+ }
151
+ if (this.border.bottom == null) {
152
+ this.border.bottom = true
153
+ }
154
+ }
155
+
156
+ // if (options.mouse || options.clickable) {
157
+ if (options.clickable) {
158
+ this.screen._listenMouse(this)
159
+ }
160
+
161
+ if (options.input || options.keyable) {
162
+ this.screen._listenKeys(this)
163
+ }
164
+
165
+ this.parseTags = options.parseTags || options.tags
166
+
167
+ this.setContent(options.content || '', true)
168
+
169
+ if (options.label) {
170
+ this.setLabel(options.label)
171
+ }
172
+
173
+ if (options.hoverText) {
174
+ this.setHover(options.hoverText)
175
+ }
176
+
177
+ // TODO: Possibly move this to Node for onScreenEvent('mouse', ...).
178
+ this.on('newListener', function fn(type) {
179
+ // type = type.split(' ').slice(1).join(' ');
180
+ if (
181
+ type === 'mouse' ||
182
+ type === 'click' ||
183
+ type === 'mouseover' ||
184
+ type === 'mouseout' ||
185
+ type === 'mousedown' ||
186
+ type === 'mouseup' ||
187
+ type === 'mousewheel' ||
188
+ type === 'wheeldown' ||
189
+ type === 'wheelup' ||
190
+ type === 'mousemove'
191
+ ) {
192
+ self.screen._listenMouse(self)
193
+ } else if (type === 'keypress' || type.indexOf('key ') === 0) {
194
+ self.screen._listenKeys(self)
195
+ }
196
+ })
197
+
198
+ this.on('resize', function () {
199
+ self.parseContent()
200
+ })
201
+
202
+ this.on('attach', function () {
203
+ self.parseContent()
204
+ })
205
+
206
+ this.on('detach', function () {
207
+ delete self.lpos
208
+ })
209
+
210
+ if (options.hoverBg != null) {
211
+ options.hoverEffects = options.hoverEffects || {}
212
+ options.hoverEffects.bg = options.hoverBg
213
+ }
214
+
215
+ if (this.style.hover) {
216
+ options.hoverEffects = this.style.hover
217
+ }
218
+
219
+ if (this.style.focus) {
220
+ options.focusEffects = this.style.focus
221
+ }
222
+
223
+ if (options.effects) {
224
+ if (options.effects.hover) {
225
+ options.hoverEffects = options.effects.hover
226
+ }
227
+ if (options.effects.focus) {
228
+ options.focusEffects = options.effects.focus
229
+ }
230
+ }
231
+
232
+ ;[
233
+ ['hoverEffects', 'mouseover', 'mouseout', '_htemp'],
234
+ ['focusEffects', 'focus', 'blur', '_ftemp']
235
+ ].forEach(function (props) {
236
+ const pname = props[0],
237
+ over = props[1],
238
+ out = props[2],
239
+ temp = props[3]
240
+ self.screen.setEffects(self, self, over, out, self.options[pname], temp)
241
+ })
242
+
243
+ if (this.options.draggable) {
244
+ this.draggable = true
245
+ }
246
+
247
+ if (options.focused) {
248
+ this.focus()
249
+ }
250
+ }
251
+
252
+ Object.setPrototypeOf(Element.prototype, Node.prototype)
253
+
254
+ Element.prototype.type = 'element'
255
+
256
+ Element.prototype.__defineGetter__('focused', function () {
257
+ return this.screen.focused === this
258
+ })
259
+
260
+ Element.prototype.sattr = function (style, fg, bg) {
261
+ let bold = style.bold,
262
+ underline = style.underline,
263
+ blink = style.blink,
264
+ inverse = style.inverse,
265
+ invisible = style.invisible
266
+
267
+ // if (arguments.length === 1) {
268
+ if (fg == null && bg == null) {
269
+ fg = style.fg
270
+ bg = style.bg
271
+ }
272
+
273
+ // This used to be a loop, but I decided
274
+ // to unroll it for performance's sake.
275
+ if (typeof bold === 'function') {
276
+ bold = bold(this)
277
+ }
278
+ if (typeof underline === 'function') {
279
+ underline = underline(this)
280
+ }
281
+ if (typeof blink === 'function') {
282
+ blink = blink(this)
283
+ }
284
+ if (typeof inverse === 'function') {
285
+ inverse = inverse(this)
286
+ }
287
+ if (typeof invisible === 'function') {
288
+ invisible = invisible(this)
289
+ }
290
+
291
+ if (typeof fg === 'function') {
292
+ fg = fg(this)
293
+ }
294
+ if (typeof bg === 'function') {
295
+ bg = bg(this)
296
+ }
297
+
298
+ // return (this.uid << 24)
299
+ // | ((this.dockBorders ? 32 : 0) << 18)
300
+ return (
301
+ ((invisible ? 16 : 0) << 18) |
302
+ ((inverse ? 8 : 0) << 18) |
303
+ ((blink ? 4 : 0) << 18) |
304
+ ((underline ? 2 : 0) << 18) |
305
+ ((bold ? 1 : 0) << 18) |
306
+ (colors.convert(fg) << 9) |
307
+ colors.convert(bg)
308
+ )
309
+ }
310
+
311
+ Element.prototype.onScreenEvent = function (type, handler) {
312
+ const listeners = (this._slisteners = this._slisteners || [])
313
+ listeners.push({ type: type, handler: handler })
314
+ this.screen.on(type, handler)
315
+ }
316
+
317
+ Element.prototype.onceScreenEvent = function (type, handler) {
318
+ const listeners = (this._slisteners = this._slisteners || [])
319
+ const entry = { type: type, handler: handler }
320
+ listeners.push(entry)
321
+ this.screen.once(type, function () {
322
+ const i = listeners.indexOf(entry)
323
+ if (~i) {
324
+ listeners.splice(i, 1)
325
+ }
326
+ return handler.apply(this, arguments)
327
+ })
328
+ }
329
+
330
+ Element.prototype.removeScreenEvent = function (type, handler) {
331
+ const listeners = (this._slisteners = this._slisteners || [])
332
+ for (let i = 0; i < listeners.length; i++) {
333
+ const listener = listeners[i]
334
+ if (listener.type === type && listener.handler === handler) {
335
+ listeners.splice(i, 1)
336
+ if (this._slisteners.length === 0) {
337
+ delete this._slisteners
338
+ }
339
+ break
340
+ }
341
+ }
342
+ this.screen.removeListener(type, handler)
343
+ }
344
+
345
+ Element.prototype.free = function () {
346
+ const listeners = (this._slisteners = this._slisteners || [])
347
+ for (let i = 0; i < listeners.length; i++) {
348
+ const listener = listeners[i]
349
+ this.screen.removeListener(listener.type, listener.handler)
350
+ }
351
+ delete this._slisteners
352
+ }
353
+
354
+ Element.prototype.hide = function () {
355
+ if (this.hidden) {
356
+ return
357
+ }
358
+ this.clearPos()
359
+ this.hidden = true
360
+ this.emit('hide')
361
+ if (this.screen.focused === this) {
362
+ this.screen.rewindFocus()
363
+ }
364
+ }
365
+
366
+ Element.prototype.show = function () {
367
+ if (!this.hidden) {
368
+ return
369
+ }
370
+ this.hidden = false
371
+ this.emit('show')
372
+ }
373
+
374
+ Element.prototype.toggle = function () {
375
+ return this.hidden ? this.show() : this.hide()
376
+ }
377
+
378
+ Element.prototype.focus = function () {
379
+ return (this.screen.focused = this)
380
+ }
381
+
382
+ Element.prototype.setContent = function (content, noClear, noTags) {
383
+ if (!noClear) {
384
+ this.clearPos()
385
+ }
386
+ this.content = content || ''
387
+ this.parseContent(noTags)
388
+ this.emit('set content')
389
+ }
390
+
391
+ Element.prototype.getContent = function () {
392
+ if (!this._clines) {
393
+ return ''
394
+ }
395
+ return this._clines.fake.join('\n')
396
+ }
397
+
398
+ Element.prototype.setText = function (content, noClear) {
399
+ content = content || ''
400
+ content = content.replace(/\x1b\[[\d;]*m/g, '')
401
+ return this.setContent(content, noClear, true)
402
+ }
403
+
404
+ Element.prototype.getText = function () {
405
+ return this.getContent().replace(/\x1b\[[\d;]*m/g, '')
406
+ }
407
+
408
+ Element.prototype.parseContent = function (noTags) {
409
+ if (this.detached) {
410
+ return false
411
+ }
412
+
413
+ const width = this.width - this.iwidth
414
+ if (
415
+ this._clines == null ||
416
+ this._clines.width !== width ||
417
+ this._clines.content !== this.content
418
+ ) {
419
+ let content = this.content
420
+
421
+ content = content
422
+ .replace(/[\x00-\x08\x0b-\x0c\x0e-\x1a\x1c-\x1f\x7f]/g, '')
423
+ .replace(/\x1b(?!\[[\d;]*m)/g, '')
424
+ .replace(/\r\n|\r/g, '\n')
425
+ .replace(/\t/g, this.screen.tabc)
426
+
427
+ if (this.screen.fullUnicode) {
428
+ // double-width chars will eat the next char after render. create a
429
+ // blank character after it so it doesn't eat the real next char.
430
+ content = content.replace(unicode.chars.all, '$1\x03')
431
+ // iTerm2 cannot render combining characters properly.
432
+ if (this.screen.program.isiTerm2) {
433
+ content = content.replace(unicode.chars.combining, '')
434
+ }
435
+ } else {
436
+ // no double-width: replace them with question-marks.
437
+ content = content.replace(unicode.chars.all, '??')
438
+ // delete combining characters since they're 0-width anyway.
439
+ // NOTE: We could drop this, the non-surrogates would get changed to ? by
440
+ // the unicode filter, and surrogates changed to ? by the surrogate
441
+ // regex. however, the user might expect them to be 0-width.
442
+ // NOTE: Might be better for performance to drop!
443
+ content = content.replace(unicode.chars.combining, '')
444
+ // no surrogate pairs: replace them with question-marks.
445
+ content = content.replace(unicode.chars.surrogate, '?')
446
+ // XXX Deduplicate code here:
447
+ // content = helpers.dropUnicode(content);
448
+ }
449
+
450
+ if (!noTags) {
451
+ content = this._parseTags(content)
452
+ }
453
+
454
+ this._clines = this._wrapContent(content, width)
455
+ this._clines.width = width
456
+ this._clines.content = this.content
457
+ this._clines.attr = this._parseAttr(this._clines)
458
+ this._clines.ci = []
459
+ this._clines.reduce(
460
+ function (total, line) {
461
+ this._clines.ci.push(total)
462
+ return total + line.length + 1
463
+ }.bind(this),
464
+ 0
465
+ )
466
+
467
+ this._pcontent = this._clines.join('\n')
468
+ this.emit('parsed content')
469
+
470
+ return true
471
+ }
472
+
473
+ // Need to calculate this every time because the default fg/bg may change.
474
+ this._clines.attr = this._parseAttr(this._clines) || this._clines.attr
475
+
476
+ return false
477
+ }
478
+
479
+ // Convert `{red-fg}foo{/red-fg}` to `\x1b[31mfoo\x1b[39m`.
480
+ Element.prototype._parseTags = function (text) {
481
+ if (!this.parseTags) {
482
+ return text
483
+ }
484
+ if (!/{\/?[\w\-,;!#]*}/.test(text)) {
485
+ return text
486
+ }
487
+
488
+ let program = this.screen.program,
489
+ out = '',
490
+ state,
491
+ bg = [],
492
+ fg = [],
493
+ flag = [],
494
+ cap,
495
+ slash,
496
+ param,
497
+ attr,
498
+ esc
499
+
500
+ for (;;) {
501
+ if (!esc && (cap = /^{escape}/.exec(text))) {
502
+ text = text.substring(cap[0].length)
503
+ esc = true
504
+ continue
505
+ }
506
+
507
+ if (esc && (cap = /^([\s\S]+?){\/escape}/.exec(text))) {
508
+ text = text.substring(cap[0].length)
509
+ out += cap[1]
510
+ esc = false
511
+ continue
512
+ }
513
+
514
+ if (esc) {
515
+ // throw new Error('Unterminated escape tag.');
516
+ out += text
517
+ break
518
+ }
519
+
520
+ if ((cap = /^{(\/?)([\w\-,;!#]*)}/.exec(text))) {
521
+ text = text.substring(cap[0].length)
522
+ slash = cap[1] === '/'
523
+ param = cap[2].replace(/-/g, ' ')
524
+
525
+ if (param === 'open') {
526
+ out += '{'
527
+ continue
528
+ } else if (param === 'close') {
529
+ out += '}'
530
+ continue
531
+ }
532
+
533
+ if (param.slice(-3) === ' bg') {
534
+ state = bg
535
+ } else if (param.slice(-3) === ' fg') {
536
+ state = fg
537
+ } else {
538
+ state = flag
539
+ }
540
+
541
+ if (slash) {
542
+ if (!param) {
543
+ out += program._attr('normal')
544
+ bg.length = 0
545
+ fg.length = 0
546
+ flag.length = 0
547
+ } else {
548
+ attr = program._attr(param, false)
549
+ if (attr == null) {
550
+ out += cap[0]
551
+ } else {
552
+ // if (param !== state[state.length - 1]) {
553
+ // throw new Error('Misnested tags.');
554
+ // }
555
+ state.pop()
556
+ if (state.length) {
557
+ out += program._attr(state[state.length - 1])
558
+ } else {
559
+ out += attr
560
+ }
561
+ }
562
+ }
563
+ } else {
564
+ if (!param) {
565
+ out += cap[0]
566
+ } else {
567
+ attr = program._attr(param)
568
+ if (attr == null) {
569
+ out += cap[0]
570
+ } else {
571
+ state.push(param)
572
+ out += attr
573
+ }
574
+ }
575
+ }
576
+
577
+ continue
578
+ }
579
+
580
+ if ((cap = /^[\s\S]+?(?={\/?[\w\-,;!#]*})/.exec(text))) {
581
+ text = text.substring(cap[0].length)
582
+ out += cap[0]
583
+ continue
584
+ }
585
+
586
+ out += text
587
+ break
588
+ }
589
+
590
+ return out
591
+ }
592
+
593
+ Element.prototype._parseAttr = function (lines) {
594
+ let dattr = this.sattr(this.style),
595
+ attr = dattr,
596
+ attrs = [],
597
+ line,
598
+ i,
599
+ j,
600
+ c
601
+
602
+ if (lines[0].attr === attr) {
603
+ return
604
+ }
605
+
606
+ for (j = 0; j < lines.length; j++) {
607
+ line = lines[j]
608
+ attrs[j] = attr
609
+ for (i = 0; i < line.length; i++) {
610
+ if (line[i] === '\x1b') {
611
+ if ((c = /^\x1b\[[\d;]*m/.exec(line.substring(i)))) {
612
+ attr = this.screen.attrCode(c[0], attr, dattr)
613
+ i += c[0].length - 1
614
+ }
615
+ }
616
+ }
617
+ }
618
+
619
+ return attrs
620
+ }
621
+
622
+ Element.prototype._align = function (line, width, align) {
623
+ if (!align) {
624
+ return line
625
+ }
626
+ //if (!align && !~line.indexOf('{|}')) return line;
627
+
628
+ let cline = line.replace(/\x1b\[[\d;]*m/g, ''),
629
+ len = cline.length,
630
+ s = width - len
631
+
632
+ if (this.shrink) {
633
+ s = 0
634
+ }
635
+
636
+ if (len === 0) {
637
+ return line
638
+ }
639
+ if (s < 0) {
640
+ return line
641
+ }
642
+
643
+ if (align === 'center') {
644
+ s = Array(((s / 2) | 0) + 1).join(' ')
645
+ return s + line + s
646
+ } else if (align === 'right') {
647
+ s = Array(s + 1).join(' ')
648
+ return s + line
649
+ } else if (this.parseTags && ~line.indexOf('{|}')) {
650
+ const parts = line.split('{|}')
651
+ const cparts = cline.split('{|}')
652
+ s = Math.max(width - cparts[0].length - cparts[1].length, 0)
653
+ s = Array(s + 1).join(' ')
654
+ return parts[0] + s + parts[1]
655
+ }
656
+
657
+ return line
658
+ }
659
+
660
+ Element.prototype._wrapContent = function (content, width) {
661
+ let tags = this.parseTags,
662
+ state = this.align,
663
+ wrap = this.wrap,
664
+ margin = 0,
665
+ rtof = [],
666
+ ftor = [],
667
+ out = [],
668
+ no = 0,
669
+ line,
670
+ align,
671
+ cap,
672
+ total,
673
+ i,
674
+ part,
675
+ j,
676
+ lines,
677
+ rest
678
+
679
+ lines = content.split('\n')
680
+
681
+ if (!content) {
682
+ out.push(content)
683
+ out.rtof = [0]
684
+ out.ftor = [[0]]
685
+ out.fake = lines
686
+ out.real = out
687
+ out.mwidth = 0
688
+ return out
689
+ }
690
+
691
+ if (this.scrollbar) {
692
+ margin++
693
+ }
694
+ if (this.type === 'textarea') {
695
+ margin++
696
+ }
697
+ if (width > margin) {
698
+ width -= margin
699
+ }
700
+
701
+ main: for (; no < lines.length; no++) {
702
+ line = lines[no]
703
+ align = state
704
+
705
+ ftor.push([])
706
+
707
+ // Handle alignment tags.
708
+ if (tags) {
709
+ if ((cap = /^{(left|center|right)}/.exec(line))) {
710
+ line = line.substring(cap[0].length)
711
+ align = state = cap[1] !== 'left' ? cap[1] : null
712
+ }
713
+ if ((cap = /{\/(left|center|right)}$/.exec(line))) {
714
+ line = line.slice(0, -cap[0].length)
715
+ //state = null;
716
+ state = this.align
717
+ }
718
+ }
719
+
720
+ // If the string is apparently too long, wrap it.
721
+ while (line.length > width) {
722
+ // Measure the real width of the string.
723
+ for (i = 0, total = 0; i < line.length; i++) {
724
+ while (line[i] === '\x1b') {
725
+ while (line[i] && line[i++] !== 'm') {}
726
+ }
727
+ if (!line[i]) {
728
+ break
729
+ }
730
+ if (++total === width) {
731
+ // If we're not wrapping the text, we have to finish up the rest of
732
+ // the control sequences before cutting off the line.
733
+ i++
734
+ if (!wrap) {
735
+ rest = line.substring(i).match(/\x1b\[[^m]*m/g)
736
+ rest = rest ? rest.join('') : ''
737
+ out.push(this._align(line.substring(0, i) + rest, width, align))
738
+ ftor[no].push(out.length - 1)
739
+ rtof.push(no)
740
+ continue main
741
+ }
742
+ if (!this.screen.fullUnicode) {
743
+ // Try to find a space to break on.
744
+ if (i !== line.length) {
745
+ j = i
746
+ while (j > i - 10 && j > 0 && line[--j] !== ' ') {}
747
+ if (line[j] === ' ') {
748
+ i = j + 1
749
+ }
750
+ }
751
+ } else {
752
+ // Try to find a character to break on.
753
+ if (i !== line.length) {
754
+ // <XXX>
755
+ // Compensate for surrogate length
756
+ // counts on wrapping (experimental):
757
+ // NOTE: Could optimize this by putting
758
+ // it in the parent for loop.
759
+ if (unicode.isSurrogate(line, i)) {
760
+ i--
761
+ }
762
+ for (let s = 0, n = 0; n < i; n++) {
763
+ if (unicode.isSurrogate(line, n)) {
764
+ s++, n++
765
+ }
766
+ }
767
+ i += s
768
+ // </XXX>
769
+ j = i
770
+ // Break _past_ space.
771
+ // Break _past_ double-width chars.
772
+ // Break _past_ surrogate pairs.
773
+ // Break _past_ combining chars.
774
+ while (j > i - 10 && j > 0) {
775
+ j--
776
+ if (
777
+ line[j] === ' ' ||
778
+ line[j] === '\x03' ||
779
+ (unicode.isSurrogate(line, j - 1) &&
780
+ line[j + 1] !== '\x03') ||
781
+ unicode.isCombining(line, j)
782
+ ) {
783
+ break
784
+ }
785
+ }
786
+ if (
787
+ line[j] === ' ' ||
788
+ line[j] === '\x03' ||
789
+ (unicode.isSurrogate(line, j - 1) && line[j + 1] !== '\x03') ||
790
+ unicode.isCombining(line, j)
791
+ ) {
792
+ i = j + 1
793
+ }
794
+ }
795
+ }
796
+ break
797
+ }
798
+ }
799
+
800
+ part = line.substring(0, i)
801
+ line = line.substring(i)
802
+
803
+ out.push(this._align(part, width, align))
804
+ ftor[no].push(out.length - 1)
805
+ rtof.push(no)
806
+
807
+ // Make sure we didn't wrap the line to the very end, otherwise
808
+ // we get a pointless empty line after a newline.
809
+ if (line === '') {
810
+ continue main
811
+ }
812
+
813
+ // If only an escape code got cut off, at it to `part`.
814
+ if (/^(?:\x1b[[\d;]*m)+$/.test(line)) {
815
+ out[out.length - 1] += line
816
+ continue main
817
+ }
818
+ }
819
+
820
+ out.push(this._align(line, width, align))
821
+ ftor[no].push(out.length - 1)
822
+ rtof.push(no)
823
+ }
824
+
825
+ out.rtof = rtof
826
+ out.ftor = ftor
827
+ out.fake = lines
828
+ out.real = out
829
+
830
+ out.mwidth = out.reduce(function (current, line) {
831
+ line = line.replace(/\x1b\[[\d;]*m/g, '')
832
+ return line.length > current ? line.length : current
833
+ }, 0)
834
+
835
+ return out
836
+ }
837
+
838
+ Element.prototype.__defineGetter__('visible', function () {
839
+ let el = this
840
+ do {
841
+ if (el.detached) {
842
+ return false
843
+ }
844
+ if (el.hidden) {
845
+ return false
846
+ }
847
+ // if (!el.lpos) return false;
848
+ // if (el.position.width === 0 || el.position.height === 0) return false;
849
+ } while ((el = el.parent))
850
+ return true
851
+ })
852
+
853
+ Element.prototype.__defineGetter__('_detached', function () {
854
+ let el = this
855
+ do {
856
+ if (el.type === 'screen') {
857
+ return false
858
+ }
859
+ if (!el.parent) {
860
+ return true
861
+ }
862
+ } while ((el = el.parent))
863
+ return false
864
+ })
865
+
866
+ Element.prototype.enableMouse = function () {
867
+ this.screen._listenMouse(this)
868
+ }
869
+
870
+ Element.prototype.enableKeys = function () {
871
+ this.screen._listenKeys(this)
872
+ }
873
+
874
+ Element.prototype.enableInput = function () {
875
+ this.screen._listenMouse(this)
876
+ this.screen._listenKeys(this)
877
+ }
878
+
879
+ Element.prototype.__defineGetter__('draggable', function () {
880
+ return this._draggable === true
881
+ })
882
+
883
+ Element.prototype.__defineSetter__('draggable', function (draggable) {
884
+ return draggable ? this.enableDrag(draggable) : this.disableDrag()
885
+ })
886
+
887
+ Element.prototype.enableDrag = function (verify) {
888
+ const self = this
889
+
890
+ if (this._draggable) {
891
+ return true
892
+ }
893
+
894
+ if (typeof verify !== 'function') {
895
+ verify = function () {
896
+ return true
897
+ }
898
+ }
899
+
900
+ this.enableMouse()
901
+
902
+ this.on(
903
+ 'mousedown',
904
+ (this._dragMD = function (data) {
905
+ if (self.screen._dragging) {
906
+ return
907
+ }
908
+ if (!verify(data)) {
909
+ return
910
+ }
911
+ self.screen._dragging = self
912
+ self._drag = {
913
+ x: data.x - self.aleft,
914
+ y: data.y - self.atop
915
+ }
916
+ self.setFront()
917
+ })
918
+ )
919
+
920
+ this.onScreenEvent(
921
+ 'mouse',
922
+ (this._dragM = function (data) {
923
+ if (self.screen._dragging !== self) {
924
+ return
925
+ }
926
+
927
+ if (data.action !== 'mousedown' && data.action !== 'mousemove') {
928
+ delete self.screen._dragging
929
+ delete self._drag
930
+ return
931
+ }
932
+
933
+ // This can happen in edge cases where the user is
934
+ // already dragging and element when it is detached.
935
+ if (!self.parent) {
936
+ return
937
+ }
938
+
939
+ const ox = self._drag.x,
940
+ oy = self._drag.y,
941
+ px = self.parent.aleft,
942
+ py = self.parent.atop,
943
+ x = data.x - px - ox,
944
+ y = data.y - py - oy
945
+
946
+ if (self.position.right != null) {
947
+ if (self.position.left != null) {
948
+ self.width = '100%-' + (self.parent.width - self.width)
949
+ }
950
+ self.position.right = null
951
+ }
952
+
953
+ if (self.position.bottom != null) {
954
+ if (self.position.top != null) {
955
+ self.height = '100%-' + (self.parent.height - self.height)
956
+ }
957
+ self.position.bottom = null
958
+ }
959
+
960
+ self.rleft = x
961
+ self.rtop = y
962
+
963
+ self.screen.render()
964
+ })
965
+ )
966
+
967
+ return (this._draggable = true)
968
+ }
969
+
970
+ Element.prototype.disableDrag = function () {
971
+ if (!this._draggable) {
972
+ return false
973
+ }
974
+ delete this.screen._dragging
975
+ delete this._drag
976
+ this.removeListener('mousedown', this._dragMD)
977
+ this.removeScreenEvent('mouse', this._dragM)
978
+ return (this._draggable = false)
979
+ }
980
+
981
+ Element.prototype.key = function () {
982
+ return this.screen.program.key.apply(this, arguments)
983
+ }
984
+
985
+ Element.prototype.onceKey = function () {
986
+ return this.screen.program.onceKey.apply(this, arguments)
987
+ }
988
+
989
+ Element.prototype.unkey = Element.prototype.removeKey = function () {
990
+ return this.screen.program.unkey.apply(this, arguments)
991
+ }
992
+
993
+ Element.prototype.setIndex = function (index) {
994
+ if (!this.parent) {
995
+ return
996
+ }
997
+
998
+ if (index < 0) {
999
+ index = this.parent.children.length + index
1000
+ }
1001
+
1002
+ index = Math.max(index, 0)
1003
+ index = Math.min(index, this.parent.children.length - 1)
1004
+
1005
+ const i = this.parent.children.indexOf(this)
1006
+ if (!~i) {
1007
+ return
1008
+ }
1009
+
1010
+ const item = this.parent.children.splice(i, 1)[0]
1011
+ this.parent.children.splice(index, 0, item)
1012
+ }
1013
+
1014
+ Element.prototype.setFront = function () {
1015
+ return this.setIndex(-1)
1016
+ }
1017
+
1018
+ Element.prototype.setBack = function () {
1019
+ return this.setIndex(0)
1020
+ }
1021
+
1022
+ Element.prototype.clearPos = function (get, override) {
1023
+ if (this.detached) {
1024
+ return
1025
+ }
1026
+ const lpos = this._getCoords(get)
1027
+ if (!lpos) {
1028
+ return
1029
+ }
1030
+ this.screen.clearRegion(lpos.xi, lpos.xl, lpos.yi, lpos.yl, override)
1031
+ }
1032
+
1033
+ Element.prototype.setLabel = function (options) {
1034
+ const self = this
1035
+ const Box = require('./box')
1036
+
1037
+ if (typeof options === 'string') {
1038
+ options = { text: options }
1039
+ }
1040
+
1041
+ if (this._label) {
1042
+ this._label.setContent(options.text)
1043
+ if (options.side !== 'right') {
1044
+ this._label.rleft = 2 + (this.border ? -1 : 0)
1045
+ this._label.position.right = undefined
1046
+ if (!this.screen.autoPadding) {
1047
+ this._label.rleft = 2
1048
+ }
1049
+ } else {
1050
+ this._label.rright = 2 + (this.border ? -1 : 0)
1051
+ this._label.position.left = undefined
1052
+ if (!this.screen.autoPadding) {
1053
+ this._label.rright = 2
1054
+ }
1055
+ }
1056
+ return
1057
+ }
1058
+
1059
+ this._label = new Box({
1060
+ screen: this.screen,
1061
+ parent: this,
1062
+ content: options.text,
1063
+ top: -this.itop,
1064
+ tags: this.parseTags,
1065
+ shrink: true,
1066
+ style: this.style.label
1067
+ })
1068
+
1069
+ if (options.side !== 'right') {
1070
+ this._label.rleft = 2 - this.ileft
1071
+ } else {
1072
+ this._label.rright = 2 - this.iright
1073
+ }
1074
+
1075
+ this._label._isLabel = true
1076
+
1077
+ if (!this.screen.autoPadding) {
1078
+ if (options.side !== 'right') {
1079
+ this._label.rleft = 2
1080
+ } else {
1081
+ this._label.rright = 2
1082
+ }
1083
+ this._label.rtop = 0
1084
+ }
1085
+
1086
+ const reposition = function () {
1087
+ self._label.rtop = (self.childBase || 0) - self.itop
1088
+ if (!self.screen.autoPadding) {
1089
+ self._label.rtop = self.childBase || 0
1090
+ }
1091
+ self.screen.render()
1092
+ }
1093
+
1094
+ this.on(
1095
+ 'scroll',
1096
+ (this._labelScroll = function () {
1097
+ reposition()
1098
+ })
1099
+ )
1100
+
1101
+ this.on(
1102
+ 'resize',
1103
+ (this._labelResize = function () {
1104
+ nextTick(function () {
1105
+ reposition()
1106
+ })
1107
+ })
1108
+ )
1109
+ }
1110
+
1111
+ Element.prototype.removeLabel = function () {
1112
+ if (!this._label) {
1113
+ return
1114
+ }
1115
+ this.removeListener('scroll', this._labelScroll)
1116
+ this.removeListener('resize', this._labelResize)
1117
+ this._label.detach()
1118
+ delete this._labelScroll
1119
+ delete this._labelResize
1120
+ delete this._label
1121
+ }
1122
+
1123
+ Element.prototype.setHover = function (options) {
1124
+ if (typeof options === 'string') {
1125
+ options = { text: options }
1126
+ }
1127
+
1128
+ this._hoverOptions = options
1129
+ this.enableMouse()
1130
+ this.screen._initHover()
1131
+ }
1132
+
1133
+ Element.prototype.removeHover = function () {
1134
+ delete this._hoverOptions
1135
+ if (!this.screen._hoverText || this.screen._hoverText.detached) {
1136
+ return
1137
+ }
1138
+ this.screen._hoverText.detach()
1139
+ this.screen.render()
1140
+ }
1141
+
1142
+ /**
1143
+ * Positioning
1144
+ */
1145
+
1146
+ // The below methods are a bit confusing: basically
1147
+ // whenever Box.render is called `lpos` gets set on
1148
+ // the element, an object containing the rendered
1149
+ // coordinates. Since these don't update if the
1150
+ // element is moved somehow, they're unreliable in
1151
+ // that situation. However, if we can guarantee that
1152
+ // lpos is good and up to date, it can be more
1153
+ // accurate than the calculated positions below.
1154
+ // In this case, if the element is being rendered,
1155
+ // it's guaranteed that the parent will have been
1156
+ // rendered first, in which case we can use the
1157
+ // parant's lpos instead of recalculating it's
1158
+ // position (since that might be wrong because
1159
+ // it doesn't handle content shrinkage).
1160
+
1161
+ Element.prototype._getPos = function () {
1162
+ const pos = this.lpos
1163
+
1164
+ assert.ok(pos)
1165
+
1166
+ if (pos.aleft != null) {
1167
+ return pos
1168
+ }
1169
+
1170
+ pos.aleft = pos.xi
1171
+ pos.atop = pos.yi
1172
+ pos.aright = this.screen.cols - pos.xl
1173
+ pos.abottom = this.screen.rows - pos.yl
1174
+ pos.width = pos.xl - pos.xi
1175
+ pos.height = pos.yl - pos.yi
1176
+
1177
+ return pos
1178
+ }
1179
+
1180
+ /**
1181
+ * Position Getters
1182
+ */
1183
+
1184
+ Element.prototype._getWidth = function (get) {
1185
+ let parent = get ? this.parent._getPos() : this.parent,
1186
+ width = this.position.width,
1187
+ left,
1188
+ expr
1189
+
1190
+ if (typeof width === 'string') {
1191
+ if (width === 'half') {
1192
+ width = '50%'
1193
+ }
1194
+ expr = width.split(/(?=\+|-)/)
1195
+ width = expr[0]
1196
+ width = +width.slice(0, -1) / 100
1197
+ width = (parent.width * width) | 0
1198
+ width += +(expr[1] || 0)
1199
+ return width
1200
+ }
1201
+
1202
+ // This is for if the element is being streched or shrunken.
1203
+ // Although the width for shrunken elements is calculated
1204
+ // in the render function, it may be calculated based on
1205
+ // the content width, and the content width is initially
1206
+ // decided by the width the element, so it needs to be
1207
+ // calculated here.
1208
+ if (width == null) {
1209
+ left = this.position.left || 0
1210
+ if (typeof left === 'string') {
1211
+ if (left === 'center') {
1212
+ left = '50%'
1213
+ }
1214
+ expr = left.split(/(?=\+|-)/)
1215
+ left = expr[0]
1216
+ left = +left.slice(0, -1) / 100
1217
+ left = (parent.width * left) | 0
1218
+ left += +(expr[1] || 0)
1219
+ }
1220
+ width = parent.width - (this.position.right || 0) - left
1221
+ if (this.screen.autoPadding) {
1222
+ if (
1223
+ (this.position.left != null || this.position.right == null) &&
1224
+ this.position.left !== 'center'
1225
+ ) {
1226
+ width -= this.parent.ileft
1227
+ }
1228
+ width -= this.parent.iright
1229
+ }
1230
+ }
1231
+
1232
+ return width
1233
+ }
1234
+
1235
+ Element.prototype.__defineGetter__('width', function () {
1236
+ return this._getWidth(false)
1237
+ })
1238
+
1239
+ Element.prototype._getHeight = function (get) {
1240
+ let parent = get ? this.parent._getPos() : this.parent,
1241
+ height = this.position.height,
1242
+ top,
1243
+ expr
1244
+
1245
+ if (typeof height === 'string') {
1246
+ if (height === 'half') {
1247
+ height = '50%'
1248
+ }
1249
+ expr = height.split(/(?=\+|-)/)
1250
+ height = expr[0]
1251
+ height = +height.slice(0, -1) / 100
1252
+ height = (parent.height * height) | 0
1253
+ height += +(expr[1] || 0)
1254
+ return height
1255
+ }
1256
+
1257
+ // This is for if the element is being streched or shrunken.
1258
+ // Although the width for shrunken elements is calculated
1259
+ // in the render function, it may be calculated based on
1260
+ // the content width, and the content width is initially
1261
+ // decided by the width the element, so it needs to be
1262
+ // calculated here.
1263
+ if (height == null) {
1264
+ top = this.position.top || 0
1265
+ if (typeof top === 'string') {
1266
+ if (top === 'center') {
1267
+ top = '50%'
1268
+ }
1269
+ expr = top.split(/(?=\+|-)/)
1270
+ top = expr[0]
1271
+ top = +top.slice(0, -1) / 100
1272
+ top = (parent.height * top) | 0
1273
+ top += +(expr[1] || 0)
1274
+ }
1275
+ height = parent.height - (this.position.bottom || 0) - top
1276
+ if (this.screen.autoPadding) {
1277
+ if (
1278
+ (this.position.top != null || this.position.bottom == null) &&
1279
+ this.position.top !== 'center'
1280
+ ) {
1281
+ height -= this.parent.itop
1282
+ }
1283
+ height -= this.parent.ibottom
1284
+ }
1285
+ }
1286
+
1287
+ return height
1288
+ }
1289
+
1290
+ Element.prototype.__defineGetter__('height', function () {
1291
+ return this._getHeight(false)
1292
+ })
1293
+
1294
+ Element.prototype._getLeft = function (get) {
1295
+ let parent = get ? this.parent._getPos() : this.parent,
1296
+ left = this.position.left || 0,
1297
+ expr
1298
+
1299
+ if (typeof left === 'string') {
1300
+ if (left === 'center') {
1301
+ left = '50%'
1302
+ }
1303
+ expr = left.split(/(?=\+|-)/)
1304
+ left = expr[0]
1305
+ left = +left.slice(0, -1) / 100
1306
+ left = (parent.width * left) | 0
1307
+ left += +(expr[1] || 0)
1308
+ if (this.position.left === 'center') {
1309
+ left -= (this._getWidth(get) / 2) | 0
1310
+ }
1311
+ }
1312
+
1313
+ if (this.position.left == null && this.position.right != null) {
1314
+ return this.screen.cols - this._getWidth(get) - this._getRight(get)
1315
+ }
1316
+
1317
+ if (this.screen.autoPadding) {
1318
+ if (
1319
+ (this.position.left != null || this.position.right == null) &&
1320
+ this.position.left !== 'center'
1321
+ ) {
1322
+ left += this.parent.ileft
1323
+ }
1324
+ }
1325
+
1326
+ return (parent.aleft || 0) + left
1327
+ }
1328
+
1329
+ Element.prototype.__defineGetter__('aleft', function () {
1330
+ return this._getLeft(false)
1331
+ })
1332
+
1333
+ Element.prototype._getRight = function (get) {
1334
+ let parent = get ? this.parent._getPos() : this.parent,
1335
+ right
1336
+
1337
+ if (this.position.right == null && this.position.left != null) {
1338
+ right = this.screen.cols - (this._getLeft(get) + this._getWidth(get))
1339
+ if (this.screen.autoPadding) {
1340
+ right += this.parent.iright
1341
+ }
1342
+ return right
1343
+ }
1344
+
1345
+ right = (parent.aright || 0) + (this.position.right || 0)
1346
+
1347
+ if (this.screen.autoPadding) {
1348
+ right += this.parent.iright
1349
+ }
1350
+
1351
+ return right
1352
+ }
1353
+
1354
+ Element.prototype.__defineGetter__('aright', function () {
1355
+ return this._getRight(false)
1356
+ })
1357
+
1358
+ Element.prototype._getTop = function (get) {
1359
+ let parent = get ? this.parent._getPos() : this.parent,
1360
+ top = this.position.top || 0,
1361
+ expr
1362
+
1363
+ if (typeof top === 'string') {
1364
+ if (top === 'center') {
1365
+ top = '50%'
1366
+ }
1367
+ expr = top.split(/(?=\+|-)/)
1368
+ top = expr[0]
1369
+ top = +top.slice(0, -1) / 100
1370
+ top = (parent.height * top) | 0
1371
+ top += +(expr[1] || 0)
1372
+ if (this.position.top === 'center') {
1373
+ top -= (this._getHeight(get) / 2) | 0
1374
+ }
1375
+ }
1376
+
1377
+ if (this.position.top == null && this.position.bottom != null) {
1378
+ return this.screen.rows - this._getHeight(get) - this._getBottom(get)
1379
+ }
1380
+
1381
+ if (this.screen.autoPadding) {
1382
+ if (
1383
+ (this.position.top != null || this.position.bottom == null) &&
1384
+ this.position.top !== 'center'
1385
+ ) {
1386
+ top += this.parent.itop
1387
+ }
1388
+ }
1389
+
1390
+ return (parent.atop || 0) + top
1391
+ }
1392
+
1393
+ Element.prototype.__defineGetter__('atop', function () {
1394
+ return this._getTop(false)
1395
+ })
1396
+
1397
+ Element.prototype._getBottom = function (get) {
1398
+ let parent = get ? this.parent._getPos() : this.parent,
1399
+ bottom
1400
+
1401
+ if (this.position.bottom == null && this.position.top != null) {
1402
+ bottom = this.screen.rows - (this._getTop(get) + this._getHeight(get))
1403
+ if (this.screen.autoPadding) {
1404
+ bottom += this.parent.ibottom
1405
+ }
1406
+ return bottom
1407
+ }
1408
+
1409
+ bottom = (parent.abottom || 0) + (this.position.bottom || 0)
1410
+
1411
+ if (this.screen.autoPadding) {
1412
+ bottom += this.parent.ibottom
1413
+ }
1414
+
1415
+ return bottom
1416
+ }
1417
+
1418
+ Element.prototype.__defineGetter__('abottom', function () {
1419
+ return this._getBottom(false)
1420
+ })
1421
+
1422
+ Element.prototype.__defineGetter__('rleft', function () {
1423
+ return this.aleft - this.parent.aleft
1424
+ })
1425
+
1426
+ Element.prototype.__defineGetter__('rright', function () {
1427
+ return this.aright - this.parent.aright
1428
+ })
1429
+
1430
+ Element.prototype.__defineGetter__('rtop', function () {
1431
+ return this.atop - this.parent.atop
1432
+ })
1433
+
1434
+ Element.prototype.__defineGetter__('rbottom', function () {
1435
+ return this.abottom - this.parent.abottom
1436
+ })
1437
+
1438
+ /**
1439
+ * Position Setters
1440
+ */
1441
+
1442
+ // NOTE:
1443
+ // For aright, abottom, right, and bottom:
1444
+ // If position.bottom is null, we could simply set top instead.
1445
+ // But it wouldn't replicate bottom behavior appropriately if
1446
+ // the parent was resized, etc.
1447
+ Element.prototype.__defineSetter__('width', function (val) {
1448
+ if (this.position.width === val) {
1449
+ return
1450
+ }
1451
+ if (/^\d+$/.test(val)) {
1452
+ val = +val
1453
+ }
1454
+ this.emit('resize')
1455
+ this.clearPos()
1456
+ return (this.position.width = val)
1457
+ })
1458
+
1459
+ Element.prototype.__defineSetter__('height', function (val) {
1460
+ if (this.position.height === val) {
1461
+ return
1462
+ }
1463
+ if (/^\d+$/.test(val)) {
1464
+ val = +val
1465
+ }
1466
+ this.emit('resize')
1467
+ this.clearPos()
1468
+ return (this.position.height = val)
1469
+ })
1470
+
1471
+ Element.prototype.__defineSetter__('aleft', function (val) {
1472
+ let expr
1473
+ if (typeof val === 'string') {
1474
+ if (val === 'center') {
1475
+ val = (this.screen.width / 2) | 0
1476
+ val -= (this.width / 2) | 0
1477
+ } else {
1478
+ expr = val.split(/(?=\+|-)/)
1479
+ val = expr[0]
1480
+ val = +val.slice(0, -1) / 100
1481
+ val = (this.screen.width * val) | 0
1482
+ val += +(expr[1] || 0)
1483
+ }
1484
+ }
1485
+ val -= this.parent.aleft
1486
+ if (this.position.left === val) {
1487
+ return
1488
+ }
1489
+ this.emit('move')
1490
+ this.clearPos()
1491
+ return (this.position.left = val)
1492
+ })
1493
+
1494
+ Element.prototype.__defineSetter__('aright', function (val) {
1495
+ val -= this.parent.aright
1496
+ if (this.position.right === val) {
1497
+ return
1498
+ }
1499
+ this.emit('move')
1500
+ this.clearPos()
1501
+ return (this.position.right = val)
1502
+ })
1503
+
1504
+ Element.prototype.__defineSetter__('atop', function (val) {
1505
+ let expr
1506
+ if (typeof val === 'string') {
1507
+ if (val === 'center') {
1508
+ val = (this.screen.height / 2) | 0
1509
+ val -= (this.height / 2) | 0
1510
+ } else {
1511
+ expr = val.split(/(?=\+|-)/)
1512
+ val = expr[0]
1513
+ val = +val.slice(0, -1) / 100
1514
+ val = (this.screen.height * val) | 0
1515
+ val += +(expr[1] || 0)
1516
+ }
1517
+ }
1518
+ val -= this.parent.atop
1519
+ if (this.position.top === val) {
1520
+ return
1521
+ }
1522
+ this.emit('move')
1523
+ this.clearPos()
1524
+ return (this.position.top = val)
1525
+ })
1526
+
1527
+ Element.prototype.__defineSetter__('abottom', function (val) {
1528
+ val -= this.parent.abottom
1529
+ if (this.position.bottom === val) {
1530
+ return
1531
+ }
1532
+ this.emit('move')
1533
+ this.clearPos()
1534
+ return (this.position.bottom = val)
1535
+ })
1536
+
1537
+ Element.prototype.__defineSetter__('rleft', function (val) {
1538
+ if (this.position.left === val) {
1539
+ return
1540
+ }
1541
+ if (/^\d+$/.test(val)) {
1542
+ val = +val
1543
+ }
1544
+ this.emit('move')
1545
+ this.clearPos()
1546
+ return (this.position.left = val)
1547
+ })
1548
+
1549
+ Element.prototype.__defineSetter__('rright', function (val) {
1550
+ if (this.position.right === val) {
1551
+ return
1552
+ }
1553
+ this.emit('move')
1554
+ this.clearPos()
1555
+ return (this.position.right = val)
1556
+ })
1557
+
1558
+ Element.prototype.__defineSetter__('rtop', function (val) {
1559
+ if (this.position.top === val) {
1560
+ return
1561
+ }
1562
+ if (/^\d+$/.test(val)) {
1563
+ val = +val
1564
+ }
1565
+ this.emit('move')
1566
+ this.clearPos()
1567
+ return (this.position.top = val)
1568
+ })
1569
+
1570
+ Element.prototype.__defineSetter__('rbottom', function (val) {
1571
+ if (this.position.bottom === val) {
1572
+ return
1573
+ }
1574
+ this.emit('move')
1575
+ this.clearPos()
1576
+ return (this.position.bottom = val)
1577
+ })
1578
+
1579
+ Element.prototype.__defineGetter__('ileft', function () {
1580
+ return (this.border ? 1 : 0) + this.padding.left
1581
+ // return (this.border && this.border.left ? 1 : 0) + this.padding.left;
1582
+ })
1583
+
1584
+ Element.prototype.__defineGetter__('itop', function () {
1585
+ return (this.border ? 1 : 0) + this.padding.top
1586
+ // return (this.border && this.border.top ? 1 : 0) + this.padding.top;
1587
+ })
1588
+
1589
+ Element.prototype.__defineGetter__('iright', function () {
1590
+ return (this.border ? 1 : 0) + this.padding.right
1591
+ // return (this.border && this.border.right ? 1 : 0) + this.padding.right;
1592
+ })
1593
+
1594
+ Element.prototype.__defineGetter__('ibottom', function () {
1595
+ return (this.border ? 1 : 0) + this.padding.bottom
1596
+ // return (this.border && this.border.bottom ? 1 : 0) + this.padding.bottom;
1597
+ })
1598
+
1599
+ Element.prototype.__defineGetter__('iwidth', function () {
1600
+ // return (this.border
1601
+ // ? ((this.border.left ? 1 : 0) + (this.border.right ? 1 : 0)) : 0)
1602
+ // + this.padding.left + this.padding.right;
1603
+ return (this.border ? 2 : 0) + this.padding.left + this.padding.right
1604
+ })
1605
+
1606
+ Element.prototype.__defineGetter__('iheight', function () {
1607
+ // return (this.border
1608
+ // ? ((this.border.top ? 1 : 0) + (this.border.bottom ? 1 : 0)) : 0)
1609
+ // + this.padding.top + this.padding.bottom;
1610
+ return (this.border ? 2 : 0) + this.padding.top + this.padding.bottom
1611
+ })
1612
+
1613
+ Element.prototype.__defineGetter__('tpadding', function () {
1614
+ return (
1615
+ this.padding.left +
1616
+ this.padding.top +
1617
+ this.padding.right +
1618
+ this.padding.bottom
1619
+ )
1620
+ })
1621
+
1622
+ /**
1623
+ * Relative coordinates as default properties
1624
+ */
1625
+
1626
+ Element.prototype.__defineGetter__('left', function () {
1627
+ return this.rleft
1628
+ })
1629
+
1630
+ Element.prototype.__defineGetter__('right', function () {
1631
+ return this.rright
1632
+ })
1633
+
1634
+ Element.prototype.__defineGetter__('top', function () {
1635
+ return this.rtop
1636
+ })
1637
+
1638
+ Element.prototype.__defineGetter__('bottom', function () {
1639
+ return this.rbottom
1640
+ })
1641
+
1642
+ Element.prototype.__defineSetter__('left', function (val) {
1643
+ return (this.rleft = val)
1644
+ })
1645
+
1646
+ Element.prototype.__defineSetter__('right', function (val) {
1647
+ return (this.rright = val)
1648
+ })
1649
+
1650
+ Element.prototype.__defineSetter__('top', function (val) {
1651
+ return (this.rtop = val)
1652
+ })
1653
+
1654
+ Element.prototype.__defineSetter__('bottom', function (val) {
1655
+ return (this.rbottom = val)
1656
+ })
1657
+
1658
+ /**
1659
+ * Rendering - here be dragons
1660
+ */
1661
+
1662
+ Element.prototype._getShrinkBox = function (xi, xl, yi, yl, get) {
1663
+ if (!this.children.length) {
1664
+ return { xi: xi, xl: xi + 1, yi: yi, yl: yi + 1 }
1665
+ }
1666
+
1667
+ let i,
1668
+ el,
1669
+ ret,
1670
+ mxi = xi,
1671
+ mxl = xi + 1,
1672
+ myi = yi,
1673
+ myl = yi + 1
1674
+
1675
+ // This is a chicken and egg problem. We need to determine how the children
1676
+ // will render in order to determine how this element renders, but it in
1677
+ // order to figure out how the children will render, they need to know
1678
+ // exactly how their parent renders, so, we can give them what we have so
1679
+ // far.
1680
+ let _lpos
1681
+ if (get) {
1682
+ _lpos = this.lpos
1683
+ this.lpos = { xi: xi, xl: xl, yi: yi, yl: yl }
1684
+ //this.shrink = false;
1685
+ }
1686
+
1687
+ for (i = 0; i < this.children.length; i++) {
1688
+ el = this.children[i]
1689
+
1690
+ ret = el._getCoords(get)
1691
+
1692
+ // Or just (seemed to work, but probably not good):
1693
+ // ret = el.lpos || this.lpos;
1694
+
1695
+ if (!ret) {
1696
+ continue
1697
+ }
1698
+
1699
+ // Since the parent element is shrunk, and the child elements think it's
1700
+ // going to take up as much space as possible, an element anchored to the
1701
+ // right or bottom will inadvertantly make the parent's shrunken size as
1702
+ // large as possible. So, we can just use the height and/or width the of
1703
+ // element.
1704
+ // if (get) {
1705
+ if (el.position.left == null && el.position.right != null) {
1706
+ ret.xl = xi + (ret.xl - ret.xi)
1707
+ ret.xi = xi
1708
+ if (this.screen.autoPadding) {
1709
+ // Maybe just do this no matter what.
1710
+ ret.xl += this.ileft
1711
+ ret.xi += this.ileft
1712
+ }
1713
+ }
1714
+ if (el.position.top == null && el.position.bottom != null) {
1715
+ ret.yl = yi + (ret.yl - ret.yi)
1716
+ ret.yi = yi
1717
+ if (this.screen.autoPadding) {
1718
+ // Maybe just do this no matter what.
1719
+ ret.yl += this.itop
1720
+ ret.yi += this.itop
1721
+ }
1722
+ }
1723
+
1724
+ if (ret.xi < mxi) {
1725
+ mxi = ret.xi
1726
+ }
1727
+ if (ret.xl > mxl) {
1728
+ mxl = ret.xl
1729
+ }
1730
+ if (ret.yi < myi) {
1731
+ myi = ret.yi
1732
+ }
1733
+ if (ret.yl > myl) {
1734
+ myl = ret.yl
1735
+ }
1736
+ }
1737
+
1738
+ if (get) {
1739
+ this.lpos = _lpos
1740
+ //this.shrink = true;
1741
+ }
1742
+
1743
+ if (
1744
+ this.position.width == null &&
1745
+ (this.position.left == null || this.position.right == null)
1746
+ ) {
1747
+ if (this.position.left == null && this.position.right != null) {
1748
+ xi = xl - (mxl - mxi)
1749
+ if (!this.screen.autoPadding) {
1750
+ xi -= this.padding.left + this.padding.right
1751
+ } else {
1752
+ xi -= this.ileft
1753
+ }
1754
+ } else {
1755
+ xl = mxl
1756
+ if (!this.screen.autoPadding) {
1757
+ xl += this.padding.left + this.padding.right
1758
+ // XXX Temporary workaround until we decide to make autoPadding default.
1759
+ // See widget-listtable.js for an example of why this is necessary.
1760
+ // XXX Maybe just to this for all this being that this would affect
1761
+ // width shrunken normal shrunken lists as well.
1762
+ // if (this._isList) {
1763
+ if (this.type === 'list-table') {
1764
+ xl -= this.padding.left + this.padding.right
1765
+ xl += this.iright
1766
+ }
1767
+ } else {
1768
+ //xl += this.padding.right;
1769
+ xl += this.iright
1770
+ }
1771
+ }
1772
+ }
1773
+
1774
+ if (
1775
+ this.position.height == null &&
1776
+ (this.position.top == null || this.position.bottom == null) &&
1777
+ (!this.scrollable || this._isList)
1778
+ ) {
1779
+ // NOTE: Lists get special treatment if they are shrunken - assume they
1780
+ // want all list items showing. This is one case we can calculate the
1781
+ // height based on items/boxes.
1782
+ if (this._isList) {
1783
+ myi = 0 - this.itop
1784
+ myl = this.items.length + this.ibottom
1785
+ }
1786
+ if (this.position.top == null && this.position.bottom != null) {
1787
+ yi = yl - (myl - myi)
1788
+ if (!this.screen.autoPadding) {
1789
+ yi -= this.padding.top + this.padding.bottom
1790
+ } else {
1791
+ yi -= this.itop
1792
+ }
1793
+ } else {
1794
+ yl = myl
1795
+ if (!this.screen.autoPadding) {
1796
+ yl += this.padding.top + this.padding.bottom
1797
+ } else {
1798
+ yl += this.ibottom
1799
+ }
1800
+ }
1801
+ }
1802
+
1803
+ return { xi: xi, xl: xl, yi: yi, yl: yl }
1804
+ }
1805
+
1806
+ Element.prototype._getShrinkContent = function (xi, xl, yi, yl) {
1807
+ const h = this._clines.length,
1808
+ w = this._clines.mwidth || 1
1809
+
1810
+ if (
1811
+ this.position.width == null &&
1812
+ (this.position.left == null || this.position.right == null)
1813
+ ) {
1814
+ if (this.position.left == null && this.position.right != null) {
1815
+ xi = xl - w - this.iwidth
1816
+ } else {
1817
+ xl = xi + w + this.iwidth
1818
+ }
1819
+ }
1820
+
1821
+ if (
1822
+ this.position.height == null &&
1823
+ (this.position.top == null || this.position.bottom == null) &&
1824
+ (!this.scrollable || this._isList)
1825
+ ) {
1826
+ if (this.position.top == null && this.position.bottom != null) {
1827
+ yi = yl - h - this.iheight
1828
+ } else {
1829
+ yl = yi + h + this.iheight
1830
+ }
1831
+ }
1832
+
1833
+ return { xi: xi, xl: xl, yi: yi, yl: yl }
1834
+ }
1835
+
1836
+ Element.prototype._getShrink = function (xi, xl, yi, yl, get) {
1837
+ let shrinkBox = this._getShrinkBox(xi, xl, yi, yl, get),
1838
+ shrinkContent = this._getShrinkContent(xi, xl, yi, yl, get),
1839
+ xll = xl,
1840
+ yll = yl
1841
+
1842
+ // Figure out which one is bigger and use it.
1843
+ if (shrinkBox.xl - shrinkBox.xi > shrinkContent.xl - shrinkContent.xi) {
1844
+ xi = shrinkBox.xi
1845
+ xl = shrinkBox.xl
1846
+ } else {
1847
+ xi = shrinkContent.xi
1848
+ xl = shrinkContent.xl
1849
+ }
1850
+
1851
+ if (shrinkBox.yl - shrinkBox.yi > shrinkContent.yl - shrinkContent.yi) {
1852
+ yi = shrinkBox.yi
1853
+ yl = shrinkBox.yl
1854
+ } else {
1855
+ yi = shrinkContent.yi
1856
+ yl = shrinkContent.yl
1857
+ }
1858
+
1859
+ // Recenter shrunken elements.
1860
+ if (xl < xll && this.position.left === 'center') {
1861
+ xll = ((xll - xl) / 2) | 0
1862
+ xi += xll
1863
+ xl += xll
1864
+ }
1865
+
1866
+ if (yl < yll && this.position.top === 'center') {
1867
+ yll = ((yll - yl) / 2) | 0
1868
+ yi += yll
1869
+ yl += yll
1870
+ }
1871
+
1872
+ return { xi: xi, xl: xl, yi: yi, yl: yl }
1873
+ }
1874
+
1875
+ Element.prototype._getCoords = function (get, noscroll) {
1876
+ if (this.hidden) {
1877
+ return
1878
+ }
1879
+
1880
+ // if (this.parent._rendering) {
1881
+ // get = true;
1882
+ // }
1883
+
1884
+ let xi = this._getLeft(get),
1885
+ xl = xi + this._getWidth(get),
1886
+ yi = this._getTop(get),
1887
+ yl = yi + this._getHeight(get),
1888
+ base = this.childBase || 0,
1889
+ el = this,
1890
+ fixed = this.fixed,
1891
+ coords,
1892
+ v,
1893
+ noleft,
1894
+ noright,
1895
+ notop,
1896
+ nobot,
1897
+ ppos,
1898
+ b
1899
+
1900
+ // Attempt to shrink the element base on the
1901
+ // size of the content and child elements.
1902
+ if (this.shrink) {
1903
+ coords = this._getShrink(xi, xl, yi, yl, get)
1904
+ ;(xi = coords.xi), (xl = coords.xl)
1905
+ ;(yi = coords.yi), (yl = coords.yl)
1906
+ }
1907
+
1908
+ // Find a scrollable ancestor if we have one.
1909
+ while ((el = el.parent)) {
1910
+ if (el.scrollable) {
1911
+ if (fixed) {
1912
+ fixed = false
1913
+ continue
1914
+ }
1915
+ break
1916
+ }
1917
+ }
1918
+
1919
+ // Check to make sure we're visible and
1920
+ // inside of the visible scroll area.
1921
+ // NOTE: Lists have a property where only
1922
+ // the list items are obfuscated.
1923
+
1924
+ // Old way of doing things, this would not render right if a shrunken element
1925
+ // with lots of boxes in it was within a scrollable element.
1926
+ // See: $ node test/widget-shrink-fail.js
1927
+ // var thisparent = this.parent;
1928
+
1929
+ const thisparent = el
1930
+ if (el && !noscroll) {
1931
+ ppos = thisparent.lpos
1932
+
1933
+ // The shrink option can cause a stack overflow
1934
+ // by calling _getCoords on the child again.
1935
+ // if (!get && !thisparent.shrink) {
1936
+ // ppos = thisparent._getCoords();
1937
+ // }
1938
+
1939
+ if (!ppos) {
1940
+ return
1941
+ }
1942
+
1943
+ // TODO: Figure out how to fix base (and cbase to only
1944
+ // take into account the *parent's* padding.
1945
+
1946
+ yi -= ppos.base
1947
+ yl -= ppos.base
1948
+
1949
+ b = thisparent.border ? 1 : 0
1950
+
1951
+ // XXX
1952
+ // Fixes non-`fixed` labels to work with scrolling (they're ON the border):
1953
+ // if (this.position.left < 0
1954
+ // || this.position.right < 0
1955
+ // || this.position.top < 0
1956
+ // || this.position.bottom < 0) {
1957
+ if (this._isLabel) {
1958
+ b = 0
1959
+ }
1960
+
1961
+ if (yi < ppos.yi + b) {
1962
+ if (yl - 1 < ppos.yi + b) {
1963
+ // Is above.
1964
+ return
1965
+ } else {
1966
+ // Is partially covered above.
1967
+ notop = true
1968
+ v = ppos.yi - yi
1969
+ if (this.border) {
1970
+ v--
1971
+ }
1972
+ if (thisparent.border) {
1973
+ v++
1974
+ }
1975
+ base += v
1976
+ yi += v
1977
+ }
1978
+ } else if (yl > ppos.yl - b) {
1979
+ if (yi > ppos.yl - 1 - b) {
1980
+ // Is below.
1981
+ return
1982
+ } else {
1983
+ // Is partially covered below.
1984
+ nobot = true
1985
+ v = yl - ppos.yl
1986
+ if (this.border) {
1987
+ v--
1988
+ }
1989
+ if (thisparent.border) {
1990
+ v++
1991
+ }
1992
+ yl -= v
1993
+ }
1994
+ }
1995
+
1996
+ // Shouldn't be necessary.
1997
+ // assert.ok(yi < yl);
1998
+ if (yi >= yl) {
1999
+ return
2000
+ }
2001
+
2002
+ // Could allow overlapping stuff in scrolling elements
2003
+ // if we cleared the pending buffer before every draw.
2004
+ if (xi < el.lpos.xi) {
2005
+ xi = el.lpos.xi
2006
+ noleft = true
2007
+ if (this.border) {
2008
+ xi--
2009
+ }
2010
+ if (thisparent.border) {
2011
+ xi++
2012
+ }
2013
+ }
2014
+ if (xl > el.lpos.xl) {
2015
+ xl = el.lpos.xl
2016
+ noright = true
2017
+ if (this.border) {
2018
+ xl++
2019
+ }
2020
+ if (thisparent.border) {
2021
+ xl--
2022
+ }
2023
+ }
2024
+ //if (xi > xl) return;
2025
+ if (xi >= xl) {
2026
+ return
2027
+ }
2028
+ }
2029
+
2030
+ if (this.noOverflow && this.parent.lpos) {
2031
+ if (xi < this.parent.lpos.xi + this.parent.ileft) {
2032
+ xi = this.parent.lpos.xi + this.parent.ileft
2033
+ }
2034
+ if (xl > this.parent.lpos.xl - this.parent.iright) {
2035
+ xl = this.parent.lpos.xl - this.parent.iright
2036
+ }
2037
+ if (yi < this.parent.lpos.yi + this.parent.itop) {
2038
+ yi = this.parent.lpos.yi + this.parent.itop
2039
+ }
2040
+ if (yl > this.parent.lpos.yl - this.parent.ibottom) {
2041
+ yl = this.parent.lpos.yl - this.parent.ibottom
2042
+ }
2043
+ }
2044
+
2045
+ // if (this.parent.lpos) {
2046
+ // this.parent.lpos._scrollBottom = Math.max(
2047
+ // this.parent.lpos._scrollBottom, yl);
2048
+ // }
2049
+
2050
+ return {
2051
+ xi: xi,
2052
+ xl: xl,
2053
+ yi: yi,
2054
+ yl: yl,
2055
+ base: base,
2056
+ noleft: noleft,
2057
+ noright: noright,
2058
+ notop: notop,
2059
+ nobot: nobot,
2060
+ renders: this.screen.renders
2061
+ }
2062
+ }
2063
+
2064
+ Element.prototype.render = function () {
2065
+ this._emit('prerender')
2066
+
2067
+ this.parseContent()
2068
+
2069
+ const coords = this._getCoords(true)
2070
+ if (!coords) {
2071
+ delete this.lpos
2072
+ return
2073
+ }
2074
+
2075
+ if (coords.xl - coords.xi <= 0) {
2076
+ coords.xl = Math.max(coords.xl, coords.xi)
2077
+ return
2078
+ }
2079
+
2080
+ if (coords.yl - coords.yi <= 0) {
2081
+ coords.yl = Math.max(coords.yl, coords.yi)
2082
+ return
2083
+ }
2084
+
2085
+ let lines = this.screen.lines,
2086
+ xi = coords.xi,
2087
+ xl = coords.xl,
2088
+ yi = coords.yi,
2089
+ yl = coords.yl,
2090
+ x,
2091
+ y,
2092
+ cell,
2093
+ attr,
2094
+ ch,
2095
+ content = this._pcontent,
2096
+ ci = this._clines.ci[coords.base],
2097
+ battr,
2098
+ dattr,
2099
+ c,
2100
+ visible,
2101
+ i,
2102
+ bch = this.ch
2103
+
2104
+ // Clip content if it's off the edge of the screen
2105
+ // if (xi + this.ileft < 0 || yi + this.itop < 0) {
2106
+ // var clines = this._clines.slice();
2107
+ // if (xi + this.ileft < 0) {
2108
+ // for (var i = 0; i < clines.length; i++) {
2109
+ // var t = 0;
2110
+ // var csi = '';
2111
+ // var csis = '';
2112
+ // for (var j = 0; j < clines[i].length; j++) {
2113
+ // while (clines[i][j] === '\x1b') {
2114
+ // csi = '\x1b';
2115
+ // while (clines[i][j++] !== 'm') csi += clines[i][j];
2116
+ // csis += csi;
2117
+ // }
2118
+ // if (++t === -(xi + this.ileft) + 1) break;
2119
+ // }
2120
+ // clines[i] = csis + clines[i].substring(j);
2121
+ // }
2122
+ // }
2123
+ // if (yi + this.itop < 0) {
2124
+ // clines = clines.slice(-(yi + this.itop));
2125
+ // }
2126
+ // content = clines.join('\n');
2127
+ // }
2128
+
2129
+ if (coords.base >= this._clines.ci.length) {
2130
+ ci = this._pcontent.length
2131
+ }
2132
+
2133
+ this.lpos = coords
2134
+
2135
+ if (this.border && this.border.type === 'line') {
2136
+ this.screen._borderStops[coords.yi] = true
2137
+ this.screen._borderStops[coords.yl - 1] = true
2138
+ // if (!this.screen._borderStops[coords.yi]) {
2139
+ // this.screen._borderStops[coords.yi] = { xi: coords.xi, xl: coords.xl };
2140
+ // } else {
2141
+ // if (this.screen._borderStops[coords.yi].xi > coords.xi) {
2142
+ // this.screen._borderStops[coords.yi].xi = coords.xi;
2143
+ // }
2144
+ // if (this.screen._borderStops[coords.yi].xl < coords.xl) {
2145
+ // this.screen._borderStops[coords.yi].xl = coords.xl;
2146
+ // }
2147
+ // }
2148
+ // this.screen._borderStops[coords.yl - 1] = this.screen._borderStops[coords.yi];
2149
+ }
2150
+
2151
+ dattr = this.sattr(this.style)
2152
+ attr = dattr
2153
+
2154
+ // If we're in a scrollable text box, check to
2155
+ // see which attributes this line starts with.
2156
+ if (ci > 0) {
2157
+ attr = this._clines.attr[Math.min(coords.base, this._clines.length - 1)]
2158
+ }
2159
+
2160
+ if (this.border) {
2161
+ xi++, xl--, yi++, yl--
2162
+ }
2163
+
2164
+ // If we have padding/valign, that means the
2165
+ // content-drawing loop will skip a few cells/lines.
2166
+ // To deal with this, we can just fill the whole thing
2167
+ // ahead of time. This could be optimized.
2168
+ if (this.tpadding || (this.valign && this.valign !== 'top')) {
2169
+ if (this.style.transparent) {
2170
+ for (y = Math.max(yi, 0); y < yl; y++) {
2171
+ if (!lines[y]) {
2172
+ break
2173
+ }
2174
+ for (x = Math.max(xi, 0); x < xl; x++) {
2175
+ if (!lines[y][x]) {
2176
+ break
2177
+ }
2178
+ lines[y][x][0] = colors.blend(attr, lines[y][x][0])
2179
+ // lines[y][x][1] = bch;
2180
+ lines[y].dirty = true
2181
+ }
2182
+ }
2183
+ } else {
2184
+ this.screen.fillRegion(dattr, bch, xi, xl, yi, yl)
2185
+ }
2186
+ }
2187
+
2188
+ if (this.tpadding) {
2189
+ ;(xi += this.padding.left), (xl -= this.padding.right)
2190
+ ;(yi += this.padding.top), (yl -= this.padding.bottom)
2191
+ }
2192
+
2193
+ // Determine where to place the text if it's vertically aligned.
2194
+ if (this.valign === 'middle' || this.valign === 'bottom') {
2195
+ visible = yl - yi
2196
+ if (this._clines.length < visible) {
2197
+ if (this.valign === 'middle') {
2198
+ visible = (visible / 2) | 0
2199
+ visible -= (this._clines.length / 2) | 0
2200
+ } else if (this.valign === 'bottom') {
2201
+ visible -= this._clines.length
2202
+ }
2203
+ ci -= visible * (xl - xi)
2204
+ }
2205
+ }
2206
+
2207
+ // Draw the content and background.
2208
+ for (y = yi; y < yl; y++) {
2209
+ if (!lines[y]) {
2210
+ if (y >= this.screen.height || yl < this.ibottom) {
2211
+ break
2212
+ } else {
2213
+ continue
2214
+ }
2215
+ }
2216
+ for (x = xi; x < xl; x++) {
2217
+ cell = lines[y][x]
2218
+ if (!cell) {
2219
+ if (x >= this.screen.width || xl < this.iright) {
2220
+ break
2221
+ } else {
2222
+ continue
2223
+ }
2224
+ }
2225
+
2226
+ ch = content[ci++] || bch
2227
+
2228
+ // if (!content[ci] && !coords._contentEnd) {
2229
+ // coords._contentEnd = { x: x - xi, y: y - yi };
2230
+ // }
2231
+
2232
+ // Handle escape codes.
2233
+ while (ch === '\x1b') {
2234
+ if ((c = /^\x1b\[[\d;]*m/.exec(content.substring(ci - 1)))) {
2235
+ ci += c[0].length - 1
2236
+ attr = this.screen.attrCode(c[0], attr, dattr)
2237
+ // Ignore foreground changes for selected items.
2238
+ if (
2239
+ this.parent._isList &&
2240
+ this.parent.interactive &&
2241
+ this.parent.items[this.parent.selected] === this &&
2242
+ this.parent.options.invertSelected !== false
2243
+ ) {
2244
+ attr = (attr & ~(0x1ff << 9)) | (dattr & (0x1ff << 9))
2245
+ }
2246
+ ch = content[ci] || bch
2247
+ ci++
2248
+ } else {
2249
+ break
2250
+ }
2251
+ }
2252
+
2253
+ // Handle newlines.
2254
+ if (ch === '\t') {
2255
+ ch = bch
2256
+ }
2257
+ if (ch === '\n') {
2258
+ // If we're on the first cell and we find a newline and the last cell
2259
+ // of the last line was not a newline, let's just treat this like the
2260
+ // newline was already "counted".
2261
+ if (x === xi && y !== yi && content[ci - 2] !== '\n') {
2262
+ x--
2263
+ continue
2264
+ }
2265
+ // We could use fillRegion here, name the
2266
+ // outer loop, and continue to it instead.
2267
+ ch = bch
2268
+ for (; x < xl; x++) {
2269
+ cell = lines[y][x]
2270
+ if (!cell) {
2271
+ break
2272
+ }
2273
+ if (this.style.transparent) {
2274
+ lines[y][x][0] = colors.blend(attr, lines[y][x][0])
2275
+ if (content[ci]) {
2276
+ lines[y][x][1] = ch
2277
+ }
2278
+ lines[y].dirty = true
2279
+ } else {
2280
+ if (attr !== cell[0] || ch !== cell[1]) {
2281
+ lines[y][x][0] = attr
2282
+ lines[y][x][1] = ch
2283
+ lines[y].dirty = true
2284
+ }
2285
+ }
2286
+ }
2287
+ continue
2288
+ }
2289
+
2290
+ if (this.screen.fullUnicode && content[ci - 1]) {
2291
+ const point = unicode.codePointAt(content, ci - 1)
2292
+ // Handle combining chars:
2293
+ // Make sure they get in the same cell and are counted as 0.
2294
+ if (unicode.combining[point]) {
2295
+ if (point > 0x00ffff) {
2296
+ ch = content[ci - 1] + content[ci]
2297
+ ci++
2298
+ }
2299
+ if (x - 1 >= xi) {
2300
+ lines[y][x - 1][1] += ch
2301
+ } else if (y - 1 >= yi) {
2302
+ lines[y - 1][xl - 1][1] += ch
2303
+ }
2304
+ x--
2305
+ continue
2306
+ }
2307
+ // Handle surrogate pairs:
2308
+ // Make sure we put surrogate pair chars in one cell.
2309
+ if (point > 0x00ffff) {
2310
+ ch = content[ci - 1] + content[ci]
2311
+ ci++
2312
+ }
2313
+ }
2314
+
2315
+ if (this._noFill) {
2316
+ continue
2317
+ }
2318
+
2319
+ if (this.style.transparent) {
2320
+ lines[y][x][0] = colors.blend(attr, lines[y][x][0])
2321
+ if (content[ci]) {
2322
+ lines[y][x][1] = ch
2323
+ }
2324
+ lines[y].dirty = true
2325
+ } else {
2326
+ if (attr !== cell[0] || ch !== cell[1]) {
2327
+ lines[y][x][0] = attr
2328
+ lines[y][x][1] = ch
2329
+ lines[y].dirty = true
2330
+ }
2331
+ }
2332
+ }
2333
+ }
2334
+
2335
+ // Draw the scrollbar.
2336
+ // Could possibly draw this after all child elements.
2337
+ if (this.scrollbar) {
2338
+ // XXX
2339
+ // i = this.getScrollHeight();
2340
+ i = Math.max(this._clines.length, this._scrollBottom())
2341
+ }
2342
+ if (coords.notop || coords.nobot) {
2343
+ i = -Infinity
2344
+ }
2345
+ if (this.scrollbar && yl - yi < i) {
2346
+ x = xl - 1
2347
+ if (this.scrollbar.ignoreBorder && this.border) {
2348
+ x++
2349
+ }
2350
+ if (this.alwaysScroll) {
2351
+ y = this.childBase / (i - (yl - yi))
2352
+ } else {
2353
+ y = (this.childBase + this.childOffset) / (i - 1)
2354
+ }
2355
+ y = yi + (((yl - yi) * y) | 0)
2356
+ if (y >= yl) {
2357
+ y = yl - 1
2358
+ }
2359
+ cell = lines[y] && lines[y][x]
2360
+ if (cell) {
2361
+ if (this.track) {
2362
+ ch = this.track.ch || ' '
2363
+ attr = this.sattr(
2364
+ this.style.track,
2365
+ this.style.track.fg || this.style.fg,
2366
+ this.style.track.bg || this.style.bg
2367
+ )
2368
+ this.screen.fillRegion(attr, ch, x, x + 1, yi, yl)
2369
+ }
2370
+ ch = this.scrollbar.ch || ' '
2371
+ attr = this.sattr(
2372
+ this.style.scrollbar,
2373
+ this.style.scrollbar.fg || this.style.fg,
2374
+ this.style.scrollbar.bg || this.style.bg
2375
+ )
2376
+ if (attr !== cell[0] || ch !== cell[1]) {
2377
+ lines[y][x][0] = attr
2378
+ lines[y][x][1] = ch
2379
+ lines[y].dirty = true
2380
+ }
2381
+ }
2382
+ }
2383
+
2384
+ if (this.border) {
2385
+ xi--, xl++, yi--, yl++
2386
+ }
2387
+
2388
+ if (this.tpadding) {
2389
+ ;(xi -= this.padding.left), (xl += this.padding.right)
2390
+ ;(yi -= this.padding.top), (yl += this.padding.bottom)
2391
+ }
2392
+
2393
+ // Draw the border.
2394
+ if (this.border) {
2395
+ battr = this.sattr(this.style.border)
2396
+ y = yi
2397
+ if (coords.notop) {
2398
+ y = -1
2399
+ }
2400
+ for (x = xi; x < xl; x++) {
2401
+ if (!lines[y]) {
2402
+ break
2403
+ }
2404
+ if (coords.noleft && x === xi) {
2405
+ continue
2406
+ }
2407
+ if (coords.noright && x === xl - 1) {
2408
+ continue
2409
+ }
2410
+ cell = lines[y][x]
2411
+ if (!cell) {
2412
+ continue
2413
+ }
2414
+ if (this.border.type === 'line') {
2415
+ if (x === xi) {
2416
+ ch = '\u250c' // '┌'
2417
+ if (!this.border.left) {
2418
+ if (this.border.top) {
2419
+ ch = '\u2500' // '─'
2420
+ } else {
2421
+ continue
2422
+ }
2423
+ } else {
2424
+ if (!this.border.top) {
2425
+ ch = '\u2502' // '│'
2426
+ }
2427
+ }
2428
+ } else if (x === xl - 1) {
2429
+ ch = '\u2510' // '┐'
2430
+ if (!this.border.right) {
2431
+ if (this.border.top) {
2432
+ ch = '\u2500' // '─'
2433
+ } else {
2434
+ continue
2435
+ }
2436
+ } else {
2437
+ if (!this.border.top) {
2438
+ ch = '\u2502' // '│'
2439
+ }
2440
+ }
2441
+ } else {
2442
+ ch = '\u2500' // '─'
2443
+ }
2444
+ } else if (this.border.type === 'bg') {
2445
+ ch = this.border.ch
2446
+ }
2447
+ if (!this.border.top && x !== xi && x !== xl - 1) {
2448
+ ch = ' '
2449
+ if (dattr !== cell[0] || ch !== cell[1]) {
2450
+ lines[y][x][0] = dattr
2451
+ lines[y][x][1] = ch
2452
+ lines[y].dirty = true
2453
+ continue
2454
+ }
2455
+ }
2456
+ if (battr !== cell[0] || ch !== cell[1]) {
2457
+ lines[y][x][0] = battr
2458
+ lines[y][x][1] = ch
2459
+ lines[y].dirty = true
2460
+ }
2461
+ }
2462
+ y = yi + 1
2463
+ for (; y < yl - 1; y++) {
2464
+ if (!lines[y]) {
2465
+ continue
2466
+ }
2467
+ cell = lines[y][xi]
2468
+ if (cell) {
2469
+ if (this.border.left) {
2470
+ if (this.border.type === 'line') {
2471
+ ch = '\u2502' // '│'
2472
+ } else if (this.border.type === 'bg') {
2473
+ ch = this.border.ch
2474
+ }
2475
+ if (!coords.noleft) {
2476
+ if (battr !== cell[0] || ch !== cell[1]) {
2477
+ lines[y][xi][0] = battr
2478
+ lines[y][xi][1] = ch
2479
+ lines[y].dirty = true
2480
+ }
2481
+ }
2482
+ } else {
2483
+ ch = ' '
2484
+ if (dattr !== cell[0] || ch !== cell[1]) {
2485
+ lines[y][xi][0] = dattr
2486
+ lines[y][xi][1] = ch
2487
+ lines[y].dirty = true
2488
+ }
2489
+ }
2490
+ }
2491
+ cell = lines[y][xl - 1]
2492
+ if (cell) {
2493
+ if (this.border.right) {
2494
+ if (this.border.type === 'line') {
2495
+ ch = '\u2502' // '│'
2496
+ } else if (this.border.type === 'bg') {
2497
+ ch = this.border.ch
2498
+ }
2499
+ if (!coords.noright) {
2500
+ if (battr !== cell[0] || ch !== cell[1]) {
2501
+ lines[y][xl - 1][0] = battr
2502
+ lines[y][xl - 1][1] = ch
2503
+ lines[y].dirty = true
2504
+ }
2505
+ }
2506
+ } else {
2507
+ ch = ' '
2508
+ if (dattr !== cell[0] || ch !== cell[1]) {
2509
+ lines[y][xl - 1][0] = dattr
2510
+ lines[y][xl - 1][1] = ch
2511
+ lines[y].dirty = true
2512
+ }
2513
+ }
2514
+ }
2515
+ }
2516
+ y = yl - 1
2517
+ if (coords.nobot) {
2518
+ y = -1
2519
+ }
2520
+ for (x = xi; x < xl; x++) {
2521
+ if (!lines[y]) {
2522
+ break
2523
+ }
2524
+ if (coords.noleft && x === xi) {
2525
+ continue
2526
+ }
2527
+ if (coords.noright && x === xl - 1) {
2528
+ continue
2529
+ }
2530
+ cell = lines[y][x]
2531
+ if (!cell) {
2532
+ continue
2533
+ }
2534
+ if (this.border.type === 'line') {
2535
+ if (x === xi) {
2536
+ ch = '\u2514' // '└'
2537
+ if (!this.border.left) {
2538
+ if (this.border.bottom) {
2539
+ ch = '\u2500' // '─'
2540
+ } else {
2541
+ continue
2542
+ }
2543
+ } else {
2544
+ if (!this.border.bottom) {
2545
+ ch = '\u2502' // '│'
2546
+ }
2547
+ }
2548
+ } else if (x === xl - 1) {
2549
+ ch = '\u2518' // '┘'
2550
+ if (!this.border.right) {
2551
+ if (this.border.bottom) {
2552
+ ch = '\u2500' // '─'
2553
+ } else {
2554
+ continue
2555
+ }
2556
+ } else {
2557
+ if (!this.border.bottom) {
2558
+ ch = '\u2502' // '│'
2559
+ }
2560
+ }
2561
+ } else {
2562
+ ch = '\u2500' // '─'
2563
+ }
2564
+ } else if (this.border.type === 'bg') {
2565
+ ch = this.border.ch
2566
+ }
2567
+ if (!this.border.bottom && x !== xi && x !== xl - 1) {
2568
+ ch = ' '
2569
+ if (dattr !== cell[0] || ch !== cell[1]) {
2570
+ lines[y][x][0] = dattr
2571
+ lines[y][x][1] = ch
2572
+ lines[y].dirty = true
2573
+ }
2574
+ continue
2575
+ }
2576
+ if (battr !== cell[0] || ch !== cell[1]) {
2577
+ lines[y][x][0] = battr
2578
+ lines[y][x][1] = ch
2579
+ lines[y].dirty = true
2580
+ }
2581
+ }
2582
+ }
2583
+
2584
+ if (this.shadow) {
2585
+ // right
2586
+ y = Math.max(yi + 1, 0)
2587
+ for (; y < yl + 1; y++) {
2588
+ if (!lines[y]) {
2589
+ break
2590
+ }
2591
+ x = xl
2592
+ for (; x < xl + 2; x++) {
2593
+ if (!lines[y][x]) {
2594
+ break
2595
+ }
2596
+ // lines[y][x][0] = colors.blend(this.dattr, lines[y][x][0]);
2597
+ lines[y][x][0] = colors.blend(lines[y][x][0])
2598
+ lines[y].dirty = true
2599
+ }
2600
+ }
2601
+ // bottom
2602
+ y = yl
2603
+ for (; y < yl + 1; y++) {
2604
+ if (!lines[y]) {
2605
+ break
2606
+ }
2607
+ for (x = Math.max(xi + 1, 0); x < xl; x++) {
2608
+ if (!lines[y][x]) {
2609
+ break
2610
+ }
2611
+ // lines[y][x][0] = colors.blend(this.dattr, lines[y][x][0]);
2612
+ lines[y][x][0] = colors.blend(lines[y][x][0])
2613
+ lines[y].dirty = true
2614
+ }
2615
+ }
2616
+ }
2617
+
2618
+ this.children.forEach(function (el) {
2619
+ if (el.screen._ci !== -1) {
2620
+ el.index = el.screen._ci++
2621
+ }
2622
+ // if (el.screen._rendering) {
2623
+ // el._rendering = true;
2624
+ // }
2625
+ el.render()
2626
+ // if (el.screen._rendering) {
2627
+ // el._rendering = false;
2628
+ // }
2629
+ })
2630
+
2631
+ this._emit('render', [coords])
2632
+
2633
+ return coords
2634
+ }
2635
+
2636
+ Element.prototype._render = Element.prototype.render
2637
+
2638
+ /**
2639
+ * Content Methods
2640
+ */
2641
+
2642
+ Element.prototype.insertLine = function (i, line) {
2643
+ if (typeof line === 'string') {
2644
+ line = line.split('\n')
2645
+ }
2646
+
2647
+ if (i !== i || i == null) {
2648
+ i = this._clines.ftor.length
2649
+ }
2650
+
2651
+ i = Math.max(i, 0)
2652
+
2653
+ while (this._clines.fake.length < i) {
2654
+ this._clines.fake.push('')
2655
+ this._clines.ftor.push([this._clines.push('') - 1])
2656
+ this._clines.rtof(this._clines.fake.length - 1)
2657
+ }
2658
+
2659
+ // NOTE: Could possibly compare the first and last ftor line numbers to see
2660
+ // if they're the same, or if they fit in the visible region entirely.
2661
+ let start = this._clines.length,
2662
+ diff,
2663
+ real
2664
+
2665
+ if (i >= this._clines.ftor.length) {
2666
+ real = this._clines.ftor[this._clines.ftor.length - 1]
2667
+ real = real[real.length - 1] + 1
2668
+ } else {
2669
+ real = this._clines.ftor[i][0]
2670
+ }
2671
+
2672
+ for (let j = 0; j < line.length; j++) {
2673
+ this._clines.fake.splice(i + j, 0, line[j])
2674
+ }
2675
+
2676
+ this.setContent(this._clines.fake.join('\n'), true)
2677
+
2678
+ diff = this._clines.length - start
2679
+
2680
+ if (diff > 0) {
2681
+ const pos = this._getCoords()
2682
+ if (!pos) {
2683
+ return
2684
+ }
2685
+
2686
+ const height = pos.yl - pos.yi - this.iheight,
2687
+ base = this.childBase || 0,
2688
+ visible = real >= base && real - base < height
2689
+
2690
+ if (pos && visible && this.screen.cleanSides(this)) {
2691
+ this.screen.insertLine(
2692
+ diff,
2693
+ pos.yi + this.itop + real - base,
2694
+ pos.yi,
2695
+ pos.yl - this.ibottom - 1
2696
+ )
2697
+ }
2698
+ }
2699
+ }
2700
+
2701
+ Element.prototype.deleteLine = function (i, n) {
2702
+ n = n || 1
2703
+
2704
+ if (i !== i || i == null) {
2705
+ i = this._clines.ftor.length - 1
2706
+ }
2707
+
2708
+ i = Math.max(i, 0)
2709
+ i = Math.min(i, this._clines.ftor.length - 1)
2710
+
2711
+ // NOTE: Could possibly compare the first and last ftor line numbers to see
2712
+ // if they're the same, or if they fit in the visible region entirely.
2713
+ let start = this._clines.length,
2714
+ diff,
2715
+ real = this._clines.ftor[i][0]
2716
+
2717
+ while (n--) {
2718
+ this._clines.fake.splice(i, 1)
2719
+ }
2720
+
2721
+ this.setContent(this._clines.fake.join('\n'), true)
2722
+
2723
+ diff = start - this._clines.length
2724
+
2725
+ // XXX clearPos() without diff statement?
2726
+ let height = 0
2727
+
2728
+ if (diff > 0) {
2729
+ const pos = this._getCoords()
2730
+ if (!pos) {
2731
+ return
2732
+ }
2733
+
2734
+ height = pos.yl - pos.yi - this.iheight
2735
+
2736
+ const base = this.childBase || 0,
2737
+ visible = real >= base && real - base < height
2738
+
2739
+ if (pos && visible && this.screen.cleanSides(this)) {
2740
+ this.screen.deleteLine(
2741
+ diff,
2742
+ pos.yi + this.itop + real - base,
2743
+ pos.yi,
2744
+ pos.yl - this.ibottom - 1
2745
+ )
2746
+ }
2747
+ }
2748
+
2749
+ if (this._clines.length < height) {
2750
+ this.clearPos()
2751
+ }
2752
+ }
2753
+
2754
+ Element.prototype.insertTop = function (line) {
2755
+ const fake = this._clines.rtof[this.childBase || 0]
2756
+ return this.insertLine(fake, line)
2757
+ }
2758
+
2759
+ Element.prototype.insertBottom = function (line) {
2760
+ const h = (this.childBase || 0) + this.height - this.iheight,
2761
+ i = Math.min(h, this._clines.length),
2762
+ fake = this._clines.rtof[i - 1] + 1
2763
+
2764
+ return this.insertLine(fake, line)
2765
+ }
2766
+
2767
+ Element.prototype.deleteTop = function (n) {
2768
+ const fake = this._clines.rtof[this.childBase || 0]
2769
+ return this.deleteLine(fake, n)
2770
+ }
2771
+
2772
+ Element.prototype.deleteBottom = function (n) {
2773
+ const h = (this.childBase || 0) + this.height - 1 - this.iheight,
2774
+ i = Math.min(h, this._clines.length - 1),
2775
+ fake = this._clines.rtof[i]
2776
+
2777
+ n = n || 1
2778
+
2779
+ return this.deleteLine(fake - (n - 1), n)
2780
+ }
2781
+
2782
+ Element.prototype.setLine = function (i, line) {
2783
+ i = Math.max(i, 0)
2784
+ while (this._clines.fake.length < i) {
2785
+ this._clines.fake.push('')
2786
+ }
2787
+ this._clines.fake[i] = line
2788
+ return this.setContent(this._clines.fake.join('\n'), true)
2789
+ }
2790
+
2791
+ Element.prototype.setBaseLine = function (i, line) {
2792
+ const fake = this._clines.rtof[this.childBase || 0]
2793
+ return this.setLine(fake + i, line)
2794
+ }
2795
+
2796
+ Element.prototype.getLine = function (i) {
2797
+ i = Math.max(i, 0)
2798
+ i = Math.min(i, this._clines.fake.length - 1)
2799
+ return this._clines.fake[i]
2800
+ }
2801
+
2802
+ Element.prototype.getBaseLine = function (i) {
2803
+ const fake = this._clines.rtof[this.childBase || 0]
2804
+ return this.getLine(fake + i)
2805
+ }
2806
+
2807
+ Element.prototype.clearLine = function (i) {
2808
+ i = Math.min(i, this._clines.fake.length - 1)
2809
+ return this.setLine(i, '')
2810
+ }
2811
+
2812
+ Element.prototype.clearBaseLine = function (i) {
2813
+ const fake = this._clines.rtof[this.childBase || 0]
2814
+ return this.clearLine(fake + i)
2815
+ }
2816
+
2817
+ Element.prototype.unshiftLine = function (line) {
2818
+ return this.insertLine(0, line)
2819
+ }
2820
+
2821
+ Element.prototype.shiftLine = function (n) {
2822
+ return this.deleteLine(0, n)
2823
+ }
2824
+
2825
+ Element.prototype.pushLine = function (line) {
2826
+ if (!this.content) {
2827
+ return this.setLine(0, line)
2828
+ }
2829
+ return this.insertLine(this._clines.fake.length, line)
2830
+ }
2831
+
2832
+ Element.prototype.popLine = function (n) {
2833
+ return this.deleteLine(this._clines.fake.length - 1, n)
2834
+ }
2835
+
2836
+ Element.prototype.getLines = function () {
2837
+ return this._clines.fake.slice()
2838
+ }
2839
+
2840
+ Element.prototype.getScreenLines = function () {
2841
+ return this._clines.slice()
2842
+ }
2843
+
2844
+ Element.prototype.strWidth = function (text) {
2845
+ text = this.parseTags ? helpers.stripTags(text) : text
2846
+ return this.screen.fullUnicode
2847
+ ? unicode.strWidth(text)
2848
+ : helpers.dropUnicode(text).length
2849
+ }
2850
+
2851
+ Element.prototype.screenshot = function (xi, xl, yi, yl) {
2852
+ xi = this.lpos.xi + this.ileft + (xi || 0)
2853
+ if (xl != null) {
2854
+ xl = this.lpos.xi + this.ileft + (xl || 0)
2855
+ } else {
2856
+ xl = this.lpos.xl - this.iright
2857
+ }
2858
+ yi = this.lpos.yi + this.itop + (yi || 0)
2859
+ if (yl != null) {
2860
+ yl = this.lpos.yi + this.itop + (yl || 0)
2861
+ } else {
2862
+ yl = this.lpos.yl - this.ibottom
2863
+ }
2864
+ return this.screen.screenshot(xi, xl, yi, yl)
2865
+ }
2866
+
2867
+ /**
2868
+ * Expose
2869
+ */
2870
+
2871
+ module.exports = Element