Files
bare-operating-system/packages/bare-os-booter/lib/services/bare-os-tui-sdk.data.mjs
T
2026-08-18 18:11:28 -04:00

3 lines
130 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/** Auto-generated by scripts/bundle-tui-sdk.mjs — do not edit. */
export const BARE_OS_TUI_SDK_SOURCE = "(function (ctx) {\n\"use strict\";\n/* src/00-prelude.js */\n/** Bare OS TUI concat prelude. Guest scripts receive this via ctx only. */\nvar BARE_TUI_VERSION = '1.3.0'\nvar bareTuiSessions = []\nvar bareTuiNextWidgetId = 1\n\n/* src/ansi/codes.js */\n/** CSI / SGR / DEC private-mode sequences for the guest TUI. */\n\nvar BARE_TUI_ESC = '\\x1b'\nvar BARE_TUI_CSI = '\\x1b['\n\nfunction bareTuiSgr(n) {\n return BARE_TUI_CSI + String(n) + 'm'\n}\n\nvar bareTuiAnsi = {\n esc: BARE_TUI_ESC,\n csi: BARE_TUI_CSI,\n reset: bareTuiSgr(0),\n cursorHide: BARE_TUI_CSI + '?25l',\n cursorShow: BARE_TUI_CSI + '?25h',\n home: BARE_TUI_CSI + 'H',\n eraseDisplay: BARE_TUI_CSI + '2J',\n eraseDisplayEnd: BARE_TUI_CSI + 'J',\n eraseScrollback: BARE_TUI_CSI + '3J',\n eraseLine: BARE_TUI_CSI + '2K',\n eraseLineEnd: BARE_TUI_CSI + 'K',\n enterAltScreen: BARE_TUI_CSI + '?1049h',\n leaveAltScreen: BARE_TUI_CSI + '?1049l',\n enableMouseBasic: BARE_TUI_CSI + '?1000h' + BARE_TUI_CSI + '?1006h',\n enableMouseDrag:\n BARE_TUI_CSI + '?1000h' + BARE_TUI_CSI + '?1002h' + BARE_TUI_CSI + '?1006h',\n enableMouseAll:\n BARE_TUI_CSI + '?1000h' + BARE_TUI_CSI + '?1003h' + BARE_TUI_CSI + '?1006h',\n disableMouse:\n BARE_TUI_CSI +\n '?1006l' +\n BARE_TUI_CSI +\n '?1003l' +\n BARE_TUI_CSI +\n '?1002l' +\n BARE_TUI_CSI +\n '?1000l',\n enableBracketPaste: BARE_TUI_CSI + '?2004h',\n disableBracketPaste: BARE_TUI_CSI + '?2004l',\n enableFocus: BARE_TUI_CSI + '?1004h',\n disableFocus: BARE_TUI_CSI + '?1004l',\n syncOutputBegin: BARE_TUI_CSI + '?2026h',\n syncOutputEnd: BARE_TUI_CSI + '?2026l',\n modifierReverse: bareTuiSgr(7),\n modifierNotReverse: bareTuiSgr(27),\n modifierDim: bareTuiSgr(2),\n cursorTo: function (row, col) {\n var r = (row | 0) + 1\n var c = (col | 0) + 1\n if (r < 1) r = 1\n if (c < 1) c = 1\n return BARE_TUI_CSI + r + ';' + c + 'H'\n },\n cursorUp: function (n) {\n return BARE_TUI_CSI + (n == null ? 1 : n | 0) + 'A'\n },\n cursorDown: function (n) {\n return BARE_TUI_CSI + (n == null ? 1 : n | 0) + 'B'\n },\n cursorForward: function (n) {\n return BARE_TUI_CSI + (n == null ? 1 : n | 0) + 'C'\n },\n cursorBack: function (n) {\n return BARE_TUI_CSI + (n == null ? 1 : n | 0) + 'D'\n },\n sgr: bareTuiSgr,\n fg256: function (n) {\n return BARE_TUI_CSI + '38;5;' + (n | 0) + 'm'\n },\n bg256: function (n) {\n return BARE_TUI_CSI + '48;5;' + (n | 0) + 'm'\n },\n fgRgb: function (r, g, b) {\n return (\n BARE_TUI_CSI + '38;2;' + (r | 0) + ';' + (g | 0) + ';' + (b | 0) + 'm'\n )\n },\n bgRgb: function (r, g, b) {\n return (\n BARE_TUI_CSI + '48;2;' + (r | 0) + ';' + (g | 0) + ';' + (b | 0) + 'm'\n )\n }\n}\n\n/* src/input/decoder.js */\n/** Byte-queue key / mouse / paste decoder. Produces TEA-style messages. */\n\nfunction bareTuiUtf8Decode(bytes) {\n try {\n if (typeof TextDecoder !== 'undefined') {\n return new TextDecoder('utf-8', { fatal: false }).decode(\n new Uint8Array(bytes)\n )\n }\n } catch (e) {\n /* fall through */\n }\n var s = ''\n for (var i = 0; i < bytes.length; i++) s += String.fromCharCode(bytes[i])\n return s\n}\n\nfunction bareTuiUtf8TrailCount(b1) {\n if (b1 >= 0xc0 && b1 < 0xe0) return 1\n if (b1 >= 0xe0 && b1 < 0xf0) return 2\n if (b1 >= 0xf0) return 3\n return 0\n}\n\nfunction bareTuiKeyToString() {\n var parts = []\n if (this.ctrl) parts.push('ctrl')\n if (this.meta) parts.push('alt')\n if (this.shift && this.name && this.name.length > 1) parts.push('shift')\n parts.push(this.name === 'return' ? 'enter' : this.name)\n return parts.join('+')\n}\n\nfunction bareTuiKeyIs() {\n var str = this.toString()\n for (var i = 0; i < arguments.length; i++) {\n var chord = arguments[i]\n if (chord === 'esc') chord = 'escape'\n if (chord === str || chord === this.name) return true\n if (chord === 'enter' && (str === 'enter' || this.name === 'return'))\n return true\n }\n return false\n}\n\nfunction bareTuiMakeKey(name, seq, ctrl, meta, shift) {\n return {\n type: 'key',\n name: name,\n sequence: seq || '',\n ctrl: !!ctrl,\n meta: !!meta,\n shift: !!shift,\n toString: bareTuiKeyToString,\n is: bareTuiKeyIs\n }\n}\n\nfunction bareTuiKeyMatches(msg) {\n if (!msg || msg.type !== 'key' || typeof msg.is !== 'function') return false\n var chords = []\n for (var i = 1; i < arguments.length; i++) {\n var item = arguments[i]\n if (item && typeof item === 'object' && item.keys && item.keys.length) {\n for (var k = 0; k < item.keys.length; k++) chords.push(item.keys[k])\n } else {\n chords.push(item)\n }\n }\n return msg.is.apply(msg, chords)\n}\n\nfunction bareTuiKeyBinding(opts) {\n var o = opts || {}\n var keys = o.keys\n if (!keys) keys = []\n if (typeof keys === 'string') keys = [keys]\n return { keys: keys.slice(), help: o.help || null }\n}\n\nvar BARE_TUI_CSI_NAMES = {\n A: 'up',\n B: 'down',\n C: 'right',\n D: 'left',\n H: 'home',\n F: 'end',\n Z: 'tab',\n P: 'f1',\n Q: 'f2',\n R: 'f3',\n S: 'f4'\n}\n\nvar BARE_TUI_TILDE_NAMES = {\n 1: 'home',\n 2: 'insert',\n 3: 'delete',\n 4: 'end',\n 5: 'pageup',\n 6: 'pagedown',\n 7: 'home',\n 8: 'end',\n 11: 'f1',\n 12: 'f2',\n 13: 'f3',\n 14: 'f4',\n 15: 'f5',\n 17: 'f6',\n 18: 'f7',\n 19: 'f8',\n 20: 'f9',\n 21: 'f10',\n 23: 'f11',\n 24: 'f12'\n}\n\nfunction bareTuiParseCsiPayload(payload) {\n if (!payload) return null\n if (payload === 'I') return { type: 'focus', gained: true }\n if (payload === 'O') return { type: 'focus', gained: false }\n\n if (payload.charAt(0) === '<') {\n var m = /^<(\\d+);(\\d+);(\\d+)([Mm])$/.exec(payload)\n if (!m) return { type: 'unknown', sequence: payload }\n var btn = parseInt(m[1], 10)\n var x = parseInt(m[2], 10)\n var y = parseInt(m[3], 10)\n var release = m[4] === 'm'\n var motion = (btn & 32) !== 0\n var wheel = (btn & 64) !== 0\n var code = btn & 3\n var button =\n code === 0\n ? 'left'\n : code === 1\n ? 'middle'\n : code === 2\n ? 'right'\n : 'none'\n var action = 'press'\n if (wheel) action = (btn & 1) === 0 ? 'scrollup' : 'scrolldown'\n else if (release) action = 'release'\n else if (motion) action = 'drag'\n return {\n type: 'mouse',\n action: action,\n button: button,\n x: x,\n y: y,\n ctrl: (btn & 16) !== 0,\n meta: (btn & 8) !== 0,\n shift: (btn & 4) !== 0\n }\n }\n\n var last = payload.charAt(payload.length - 1)\n var body = payload.slice(0, payload.length - 1)\n var mods = 1\n var num = ''\n var semi = body.indexOf(';')\n if (last === '~') {\n if (semi >= 0) {\n num = body.slice(0, semi)\n mods = parseInt(body.slice(semi + 1), 10) || 1\n } else {\n num = body\n }\n if (num === '200') return { type: 'paste-start' }\n if (num === '201') return { type: 'paste-end' }\n var tname = BARE_TUI_TILDE_NAMES[num]\n if (!tname) return { type: 'unknown', sequence: payload }\n return bareTuiMakeKey(\n tname,\n payload,\n !!((mods - 1) & 4),\n !!((mods - 1) & 2),\n !!((mods - 1) & 1)\n )\n }\n var letter = last\n if (semi >= 0) {\n var parts = body.split(';')\n if (parts.length >= 2) mods = parseInt(parts[1], 10) || 1\n }\n var lname = BARE_TUI_CSI_NAMES[letter]\n if (!lname) return { type: 'unknown', sequence: payload }\n var shift = !!((mods - 1) & 1)\n if (letter === 'Z') shift = true\n return bareTuiMakeKey(\n lname,\n payload,\n !!((mods - 1) & 4),\n !!((mods - 1) & 2),\n shift\n )\n}\n\nfunction bareTuiTryConsume(q) {\n if (!q.length) return null\n var b1 = q[0]\n\n if (b1 === 27) {\n if (q.length < 2) return { type: 'incomplete' }\n var b2 = q[1]\n if (b2 === 91) {\n var i = 2\n while (i < q.length) {\n var b = q[i]\n if (b >= 0x40 && b <= 0x7e) {\n var seq = String.fromCharCode.apply(null, q.slice(2, i + 1))\n q.splice(0, i + 1)\n return bareTuiParseCsiPayload(seq)\n }\n i++\n }\n return { type: 'incomplete' }\n }\n if (b2 === 79) {\n if (q.length < 3) return { type: 'incomplete' }\n var b3 = q[2]\n q.splice(0, 3)\n var ss3 = String.fromCharCode(b3)\n var ssName = {\n A: 'up',\n B: 'down',\n C: 'right',\n D: 'left',\n H: 'home',\n F: 'end',\n P: 'f1',\n Q: 'f2',\n R: 'f3',\n S: 'f4'\n }[ss3]\n if (!ssName) return { type: 'unknown', sequence: 'O' + ss3 }\n return bareTuiMakeKey(ssName, 'O' + ss3, false, false, false)\n }\n q.splice(0, 2)\n if (b2 === 27) return bareTuiMakeKey('escape', '\\x1b', false, false, false)\n if (b2 >= 1 && b2 <= 26) {\n return bareTuiMakeKey(\n String.fromCharCode(96 + b2),\n String.fromCharCode(b2),\n true,\n true,\n false\n )\n }\n return bareTuiMakeKey(\n String.fromCharCode(b2),\n String.fromCharCode(b2),\n false,\n true,\n false\n )\n }\n\n if (b1 === 3) {\n q.shift()\n return bareTuiMakeKey('c', '\\x03', true, false, false)\n }\n if (b1 === 4) {\n q.shift()\n return bareTuiMakeKey('d', '\\x04', true, false, false)\n }\n if (b1 === 8 || b1 === 127) {\n q.shift()\n return bareTuiMakeKey(\n 'backspace',\n String.fromCharCode(b1),\n false,\n false,\n false\n )\n }\n if (b1 === 13 || b1 === 10) {\n q.shift()\n return bareTuiMakeKey('enter', String.fromCharCode(b1), false, false, false)\n }\n if (b1 === 9) {\n q.shift()\n return bareTuiMakeKey('tab', '\\t', false, false, false)\n }\n if (b1 === 32) {\n q.shift()\n return bareTuiMakeKey('space', ' ', false, false, false)\n }\n if (b1 === 27) {\n q.shift()\n return bareTuiMakeKey('escape', '\\x1b', false, false, false)\n }\n if (b1 < 32) {\n q.shift()\n if (b1 === 0) return bareTuiMakeKey('space', '\\x00', true, false, false)\n return bareTuiMakeKey(\n String.fromCharCode(96 + b1),\n String.fromCharCode(b1),\n true,\n false,\n false\n )\n }\n\n if (b1 >= 0xc0) {\n var trail = bareTuiUtf8TrailCount(b1)\n if (q.length < trail + 1) return { type: 'incomplete' }\n var ub = q.splice(0, trail + 1)\n var ch = bareTuiUtf8Decode(ub)\n return bareTuiMakeKey(ch, ch, false, false, false)\n }\n\n q.shift()\n var one = String.fromCharCode(b1)\n return bareTuiMakeKey(one, one, false, false, false)\n}\n\nfunction bareTuiCreateDecoder() {\n var q = []\n var paste = null\n return {\n push: function (chunk) {\n var i\n if (chunk == null) return\n if (typeof chunk === 'string') {\n for (i = 0; i < chunk.length; ) {\n var cp = chunk.codePointAt(i)\n i += cp > 0xffff ? 2 : 1\n if (cp < 0x80) q.push(cp)\n else if (cp < 0x800) {\n q.push(0xc0 | (cp >> 6))\n q.push(0x80 | (cp & 63))\n } else if (cp < 0x10000) {\n q.push(0xe0 | (cp >> 12))\n q.push(0x80 | ((cp >> 6) & 63))\n q.push(0x80 | (cp & 63))\n } else {\n q.push(0xf0 | (cp >> 18))\n q.push(0x80 | ((cp >> 12) & 63))\n q.push(0x80 | ((cp >> 6) & 63))\n q.push(0x80 | (cp & 63))\n }\n }\n return\n }\n if (chunk instanceof Uint8Array || Array.isArray(chunk)) {\n for (i = 0; i < chunk.length; i++) q.push(chunk[i] & 255)\n return\n }\n if (typeof chunk === 'number') q.push(chunk & 255)\n },\n flushEscape: function () {\n if (q.length === 1 && q[0] === 27) {\n q.shift()\n return bareTuiMakeKey('escape', '\\x1b', false, false, false)\n }\n return null\n },\n take: function () {\n var out = []\n for (;;) {\n if (!q.length) break\n if (paste !== null) {\n var end = -1\n var j\n for (j = 0; j <= q.length - 6; j++) {\n if (\n q[j] === 27 &&\n q[j + 1] === 91 &&\n q[j + 2] === 50 &&\n q[j + 3] === 48 &&\n q[j + 4] === 49 &&\n q[j + 5] === 126\n ) {\n end = j\n break\n }\n }\n if (end < 0) break\n var inner = q.splice(0, end)\n q.splice(0, 6)\n paste = null\n out.push({ type: 'paste', text: bareTuiUtf8Decode(inner) })\n continue\n }\n var ev = bareTuiTryConsume(q)\n if (!ev || ev.type === 'incomplete') break\n if (ev.type === 'paste-start') {\n paste = []\n continue\n }\n if (ev.type === 'paste-end') continue\n out.push(ev)\n }\n return out\n },\n pending: function () {\n return q.length\n }\n }\n}\n\nfunction bareTuiDecodeBytes(chunk) {\n var d = bareTuiCreateDecoder()\n d.push(chunk)\n var evs = d.take()\n var esc = d.flushEscape()\n if (esc) evs.push(esc)\n return evs\n}\n\n/* src/adapter/session.js */\n/** Session adapter: Fish suspend, raw mode, stream resolve. Widgets never call this. */\n\nfunction bareTuiEnv(ctx) {\n return ctx && ctx.env && typeof ctx.env === 'object' ? ctx.env : {}\n}\n\nfunction bareTuiGetSession(ctx) {\n var i\n for (i = 0; i < bareTuiSessions.length; i++) {\n if (bareTuiSessions[i].ctx === ctx) return bareTuiSessions[i]\n }\n var s = {\n ctx: ctx,\n depth: 0,\n didSuspend: false,\n didRaw: false,\n stdin: null\n }\n bareTuiSessions.push(s)\n return s\n}\n\nfunction bareTuiResolveStdin(ctx, opts) {\n var o = opts || {}\n if (o.input) return o.input\n if (ctx && ctx.replStdin) return ctx.replStdin\n if (ctx && ctx.stdin) return ctx.stdin\n var p = typeof globalThis !== 'undefined' ? globalThis.process : null\n return p && p.stdin ? p.stdin : null\n}\n\nfunction bareTuiResolveStdout(ctx, opts) {\n var o = opts || {}\n if (o.output) return o.output\n if (ctx && ctx.replStdout) return ctx.replStdout\n if (ctx && ctx.stdout) return ctx.stdout\n var p = typeof globalThis !== 'undefined' ? globalThis.process : null\n return p && p.stdout ? p.stdout : null\n}\n\nfunction bareTuiWriteRaw(ctx, opts, chunk) {\n var out = bareTuiResolveStdout(ctx, opts)\n var s = typeof chunk === 'string' ? chunk : String(chunk)\n if (out && typeof out.write === 'function') {\n out.write(s)\n return\n }\n if (ctx && typeof ctx.writeScreen === 'function') ctx.writeScreen(s)\n}\n\nfunction bareTuiIsTTY(ctx, opts) {\n var o = opts || {}\n if (o.isTTY === true) return true\n if (o.isTTY === false) return false\n if (ctx && ctx.bareOsStdoutCaptured) return false\n var stdin = bareTuiResolveStdin(ctx, o)\n var stdout = bareTuiResolveStdout(ctx, o)\n var inTty = !!(stdin && stdin.isTTY)\n var outTty = !!(stdout && stdout.isTTY)\n return inTty || outTty\n}\n\nfunction bareTuiSize(ctx, opts) {\n var o = opts || {}\n if (o.width > 0 && o.height > 0) {\n return { width: o.width | 0, height: o.height | 0 }\n }\n var stdout = bareTuiResolveStdout(ctx, o)\n var env = bareTuiEnv(ctx)\n var w =\n (stdout && stdout.columns) ||\n parseInt(env.COLUMNS || '', 10) ||\n o.width ||\n 80\n var h =\n (stdout && stdout.rows) || parseInt(env.LINES || '', 10) || o.height || 24\n if (!isFinite(w) || w < 1) w = 80\n if (!isFinite(h) || h < 1) h = 24\n return { width: w | 0, height: h | 0 }\n}\n\nfunction bareTuiNoAltScreen(ctx, opts) {\n var o = opts || {}\n if (o.altScreen === false) return true\n var env = bareTuiEnv(ctx)\n var v = env.BARE_OS_TUI_NO_ALTSCREEN\n return v != null && String(v) !== ''\n}\n\nfunction bareTuiAcquire(ctx, opts) {\n var sess = bareTuiGetSession(ctx)\n sess.depth++\n if (sess.depth !== 1) return sess\n if (ctx && typeof ctx.suspendReplForSubprocess === 'function') {\n ctx.suspendReplForSubprocess()\n sess.didSuspend = true\n }\n var stdin = bareTuiResolveStdin(ctx, opts)\n sess.stdin = stdin\n if (stdin && typeof stdin.setRawMode === 'function') {\n try {\n stdin.setRawMode(true)\n sess.didRaw = true\n } catch (e) {\n sess.didRaw = false\n }\n }\n if (stdin && typeof stdin.resume === 'function') {\n try {\n stdin.resume()\n } catch (e2) {\n /* ignore */\n }\n }\n return sess\n}\n\nfunction bareTuiRelease(ctx, opts) {\n var sess = bareTuiGetSession(ctx)\n if (sess.depth < 1) return sess\n sess.depth--\n if (sess.depth !== 0) return sess\n var stdin = sess.stdin || bareTuiResolveStdin(ctx, opts)\n if (sess.didRaw && stdin && typeof stdin.setRawMode === 'function') {\n try {\n stdin.setRawMode(false)\n } catch (e) {\n /* ignore */\n }\n }\n sess.didRaw = false\n if (\n sess.didSuspend &&\n ctx &&\n typeof ctx.resumeReplAfterSubprocess === 'function'\n ) {\n try {\n ctx.resumeReplAfterSubprocess()\n } catch (e2) {\n /* ignore */\n }\n }\n sess.didSuspend = false\n sess.stdin = null\n return sess\n}\n\nasync function bareTuiWithSession(ctx, fn, opts) {\n bareTuiAcquire(ctx, opts)\n var entered = false\n try {\n bareTuiScreenEnter(ctx, opts)\n entered = true\n return await fn()\n } finally {\n if (entered) {\n try {\n bareTuiScreenLeave(ctx, opts)\n } catch (e) {\n /* ignore */\n }\n }\n bareTuiRelease(ctx, opts)\n }\n}\n\n/* src/screen/screen.js */\n/** Alternate-screen / cursor / mouse / paste enter-leave. Always pair with adapter. */\n\nfunction bareTuiMouseMode(opts) {\n var m = opts && opts.mouse\n if (m === true || m === 'basic') return 'basic'\n if (m === 'drag' || m === 'motion') return 'drag'\n if (m === 'all') return 'all'\n return null\n}\n\nfunction bareTuiScreenEnter(ctx, opts) {\n var o = opts || {}\n var parts = []\n if (!bareTuiNoAltScreen(ctx, o)) parts.push(bareTuiAnsi.enterAltScreen)\n else parts.push(bareTuiAnsi.home + bareTuiAnsi.eraseDisplay)\n parts.push(bareTuiAnsi.cursorHide)\n parts.push(bareTuiAnsi.home)\n if (o.bracketedPaste !== false) parts.push(bareTuiAnsi.enableBracketPaste)\n if (o.focus) parts.push(bareTuiAnsi.enableFocus)\n var mouse = bareTuiMouseMode(o)\n if (mouse === 'basic') parts.push(bareTuiAnsi.enableMouseBasic)\n else if (mouse === 'drag') parts.push(bareTuiAnsi.enableMouseDrag)\n else if (mouse === 'all') parts.push(bareTuiAnsi.enableMouseAll)\n bareTuiWriteRaw(ctx, o, parts.join(''))\n}\n\nfunction bareTuiScreenLeave(ctx, opts) {\n var o = opts || {}\n var parts = []\n parts.push(bareTuiAnsi.disableMouse)\n parts.push(bareTuiAnsi.disableFocus)\n parts.push(bareTuiAnsi.disableBracketPaste)\n parts.push(bareTuiAnsi.cursorShow)\n parts.push(bareTuiAnsi.reset)\n if (!bareTuiNoAltScreen(ctx, o)) parts.push(bareTuiAnsi.leaveAltScreen)\n bareTuiWriteRaw(ctx, o, parts.join(''))\n}\n\n/* src/theme/theme.js */\n/** Resolve BARE_OS_THEME / BARE_OS_COLOR_* / NO_COLOR into TUI tokens. */\n\nvar BARE_TUI_THEME_FALLBACK = {\n default: {\n accent: 'cyan',\n muted: 'gray',\n error: 'red',\n ok: 'green',\n border: 'blue'\n },\n nord: {\n accent: 'cyan',\n muted: 'gray',\n error: 'red',\n ok: 'green',\n border: 'blue'\n },\n dracula: {\n accent: 'magenta',\n muted: 'gray',\n error: 'red',\n ok: 'green',\n border: 'magenta'\n },\n solarized_dark: {\n accent: 'blue',\n muted: 'gray',\n error: 'red',\n ok: 'green',\n border: 'cyan'\n },\n gruvbox_dark: {\n accent: 'yellow',\n muted: 'gray',\n error: 'red',\n ok: 'green',\n border: 'yellow'\n },\n catppuccin_mocha: {\n accent: 'blue',\n muted: 'gray',\n error: 'red',\n ok: 'green',\n border: 'magenta'\n },\n tokyo_night: {\n accent: 'blue',\n muted: 'gray',\n error: 'red',\n ok: 'green',\n border: 'blue'\n },\n github_dark: {\n accent: 'cyan',\n muted: 'gray',\n error: 'red',\n ok: 'green',\n border: 'blue'\n }\n}\n\nfunction bareTuiColorDepth(env) {\n var raw = env && env.BARE_OS_COLOR_DEPTH\n var d = raw == null ? '' : String(raw).toLowerCase()\n if (d === '16' || d === '8' || d === 'ansi') return '16'\n if (d === '256' || d === '8bit') return '256'\n return 'truecolor'\n}\n\nfunction bareTuiNoColor(env) {\n if (!env) return false\n if (env.NO_COLOR != null && String(env.NO_COLOR) !== '') return true\n if (String(env.TERM || '').toLowerCase() === 'dumb') return true\n return false\n}\n\nfunction bareTuiThemeName(env, opts) {\n var o = opts || {}\n if (o.theme && typeof o.theme === 'string') return String(o.theme)\n var e = env || {}\n var raw = e.BARE_OS_THEME\n var name = raw == null || raw === '' ? 'default' : String(raw)\n return name.toLowerCase().trim().replace(/\\s+/g, '_')\n}\n\nfunction bareTuiEnvColor(env, short) {\n if (!env) return ''\n var key = 'BARE_OS_COLOR_' + String(short).toUpperCase()\n var v = env[key]\n return v == null ? '' : String(v)\n}\n\nfunction bareTuiResolveTheme(ctx, opts) {\n var env = bareTuiEnv(ctx)\n var name = bareTuiThemeName(env, opts)\n var fb = BARE_TUI_THEME_FALLBACK[name] || BARE_TUI_THEME_FALLBACK.default\n var noColor = bareTuiNoColor(env)\n return {\n name: name,\n noColor: noColor,\n depth: bareTuiColorDepth(env),\n tokens: {\n accent: bareTuiEnvColor(env, 'command') || fb.accent,\n muted: bareTuiEnvColor(env, 'ghost') || fb.muted,\n error: bareTuiEnvColor(env, 'envunset') || fb.error,\n ok: bareTuiEnvColor(env, 'prompt') || fb.ok,\n border: fb.border,\n path: bareTuiEnvColor(env, 'path') || 'yellow',\n search: bareTuiEnvColor(env, 'search') || fb.accent,\n status: bareTuiEnvColor(env, 'prompt') || fb.ok\n }\n }\n}\n\n/* src/layout/style.js */\n/** Lip Glossstyle chainable style + ANSI-aware width. */\n\nvar BARE_TUI_ANSI_RE = /\\x1b\\[[0-9;?]*[A-Za-z]/g\nvar BARE_TUI_ANSI_STICKY = /\\x1b\\[[0-9;?]*[A-Za-z]/y\n\nfunction bareTuiStripAnsi(str) {\n return String(str).replace(BARE_TUI_ANSI_RE, '')\n}\n\nfunction bareTuiIsZeroWidth(cp) {\n return (\n (cp >= 0x0300 && cp <= 0x036f) ||\n (cp >= 0x1ab0 && cp <= 0x1aff) ||\n (cp >= 0x1dc0 && cp <= 0x1dff) ||\n (cp >= 0x20d0 && cp <= 0x20ff) ||\n (cp >= 0xfe20 && cp <= 0xfe2f) ||\n cp === 0x200b ||\n (cp >= 0x200c && cp <= 0x200f) ||\n cp === 0xfeff\n )\n}\n\nfunction bareTuiIsWide(cp) {\n return (\n (cp >= 0x1100 && cp <= 0x115f) ||\n (cp >= 0x2e80 && cp <= 0x303e) ||\n (cp >= 0x3041 && cp <= 0x33ff) ||\n (cp >= 0x3400 && cp <= 0x4dbf) ||\n (cp >= 0x4e00 && cp <= 0x9fff) ||\n (cp >= 0xa000 && cp <= 0xa4cf) ||\n (cp >= 0xac00 && cp <= 0xd7a3) ||\n (cp >= 0xf900 && cp <= 0xfaff) ||\n (cp >= 0xfe30 && cp <= 0xfe4f) ||\n (cp >= 0xff00 && cp <= 0xff60) ||\n (cp >= 0xffe0 && cp <= 0xffe6) ||\n (cp >= 0x1f300 && cp <= 0x1faff) ||\n (cp >= 0x20000 && cp <= 0x3fffd)\n )\n}\n\nfunction bareTuiCharWidth(cp) {\n if (cp === 0) return 0\n if (cp < 32 || (cp >= 0x7f && cp < 0xa0)) return 0\n if (bareTuiIsZeroWidth(cp)) return 0\n if (bareTuiIsWide(cp)) return 2\n return 1\n}\n\nfunction bareTuiLineWidth(line) {\n var w = 0\n var plain = bareTuiStripAnsi(line)\n for (var i = 0; i < plain.length; ) {\n var cp = plain.codePointAt(i)\n w += bareTuiCharWidth(cp)\n i += cp > 0xffff ? 2 : 1\n }\n return w\n}\n\nfunction bareTuiBlockWidth(str) {\n var w = 0\n var lines = String(str).split('\\n')\n for (var i = 0; i < lines.length; i++)\n w = Math.max(w, bareTuiLineWidth(lines[i]))\n return w\n}\n\nfunction bareTuiBlockHeight(str) {\n return String(str).split('\\n').length\n}\n\nfunction bareTuiTruncate(str, w) {\n if (w <= 0) return ''\n str = String(str)\n var out = ''\n var used = 0\n var sawAnsi = false\n var i = 0\n while (i < str.length) {\n if (str.charAt(i) === '\\x1b') {\n BARE_TUI_ANSI_STICKY.lastIndex = i\n var m = BARE_TUI_ANSI_STICKY.exec(str)\n if (m) {\n out += m[0]\n sawAnsi = true\n i = BARE_TUI_ANSI_STICKY.lastIndex\n continue\n }\n }\n var cp = str.codePointAt(i)\n var ch = String.fromCodePoint(cp)\n var cw = bareTuiCharWidth(cp)\n if (used + cw > w) break\n out += ch\n used += cw\n i += ch.length\n }\n if (sawAnsi) out += bareTuiAnsi.reset\n return out\n}\n\nfunction bareTuiPadLine(line, w, pos) {\n if (pos == null) pos = 0\n var lw = bareTuiLineWidth(line)\n if (lw > w) return bareTuiTruncate(line, w)\n var space = w - lw\n if (space === 0) return line\n if (pos <= 0) return line + bareTuiRepeat(' ', space)\n if (pos >= 1) return bareTuiRepeat(' ', space) + line\n var left = Math.floor(space * pos)\n return bareTuiRepeat(' ', left) + line + bareTuiRepeat(' ', space - left)\n}\n\nfunction bareTuiRepeat(ch, n) {\n if (n <= 0) return ''\n var s = ''\n while (s.length < n) s += ch\n return s\n}\n\nvar BARE_TUI_NAMED = {\n black: 30,\n red: 31,\n green: 32,\n yellow: 33,\n blue: 34,\n magenta: 35,\n cyan: 36,\n white: 37,\n default: 39,\n gray: 90,\n grey: 90,\n brightblack: 90,\n brightred: 91,\n brightgreen: 92,\n brightyellow: 93,\n brightblue: 94,\n brightmagenta: 95,\n brightcyan: 96,\n brightwhite: 97\n}\n\nfunction bareTuiHexToRgb(hex) {\n var h = String(hex).replace(/^#/, '')\n if (h.length === 3)\n h =\n h.charAt(0) +\n h.charAt(0) +\n h.charAt(1) +\n h.charAt(1) +\n h.charAt(2) +\n h.charAt(2)\n var n = parseInt(h, 16)\n if (!isFinite(n)) return null\n return [(n >> 16) & 255, (n >> 8) & 255, n & 255]\n}\n\nfunction bareTuiRgbTo256(r, g, b) {\n if (r === g && g === b) {\n if (r < 8) return 16\n if (r > 248) return 231\n return Math.round(((r - 8) / 247) * 24) + 232\n }\n return (\n 16 +\n 36 * Math.round((r / 255) * 5) +\n 6 * Math.round((g / 255) * 5) +\n Math.round((b / 255) * 5)\n )\n}\n\nfunction bareTuiRgbTo16(r, g, b) {\n var bright = r > 180 || g > 180 || b > 180\n var max = Math.max(r, g, b)\n var min = Math.min(r, g, b)\n if (max - min < 30) return bright ? 97 : 37\n if (r >= g && r >= b)\n return g > 80 && b < 80 ? (bright ? 93 : 33) : bright ? 91 : 31\n if (g >= r && g >= b) return b > 80 ? (bright ? 96 : 36) : bright ? 92 : 32\n return r > 80 ? (bright ? 95 : 35) : bright ? 94 : 34\n}\n\nfunction bareTuiColorParams(spec, bg, depth) {\n if (spec === undefined || spec === null || spec === '') return []\n var lead = bg ? 48 : 38\n var d = depth || 'truecolor'\n\n if (typeof spec === 'number') {\n if (d === '16')\n return [\n bg\n ? spec >= 8\n ? spec - 8 + 100\n : spec + 40\n : spec >= 8\n ? spec - 8 + 90\n : spec + 30\n ]\n return [lead, 5, spec & 255]\n }\n\n var s = String(spec)\n if (s.charAt(0) === '\\x1b') return []\n\n if (s.charAt(0) === '#') {\n var rgb = bareTuiHexToRgb(s)\n if (!rgb) return []\n if (d === 'truecolor') return [lead, 2, rgb[0], rgb[1], rgb[2]]\n if (d === '256') return [lead, 5, bareTuiRgbTo256(rgb[0], rgb[1], rgb[2])]\n var n16 = bareTuiRgbTo16(rgb[0], rgb[1], rgb[2])\n return [bg ? n16 + 10 : n16]\n }\n var name = s.toLowerCase()\n if (name in BARE_TUI_NAMED)\n return [bg ? BARE_TUI_NAMED[name] + 10 : BARE_TUI_NAMED[name]]\n if (/^\\d+$/.test(s)) {\n var idx = parseInt(s, 10) & 255\n if (d === '16') return [bg ? 40 : 30]\n return [lead, 5, idx]\n }\n return []\n}\n\nfunction bareTuiSgrParams(params) {\n return params.length ? bareTuiAnsi.csi + params.join(';') + 'm' : ''\n}\n\nvar BARE_TUI_BORDERS = {\n normal: {\n topLeft: '\\u250c',\n top: '\\u2500',\n topRight: '\\u2510',\n left: '\\u2502',\n right: '\\u2502',\n bottomLeft: '\\u2514',\n bottom: '\\u2500',\n bottomRight: '\\u2518'\n },\n rounded: {\n topLeft: '\\u256d',\n top: '\\u2500',\n topRight: '\\u256e',\n left: '\\u2502',\n right: '\\u2502',\n bottomLeft: '\\u2570',\n bottom: '\\u2500',\n bottomRight: '\\u256f'\n },\n thick: {\n topLeft: '\\u250f',\n top: '\\u2501',\n topRight: '\\u2513',\n left: '\\u2503',\n right: '\\u2503',\n bottomLeft: '\\u2517',\n bottom: '\\u2501',\n bottomRight: '\\u251b'\n },\n double: {\n topLeft: '\\u2554',\n top: '\\u2550',\n topRight: '\\u2557',\n left: '\\u2551',\n right: '\\u2551',\n bottomLeft: '\\u255a',\n bottom: '\\u2550',\n bottomRight: '\\u255d'\n }\n}\n\nvar BARE_TUI_POSITION = { top: 0, left: 0, center: 0.5, right: 1, bottom: 1 }\n\nfunction bareTuiSides(args) {\n var a = []\n var i\n for (i = 0; i < args.length; i++) a.push(args[i] || 0)\n if (a.length <= 1) return [a[0] || 0, a[0] || 0, a[0] || 0, a[0] || 0]\n if (a.length === 2) return [a[0], a[1], a[0], a[1]]\n if (a.length === 3) return [a[0], a[1], a[2], a[1]]\n return [a[0], a[1], a[2], a[3]]\n}\n\nfunction BareTuiStyle(props) {\n this.props = props || {}\n}\n\nBareTuiStyle.prototype._with = function (patch) {\n var next = {}\n var k\n for (k in this.props) {\n if (Object.prototype.hasOwnProperty.call(this.props, k))\n next[k] = this.props[k]\n }\n for (k in patch) {\n if (Object.prototype.hasOwnProperty.call(patch, k)) next[k] = patch[k]\n }\n return new BareTuiStyle(next)\n}\n\nBareTuiStyle.prototype.bold = function (v) {\n return this._with({ bold: v !== false })\n}\nBareTuiStyle.prototype.faint = function (v) {\n return this._with({ faint: v !== false })\n}\nBareTuiStyle.prototype.dim = function (v) {\n return this.faint(v)\n}\nBareTuiStyle.prototype.italic = function (v) {\n return this._with({ italic: v !== false })\n}\nBareTuiStyle.prototype.underline = function (v) {\n return this._with({ underline: v !== false })\n}\nBareTuiStyle.prototype.strikethrough = function (v) {\n return this._with({ strikethrough: v !== false })\n}\nBareTuiStyle.prototype.reverse = function (v) {\n return this._with({ reverse: v !== false })\n}\nBareTuiStyle.prototype.foreground = function (c) {\n return this._with({ fg: c })\n}\nBareTuiStyle.prototype.background = function (c) {\n return this._with({ bg: c })\n}\nBareTuiStyle.prototype.width = function (n) {\n return this._with({ width: n })\n}\nBareTuiStyle.prototype.height = function (n) {\n return this._with({ height: n })\n}\nBareTuiStyle.prototype.align = function (pos) {\n return this._with({ align: pos })\n}\nBareTuiStyle.prototype.alignVertical = function (pos) {\n return this._with({ alignV: pos })\n}\nBareTuiStyle.prototype.padding = function () {\n return this._with({ padding: bareTuiSides(arguments) })\n}\nBareTuiStyle.prototype.margin = function () {\n return this._with({ margin: bareTuiSides(arguments) })\n}\nBareTuiStyle.prototype.border = function (chars) {\n var rest = []\n var i\n for (i = 1; i < arguments.length; i++) rest.push(arguments[i])\n var on = rest.length\n ? bareTuiSides(rest).map(Boolean)\n : [true, true, true, true]\n return this._with({ border: chars, borderSides: on })\n}\nBareTuiStyle.prototype.borderForeground = function (c) {\n return this._with({ borderFg: c })\n}\n\nBareTuiStyle.prototype._open = function () {\n if (this.props.noColor) return ''\n var p = this.props\n var params = []\n if (p.bold) params.push(1)\n if (p.faint) params.push(2)\n if (p.italic) params.push(3)\n if (p.underline) params.push(4)\n if (p.reverse) params.push(7)\n if (p.strikethrough) params.push(9)\n var depth = p.depth || 'truecolor'\n var fg = bareTuiColorParams(p.fg, false, depth)\n var bg = bareTuiColorParams(p.bg, true, depth)\n var i\n for (i = 0; i < fg.length; i++) params.push(fg[i])\n for (i = 0; i < bg.length; i++) params.push(bg[i])\n return bareTuiSgrParams(params)\n}\n\nBareTuiStyle.prototype.render = function (text) {\n var p = this.props\n var pad = p.padding || [0, 0, 0, 0]\n var mar = p.margin || [0, 0, 0, 0]\n var align = p.align || 0\n var lines = String(text).split('\\n')\n var block =\n !!p.border ||\n (p.bg !== undefined && p.bg !== null) ||\n !!p.width ||\n align !== 0 ||\n pad[0] ||\n pad[1] ||\n pad[2] ||\n pad[3]\n var contentW = p.width || bareTuiBlockWidth(lines.join('\\n'))\n var i\n if (block) {\n for (i = 0; i < lines.length; i++)\n lines[i] = bareTuiPadLine(lines[i], contentW, align)\n } else {\n for (i = 0; i < lines.length; i++) {\n if (bareTuiLineWidth(lines[i]) > contentW)\n lines[i] = bareTuiTruncate(lines[i], contentW)\n }\n }\n if (p.height)\n lines = bareTuiFitHeight(lines, p.height, contentW, p.alignV || 0)\n var innerW = contentW + pad[1] + pad[3]\n if (pad[1] || pad[3]) {\n var lp = bareTuiRepeat(' ', pad[3])\n var rp = bareTuiRepeat(' ', pad[1])\n for (i = 0; i < lines.length; i++) lines[i] = lp + lines[i] + rp\n }\n var blank = bareTuiRepeat(' ', innerW)\n for (i = 0; i < pad[0]; i++) lines.unshift(blank)\n for (i = 0; i < pad[2]; i++) lines.push(blank)\n var open = this._open()\n if (open) {\n var reset = bareTuiAnsi.reset\n for (i = 0; i < lines.length; i++) {\n lines[i] =\n open +\n String(lines[i])\n .split(reset)\n .join(reset + open) +\n reset\n }\n }\n if (p.border)\n lines = bareTuiApplyBorder(\n lines,\n innerW,\n p.border,\n p.borderSides,\n p.borderFg,\n p\n )\n if (mar[3] || mar[1]) {\n var lm = bareTuiRepeat(' ', mar[3])\n var rm = bareTuiRepeat(' ', mar[1])\n for (i = 0; i < lines.length; i++) lines[i] = lm + lines[i] + rm\n }\n var fullW = bareTuiBlockWidth(lines.join('\\n'))\n var marginBlank = bareTuiRepeat(' ', fullW)\n for (i = 0; i < mar[0]; i++) lines.unshift(marginBlank)\n for (i = 0; i < mar[2]; i++) lines.push(marginBlank)\n return lines.join('\\n')\n}\n\nfunction bareTuiFitHeight(lines, h, w, posV) {\n if (lines.length >= h) return lines.slice(0, h)\n var extra = h - lines.length\n var before = posV <= 0 ? 0 : posV >= 1 ? extra : Math.floor(extra * posV)\n var blank = bareTuiRepeat(' ', w)\n var out = []\n var i\n for (i = 0; i < before; i++) out.push(blank)\n for (i = 0; i < lines.length; i++) out.push(lines[i])\n for (i = 0; i < extra - before; i++) out.push(blank)\n return out\n}\n\nfunction bareTuiApplyBorder(lines, innerW, chars, on, fg, props) {\n var t = on[0]\n var r = on[1]\n var b = on[2]\n var l = on[3]\n var depth = (props && props.depth) || 'truecolor'\n var noColor = props && props.noColor\n var paint = function (s) {\n if (noColor) return s\n var params = bareTuiColorParams(fg, false, depth)\n return params.length ? bareTuiSgrParams(params) + s + bareTuiAnsi.reset : s\n }\n var out = []\n if (t) {\n out.push(\n paint(\n (l ? chars.topLeft : '') +\n bareTuiRepeat(chars.top, innerW) +\n (r ? chars.topRight : '')\n )\n )\n }\n var left = l ? paint(chars.left) : ''\n var right = r ? paint(chars.right) : ''\n var i\n for (i = 0; i < lines.length; i++) out.push(left + lines[i] + right)\n if (b) {\n out.push(\n paint(\n (l ? chars.bottomLeft : '') +\n bareTuiRepeat(chars.bottom, innerW) +\n (r ? chars.bottomRight : '')\n )\n )\n }\n return out\n}\n\nfunction bareTuiJoinHorizontal(pos) {\n var blocks = []\n var i\n for (i = 1; i < arguments.length; i++) blocks.push(arguments[i])\n var cols = []\n var widths = []\n var h = 0\n for (i = 0; i < blocks.length; i++) {\n var lines = String(blocks[i]).split('\\n')\n cols.push(lines)\n widths.push(bareTuiBlockWidth(lines.join('\\n')))\n if (lines.length > h) h = lines.length\n }\n var padded = []\n for (i = 0; i < cols.length; i++) {\n var filled = []\n var j\n for (j = 0; j < cols[i].length; j++)\n filled.push(bareTuiPadLine(cols[i][j], widths[i], 0))\n var extra = h - filled.length\n var before = pos <= 0 ? 0 : pos >= 1 ? extra : Math.floor(extra * pos)\n var blank = bareTuiRepeat(' ', widths[i])\n var col = []\n for (j = 0; j < before; j++) col.push(blank)\n for (j = 0; j < filled.length; j++) col.push(filled[j])\n for (j = 0; j < extra - before; j++) col.push(blank)\n padded.push(col)\n }\n var out = []\n var row\n for (row = 0; row < h; row++) {\n var s = ''\n for (i = 0; i < padded.length; i++) s += padded[i][row]\n out.push(s)\n }\n return out.join('\\n')\n}\n\nfunction bareTuiJoinVertical(pos) {\n var blocks = []\n var i\n for (i = 1; i < arguments.length; i++) blocks.push(arguments[i])\n var w = 0\n var cols = []\n for (i = 0; i < blocks.length; i++) {\n var lines = String(blocks[i]).split('\\n')\n cols.push(lines)\n var bw = bareTuiBlockWidth(lines.join('\\n'))\n if (bw > w) w = bw\n }\n var out = []\n for (i = 0; i < cols.length; i++) {\n var j\n for (j = 0; j < cols[i].length; j++)\n out.push(bareTuiPadLine(cols[i][j], w, pos))\n }\n return out.join('\\n')\n}\n\nfunction bareTuiMakeStyleFactory(ctx) {\n function style() {\n var theme = bareTuiResolveTheme(ctx, {})\n return new BareTuiStyle({ noColor: theme.noColor, depth: theme.depth })\n }\n style.Style = BareTuiStyle\n style.borders = BARE_TUI_BORDERS\n style.position = BARE_TUI_POSITION\n style.joinHorizontal = bareTuiJoinHorizontal\n style.joinVertical = bareTuiJoinVertical\n style.width = bareTuiBlockWidth\n style.height = bareTuiBlockHeight\n style.truncate = bareTuiTruncate\n style.stripAnsi = bareTuiStripAnsi\n return style\n}\n\n/* src/buffer/grid.js */\n/** Cell grid: parse ANSI text, blit overlays, serialize rows. */\n\nvar BARE_TUI_CELL_BOLD = 1\nvar BARE_TUI_CELL_DIM = 2\nvar BARE_TUI_CELL_REV = 4\n\nfunction bareTuiCellEmpty() {\n return { ch: ' ', fg: '', bg: '', attrs: 0 }\n}\n\nfunction bareTuiGridCreate(rows, cols) {\n rows = Math.max(1, rows | 0)\n cols = Math.max(1, cols | 0)\n var cells = []\n var r\n for (r = 0; r < rows; r++) {\n var row = []\n var c\n for (c = 0; c < cols; c++) row.push(bareTuiCellEmpty())\n cells.push(row)\n }\n return { rows: rows, cols: cols, cells: cells }\n}\n\nfunction bareTuiGridClear(grid) {\n var r, c\n for (r = 0; r < grid.rows; r++) {\n for (c = 0; c < grid.cols; c++) grid.cells[r][c] = bareTuiCellEmpty()\n }\n}\n\nfunction bareTuiGridPut(grid, r, c, ch, fg, bg, attrs) {\n if (r < 0 || c < 0 || r >= grid.rows || c >= grid.cols) return\n grid.cells[r][c] = { ch: ch, fg: fg || '', bg: bg || '', attrs: attrs | 0 }\n}\n\nfunction bareTuiApplySgr(state, params) {\n var i = 0\n if (!params.length) params = [0]\n while (i < params.length) {\n var n = params[i++] | 0\n if (n === 0) {\n state.fg = ''\n state.bg = ''\n state.attrs = 0\n } else if (n === 1) state.attrs |= BARE_TUI_CELL_BOLD\n else if (n === 2) state.attrs |= BARE_TUI_CELL_DIM\n else if (n === 22) state.attrs &= ~(BARE_TUI_CELL_BOLD | BARE_TUI_CELL_DIM)\n else if (n === 7) state.attrs |= BARE_TUI_CELL_REV\n else if (n === 27) state.attrs &= ~BARE_TUI_CELL_REV\n else if ((n >= 30 && n <= 37) || (n >= 90 && n <= 97)) state.fg = String(n)\n else if (n === 39) state.fg = ''\n else if ((n >= 40 && n <= 47) || (n >= 100 && n <= 107))\n state.bg = String(n)\n else if (n === 49) state.bg = ''\n else if (n === 38 || n === 48) {\n var kind = params[i++] | 0\n var key = n === 38 ? 'fg' : 'bg'\n if (kind === 5) {\n state[key] = n + ';5;' + (params[i++] | 0)\n } else if (kind === 2) {\n var r = params[i++] | 0\n var g = params[i++] | 0\n var b = params[i++] | 0\n state[key] = n + ';2;' + r + ';' + g + ';' + b\n }\n }\n }\n}\n\nfunction bareTuiParseSgrParams(body) {\n if (!body) return [0]\n var parts = String(body).split(';')\n var out = []\n var i\n for (i = 0; i < parts.length; i++) {\n if (parts[i] === '') out.push(0)\n else out.push(parseInt(parts[i], 10) || 0)\n }\n return out\n}\n\nfunction bareTuiGridWriteText(grid, startRow, startCol, text) {\n var state = { fg: '', bg: '', attrs: 0 }\n var r = startRow\n var c = startCol\n var i = 0\n text = String(text == null ? '' : text)\n while (i < text.length) {\n var ch0 = text.charAt(i)\n if (ch0 === '\\n') {\n r++\n c = startCol\n i++\n continue\n }\n if (ch0 === '\\r') {\n i++\n continue\n }\n if (ch0 === '\\x1b') {\n BARE_TUI_ANSI_STICKY.lastIndex = i\n var m = BARE_TUI_ANSI_STICKY.exec(text)\n if (m) {\n var seq = m[0]\n i = BARE_TUI_ANSI_STICKY.lastIndex\n if (seq.charAt(seq.length - 1) === 'm') {\n var inner = seq.slice(2, seq.length - 1)\n bareTuiApplySgr(state, bareTuiParseSgrParams(inner))\n }\n continue\n }\n }\n var cp = text.codePointAt(i)\n var glyph = String.fromCodePoint(cp)\n var cw = bareTuiCharWidth(cp)\n i += glyph.length\n if (cw <= 0) continue\n bareTuiGridPut(grid, r, c, glyph, state.fg, state.bg, state.attrs)\n if (cw === 2 && c + 1 < grid.cols) {\n bareTuiGridPut(grid, r, c + 1, '', state.fg, state.bg, state.attrs)\n }\n c += cw\n }\n}\n\nfunction bareTuiGridFill(grid, text) {\n bareTuiGridClear(grid)\n bareTuiGridWriteText(grid, 0, 0, text)\n return grid\n}\n\nfunction bareTuiGridBlit(grid, row, col, text) {\n var tmpRows = String(text == null ? '' : text).split('\\n').length\n var tmpCols = Math.max(1, bareTuiBlockWidth(text || ' '))\n var tmp = bareTuiGridCreate(tmpRows, tmpCols)\n bareTuiGridWriteText(tmp, 0, 0, text)\n var r, c\n for (r = 0; r < tmp.rows; r++) {\n for (c = 0; c < tmp.cols; c++) {\n var cell = tmp.cells[r][c]\n if (cell.ch === ' ' && !cell.fg && !cell.bg && !cell.attrs) continue\n bareTuiGridPut(\n grid,\n row + r,\n col + c,\n cell.ch,\n cell.fg,\n cell.bg,\n cell.attrs\n )\n }\n }\n return grid\n}\n\nfunction bareTuiGridPlain(grid) {\n var lines = []\n var r, c\n for (r = 0; r < grid.rows; r++) {\n var s = ''\n for (c = 0; c < grid.cols; c++) {\n var ch = grid.cells[r][c].ch\n if (ch !== '') s += ch\n }\n lines.push(s.replace(/\\s+$/, ''))\n }\n return lines\n}\n\nfunction bareTuiGridRowKey(grid, r) {\n var s = ''\n var c\n for (c = 0; c < grid.cols; c++) {\n var cell = grid.cells[r][c]\n s +=\n cell.ch +\n '\\x01' +\n cell.fg +\n '\\x01' +\n cell.bg +\n '\\x01' +\n cell.attrs +\n '\\x02'\n }\n return s\n}\n\nfunction bareTuiCellSgr(cell) {\n var params = []\n if (cell.attrs & BARE_TUI_CELL_BOLD) params.push(1)\n if (cell.attrs & BARE_TUI_CELL_DIM) params.push(2)\n if (cell.attrs & BARE_TUI_CELL_REV) params.push(7)\n if (cell.fg) {\n var fg = String(cell.fg)\n if (fg.indexOf(';') >= 0) {\n var fp = fg.split(';')\n var fi\n for (fi = 0; fi < fp.length; fi++) params.push(parseInt(fp[fi], 10) || 0)\n } else params.push(parseInt(fg, 10) || 0)\n }\n if (cell.bg) {\n var bg = String(cell.bg)\n if (bg.indexOf(';') >= 0) {\n var bp = bg.split(';')\n var bi\n for (bi = 0; bi < bp.length; bi++) params.push(parseInt(bp[bi], 10) || 0)\n } else params.push(parseInt(bg, 10) || 0)\n }\n return params.length ? bareTuiAnsi.csi + params.join(';') + 'm' : ''\n}\n\nfunction bareTuiGridPaintRow(grid, r) {\n var out = ''\n var last = ''\n var c\n for (c = 0; c < grid.cols; c++) {\n var cell = grid.cells[r][c]\n if (cell.ch === '') continue\n var sg = bareTuiCellSgr(cell)\n if (sg !== last) {\n out += bareTuiAnsi.reset + sg\n last = sg\n }\n out += cell.ch\n }\n if (last) out += bareTuiAnsi.reset\n return out\n}\n\n/* src/render/line-diff.js */\n/** Line-diff renderer. Repaints only changed rows. Does not own alt-screen. */\n\nfunction BareTuiRenderer(output) {\n this.out = output\n this.mode = 'line'\n this.lastLines = null\n}\n\nBareTuiRenderer.prototype.clear = function () {\n this.lastLines = null\n}\n\nBareTuiRenderer.prototype.write = function (s) {\n if (!s) return\n if (this.out && typeof this.out.write === 'function') this.out.write(s)\n}\n\nBareTuiRenderer.prototype.render = function (view) {\n var lines = String(view).split('\\n')\n var s = ''\n var i\n if (this.lastLines === null) {\n s += bareTuiAnsi.home\n for (i = 0; i < lines.length; i++) {\n s += bareTuiAnsi.eraseLineEnd + lines[i]\n if (i < lines.length - 1) s += '\\r\\n'\n }\n s += bareTuiAnsi.eraseDisplayEnd\n } else {\n for (i = 0; i < lines.length; i++) {\n if (lines[i] !== this.lastLines[i]) {\n s += bareTuiAnsi.cursorTo(i, 0) + bareTuiAnsi.eraseLineEnd + lines[i]\n }\n }\n if (this.lastLines.length > lines.length) {\n s += bareTuiAnsi.cursorTo(lines.length, 0) + bareTuiAnsi.eraseDisplayEnd\n }\n }\n this.lastLines = lines\n this.write(s)\n}\n\n/* src/render/cell.js */\n/** Dirty-row cell renderer. Base view + overlays; no layout insert. */\n\nfunction BareTuiCellRenderer(output, opts) {\n opts = opts || {}\n this.out = output\n this.mode = 'cell'\n this.rows = Math.max(1, opts.rows || opts.height || 24)\n this.cols = Math.max(1, opts.cols || opts.width || 80)\n this.grid = bareTuiGridCreate(this.rows, this.cols)\n this.lastKeys = null\n}\n\nBareTuiCellRenderer.prototype.write = function (s) {\n if (!s) return\n if (this.out && typeof this.out.write === 'function') this.out.write(s)\n}\n\nBareTuiCellRenderer.prototype.resize = function (rows, cols) {\n rows = Math.max(1, rows | 0)\n cols = Math.max(1, cols | 0)\n if (rows === this.rows && cols === this.cols) return\n this.rows = rows\n this.cols = cols\n this.grid = bareTuiGridCreate(rows, cols)\n this.lastKeys = null\n}\n\nBareTuiCellRenderer.prototype.clear = function () {\n this.lastKeys = null\n}\n\nBareTuiCellRenderer.prototype.render = function (view, overlays) {\n bareTuiGridFill(this.grid, view == null ? '' : view)\n if (overlays && overlays.length) {\n var i\n for (i = 0; i < overlays.length; i++) {\n var ov = overlays[i]\n if (!ov || ov.text == null) continue\n bareTuiGridBlit(this.grid, ov.row | 0, ov.col | 0, ov.text)\n }\n }\n var keys = []\n var s = ''\n var r\n for (r = 0; r < this.grid.rows; r++) {\n keys[r] = bareTuiGridRowKey(this.grid, r)\n if (this.lastKeys && this.lastKeys[r] === keys[r]) continue\n s +=\n bareTuiAnsi.cursorTo(r, 0) +\n bareTuiAnsi.eraseLineEnd +\n bareTuiGridPaintRow(this.grid, r)\n }\n if (!this.lastKeys) s = bareTuiAnsi.home + s\n this.lastKeys = keys\n this.write(s)\n}\n\nBareTuiCellRenderer.prototype.plain = function () {\n return bareTuiGridPlain(this.grid)\n}\n\n/* src/program/commands.js */\n/** TEA commands. A Cmd is () => Msg | Promise<Msg> | null, or a marker object. */\n\nfunction bareTuiQuitCmd() {\n return { type: 'quit' }\n}\n\nfunction bareTuiTick(ms, fn) {\n var delay = ms | 0\n if (delay < 0) delay = 0\n return function () {\n return new Promise(function (resolve) {\n setTimeout(function () {\n resolve(fn ? fn(new Date()) : { type: 'tick' })\n }, delay)\n })\n }\n}\n\nfunction bareTuiEvery(ms, fn) {\n var period = ms | 0\n if (period < 1) period = 1\n return function () {\n return new Promise(function (resolve) {\n var wait = period - (Date.now() % period)\n setTimeout(function () {\n resolve(fn ? fn(new Date()) : { type: 'tick' })\n }, wait)\n })\n }\n}\n\nfunction bareTuiBatch() {\n var out = []\n var i\n for (i = 0; i < arguments.length; i++) {\n var c = arguments[i]\n if (Array.isArray(c)) {\n var j\n for (j = 0; j < c.length; j++) if (c[j]) out.push(c[j])\n } else if (c) {\n out.push(c)\n }\n }\n return out\n}\n\nfunction bareTuiSequence() {\n var out = []\n var i\n for (i = 0; i < arguments.length; i++) {\n var c = arguments[i]\n if (Array.isArray(c)) {\n var j\n for (j = 0; j < c.length; j++) if (c[j]) out.push(c[j])\n } else if (c) {\n out.push(c)\n }\n }\n return { __seq: out }\n}\n\nfunction bareTuiSuspend(fn) {\n return { __suspend: fn }\n}\n\n/* src/program/program.js */\n/** TEA Program: init / update / view over the session adapter. */\n\nvar bareTuiActivePrograms = []\n\nfunction bareTuiActiveProgram(ctx) {\n var i\n for (i = bareTuiActivePrograms.length - 1; i >= 0; i--) {\n if (bareTuiActivePrograms[i].ctx === ctx) return bareTuiActivePrograms[i]\n }\n return null\n}\n\nfunction BareTuiProgram(ctx, model, opts) {\n this.ctx = ctx\n this.model = model\n this.opts = opts || {}\n this.fps = this.opts.fps == null ? 60 : this.opts.fps\n this._frameMs = this.fps > 0 ? Math.max(1, Math.round(1000 / this.fps)) : 0\n this._frameTimer = null\n this._needsRender = false\n this._queue = []\n this._wake = null\n this._running = false\n this._tornDown = false\n this._suspended = false\n this._decoder = null\n this._onInput = null\n this._onResize = null\n this._escTimer = null\n this._abortOn = null\n this.input = bareTuiResolveStdin(ctx, this.opts)\n this.output = bareTuiResolveStdout(ctx, this.opts)\n if (!this.output || typeof this.output.write !== 'function') {\n throw new Error('tui: no output stream; pass opts.output')\n }\n this._overlayMap = {}\n var size0 = bareTuiSize(ctx, this.opts)\n if (this.opts.buffer === 'cell') {\n this.renderer = new BareTuiCellRenderer(this.output, {\n rows: this.opts.height || size0.height,\n cols: this.opts.width || size0.width\n })\n } else {\n this.renderer = new BareTuiRenderer(this.output)\n }\n}\n\nBareTuiProgram.prototype.setOverlay = function (id, spec) {\n if (!id) return\n if (!spec) {\n delete this._overlayMap[id]\n return\n }\n this._overlayMap[id] = spec\n}\n\nBareTuiProgram.prototype.clearOverlay = function (id) {\n if (id) delete this._overlayMap[id]\n else this._overlayMap = {}\n}\n\nBareTuiProgram.prototype._overlaysForPaint = function () {\n var out = []\n var id\n for (id in this._overlayMap) {\n if (\n Object.prototype.hasOwnProperty.call(this._overlayMap, id) &&\n this._overlayMap[id]\n ) {\n out.push(this._overlayMap[id])\n }\n }\n var model = this.model\n if (!model) return out\n var size = bareTuiSize(this.ctx, this.opts)\n if (typeof model.overlays === 'function') {\n var list = model.overlays(size) || []\n var i\n for (i = 0; i < list.length; i++) if (list[i]) out.push(list[i])\n } else if (typeof model.overlay === 'function') {\n var one = model.overlay(size)\n if (one) out.push(one)\n }\n return out\n}\n\nBareTuiProgram.prototype._paint = function () {\n var view = this._view()\n if (this.renderer && this.renderer.mode === 'cell') {\n var sz = bareTuiSize(this.ctx, this.opts)\n this.renderer.resize(\n this.opts.height || sz.height,\n this.opts.width || sz.width\n )\n this.renderer.render(view, this._overlaysForPaint())\n } else {\n this.renderer.render(view)\n }\n}\n\nBareTuiProgram.prototype.send = function (msg) {\n if (!msg) return\n this._queue.push(msg)\n if (this._wake) {\n var wake = this._wake\n this._wake = null\n wake()\n }\n}\n\nBareTuiProgram.prototype.quit = function () {\n this.send({ type: 'quit' })\n}\n\nBareTuiProgram.prototype.run = async function () {\n this._running = true\n bareTuiActivePrograms.push(this)\n var acquired = false\n var entered = false\n try {\n if (\n !this.opts.input &&\n !this.opts.allowDumb &&\n !bareTuiIsTTY(this.ctx, this.opts)\n ) {\n if (\n this.ctx &&\n this.ctx.console &&\n typeof this.ctx.console.error === 'function'\n ) {\n this.ctx.console.error('tui: needs a TTY')\n }\n if (\n this.ctx &&\n (this.ctx.exitCode === undefined || this.ctx.exitCode === null)\n ) {\n this.ctx.exitCode = 1\n }\n return this.model\n }\n bareTuiAcquire(this.ctx, this.opts)\n acquired = true\n bareTuiScreenEnter(this.ctx, this.opts)\n entered = true\n this._setupInput()\n if (typeof this.model.init === 'function') this._exec(this.model.init())\n var size = bareTuiSize(this.ctx, this.opts)\n this.send({ type: 'resize', width: size.width, height: size.height })\n this._paint()\n while (this._running) {\n var msg = await this._next()\n if (!msg) continue\n if (msg.type === 'quit') break\n if (msg.type === 'resize') this.renderer.clear()\n var pair = this._update(msg)\n this.model = pair[0]\n this._invalidate()\n this._exec(pair[1])\n }\n } finally {\n this._running = false\n this._cancelFrame()\n if (this._needsRender) {\n this._needsRender = false\n try {\n this._paint()\n } catch (e) {\n /* ignore */\n }\n }\n this._teardownInput()\n if (entered) {\n try {\n bareTuiScreenLeave(this.ctx, this.opts)\n } catch (e2) {\n /* ignore */\n }\n }\n if (acquired) {\n try {\n bareTuiRelease(this.ctx, this.opts)\n } catch (e3) {\n /* ignore */\n }\n }\n var idx = bareTuiActivePrograms.indexOf(this)\n if (idx >= 0) bareTuiActivePrograms.splice(idx, 1)\n }\n return this.model\n}\n\nBareTuiProgram.prototype._invalidate = function () {\n var self = this\n if (this._suspended) return\n if (this._frameMs === 0) {\n this._paint()\n return\n }\n this._needsRender = true\n if (this._frameTimer) return\n this._frameTimer = setTimeout(function () {\n self._frameTimer = null\n if (self._needsRender) {\n self._needsRender = false\n self._paint()\n }\n }, this._frameMs)\n}\n\nBareTuiProgram.prototype._cancelFrame = function () {\n if (this._frameTimer) {\n clearTimeout(this._frameTimer)\n this._frameTimer = null\n }\n}\n\nBareTuiProgram.prototype._setupInput = function () {\n var self = this\n this._decoder = bareTuiCreateDecoder()\n this._onInput = function (data) {\n self._decoder.push(data)\n if (self._escTimer) {\n clearTimeout(self._escTimer)\n self._escTimer = null\n }\n var evs = self._decoder.take()\n var i\n for (i = 0; i < evs.length; i++) self.send(evs[i])\n if (self._decoder.pending()) {\n self._escTimer = setTimeout(function () {\n self._escTimer = null\n var esc = self._decoder.flushEscape()\n if (esc) self.send(esc)\n var more = self._decoder.take()\n var j\n for (j = 0; j < more.length; j++) self.send(more[j])\n }, 50)\n }\n }\n if (this.input && typeof this.input.on === 'function') {\n this.input.on('data', this._onInput)\n }\n if (this.output && typeof this.output.on === 'function') {\n this._onResize = function () {\n var sz = bareTuiSize(self.ctx, self.opts)\n self.send({ type: 'resize', width: sz.width, height: sz.height })\n }\n this.output.on('resize', this._onResize)\n }\n var sig = this.opts.signal\n if (sig && typeof sig.addEventListener === 'function') {\n this._abortOn = function () {\n self.quit()\n }\n if (sig.aborted) this.quit()\n else sig.addEventListener('abort', this._abortOn)\n }\n}\n\nBareTuiProgram.prototype._teardownInput = function () {\n if (this._tornDown) return\n this._tornDown = true\n this._cancelFrame()\n if (this._escTimer) {\n clearTimeout(this._escTimer)\n this._escTimer = null\n }\n try {\n if (\n this.input &&\n this._onInput &&\n typeof this.input.removeListener === 'function'\n ) {\n this.input.removeListener('data', this._onInput)\n }\n } catch (e) {\n /* ignore */\n }\n try {\n if (\n this.output &&\n this._onResize &&\n typeof this.output.removeListener === 'function'\n ) {\n this.output.removeListener('resize', this._onResize)\n }\n } catch (e2) {\n /* ignore */\n }\n if (\n this.opts.signal &&\n this._abortOn &&\n typeof this.opts.signal.removeEventListener === 'function'\n ) {\n try {\n this.opts.signal.removeEventListener('abort', this._abortOn)\n } catch (e3) {\n /* ignore */\n }\n }\n}\n\nBareTuiProgram.prototype._suspendTerminal = function () {\n this._suspended = true\n this._cancelFrame()\n try {\n if (\n this.input &&\n this._onInput &&\n typeof this.input.removeListener === 'function'\n ) {\n this.input.removeListener('data', this._onInput)\n }\n } catch (e) {\n /* ignore */\n }\n try {\n if (this.input && typeof this.input.pause === 'function') this.input.pause()\n } catch (e2) {\n /* ignore */\n }\n try {\n bareTuiScreenLeave(this.ctx, this.opts)\n } catch (e3) {\n /* ignore */\n }\n}\n\nBareTuiProgram.prototype._resumeTerminal = function () {\n try {\n bareTuiScreenEnter(this.ctx, this.opts)\n } catch (e) {\n /* ignore */\n }\n if (this.input && this._onInput && typeof this.input.on === 'function') {\n this.input.on('data', this._onInput)\n }\n try {\n if (this.input && typeof this.input.resume === 'function')\n this.input.resume()\n } catch (e2) {\n /* ignore */\n }\n this.renderer.clear()\n this._suspended = false\n}\n\nBareTuiProgram.prototype._update = function (msg) {\n if (!this.model || typeof this.model.update !== 'function')\n return [this.model, null]\n var ret = this.model.update(msg)\n if (ret === undefined || ret === null) return [this.model, null]\n if (Array.isArray(ret))\n return [\n ret[0] != null ? ret[0] : this.model,\n ret[1] != null ? ret[1] : null\n ]\n return [ret, null]\n}\n\nBareTuiProgram.prototype._view = function () {\n try {\n if (!this.model || typeof this.model.view !== 'function') return ''\n return String(this.model.view())\n } catch (err) {\n return 'view error: ' + (err && err.message)\n }\n}\n\nBareTuiProgram.prototype._exec = function (cmd) {\n this._runCmd(cmd)\n}\n\nBareTuiProgram.prototype._runCmd = async function (cmd) {\n if (!cmd || !this._running) return\n var self = this\n if (Array.isArray(cmd)) {\n await Promise.all(\n cmd.map(function (c) {\n return self._runCmd(c)\n })\n )\n return\n }\n if (cmd.__seq) {\n var i\n for (i = 0; i < cmd.__seq.length; i++) {\n if (!this._running) return\n await this._runCmd(cmd.__seq[i])\n }\n return\n }\n if (cmd.__suspend) {\n this._suspendTerminal()\n var msg = null\n try {\n msg = await cmd.__suspend()\n } catch (error) {\n msg = { type: 'error', error: error }\n }\n if (this._running) {\n this._resumeTerminal()\n this._invalidate()\n }\n this.send(msg)\n return\n }\n if (typeof cmd !== 'function') return\n try {\n this.send(await cmd())\n } catch (error) {\n this.send({ type: 'error', error: error })\n }\n}\n\nBareTuiProgram.prototype._next = async function () {\n var self = this\n if (this._queue.length === 0) {\n await new Promise(function (resolve) {\n self._wake = resolve\n })\n }\n return this._queue.shift()\n}\n\nfunction bareTuiCreateProgram(ctx, model, opts) {\n return new BareTuiProgram(ctx, model, opts)\n}\n\nfunction bareTuiRunProgram(ctx, model, opts) {\n return bareTuiCreateProgram(ctx, model, opts).run()\n}\n\nfunction bareTuiSendActive(ctx, msg) {\n var p = bareTuiActiveProgram(ctx)\n if (p) p.send(msg)\n}\n\n/* src/widgets/spinner.js */\n/** Cmd-driven spinner. Route spinner.tick and thread the Cmd up. */\n\nvar BARE_TUI_SPINNER_DOTS = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']\nvar BARE_TUI_SPINNER_LINE = ['|', '/', '-', '\\\\']\nvar BARE_TUI_SPINNER_POINTS = ['∙∙∙', '●∙∙', '∙●∙', '∙∙●']\n\nfunction BareTuiSpinner(opts) {\n opts = opts || {}\n this.frames = opts.frames || BARE_TUI_SPINNER_DOTS\n this.fps = opts.fps || 10\n this.frame = 0\n this.id = bareTuiNextWidgetId++\n this.tag = 0\n}\n\nBareTuiSpinner.prototype.init = function () {\n return this._tick()\n}\n\nBareTuiSpinner.prototype._tick = function () {\n var id = this.id\n var tag = this.tag\n var ms = Math.max(1, Math.round(1000 / this.fps))\n return bareTuiTick(ms, function () {\n return { type: 'spinner.tick', id: id, tag: tag }\n })\n}\n\nBareTuiSpinner.prototype.update = function (msg) {\n if (!msg || msg.type !== 'spinner.tick') return [this, null]\n if (msg.id !== this.id || msg.tag !== this.tag) return [this, null]\n this.frame = (this.frame + 1) % this.frames.length\n this.tag++\n return [this, this._tick()]\n}\n\nBareTuiSpinner.prototype.view = function () {\n return this.frames[this.frame]\n}\n\nvar bareTuiSpinner = {\n create: function (opts) {\n return new BareTuiSpinner(opts)\n },\n dots: BARE_TUI_SPINNER_DOTS,\n line: BARE_TUI_SPINNER_LINE,\n points: BARE_TUI_SPINNER_POINTS\n}\n\n/* src/widgets/textinput.js */\n/** Single-line field. Consumes keys only when focused. */\n\nfunction BareTuiTextInput(opts) {\n opts = opts || {}\n this.value = opts.value || ''\n this.placeholder = opts.placeholder || ''\n this.prompt = opts.prompt || ''\n this.charLimit = opts.charLimit || 0\n this.echoMode = opts.echoMode || 'normal'\n this.maskChar = opts.maskChar || '•'\n this.focused = !!opts.focused\n this.cursor = this.value.length\n}\n\nBareTuiTextInput.prototype.focus = function () {\n this.focused = true\n return this\n}\nBareTuiTextInput.prototype.blur = function () {\n this.focused = false\n return this\n}\nBareTuiTextInput.prototype.setValue = function (v) {\n v = String(v)\n this.value = this.charLimit ? v.slice(0, this.charLimit) : v\n if (this.cursor > this.value.length) this.cursor = this.value.length\n return this\n}\nBareTuiTextInput.prototype.reset = function () {\n this.value = ''\n this.cursor = 0\n return this\n}\n\nBareTuiTextInput.prototype.update = function (msg) {\n if (!this.focused || !msg || msg.type !== 'key') return [this, null]\n if (msg.is('left')) this.cursor = Math.max(0, this.cursor - 1)\n else if (msg.is('right'))\n this.cursor = Math.min(this.value.length, this.cursor + 1)\n else if (msg.is('home')) this.cursor = 0\n else if (msg.is('end')) this.cursor = this.value.length\n else if (msg.is('backspace')) {\n if (this.cursor > 0) {\n this.value =\n this.value.slice(0, this.cursor - 1) + this.value.slice(this.cursor)\n this.cursor--\n }\n } else if (msg.is('delete')) {\n if (this.cursor < this.value.length) {\n this.value =\n this.value.slice(0, this.cursor) + this.value.slice(this.cursor + 1)\n }\n } else this._insert(msg)\n return [this, null]\n}\n\nBareTuiTextInput.prototype._insert = function (msg) {\n var ch = msg.sequence\n var printable =\n !msg.ctrl &&\n !msg.meta &&\n typeof ch === 'string' &&\n ch.length === 1 &&\n ch >= ' ' &&\n ch !== '\\x7f'\n if (!printable) return\n if (this.charLimit && this.value.length >= this.charLimit) return\n this.value =\n this.value.slice(0, this.cursor) + ch + this.value.slice(this.cursor)\n this.cursor++\n}\n\nBareTuiTextInput.prototype._display = function () {\n if (this.echoMode === 'password') {\n var s = ''\n var i\n for (i = 0; i < this.value.length; i++) s += this.maskChar\n return s\n }\n return this.value\n}\n\nBareTuiTextInput.prototype.view = function () {\n var rev = function (s) {\n return bareTuiAnsi.modifierReverse + s + bareTuiAnsi.modifierNotReverse\n }\n var dim = function (s) {\n return bareTuiAnsi.modifierDim + s + bareTuiAnsi.reset\n }\n if (this.value.length === 0) {\n if (!this.focused) return this.prompt + dim(this.placeholder)\n var head = this.placeholder.slice(0, 1) || ' '\n return this.prompt + rev(head) + dim(this.placeholder.slice(1))\n }\n var text = this._display()\n if (!this.focused) return this.prompt + text\n var at = text.slice(this.cursor, this.cursor + 1) || ' '\n return (\n this.prompt +\n text.slice(0, this.cursor) +\n rev(at) +\n text.slice(this.cursor + 1)\n )\n}\n\nvar bareTuiTextinput = {\n create: function (opts) {\n return new BareTuiTextInput(opts)\n }\n}\n\n/* src/widgets/choices.js */\n/** Checkbox, radio, and compact select. Focus-gated. */\n\nfunction BareTuiCheckbox(opts) {\n opts = opts || {}\n this.label = opts.label || ''\n this.checked = !!opts.checked\n this.focused = !!opts.focused\n this.checkedGlyph = opts.checkedGlyph || '[x]'\n this.uncheckedGlyph = opts.uncheckedGlyph || '[ ]'\n}\nBareTuiCheckbox.prototype.focus = function () {\n this.focused = true\n return this\n}\nBareTuiCheckbox.prototype.blur = function () {\n this.focused = false\n return this\n}\nBareTuiCheckbox.prototype.setChecked = function (v) {\n this.checked = !!v\n return this\n}\nBareTuiCheckbox.prototype.toggle = function () {\n this.checked = !this.checked\n return this\n}\nBareTuiCheckbox.prototype.update = function (msg) {\n if (!this.focused || !msg || msg.type !== 'key') return [this, null]\n if (msg.is('space')) this.toggle()\n return [this, null]\n}\nBareTuiCheckbox.prototype.view = function () {\n var pointer = this.focused ? ' ' : ' '\n var box = this.checked ? this.checkedGlyph : this.uncheckedGlyph\n return pointer + (this.label ? box + ' ' + this.label : box)\n}\n\nfunction bareTuiNormOptions(opts) {\n var raw = (opts && opts.options) || []\n var out = []\n var i\n for (i = 0; i < raw.length; i++) {\n var it = raw[i]\n if (it && typeof it === 'object') {\n out.push({\n label: it.label != null ? String(it.label) : String(it.value),\n value: it.value\n })\n } else {\n out.push({ label: String(it), value: it })\n }\n }\n return out\n}\n\nfunction BareTuiRadio(opts) {\n opts = opts || {}\n this.options = bareTuiNormOptions(opts)\n this.selected = opts.selected | 0\n this.focused = !!opts.focused\n if (this.selected < 0) this.selected = 0\n if (this.selected >= this.options.length)\n this.selected = Math.max(0, this.options.length - 1)\n}\nBareTuiRadio.prototype.focus = function () {\n this.focused = true\n return this\n}\nBareTuiRadio.prototype.blur = function () {\n this.focused = false\n return this\n}\nBareTuiRadio.prototype.value = function () {\n var o = this.options[this.selected]\n return o ? o.value : null\n}\nBareTuiRadio.prototype.update = function (msg) {\n if (!this.focused || !msg || msg.type !== 'key') return [this, null]\n if (msg.is('up', 'k')) this.selected = Math.max(0, this.selected - 1)\n else if (msg.is('down', 'j'))\n this.selected = Math.min(this.options.length - 1, this.selected + 1)\n return [this, null]\n}\nBareTuiRadio.prototype.view = function () {\n var lines = []\n var i\n for (i = 0; i < this.options.length; i++) {\n var mark = i === this.selected ? '(•)' : '( )'\n var ptr = this.focused && i === this.selected ? ' ' : ' '\n lines.push(ptr + mark + ' ' + this.options[i].label)\n }\n return lines.join('\\n')\n}\n\nfunction BareTuiSelect(opts) {\n opts = opts || {}\n this.options = bareTuiNormOptions(opts)\n this.selected = opts.selected | 0\n this.placeholder = opts.placeholder || ''\n this.focused = !!opts.focused\n this.open = false\n if (this.selected < 0) this.selected = 0\n}\nBareTuiSelect.prototype.focus = function () {\n this.focused = true\n return this\n}\nBareTuiSelect.prototype.blur = function () {\n this.focused = false\n this.open = false\n return this\n}\nBareTuiSelect.prototype.value = function () {\n var o = this.options[this.selected]\n return o ? o.value : null\n}\nBareTuiSelect.prototype.update = function (msg) {\n if (!this.focused || !msg || msg.type !== 'key') return [this, null]\n if (!this.open) {\n if (msg.is('enter', 'space', 'down')) this.open = true\n return [this, null]\n }\n if (msg.is('esc')) this.open = false\n else if (msg.is('enter')) this.open = false\n else if (msg.is('up', 'k')) this.selected = Math.max(0, this.selected - 1)\n else if (msg.is('down', 'j'))\n this.selected = Math.min(this.options.length - 1, this.selected + 1)\n return [this, null]\n}\nBareTuiSelect.prototype.view = function () {\n var cur = this.options[this.selected]\n var label = cur ? cur.label : this.placeholder\n var ptr = this.focused ? ' ' : ' '\n return ptr + (label || this.placeholder)\n}\nBareTuiSelect.prototype.menuView = function () {\n if (!this.open) return ''\n var lines = []\n var i\n for (i = 0; i < this.options.length; i++) {\n var mark = i === this.selected ? ' ' : ' '\n lines.push(mark + this.options[i].label)\n }\n return lines.join('\\n')\n}\n\nvar bareTuiCheckbox = {\n create: function (opts) {\n return new BareTuiCheckbox(opts)\n }\n}\nvar bareTuiRadio = {\n create: function (opts) {\n return new BareTuiRadio(opts)\n }\n}\nvar bareTuiSelect = {\n create: function (opts) {\n return new BareTuiSelect(opts)\n }\n}\n\n/* src/widgets/scroll.js */\n/** Viewport and paginator. */\n\nfunction BareTuiViewport(opts) {\n opts = opts || {}\n this.width = opts.width || 0\n this.height = opts.height || 0\n this.yOffset = 0\n this.lines = []\n}\nBareTuiViewport.prototype.setContent = function (content) {\n this.lines = String(content).split('\\n')\n this._clamp()\n return this\n}\nBareTuiViewport.prototype._max = function () {\n return Math.max(0, this.lines.length - this.height)\n}\nBareTuiViewport.prototype.atTop = function () {\n return this.yOffset <= 0\n}\nBareTuiViewport.prototype.atBottom = function () {\n return this.yOffset >= this._max()\n}\nBareTuiViewport.prototype.setYOffset = function (n) {\n this.yOffset = n\n this._clamp()\n return this\n}\nBareTuiViewport.prototype.scrollUp = function (n) {\n return this.setYOffset(this.yOffset - (n == null ? 1 : n))\n}\nBareTuiViewport.prototype.scrollDown = function (n) {\n return this.setYOffset(this.yOffset + (n == null ? 1 : n))\n}\nBareTuiViewport.prototype.gotoTop = function () {\n return this.setYOffset(0)\n}\nBareTuiViewport.prototype.gotoBottom = function () {\n return this.setYOffset(this._max())\n}\nBareTuiViewport.prototype._clamp = function () {\n var max = this._max()\n if (this.yOffset < 0) this.yOffset = 0\n if (this.yOffset > max) this.yOffset = max\n}\nBareTuiViewport.prototype.update = function (msg) {\n if (!msg || msg.type !== 'key') return [this, null]\n var h = this.height || 1\n if (msg.is('up', 'k')) this.scrollUp(1)\n else if (msg.is('down', 'j')) this.scrollDown(1)\n else if (msg.is('pageup', 'b')) this.scrollUp(h)\n else if (msg.is('pagedown', 'f')) this.scrollDown(h)\n else if (msg.is('home')) this.gotoTop()\n else if (msg.is('end')) this.gotoBottom()\n return [this, null]\n}\nBareTuiViewport.prototype.view = function () {\n var out = []\n var i\n for (i = 0; i < this.height; i++) {\n var line = this.lines[this.yOffset + i]\n if (line == null) line = ''\n if (this.width > 0) line = bareTuiTruncate(line, this.width)\n out.push(line)\n }\n return out.join('\\n')\n}\n\nfunction BareTuiPaginator(opts) {\n opts = opts || {}\n this.perPage = opts.perPage || 10\n this.total = opts.total || 0\n this.page = opts.page || 0\n this.kind = opts.type || 'dots'\n}\nBareTuiPaginator.prototype.pages = function () {\n if (this.perPage <= 0) return 1\n return Math.max(1, Math.ceil(this.total / this.perPage))\n}\nBareTuiPaginator.prototype.update = function (msg) {\n if (!msg || msg.type !== 'key') return [this, null]\n var n = this.pages()\n if (msg.is('left', 'h', 'pageup')) this.page = Math.max(0, this.page - 1)\n else if (msg.is('right', 'l', 'pagedown'))\n this.page = Math.min(n - 1, this.page + 1)\n return [this, null]\n}\nBareTuiPaginator.prototype.view = function () {\n var n = this.pages()\n if (this.kind === 'arabic') return this.page + 1 + '/' + n\n var s = ''\n var i\n for (i = 0; i < n; i++) s += i === this.page ? '●' : '○'\n return s\n}\n\nvar bareTuiViewport = {\n create: function (opts) {\n return new BareTuiViewport(opts)\n }\n}\nvar bareTuiPaginator = {\n create: function (opts) {\n return new BareTuiPaginator(opts)\n }\n}\n\n/* src/widgets/list.js */\n/** Selectable, optionally filterable list. */\n\nfunction bareTuiItemTitle(item) {\n if (item == null) return ''\n if (typeof item === 'string') return item\n return item.title != null ? String(item.title) : String(item)\n}\nfunction bareTuiItemFilter(item) {\n if (item == null) return ''\n if (typeof item === 'string') return item\n return String(item.filterValue || item.title || item)\n}\n\nfunction BareTuiList(opts) {\n opts = opts || {}\n this.items = opts.items ? opts.items.slice() : []\n this.height = opts.height || 10\n this.width = opts.width || 0\n this.title = opts.title || ''\n this.filterable = opts.filterable !== false\n this.input = bareTuiTextinput.create({ prompt: '' })\n this.filter = ''\n this.filtering = false\n this.selected = 0\n this.offset = 0\n this.filtered = []\n this._applyFilter()\n}\nBareTuiList.prototype.selectedItem = function () {\n if (!this.filtered.length) return null\n return this.items[this.filtered[this.selected]]\n}\nBareTuiList.prototype.setItems = function (items) {\n this.items = items.slice()\n this._applyFilter()\n return this\n}\nBareTuiList.prototype._applyFilter = function () {\n var q = this.filter.toLowerCase()\n this.filtered = []\n var i\n for (i = 0; i < this.items.length; i++) {\n if (!q || bareTuiItemFilter(this.items[i]).toLowerCase().indexOf(q) >= 0) {\n this.filtered.push(i)\n }\n }\n if (this.selected >= this.filtered.length)\n this.selected = Math.max(0, this.filtered.length - 1)\n this._keepVisible()\n}\nBareTuiList.prototype._keepVisible = function () {\n if (this.selected < this.offset) this.offset = this.selected\n if (this.selected >= this.offset + this.height)\n this.offset = this.selected - this.height + 1\n if (this.offset < 0) this.offset = 0\n}\nBareTuiList.prototype.update = function (msg) {\n if (!msg || msg.type !== 'key') return [this, null]\n if (this.filtering) {\n if (msg.is('escape', 'esc')) {\n this.filtering = false\n this.filter = ''\n this.input.reset().blur()\n this._applyFilter()\n return [this, null]\n }\n if (msg.is('enter')) {\n this.filtering = false\n this.input.blur()\n return [this, null]\n }\n var pair = this.input.update(msg)\n this.input = pair[0]\n this.filter = this.input.value\n this._applyFilter()\n return [this, pair[1]]\n }\n if (this.filterable && msg.is('/')) {\n this.filtering = true\n this.input.focus()\n return [this, null]\n }\n if (msg.is('up', 'k')) this.selected = Math.max(0, this.selected - 1)\n else if (msg.is('down', 'j'))\n this.selected = Math.min(this.filtered.length - 1, this.selected + 1)\n else if (msg.is('pageup'))\n this.selected = Math.max(0, this.selected - this.height)\n else if (msg.is('pagedown')) {\n this.selected = Math.min(\n this.filtered.length - 1,\n this.selected + this.height\n )\n }\n this._keepVisible()\n return [this, null]\n}\nBareTuiList.prototype.view = function () {\n var lines = []\n if (this.title) lines.push(this.title)\n if (this.filtering) lines.push('/' + this.input.value)\n var i\n for (i = 0; i < this.height; i++) {\n var idx = this.offset + i\n if (idx >= this.filtered.length) {\n lines.push('')\n continue\n }\n var item = this.items[this.filtered[idx]]\n var title = bareTuiItemTitle(item)\n if (this.width > 0) title = bareTuiTruncate(title, this.width)\n if (idx === this.selected) {\n title =\n bareTuiAnsi.modifierReverse + title + bareTuiAnsi.modifierNotReverse\n }\n lines.push(title)\n }\n return lines.join('\\n')\n}\n\nvar bareTuiList = {\n create: function (opts) {\n return new BareTuiList(opts)\n }\n}\n\n/* src/widgets/rest.js */\n/** Progress, table, textarea, help, focus, stopwatch, timer, autocomplete. */\n\nfunction BareTuiProgress(opts) {\n opts = opts || {}\n this.width = opts.width || 40\n this.full = opts.full || '█'\n this.empty = opts.empty || '░'\n this.showPercentage = opts.showPercentage !== false\n}\nBareTuiProgress.prototype.setWidth = function (n) {\n this.width = n\n return this\n}\nBareTuiProgress.prototype.view = function (percent) {\n percent = Math.max(0, Math.min(1, percent || 0))\n var reserve = this.showPercentage ? 5 : 0\n var w = Math.max(1, this.width - reserve)\n var filled = Math.round(w * percent)\n var gap = w - filled\n var bar = bareTuiRepeat(this.full, filled) + bareTuiRepeat(this.empty, gap)\n if (!this.showPercentage) return bar\n var pct = Math.round(percent * 100)\n var label = String(pct) + '%'\n while (label.length < 4) label = ' ' + label\n return bar + ' ' + label\n}\n\nfunction BareTuiTable(opts) {\n opts = opts || {}\n this.columns = opts.columns || []\n this.rows = opts.rows || []\n this.height = opts.height || 8\n this.selected = 0\n this.offset = 0\n}\nBareTuiTable.prototype.update = function (msg) {\n if (!msg || msg.type !== 'key') return [this, null]\n if (msg.is('up', 'k')) this.selected = Math.max(0, this.selected - 1)\n else if (msg.is('down', 'j'))\n this.selected = Math.min(this.rows.length - 1, this.selected + 1)\n if (this.selected < this.offset) this.offset = this.selected\n if (this.selected >= this.offset + this.height)\n this.offset = this.selected - this.height + 1\n return [this, null]\n}\nBareTuiTable.prototype.selectedRow = function () {\n return this.rows[this.selected] || null\n}\nBareTuiTable.prototype.view = function () {\n var lines = []\n var cols = this.columns\n var header = []\n var i\n for (i = 0; i < cols.length; i++) {\n var c = cols[i]\n header.push(typeof c === 'string' ? c : c.title || c.key || '')\n }\n lines.push(header.join(' '))\n var r\n for (r = 0; r < this.height; r++) {\n var idx = this.offset + r\n var row = this.rows[idx]\n if (!row) {\n lines.push('')\n continue\n }\n var cells = []\n for (i = 0; i < cols.length; i++) {\n var col = cols[i]\n var key = typeof col === 'string' ? col : col.key\n var val = Array.isArray(row) ? row[i] : row[key]\n cells.push(val == null ? '' : String(val))\n }\n var line = cells.join(' ')\n if (idx === this.selected)\n line = bareTuiAnsi.modifierReverse + line + bareTuiAnsi.modifierNotReverse\n lines.push(line)\n }\n return lines.join('\\n')\n}\n\nfunction BareTuiTextarea(opts) {\n opts = opts || {}\n this.lines = String(opts.value || '').split('\\n')\n if (!this.lines.length) this.lines = ['']\n this.width = opts.width || 40\n this.height = opts.height || 6\n this.placeholder = opts.placeholder || ''\n this.charLimit = opts.charLimit || 0\n this.focused = !!opts.focused\n this.row = 0\n this.col = 0\n}\nBareTuiTextarea.prototype.focus = function () {\n this.focused = true\n return this\n}\nBareTuiTextarea.prototype.blur = function () {\n this.focused = false\n return this\n}\nBareTuiTextarea.prototype.value = function () {\n return this.lines.join('\\n')\n}\nBareTuiTextarea.prototype.update = function (msg) {\n if (!this.focused || !msg || msg.type !== 'key') return [this, null]\n var line = this.lines[this.row] || ''\n if (msg.is('up')) this.row = Math.max(0, this.row - 1)\n else if (msg.is('down'))\n this.row = Math.min(this.lines.length - 1, this.row + 1)\n else if (msg.is('left')) {\n if (this.col > 0) this.col--\n else if (this.row > 0) {\n this.row--\n this.col = (this.lines[this.row] || '').length\n }\n } else if (msg.is('right')) {\n if (this.col < line.length) this.col++\n else if (this.row < this.lines.length - 1) {\n this.row++\n this.col = 0\n }\n } else if (msg.is('enter')) {\n var left = line.slice(0, this.col)\n var right = line.slice(this.col)\n this.lines[this.row] = left\n this.lines.splice(this.row + 1, 0, right)\n this.row++\n this.col = 0\n } else if (msg.is('backspace')) {\n if (this.col > 0) {\n this.lines[this.row] = line.slice(0, this.col - 1) + line.slice(this.col)\n this.col--\n } else if (this.row > 0) {\n var prev = this.lines[this.row - 1]\n this.col = prev.length\n this.lines[this.row - 1] = prev + line\n this.lines.splice(this.row, 1)\n this.row--\n }\n } else if (\n !msg.ctrl &&\n !msg.meta &&\n msg.sequence &&\n msg.sequence.length === 1 &&\n msg.sequence >= ' '\n ) {\n var all = this.value()\n if (this.charLimit && all.length >= this.charLimit) return [this, null]\n this.lines[this.row] =\n line.slice(0, this.col) + msg.sequence + line.slice(this.col)\n this.col++\n }\n if (this.col > (this.lines[this.row] || '').length)\n this.col = (this.lines[this.row] || '').length\n return [this, null]\n}\nBareTuiTextarea.prototype.view = function () {\n if (!this.value() && this.placeholder && !this.focused) {\n return bareTuiAnsi.modifierDim + this.placeholder + bareTuiAnsi.reset\n }\n var out = []\n var i\n for (i = 0; i < this.height; i++) {\n var line = this.lines[i] || ''\n if (this.focused && i === this.row) {\n var at = line.slice(this.col, this.col + 1) || ' '\n line =\n line.slice(0, this.col) +\n bareTuiAnsi.modifierReverse +\n at +\n bareTuiAnsi.modifierNotReverse +\n line.slice(this.col + 1)\n }\n if (this.width > 0) line = bareTuiTruncate(line, this.width)\n out.push(line)\n }\n return out.join('\\n')\n}\n\nfunction BareTuiHelp() {}\nBareTuiHelp.prototype.view = function (keymap) {\n if (!keymap) return ''\n var parts = []\n var k\n for (k in keymap) {\n if (!Object.prototype.hasOwnProperty.call(keymap, k)) continue\n var b = keymap[k]\n var help = b && b.help\n if (help) parts.push((help.key || k) + ' ' + (help.desc || ''))\n else if (b && b.keys) parts.push(b.keys.join('/') + ' ' + k)\n }\n return parts.join(' · ')\n}\n\nfunction BareTuiFocus(opts) {\n opts = opts || {}\n this.items = opts.items ? opts.items.slice() : []\n this.index = opts.index || 0\n this._clamp()\n this._sync()\n}\nBareTuiFocus.prototype.focused = function () {\n return this.items[this.index] || null\n}\nBareTuiFocus.prototype.setItems = function (items) {\n this.items = items ? items.slice() : []\n this._clamp()\n this._sync()\n return this\n}\nBareTuiFocus.prototype.focus = function (i) {\n this.index = i\n this._clamp()\n this._sync()\n return this\n}\nBareTuiFocus.prototype.next = function () {\n this._move(1)\n return this\n}\nBareTuiFocus.prototype.prev = function () {\n this._move(-1)\n return this\n}\nBareTuiFocus.prototype.update = function (msg) {\n if (msg && msg.type === 'key' && msg.is('shift+tab')) {\n this._move(-1)\n return [this, null]\n }\n if (msg && msg.type === 'key' && msg.is('tab')) {\n this._move(1)\n return [this, null]\n }\n var cur = this.items[this.index]\n if (cur && typeof cur.update === 'function') {\n var pair = cur.update(msg)\n this.items[this.index] = pair[0]\n return [this, pair[1]]\n }\n return [this, null]\n}\nBareTuiFocus.prototype._move = function (dir) {\n if (this.items.length < 2) return\n this.index = (this.index + dir + this.items.length) % this.items.length\n this._sync()\n}\nBareTuiFocus.prototype._clamp = function () {\n if (!this.items.length) this.index = 0\n else {\n if (this.index < 0) this.index = 0\n if (this.index > this.items.length - 1) this.index = this.items.length - 1\n }\n}\nBareTuiFocus.prototype._sync = function () {\n var i\n for (i = 0; i < this.items.length; i++) {\n var it = this.items[i]\n if (!it) continue\n if (i === this.index) {\n if (typeof it.focus === 'function') it.focus()\n } else if (typeof it.blur === 'function') it.blur()\n }\n}\n\nfunction BareTuiStopwatch(opts) {\n opts = opts || {}\n this.interval = opts.interval || 100\n this.elapsed = 0\n this.running = false\n this.id = bareTuiNextWidgetId++\n this.tag = 0\n this._last = 0\n}\nBareTuiStopwatch.prototype.start = function () {\n if (this.running) return this\n this.running = true\n this._last = Date.now()\n return this\n}\nBareTuiStopwatch.prototype.stop = function () {\n this.running = false\n return this\n}\nBareTuiStopwatch.prototype.toggle = function () {\n return this.running ? this.stop() : this.start()\n}\nBareTuiStopwatch.prototype.reset = function () {\n this.elapsed = 0\n this._last = Date.now()\n return this\n}\nBareTuiStopwatch.prototype.init = function () {\n return this._tick()\n}\nBareTuiStopwatch.prototype._tick = function () {\n var id = this.id\n var tag = this.tag\n var ms = this.interval\n return bareTuiTick(ms, function () {\n return { type: 'stopwatch.tick', id: id, tag: tag }\n })\n}\nBareTuiStopwatch.prototype.update = function (msg) {\n if (msg && msg.type === 'key' && msg.is('space')) {\n this.toggle()\n return [this, null]\n }\n if (\n !msg ||\n msg.type !== 'stopwatch.tick' ||\n msg.id !== this.id ||\n msg.tag !== this.tag\n ) {\n return [this, null]\n }\n if (this.running) {\n var now = Date.now()\n this.elapsed += now - this._last\n this._last = now\n }\n this.tag++\n return [this, this._tick()]\n}\nBareTuiStopwatch.prototype.view = function () {\n var ms = this.elapsed\n var s = Math.floor(ms / 1000)\n var m = Math.floor(s / 60)\n s = s % 60\n var mm = m < 10 ? '0' + m : String(m)\n var ss = s < 10 ? '0' + s : String(s)\n return mm + ':' + ss\n}\n\nfunction BareTuiTimer(opts) {\n opts = opts || {}\n this.timeout = opts.timeout || 10000\n this.interval = opts.interval || 100\n this.remaining = this.timeout\n this.running = true\n this.id = bareTuiNextWidgetId++\n this.tag = 0\n this._last = Date.now()\n}\nBareTuiTimer.prototype.init = function () {\n return this._tick()\n}\nBareTuiTimer.prototype._tick = function () {\n var id = this.id\n var tag = this.tag\n var ms = this.interval\n return bareTuiTick(ms, function () {\n return { type: 'timer.tick', id: id, tag: tag }\n })\n}\nBareTuiTimer.prototype.update = function (msg) {\n if (\n !msg ||\n msg.type !== 'timer.tick' ||\n msg.id !== this.id ||\n msg.tag !== this.tag\n ) {\n return [this, null]\n }\n if (this.running) {\n var now = Date.now()\n this.remaining -= now - this._last\n this._last = now\n if (this.remaining <= 0) {\n this.remaining = 0\n this.running = false\n this.tag++\n return [\n this,\n function () {\n return { type: 'timer.timeout' }\n }\n ]\n }\n }\n this.tag++\n return [this, this._tick()]\n}\nBareTuiTimer.prototype.view = function () {\n var s = Math.ceil(this.remaining / 1000)\n return String(s) + 's'\n}\n\nfunction BareTuiAutocomplete(opts) {\n opts = opts || {}\n this.input = bareTuiTextinput.create({\n prompt: opts.prompt || '',\n placeholder: opts.placeholder || '',\n focused: opts.focused\n })\n this.suggestions = opts.suggestions || []\n this.trigger = opts.trigger || ''\n this.filtered = []\n this.selected = 0\n this.open = false\n}\nBareTuiAutocomplete.prototype.focus = function () {\n this.input.focus()\n return this\n}\nBareTuiAutocomplete.prototype.blur = function () {\n this.input.blur()\n this.open = false\n return this\n}\nBareTuiAutocomplete.prototype.value = function () {\n return this.input.value\n}\nBareTuiAutocomplete.prototype._refresh = function () {\n var q = this.input.value\n if (this.trigger && q.indexOf(this.trigger) < 0) {\n this.open = false\n this.filtered = []\n return\n }\n var needle = q.toLowerCase()\n this.filtered = []\n var i\n for (i = 0; i < this.suggestions.length; i++) {\n var s = String(this.suggestions[i])\n if (!needle || s.toLowerCase().indexOf(needle) >= 0) this.filtered.push(s)\n }\n this.open = this.filtered.length > 0\n if (this.selected >= this.filtered.length) this.selected = 0\n}\nBareTuiAutocomplete.prototype.update = function (msg) {\n if (!this.input.focused || !msg || msg.type !== 'key') return [this, null]\n if (this.open && msg.is('down')) {\n this.selected = Math.min(this.filtered.length - 1, this.selected + 1)\n return [this, null]\n }\n if (this.open && msg.is('up')) {\n this.selected = Math.max(0, this.selected - 1)\n return [this, null]\n }\n if (this.open && msg.is('enter', 'tab')) {\n if (this.filtered[this.selected] != null)\n this.input.setValue(this.filtered[this.selected])\n this.open = false\n return [this, null]\n }\n var pair = this.input.update(msg)\n this.input = pair[0]\n this._refresh()\n return [this, pair[1]]\n}\nBareTuiAutocomplete.prototype.view = function () {\n var out = this.input.view()\n if (!this.open) return out\n var i\n for (i = 0; i < this.filtered.length && i < 6; i++) {\n var line = this.filtered[i]\n if (i === this.selected)\n line = bareTuiAnsi.modifierReverse + line + bareTuiAnsi.modifierNotReverse\n out += '\\n' + line\n }\n return out\n}\n\nvar bareTuiProgress = {\n create: function (opts) {\n return new BareTuiProgress(opts)\n }\n}\nvar bareTuiTable = {\n create: function (opts) {\n return new BareTuiTable(opts)\n }\n}\nvar bareTuiTextarea = {\n create: function (opts) {\n return new BareTuiTextarea(opts)\n }\n}\nvar bareTuiHelp = {\n create: function () {\n return new BareTuiHelp()\n }\n}\nvar bareTuiFocus = {\n create: function (opts) {\n return new BareTuiFocus(opts)\n }\n}\nvar bareTuiStopwatch = {\n create: function (opts) {\n return new BareTuiStopwatch(opts)\n }\n}\nvar bareTuiTimer = {\n create: function (opts) {\n return new BareTuiTimer(opts)\n }\n}\nvar bareTuiAutocomplete = {\n create: function (opts) {\n return new BareTuiAutocomplete(opts)\n }\n}\n\n/* src/widgets/filepicker.js */\n/** VFS file picker. Inject vfs (or mock). Never opens host fs. */\n\nfunction bareTuiJoinPath(a, b) {\n var left = String(a == null ? '/' : a)\n var right = String(b == null ? '' : b).replace(/^\\/+/, '')\n if (!left || left === '/') return '/' + right\n return left.replace(/\\/+$/, '') + '/' + right\n}\n\nfunction bareTuiDirname(p) {\n p = String(p || '/').replace(/\\/+$/, '')\n if (!p) return '/'\n var i = p.lastIndexOf('/')\n if (i <= 0) return '/'\n return p.slice(0, i)\n}\n\nfunction bareTuiSortEntries(entries, showHidden) {\n var out = []\n var i\n for (i = 0; i < entries.length; i++) {\n if (showHidden || String(entries[i].name).charAt(0) !== '.')\n out.push(entries[i])\n }\n out.sort(function (a, b) {\n if (a.directory !== b.directory) return a.directory ? -1 : 1\n if (a.name < b.name) return -1\n if (a.name > b.name) return 1\n return 0\n })\n return out\n}\n\nfunction bareTuiIsDirStat(st) {\n if (!st) return false\n if (st.type === 'directory') return true\n if (typeof st.isDirectory === 'function') return !!st.isDirectory()\n return false\n}\n\nfunction bareTuiListVfs(vfs, dir) {\n if (!vfs || typeof vfs.readdir !== 'function') {\n return Promise.reject(new Error('filepicker: vfs.readdir missing'))\n }\n return Promise.resolve(vfs.readdir(dir)).then(function (names) {\n var list = names || []\n var i = 0\n var entries = []\n function next() {\n if (i >= list.length) return entries\n var name = list[i++]\n if (name && typeof name === 'object' && name.name) {\n var directory = !!(\n name.directory ||\n (typeof name.isDirectory === 'function' && name.isDirectory())\n )\n entries.push({ name: name.name, directory: directory })\n return next()\n }\n var full = bareTuiJoinPath(dir, name)\n if (typeof vfs.stat !== 'function') {\n entries.push({ name: String(name), directory: false })\n return next()\n }\n return Promise.resolve(vfs.stat(full)).then(\n function (st) {\n entries.push({ name: String(name), directory: bareTuiIsDirStat(st) })\n return next()\n },\n function () {\n entries.push({ name: String(name), directory: false })\n return next()\n }\n )\n }\n return next()\n })\n}\n\nfunction BareTuiFilepicker(opts) {\n opts = opts || {}\n this.vfs = opts.vfs\n this.cwd = opts.cwd || '/'\n this.height = opts.height || 12\n this.showHidden = !!opts.showHidden\n this.pick = opts.pick === 'dir' ? 'dir' : opts.pick === 'any' ? 'any' : 'file'\n this.filter = typeof opts.filter === 'function' ? opts.filter : null\n this.entries = []\n this.cursor = 0\n this.offset = 0\n this.selected = null\n this.error = null\n this.loading = true\n}\n\nBareTuiFilepicker.prototype.init = function () {\n return this._read(this.cwd)\n}\n\nBareTuiFilepicker.prototype.selectedPath = function () {\n return this.selected\n}\n\nBareTuiFilepicker.prototype._read = function (dir) {\n var vfs = this.vfs\n var showHidden = this.showHidden\n var filter = this.filter\n return function () {\n return bareTuiListVfs(vfs, dir).then(\n function (entries) {\n if (filter) {\n var kept = []\n var i\n for (i = 0; i < entries.length; i++) {\n if (filter(entries[i].name, entries[i])) kept.push(entries[i])\n }\n entries = kept\n }\n return {\n type: 'filepicker.entries',\n dir: dir,\n entries: bareTuiSortEntries(entries, showHidden)\n }\n },\n function (err) {\n return {\n type: 'filepicker.error',\n dir: dir,\n error: (err && err.message) || String(err)\n }\n }\n )\n }\n}\n\nBareTuiFilepicker.prototype.update = function (msg) {\n if (!msg) return [this, null]\n if (msg.type === 'filepicker.entries' && msg.dir === this.cwd) {\n this.entries = msg.entries || []\n this.cursor = 0\n this.offset = 0\n this.loading = false\n this.error = null\n return [this, null]\n }\n if (msg.type === 'filepicker.error' && msg.dir === this.cwd) {\n this.error = msg.error\n this.entries = []\n this.loading = false\n return [this, null]\n }\n if (msg.type === 'key') return this._key(msg)\n return [this, null]\n}\n\nBareTuiFilepicker.prototype._open = function (dir) {\n this.cwd = dir\n this.loading = true\n return [this, this._read(dir)]\n}\n\nBareTuiFilepicker.prototype._move = function (delta) {\n if (!this.entries.length) return\n this.cursor = Math.max(\n 0,\n Math.min(this.cursor + delta, this.entries.length - 1)\n )\n if (this.cursor < this.offset) this.offset = this.cursor\n else if (this.cursor >= this.offset + this.height)\n this.offset = this.cursor - this.height + 1\n}\n\nBareTuiFilepicker.prototype._choose = function (full) {\n this.selected = full\n return [\n this,\n function () {\n return { type: 'filepicker.select', path: full }\n }\n ]\n}\n\nBareTuiFilepicker.prototype._key = function (msg) {\n if (msg.is('up', 'k')) {\n this._move(-1)\n return [this, null]\n }\n if (msg.is('down', 'j')) {\n this._move(1)\n return [this, null]\n }\n if (msg.is('backspace', 'left', 'h'))\n return this._open(bareTuiDirname(this.cwd))\n var entry = this.entries[this.cursor]\n if (!entry) return [this, null]\n var full = bareTuiJoinPath(this.cwd, entry.name)\n if (this.pick === 'dir') {\n if (!entry.directory) return [this, null]\n if (msg.is('right', 'l')) return this._open(full)\n if (msg.is('enter')) return this._choose(full)\n return [this, null]\n }\n if (msg.is('enter', 'right', 'l')) {\n if (entry.directory) return this._open(full)\n return this._choose(full)\n }\n return [this, null]\n}\n\nBareTuiFilepicker.prototype.view = function () {\n var lines = [this.cwd || '/']\n var rows = []\n if (this.loading) rows.push(' loading…')\n else if (this.error) rows.push(' ! ' + this.error)\n else if (!this.entries.length) rows.push(' (empty)')\n else {\n var end = Math.min(this.offset + this.height, this.entries.length)\n var p\n for (p = this.offset; p < end; p++) {\n var entry = this.entries[p]\n var label = entry.directory ? entry.name + '/' : entry.name\n var text = (p === this.cursor ? ' ' : ' ') + label\n if (p === this.cursor) {\n text =\n bareTuiAnsi.modifierReverse + text + bareTuiAnsi.modifierNotReverse\n }\n rows.push(text)\n }\n }\n while (rows.length < this.height) rows.push('')\n return lines.concat(rows).join('\\n')\n}\n\nfunction bareTuiMockResolve(tree, root, p) {\n if (p === root) return tree\n var rel = p\n if (root !== '/' && String(p).indexOf(root) === 0) rel = p.slice(root.length)\n var segs = String(rel).split('/').filter(Boolean)\n var node = tree\n var i\n for (i = 0; i < segs.length; i++) {\n if (node && typeof node === 'object' && segs[i] in node)\n node = node[segs[i]]\n else return undefined\n }\n return node\n}\n\nfunction bareTuiFilepickerMock(tree, opts) {\n opts = opts || {}\n var root = opts.root || '/'\n function readdir(dir) {\n var node = bareTuiMockResolve(tree, root, dir)\n if (!node || typeof node !== 'object') {\n return Promise.reject(new Error('ENOTDIR: ' + dir))\n }\n return Promise.resolve(Object.keys(node))\n }\n function stat(p) {\n var node = bareTuiMockResolve(tree, root, p)\n if (node === undefined) return Promise.reject(new Error('ENOENT: ' + p))\n var directory = !!(node && typeof node === 'object')\n return Promise.resolve({ type: directory ? 'directory' : 'file' })\n }\n return {\n root: root,\n vfs: { readdir: readdir, stat: stat },\n path: { join: bareTuiJoinPath, dirname: bareTuiDirname }\n }\n}\n\nfunction bareTuiFilepickerCreate(ctx, opts) {\n opts = opts || {}\n var vfs = opts.vfs\n if (!vfs && ctx && ctx.vfs) vfs = ctx.vfs\n var cwd = opts.cwd\n if (!cwd && ctx && ctx.env) cwd = ctx.env.PWD || ctx.env.HOME\n if (!cwd) cwd = '/'\n return new BareTuiFilepicker({\n vfs: vfs,\n cwd: cwd,\n height: opts.height,\n showHidden: opts.showHidden,\n pick: opts.pick,\n filter: opts.filter\n })\n}\n\nvar bareTuiFilepicker = {\n create: null,\n mock: bareTuiFilepickerMock\n}\n\n/* src/widgets/oneshot.js */\n/** One-shot confirm / prompt / choose models and runners. */\n\nfunction bareTuiBox(title, body, hint) {\n var inner = (title ? title + '\\n\\n' : '') + body + (hint ? '\\n\\n' + hint : '')\n return inner\n}\n\nfunction BareTuiConfirmApp(opts) {\n opts = opts || {}\n this.title = opts.title || 'Confirm'\n this.body = opts.body || opts.message || ''\n this.okLabel = opts.ok || 'Yes'\n this.cancelLabel = opts.cancel || 'No'\n this.result = false\n}\n\nBareTuiConfirmApp.prototype.update = function (msg) {\n if (!msg || msg.type !== 'key') return [this, null]\n if (msg.is('y', 'Y', 'enter')) {\n this.result = true\n return [this, bareTuiQuitCmd]\n }\n if (msg.is('n', 'N', 'escape', 'ctrl+c')) {\n this.result = false\n return [this, bareTuiQuitCmd]\n }\n return [this, null]\n}\n\nBareTuiConfirmApp.prototype.view = function () {\n return bareTuiBox(\n this.title,\n this.body,\n this.okLabel + ' (y/enter) · ' + this.cancelLabel + ' (n/esc)'\n )\n}\n\nfunction BareTuiPromptApp(opts) {\n opts = opts || {}\n this.title = opts.title || ''\n this.label = opts.label || opts.prompt || '> '\n this.field = bareTuiTextinput.create({\n prompt: this.label,\n placeholder: opts.placeholder || '',\n echoMode: opts.echoMode || 'normal',\n focused: true,\n value: opts.value || ''\n })\n this.result = null\n this.cancelled = false\n}\n\nBareTuiPromptApp.prototype.update = function (msg) {\n if (!msg || msg.type !== 'key') return [this, null]\n if (msg.is('enter')) {\n this.result = this.field.value\n return [this, bareTuiQuitCmd]\n }\n if (msg.is('escape', 'ctrl+c')) {\n this.cancelled = true\n this.result = null\n return [this, bareTuiQuitCmd]\n }\n var pair = this.field.update(msg)\n this.field = pair[0]\n return [this, pair[1]]\n}\n\nBareTuiPromptApp.prototype.view = function () {\n return bareTuiBox(this.title, this.field.view(), 'enter accept · esc cancel')\n}\n\nfunction BareTuiChooseApp(opts) {\n opts = opts || {}\n this.title = opts.title || 'Choose'\n var items = opts.options || opts.items || []\n this.list = bareTuiList.create({\n items: items,\n height: opts.height || Math.min(8, Math.max(3, items.length)),\n filterable: opts.filterable === true,\n title: ''\n })\n this.result = null\n this.cancelled = false\n}\n\nBareTuiChooseApp.prototype.update = function (msg) {\n if (!msg || msg.type !== 'key') return [this, null]\n if (msg.is('enter')) {\n this.result = this.list.selectedItem()\n return [this, bareTuiQuitCmd]\n }\n if (msg.is('escape', 'q', 'ctrl+c')) {\n this.cancelled = true\n this.result = null\n return [this, bareTuiQuitCmd]\n }\n var pair = this.list.update(msg)\n this.list = pair[0]\n return [this, pair[1]]\n}\n\nBareTuiChooseApp.prototype.view = function () {\n return bareTuiBox(this.title, this.list.view(), 'enter select · q/esc cancel')\n}\n\nfunction bareTuiConfirm(ctx, opts) {\n var app = new BareTuiConfirmApp(opts)\n return bareTuiRunProgram(ctx, app, opts).then(function () {\n return app.result\n })\n}\n\nfunction bareTuiPrompt(ctx, opts) {\n var app = new BareTuiPromptApp(opts)\n return bareTuiRunProgram(ctx, app, opts).then(function () {\n return app.result\n })\n}\n\nfunction bareTuiChoose(ctx, opts) {\n var app = new BareTuiChooseApp(opts)\n return bareTuiRunProgram(ctx, app, opts).then(function () {\n return app.result\n })\n}\n\n/* src/widgets/form.js */\n/** Declarative form: fields + focus + validate. Emits form.submit / form.cancel. */\n\nfunction bareTuiFormFieldValue(field) {\n if (!field) return undefined\n var c = field.control\n if (c && typeof c.value === 'function') return c.value()\n if (c && c.value != null && typeof c.value !== 'function') return c.value\n if (c && c.checked != null) return !!c.checked\n if (field.checked != null) return !!field.checked\n return field._value\n}\n\nfunction BareTuiFormField(def) {\n def = def || {}\n this.name = def.name || ''\n this.label = def.label || this.name\n this.description = def.description || def.help || ''\n this.required = !!def.required\n this.requiredMessage = def.requiredMessage || 'required'\n this.validate = def.validate || null\n this.type = def.type || 'text'\n this.hidden = !!def.hidden\n this.readonly = !!def.readonly\n this.error = ''\n this.control = def.control || null\n}\n\nBareTuiFormField.prototype.focus = function () {\n if (this.control && typeof this.control.focus === 'function')\n this.control.focus()\n return this\n}\nBareTuiFormField.prototype.blur = function () {\n if (this.control && typeof this.control.blur === 'function')\n this.control.blur()\n return this\n}\nBareTuiFormField.prototype.value = function () {\n return bareTuiFormFieldValue(this)\n}\nBareTuiFormField.prototype.check = function () {\n this.error = ''\n if (this.hidden) return true\n var v = this.value()\n var empty = v == null || v === '' || v === false\n if (this.required && empty) {\n this.error = this.requiredMessage\n return false\n }\n if (\n this.type === 'number' &&\n v != null &&\n v !== '' &&\n typeof v === 'number' &&\n !isFinite(v)\n ) {\n this.error = 'not a number'\n return false\n }\n if (typeof this.validate === 'function') {\n var r = this.validate(v)\n if (r === false) {\n this.error = 'invalid'\n return false\n }\n if (typeof r === 'string' && r) {\n this.error = r\n return false\n }\n }\n return true\n}\nBareTuiFormField.prototype.update = function (msg) {\n if (\n this.readonly ||\n !this.control ||\n typeof this.control.update !== 'function'\n ) {\n return [this, null]\n }\n var pair = this.control.update(msg)\n this.control = pair[0]\n return [this, pair[1]]\n}\nBareTuiFormField.prototype.view = function () {\n var lines = []\n var lab = this.label || this.name\n if (lab) lines.push(lab + (this.required ? ' *' : ''))\n if (this.description) lines.push(this.description)\n if (this.control && typeof this.control.view === 'function')\n lines.push(this.control.view())\n if (this.control && typeof this.control.menuView === 'function') {\n var menu = this.control.menuView()\n if (menu) lines.push(menu)\n }\n if (this.error) lines.push('! ' + this.error)\n return lines.join('\\n')\n}\n\nfunction bareTuiFormBuildControl(def) {\n var type = def.type || 'text'\n if (type === 'textarea') {\n return bareTuiTextarea.create({\n value: def.value || '',\n placeholder: def.placeholder || '',\n rows: def.rows,\n height: def.rows || 4,\n focused: !!def.autofocus\n })\n }\n if (type === 'checkbox' || type === 'confirm') {\n return bareTuiCheckbox.create({\n label: '',\n checked: !!def.value || !!def.checked,\n focused: !!def.autofocus\n })\n }\n if (type === 'radio') {\n return bareTuiRadio.create({\n options: def.options || [],\n selected: def.selected || 0,\n focused: !!def.autofocus\n })\n }\n if (type === 'select') {\n return bareTuiSelect.create({\n options: def.options || [],\n placeholder: def.placeholder || '',\n selected: def.selected || 0,\n focused: !!def.autofocus\n })\n }\n if (type === 'multiselect') {\n return bareTuiList.create({\n items: def.options || [],\n height: def.height || 6,\n filterable: false\n })\n }\n var echo = def.echoMode || (type === 'password' ? 'password' : 'normal')\n return bareTuiTextinput.create({\n value: def.value != null ? String(def.value) : '',\n placeholder: def.placeholder || '',\n echoMode: echo,\n focused: !!def.autofocus\n })\n}\n\nfunction bareTuiFormFromDef(def) {\n if (def instanceof BareTuiFormField) return def\n if (def && def.control) return new BareTuiFormField(def)\n def = def || {}\n var control = bareTuiFormBuildControl(def)\n var field = new BareTuiFormField(def)\n field.control = control\n if (field.type === 'number') {\n field.value = function () {\n var raw = field.control && field.control.value\n if (raw == null || raw === '') return null\n var n = parseFloat(raw)\n return isFinite(n) ? n : NaN\n }\n }\n if (field.type === 'checkbox' || field.type === 'confirm') {\n field.value = function () {\n return !!(field.control && field.control.checked)\n }\n }\n if (field.type === 'radio' || field.type === 'select') {\n field.value = function () {\n return field.control && typeof field.control.value === 'function'\n ? field.control.value()\n : null\n }\n }\n return field\n}\n\nfunction bareTuiFormText(opts) {\n opts = opts || {}\n opts.type = opts.type || 'text'\n return bareTuiFormFromDef(opts)\n}\nfunction bareTuiFormTextarea(opts) {\n opts = opts || {}\n opts.type = 'textarea'\n return bareTuiFormFromDef(opts)\n}\nfunction bareTuiFormNumber(opts) {\n opts = opts || {}\n opts.type = 'number'\n return bareTuiFormFromDef(opts)\n}\nfunction bareTuiFormSelect(opts) {\n opts = opts || {}\n opts.type = 'select'\n return bareTuiFormFromDef(opts)\n}\nfunction bareTuiFormRadio(opts) {\n opts = opts || {}\n opts.type = 'radio'\n return bareTuiFormFromDef(opts)\n}\nfunction bareTuiFormConfirm(opts) {\n opts = opts || {}\n opts.type = 'confirm'\n return bareTuiFormFromDef(opts)\n}\n\nfunction BareTuiForm(opts) {\n opts = opts || {}\n this.title = opts.title || ''\n this.fields = []\n var raw = opts.fields || []\n var i\n for (i = 0; i < raw.length; i++) this.fields.push(bareTuiFormFromDef(raw[i]))\n this.index = 0\n this._sync()\n}\n\nBareTuiForm.prototype._visible = function () {\n var out = []\n var i\n for (i = 0; i < this.fields.length; i++) {\n if (!this.fields[i].hidden) out.push(this.fields[i])\n }\n return out\n}\n\nBareTuiForm.prototype._sync = function () {\n var vis = this._visible()\n if (this.index >= vis.length) this.index = Math.max(0, vis.length - 1)\n var i\n for (i = 0; i < vis.length; i++) {\n if (i === this.index) vis[i].focus()\n else vis[i].blur()\n }\n}\n\nBareTuiForm.prototype.value = function () {\n var o = {}\n var i\n for (i = 0; i < this.fields.length; i++) {\n var f = this.fields[i]\n if (f.hidden || !f.name) continue\n o[f.name] = f.value()\n }\n return o\n}\n\nBareTuiForm.prototype.errors = function () {\n var o = {}\n var i\n for (i = 0; i < this.fields.length; i++) {\n if (this.fields[i].error) o[this.fields[i].name] = this.fields[i].error\n }\n return o\n}\n\nBareTuiForm.prototype._submit = function () {\n var ok = true\n var i\n for (i = 0; i < this.fields.length; i++) {\n if (!this.fields[i].check()) ok = false\n }\n if (!ok) return [this, null]\n var values = this.value()\n return [\n this,\n function () {\n return { type: 'form.submit', values: values }\n }\n ]\n}\n\nBareTuiForm.prototype.update = function (msg) {\n if (!msg || msg.type !== 'key') return [this, null]\n if (msg.is('ctrl+c')) {\n return [\n this,\n function () {\n return { type: 'form.cancel' }\n }\n ]\n }\n if (msg.is('ctrl+s')) return this._submit()\n var vis = this._visible()\n if (msg.is('shift+tab')) {\n this.index = (this.index - 1 + vis.length) % Math.max(1, vis.length)\n this._sync()\n return [this, null]\n }\n if (msg.is('tab')) {\n this.index = (this.index + 1) % Math.max(1, vis.length)\n this._sync()\n return [this, null]\n }\n if (msg.is('enter')) {\n var cur = vis[this.index]\n if (cur && (cur.type === 'select' || cur.type === 'textarea')) {\n var p0 = cur.update(msg)\n this._replace(cur, p0[0])\n return [this, p0[1]]\n }\n if (this.index < vis.length - 1) {\n this.index++\n this._sync()\n return [this, null]\n }\n return this._submit()\n }\n var focused = vis[this.index]\n if (!focused) return [this, null]\n var pair = focused.update(msg)\n this._replace(focused, pair[0])\n return [this, pair[1]]\n}\n\nBareTuiForm.prototype._replace = function (oldF, next) {\n var i\n for (i = 0; i < this.fields.length; i++) {\n if (this.fields[i] === oldF) this.fields[i] = next\n }\n}\n\nBareTuiForm.prototype.view = function () {\n var lines = []\n if (this.title) lines.push(this.title, '')\n var vis = this._visible()\n var i\n for (i = 0; i < vis.length; i++) {\n lines.push(vis[i].view())\n lines.push('')\n }\n lines.push('tab next · ctrl+s submit · ctrl+c cancel')\n return lines.join('\\n')\n}\n\nfunction bareTuiFormCreate(opts) {\n return new BareTuiForm(opts)\n}\n\nfunction bareTuiFormRun(ctx, form, opts) {\n var host = {\n form: form,\n result: undefined,\n update: function (msg) {\n if (msg && msg.type === 'form.submit') {\n this.result = msg.values\n return [this, bareTuiQuitCmd]\n }\n if (msg && msg.type === 'form.cancel') {\n this.result = null\n return [this, bareTuiQuitCmd]\n }\n var pair = this.form.update(msg)\n this.form = pair[0]\n return [this, pair[1]]\n },\n view: function () {\n return this.form.view()\n }\n }\n return bareTuiRunProgram(ctx, host, opts).then(function () {\n return host.result\n })\n}\n\nvar bareTuiForm = {\n create: bareTuiFormCreate,\n run: null,\n text: bareTuiFormText,\n textarea: bareTuiFormTextarea,\n number: bareTuiFormNumber,\n select: bareTuiFormSelect,\n radio: bareTuiFormRadio,\n confirm: bareTuiFormConfirm\n}\n\n/* src/widgets/extras.js */\n/** Extra widgets: tabs, modal, dialog, tree, statusbar, split, toast, markdown. */\n\nfunction BareTuiTabs(opts) {\n opts = opts || {}\n this.tabs = opts.tabs ? opts.tabs.slice() : []\n this.index = opts.index || 0\n}\nBareTuiTabs.prototype.active = function () {\n return this.tabs[this.index] || null\n}\nBareTuiTabs.prototype.update = function (msg) {\n if (!msg || msg.type !== 'key') return [this, null]\n if (msg.is('left', 'h')) this.index = Math.max(0, this.index - 1)\n else if (msg.is('right', 'l'))\n this.index = Math.min(this.tabs.length - 1, this.index + 1)\n else if (msg.name && /^[1-9]$/.test(msg.name)) {\n var n = parseInt(msg.name, 10) - 1\n if (n < this.tabs.length) this.index = n\n } else {\n var tab = this.active()\n if (tab && tab.model && typeof tab.model.update === 'function') {\n var pair = tab.model.update(msg)\n tab.model = pair[0]\n return [this, pair[1]]\n }\n }\n return [this, null]\n}\nBareTuiTabs.prototype.view = function () {\n var bar = []\n var i\n for (i = 0; i < this.tabs.length; i++) {\n var title = this.tabs[i].title || String(i + 1)\n if (i === this.index) title = '[' + title + ']'\n bar.push(title)\n }\n var body = ''\n var tab = this.active()\n if (tab) {\n if (tab.model && typeof tab.model.view === 'function')\n body = tab.model.view()\n else if (tab.body != null) body = String(tab.body)\n else if (tab.view)\n body = typeof tab.view === 'function' ? tab.view() : String(tab.view)\n }\n return bar.join(' ') + '\\n' + body\n}\n\nfunction BareTuiModal(opts) {\n opts = opts || {}\n this.child = opts.child || null\n this.open = !!opts.open\n this.title = opts.title || ''\n}\nBareTuiModal.prototype.show = function () {\n this.open = true\n return this\n}\nBareTuiModal.prototype.hide = function () {\n this.open = false\n return this\n}\nBareTuiModal.prototype.update = function (msg) {\n if (this.open && msg && msg.type === 'key' && msg.is('escape')) {\n this.open = false\n return [this, null]\n }\n if (this.child && typeof this.child.update === 'function') {\n var pair = this.child.update(msg)\n this.child = pair[0]\n return [this, pair[1]]\n }\n return [this, null]\n}\nBareTuiModal.prototype.view = function () {\n if (this.child && typeof this.child.view === 'function')\n return this.child.view()\n return ''\n}\n\nBareTuiModal.prototype.frame = function () {\n var inner = this.view()\n if (!this.open) return inner\n return (this.title || 'dialog') + '\\n' + inner + '\\n(esc close)'\n}\n\nBareTuiModal.prototype.overlay = function (size) {\n if (!this.open) return null\n var inner = ''\n if (this.child && typeof this.child.view === 'function')\n inner = this.child.view()\n var body = (this.title || 'dialog') + '\\n' + inner + '\\n(esc close)'\n var boxed = body\n var h = bareTuiBlockHeight(boxed)\n var w = bareTuiBlockWidth(boxed)\n var rows = (size && size.height) || 24\n var cols = (size && size.width) || 80\n return {\n row: Math.max(0, Math.floor((rows - h) / 2)),\n col: Math.max(0, Math.floor((cols - w) / 2)),\n text: boxed\n }\n}\n\nfunction BareTuiDialog(opts) {\n opts = opts || {}\n this.title = opts.title || ''\n this.body = opts.body || opts.message || ''\n this.buttons = opts.buttons || ['OK']\n this.index = opts.index || 0\n this.choice = null\n}\nBareTuiDialog.prototype.update = function (msg) {\n if (!msg || msg.type !== 'key') return [this, null]\n if (msg.is('left', 'h')) this.index = Math.max(0, this.index - 1)\n else if (msg.is('right', 'l'))\n this.index = Math.min(this.buttons.length - 1, this.index + 1)\n else if (msg.is('enter', 'space')) {\n this.choice = this.buttons[this.index]\n var choice = this.choice\n return [\n this,\n function () {\n return { type: 'dialog.choose', value: choice }\n }\n ]\n } else if (msg.is('escape', 'ctrl+c')) {\n this.choice = null\n return [\n this,\n function () {\n return { type: 'dialog.choose', value: null }\n }\n ]\n }\n return [this, null]\n}\nBareTuiDialog.prototype.view = function () {\n var btns = []\n var i\n for (i = 0; i < this.buttons.length; i++) {\n var b = this.buttons[i]\n btns.push(i === this.index ? '[' + b + ']' : ' ' + b + ' ')\n }\n return (\n (this.title ? this.title + '\\n' : '') + this.body + '\\n' + btns.join(' ')\n )\n}\n\nfunction BareTuiTree(opts) {\n opts = opts || {}\n this.items = opts.items ? opts.items.slice() : []\n this.cursor = 0\n}\nfunction bareTuiTreeFlat(items, depth, out) {\n var i\n for (i = 0; i < items.length; i++) {\n var it = items[i]\n out.push({ item: it, depth: depth })\n if (it.open && it.children && it.children.length) {\n bareTuiTreeFlat(it.children, depth + 1, out)\n }\n }\n}\nBareTuiTree.prototype._flat = function () {\n var out = []\n bareTuiTreeFlat(this.items, 0, out)\n return out\n}\nBareTuiTree.prototype.selectedItem = function () {\n var flat = this._flat()\n return flat[this.cursor] ? flat[this.cursor].item : null\n}\nBareTuiTree.prototype.update = function (msg) {\n if (!msg || msg.type !== 'key') return [this, null]\n var flat = this._flat()\n if (msg.is('up', 'k')) this.cursor = Math.max(0, this.cursor - 1)\n else if (msg.is('down', 'j'))\n this.cursor = Math.min(flat.length - 1, this.cursor + 1)\n else if (msg.is('right', 'l', 'enter')) {\n var it = this.selectedItem()\n if (it && it.children) it.open = true\n } else if (msg.is('left', 'h')) {\n var it2 = this.selectedItem()\n if (it2 && it2.children) it2.open = false\n }\n return [this, null]\n}\nBareTuiTree.prototype.view = function () {\n var flat = this._flat()\n var lines = []\n var i\n for (i = 0; i < flat.length; i++) {\n var it = flat[i].item\n var pad = ''\n var d\n for (d = 0; d < flat[i].depth; d++) pad += ' '\n var mark = it.children ? (it.open ? '▾ ' : '▸ ') : ' '\n var line = pad + mark + (it.title || it.name || '')\n if (i === this.cursor)\n line = bareTuiAnsi.modifierReverse + line + bareTuiAnsi.modifierNotReverse\n lines.push(line)\n }\n return lines.join('\\n')\n}\n\nfunction BareTuiStatusbar(opts) {\n opts = opts || {}\n this.width = opts.width || 0\n this.left = opts.left || ''\n this.center = opts.center || ''\n this.right = opts.right || ''\n}\nBareTuiStatusbar.prototype.set = function (part, text) {\n if (part === 'left') this.left = text\n else if (part === 'center') this.center = text\n else if (part === 'right') this.right = text\n return this\n}\nBareTuiStatusbar.prototype.update = function () {\n return [this, null]\n}\nBareTuiStatusbar.prototype.view = function () {\n var w = this.width || 80\n var l = String(this.left)\n var c = String(this.center)\n var r = String(this.right)\n var inner = w - bareTuiLineWidth(l) - bareTuiLineWidth(r)\n if (inner < 1) return bareTuiTruncate(l + ' ' + r, w)\n var leftPad = Math.max(0, Math.floor((inner - bareTuiLineWidth(c)) / 2))\n var rightPad = Math.max(0, inner - bareTuiLineWidth(c) - leftPad)\n return l + bareTuiRepeat(' ', leftPad) + c + bareTuiRepeat(' ', rightPad) + r\n}\n\nfunction BareTuiSplit(opts) {\n opts = opts || {}\n this.direction = opts.direction === 'column' ? 'column' : 'row'\n this.ratio = opts.ratio == null ? 0.5 : opts.ratio\n this.a = opts.left || opts.a || null\n this.b = opts.right || opts.b || null\n this.focusPane = opts.focus || 'a'\n this.width = opts.width || 0\n this.height = opts.height || 0\n}\nBareTuiSplit.prototype.update = function (msg) {\n if (msg && msg.type === 'key' && msg.is('ctrl+w')) {\n this.focusPane = this.focusPane === 'a' ? 'b' : 'a'\n return [this, null]\n }\n var pane = this.focusPane === 'b' ? this.b : this.a\n if (pane && typeof pane.update === 'function') {\n var pair = pane.update(msg)\n if (this.focusPane === 'b') this.b = pair[0]\n else this.a = pair[0]\n return [this, pair[1]]\n }\n return [this, null]\n}\nBareTuiSplit.prototype.view = function () {\n var va =\n this.a && typeof this.a.view === 'function'\n ? this.a.view()\n : String(this.a || '')\n var vb =\n this.b && typeof this.b.view === 'function'\n ? this.b.view()\n : String(this.b || '')\n if (this.direction === 'column') {\n return bareTuiJoinVertical(0, va, vb)\n }\n return bareTuiJoinHorizontal(0, va, ' │ ', vb)\n}\n\nfunction BareTuiToast(opts) {\n opts = opts || {}\n this.text = ''\n this.ttl = opts.ttl || 2000\n this.visible = false\n this.id = bareTuiNextWidgetId++\n this.tag = 0\n}\nBareTuiToast.prototype.show = function (text, ms) {\n this.text = String(text || '')\n this.visible = true\n if (ms) this.ttl = ms\n this.tag++\n return this._tick()\n}\nBareTuiToast.prototype._tick = function () {\n var id = this.id\n var tag = this.tag\n var ms = this.ttl\n return bareTuiTick(ms, function () {\n return { type: 'toast.hide', id: id, tag: tag }\n })\n}\nBareTuiToast.prototype.update = function (msg) {\n if (!msg || msg.type !== 'toast.hide') return [this, null]\n if (msg.id !== this.id || msg.tag !== this.tag) return [this, null]\n this.visible = false\n this.text = ''\n return [this, null]\n}\nBareTuiToast.prototype.view = function () {\n return this.visible ? this.text : ''\n}\n\nfunction bareTuiInlineMd(s) {\n var out = ''\n var i = 0\n while (i < s.length) {\n if (s.slice(i, i + 2) === '**') {\n var end = s.indexOf('**', i + 2)\n if (end > i) {\n out += bareTuiAnsi.sgr(1) + s.slice(i + 2, end) + bareTuiAnsi.reset\n i = end + 2\n continue\n }\n }\n if (s.charAt(i) === '`') {\n var e2 = s.indexOf('`', i + 1)\n if (e2 > i) {\n out += bareTuiAnsi.modifierDim + s.slice(i + 1, e2) + bareTuiAnsi.reset\n i = e2 + 1\n continue\n }\n }\n out += s.charAt(i)\n i++\n }\n return out\n}\n\nfunction bareTuiRenderMarkdown(src) {\n var lines = String(src || '').split('\\n')\n var out = []\n var fence = false\n var i\n for (i = 0; i < lines.length; i++) {\n var line = lines[i]\n if (line.slice(0, 3) === '```') {\n fence = !fence\n continue\n }\n if (fence) {\n out.push(bareTuiAnsi.modifierDim + line + bareTuiAnsi.reset)\n continue\n }\n if (/^#{1,3} /.test(line)) {\n var text = line.replace(/^#{1,3} /, '')\n out.push(bareTuiAnsi.sgr(1) + text + bareTuiAnsi.reset)\n continue\n }\n if (/^[-*] /.test(line)) {\n out.push('• ' + bareTuiInlineMd(line.slice(2)))\n continue\n }\n if (\n line.charAt(0) === '>' &&\n (line.charAt(1) === ' ' || line.length === 1)\n ) {\n out.push(bareTuiAnsi.modifierDim + line.slice(2) + bareTuiAnsi.reset)\n continue\n }\n out.push(bareTuiInlineMd(line))\n }\n return out.join('\\n')\n}\n\nfunction BareTuiMarkdown(opts) {\n opts = opts || {}\n this.source = opts.source || opts.text || ''\n this.viewport = bareTuiViewport.create({\n width: opts.width || 0,\n height: opts.height || 12\n })\n this.viewport.setContent(bareTuiRenderMarkdown(this.source))\n}\nBareTuiMarkdown.prototype.setSource = function (src) {\n this.source = src\n this.viewport.setContent(bareTuiRenderMarkdown(src))\n return this\n}\nBareTuiMarkdown.prototype.update = function (msg) {\n var pair = this.viewport.update(msg)\n this.viewport = pair[0]\n return [this, pair[1]]\n}\nBareTuiMarkdown.prototype.view = function () {\n return this.viewport.view()\n}\n\nvar bareTuiTabs = {\n create: function (opts) {\n return new BareTuiTabs(opts)\n }\n}\nvar bareTuiModal = {\n create: function (opts) {\n return new BareTuiModal(opts)\n }\n}\nvar bareTuiDialog = {\n create: function (opts) {\n return new BareTuiDialog(opts)\n }\n}\nvar bareTuiTree = {\n create: function (opts) {\n return new BareTuiTree(opts)\n }\n}\nvar bareTuiStatusbar = {\n create: function (opts) {\n return new BareTuiStatusbar(opts)\n }\n}\nvar bareTuiSplit = {\n create: function (opts) {\n return new BareTuiSplit(opts)\n }\n}\nvar bareTuiToast = {\n create: function (opts) {\n return new BareTuiToast(opts)\n }\n}\nvar bareTuiMarkdown = {\n create: function (opts) {\n return new BareTuiMarkdown(opts)\n },\n render: bareTuiRenderMarkdown\n}\n\n/* src/zz-export.js */\n/** Public ctx.tui / ctx.sdk surface. */\n\nfunction bareTuiBuildPublic(ctx) {\n return {\n version: BARE_TUI_VERSION,\n isTTY: function (opts) {\n return bareTuiIsTTY(ctx, opts)\n },\n buffer: {\n create: bareTuiGridCreate,\n fill: bareTuiGridFill,\n blit: bareTuiGridBlit,\n plain: bareTuiGridPlain\n },\n size: function (opts) {\n return bareTuiSize(ctx, opts)\n },\n ansi: bareTuiAnsi,\n key: {\n matches: bareTuiKeyMatches,\n binding: bareTuiKeyBinding\n },\n decode: bareTuiDecodeBytes,\n createDecoder: bareTuiCreateDecoder,\n acquire: function (opts) {\n return bareTuiAcquire(ctx, opts)\n },\n release: function (opts) {\n return bareTuiRelease(ctx, opts)\n },\n withSession: function (fn, opts) {\n return bareTuiWithSession(ctx, fn, opts)\n },\n screen: {\n enter: function (opts) {\n return bareTuiScreenEnter(ctx, opts)\n },\n leave: function (opts) {\n return bareTuiScreenLeave(ctx, opts)\n }\n },\n style: bareTuiMakeStyleFactory(ctx),\n theme: function (opts) {\n return bareTuiResolveTheme(ctx, opts)\n },\n run: function (model, opts) {\n return bareTuiRunProgram(ctx, model, opts)\n },\n create: function (model, opts) {\n return bareTuiCreateProgram(ctx, model, opts)\n },\n send: function (msg) {\n return bareTuiSendActive(ctx, msg)\n },\n quit: bareTuiQuitCmd,\n tick: bareTuiTick,\n every: bareTuiEvery,\n batch: bareTuiBatch,\n sequence: bareTuiSequence,\n suspend: bareTuiSuspend,\n spinner: bareTuiSpinner,\n textinput: bareTuiTextinput,\n autocomplete: bareTuiAutocomplete,\n textarea: bareTuiTextarea,\n viewport: bareTuiViewport,\n list: bareTuiList,\n table: bareTuiTable,\n help: bareTuiHelp,\n progress: bareTuiProgress,\n paginator: bareTuiPaginator,\n stopwatch: bareTuiStopwatch,\n timer: bareTuiTimer,\n checkbox: bareTuiCheckbox,\n radio: bareTuiRadio,\n select: bareTuiSelect,\n focus: bareTuiFocus,\n filepicker: {\n create: function (opts) {\n return bareTuiFilepickerCreate(ctx, opts)\n },\n mock: bareTuiFilepickerMock\n },\n form: {\n create: bareTuiFormCreate,\n run: function (form, opts) {\n return bareTuiFormRun(ctx, form, opts)\n },\n text: bareTuiFormText,\n textarea: bareTuiFormTextarea,\n number: bareTuiFormNumber,\n select: bareTuiFormSelect,\n radio: bareTuiFormRadio,\n confirm: bareTuiFormConfirm\n },\n confirm: (function () {\n var fn = function (opts) {\n return bareTuiConfirm(ctx, opts)\n }\n fn.create = function (opts) {\n return new BareTuiConfirmApp(opts)\n }\n return fn\n })(),\n prompt: (function () {\n var fn = function (opts) {\n return bareTuiPrompt(ctx, opts)\n }\n fn.create = function (opts) {\n return new BareTuiPromptApp(opts)\n }\n return fn\n })(),\n choose: (function () {\n var fn = function (opts) {\n return bareTuiChoose(ctx, opts)\n }\n fn.create = function (opts) {\n return new BareTuiChooseApp(opts)\n }\n return fn\n })(),\n tabs: bareTuiTabs,\n modal: bareTuiModal,\n dialog: bareTuiDialog,\n tree: bareTuiTree,\n statusbar: bareTuiStatusbar,\n split: bareTuiSplit,\n toast: bareTuiToast,\n markdown: bareTuiMarkdown\n }\n}\n\nfunction bareTuiBuildSdk(ctx, tui) {\n return {\n tui: tui,\n theme: {\n name: function (opts) {\n return tui.theme(opts).name\n },\n tokens: function (opts) {\n return tui.theme(opts).tokens\n },\n apply: function (name) {\n if (name && ctx && ctx.env) ctx.env.BARE_OS_THEME = String(name)\n if (ctx && typeof ctx.bareOsApplyTheme === 'function') {\n return Promise.resolve(ctx.bareOsApplyTheme())\n }\n return Promise.resolve()\n }\n },\n env: {\n get: function (key) {\n if (!ctx || !ctx.env) return ''\n var v = ctx.env[key]\n return v == null ? '' : String(v)\n },\n has: function (key) {\n return !!(\n ctx &&\n ctx.env &&\n ctx.env[key] != null &&\n String(ctx.env[key]) !== ''\n )\n },\n term: function () {\n return this.get('TERM') || 'unknown'\n },\n colorDepth: function () {\n return tui.theme().depth\n },\n noColor: function () {\n return tui.theme().noColor\n }\n },\n proc: {\n read: function (name) {\n var path = String(name || '')\n if (path.indexOf('/') < 0) path = '/proc/bare_os/' + path\n if (!ctx || !ctx.vfs || typeof ctx.vfs.readFile !== 'function') {\n return Promise.resolve(null)\n }\n return Promise.resolve(ctx.vfs.readFile(path)).then(function (buf) {\n if (!buf) return null\n if (ctx.b4a && typeof ctx.b4a.toString === 'function')\n return ctx.b4a.toString(buf)\n if (typeof TextDecoder !== 'undefined') {\n return new TextDecoder('utf-8').decode(buf)\n }\n return String(buf)\n })\n }\n },\n ipc: {\n pushJson: function (name, obj) {\n if (\n !ctx ||\n !ctx.bareOsIpc ||\n typeof ctx.bareOsIpc.pushJson !== 'function'\n ) {\n return false\n }\n ctx.bareOsIpc.pushJson(name, obj)\n return true\n },\n takeJson: function (name) {\n if (\n !ctx ||\n !ctx.bareOsIpc ||\n typeof ctx.bareOsIpc.takeJson !== 'function'\n ) {\n return Promise.resolve(null)\n }\n return ctx.bareOsIpc.takeJson(name)\n }\n },\n app: {\n run: function (model, opts) {\n return tui.run(model, opts)\n },\n confirm: function (opts) {\n return tui.confirm(opts)\n },\n prompt: function (opts) {\n return tui.prompt(opts)\n },\n select: function (opts) {\n return tui.choose(opts)\n },\n form: function (spec, opts) {\n var f = tui.form.create(spec)\n return tui.form.run(f, opts)\n }\n },\n vfs: {\n list: function (path) {\n if (!ctx || !ctx.vfs || typeof ctx.vfs.readdir !== 'function') {\n return Promise.resolve([])\n }\n return ctx.vfs.readdir(path)\n },\n readText: function (path) {\n if (!ctx || !ctx.vfs || typeof ctx.vfs.readFile !== 'function') {\n return Promise.resolve(null)\n }\n return Promise.resolve(ctx.vfs.readFile(path)).then(function (buf) {\n if (!buf) return null\n if (ctx.b4a && typeof ctx.b4a.toString === 'function')\n return ctx.b4a.toString(buf)\n if (typeof TextDecoder !== 'undefined') {\n return new TextDecoder('utf-8').decode(buf)\n }\n return String(buf)\n })\n },\n writeText: function (path, text) {\n if (!ctx || !ctx.vfs || typeof ctx.vfs.writeFile !== 'function') {\n return Promise.resolve(false)\n }\n var s = String(text == null ? '' : text)\n var buf\n if (ctx.b4a && typeof ctx.b4a.from === 'function') buf = ctx.b4a.from(s)\n else if (typeof TextEncoder !== 'undefined')\n buf = new TextEncoder().encode(s)\n else buf = s\n return Promise.resolve(ctx.vfs.writeFile(path, buf)).then(function () {\n return true\n })\n }\n },\n tty: {\n isTTY: function (opts) {\n return tui.isTTY(opts)\n },\n size: function (opts) {\n return tui.size(opts)\n },\n acquire: function (opts) {\n return tui.acquire(opts)\n },\n release: function (opts) {\n return tui.release(opts)\n },\n withSession: function (fn, opts) {\n return tui.withSession(fn, opts)\n }\n }\n }\n}\n\nfunction bareTuiAttachToCtx(ctx) {\n var tui = bareTuiBuildPublic(ctx)\n var sdk = bareTuiBuildSdk(ctx, tui)\n return { tui: tui, sdk: sdk }\n}\nreturn bareTuiAttachToCtx(ctx);\n})"