3 lines
130 KiB
JavaScript
3 lines
130 KiB
JavaScript
/** 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 Gloss–style 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})"
|