@herbertgao/pi-extensions 2026.8.1 → 2026.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/node_modules/@czottmann/pi-automode/README.md +16 -2
- package/node_modules/@czottmann/pi-automode/docs/GLOSSARY.md +35 -0
- package/node_modules/@czottmann/pi-automode/docs/automode-classifier-flow.md +18 -9
- package/node_modules/@czottmann/pi-automode/docs/defaults.md +6 -2
- package/node_modules/@czottmann/pi-automode/examples/automode.local.json +6 -0
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/classifier.ts +11 -7
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/config.ts +100 -0
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/constants.ts +32 -0
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/extension.ts +78 -3
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/hard-deny.ts +16 -4
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/paths.ts +23 -1
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/permissions.ts +22 -1
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/types.ts +18 -2
- package/node_modules/@czottmann/pi-automode/package.json +4 -4
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-audit.md +5 -0
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-debt.md +5 -0
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-gain.md +5 -0
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-help.md +5 -0
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-review.md +5 -0
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail.md +5 -0
- package/node_modules/@dietrichgebert/ponytail/.opencode/plugins/ponytail-frontmatter.cjs +23 -0
- package/node_modules/@dietrichgebert/ponytail/.opencode/plugins/ponytail.mjs +99 -0
- package/node_modules/@dietrichgebert/ponytail/.qoder/rules/ponytail.md +30 -0
- package/node_modules/@dietrichgebert/ponytail/.qoder-plugin/plugin.json +16 -0
- package/node_modules/@dietrichgebert/ponytail/AGENTS.md +32 -0
- package/node_modules/@dietrichgebert/ponytail/LICENSE +21 -0
- package/node_modules/@dietrichgebert/ponytail/README.es.md +298 -0
- package/node_modules/@dietrichgebert/ponytail/README.ko.md +315 -0
- package/node_modules/@dietrichgebert/ponytail/README.md +351 -0
- package/node_modules/@dietrichgebert/ponytail/assets/benchmark-3model.svg +21 -0
- package/node_modules/@dietrichgebert/ponytail/assets/benchmark-agentic.svg +62 -0
- package/node_modules/@dietrichgebert/ponytail/assets/logo-dark.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/logo-dark.svg +115 -0
- package/node_modules/@dietrichgebert/ponytail/assets/logo-greenpt-dark.svg +27 -0
- package/node_modules/@dietrichgebert/ponytail/assets/logo-greenpt.svg +27 -0
- package/node_modules/@dietrichgebert/ponytail/assets/logo.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/social-preview.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner-es.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner-ko.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/claude-codex-hooks.json +44 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/copilot-hooks.json +21 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-activate.js +96 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-config.js +169 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-instructions.js +98 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-mode-tracker.js +130 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-runtime.js +85 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-statusline.ps1 +24 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-statusline.sh +18 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-subagent.js +77 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/qoder-hooks.json +26 -0
- package/node_modules/@dietrichgebert/ponytail/package.json +47 -0
- package/node_modules/@dietrichgebert/ponytail/pi-extension/index.js +211 -0
- package/node_modules/@dietrichgebert/ponytail/pi-extension/package.json +8 -0
- package/node_modules/@dietrichgebert/ponytail/scripts/uninstall.js +60 -0
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail/SKILL.md +120 -0
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail-audit/SKILL.md +41 -0
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail-debt/SKILL.md +44 -0
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail-gain/SKILL.md +50 -0
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail-help/SKILL.md +71 -0
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail-review/SKILL.md +57 -0
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +1 -3
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +1 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +10 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/agent-summary.ts +6 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +24 -83
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/markdown-enhance.ts +119 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +73 -9
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/index.ts +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse-hover.ts +130 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse-interaction.ts +65 -542
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse-layout.ts +160 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse-packets.ts +143 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse-scroll.ts +184 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool-diff/diff-renderer.ts +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool-grouping.ts +9 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/transcript-refresh.ts +91 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/agent-summary.ts +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/@herbertgao/pi-cc-extensions/themes/cc-dark.json +1 -0
- package/node_modules/@herbertgao/pi-cc-extensions/themes/cc-light.json +2 -2
- package/node_modules/@herbertgao/pi-stash/README.md +9 -9
- package/node_modules/@herbertgao/pi-stash/package.json +1 -1
- package/node_modules/@herbertgao/pi-stash/src/index.ts +2 -1
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +14 -0
- package/node_modules/@herbertgao/pi-subagents/README.md +6 -2
- package/node_modules/@herbertgao/pi-subagents/package.json +3 -3
- package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +85 -11
- package/node_modules/@herbertgao/pi-subagents/src/index.ts +28 -4
- package/node_modules/@herbertgao/pi-subagents/src/settings.ts +12 -0
- package/node_modules/@herbertgao/pi-subagents/src/types.ts +2 -0
- package/node_modules/@narumitw/pi-btw/LICENSE +21 -0
- package/node_modules/@narumitw/pi-btw/README.md +210 -0
- package/node_modules/@narumitw/pi-btw/package.json +53 -0
- package/node_modules/@narumitw/pi-btw/src/bring-to-main.ts +632 -0
- package/node_modules/@narumitw/pi-btw/src/btw.ts +996 -0
- package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +339 -0
- package/node_modules/@narumitw/pi-btw/src/index.ts +1 -0
- package/node_modules/@narumitw/pi-btw/src/menu.ts +296 -0
- package/node_modules/@narumitw/pi-btw/src/settings.ts +237 -0
- package/node_modules/@narumitw/pi-btw/src/side-thread.ts +238 -0
- package/node_modules/@narumitw/pi-btw/src/text.ts +10 -0
- package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +620 -0
- package/node_modules/@pi-plugins/fast-mode/LICENSE +21 -0
- package/node_modules/@pi-plugins/fast-mode/README.md +92 -0
- package/node_modules/@pi-plugins/fast-mode/dist/index.d.mts +6 -0
- package/node_modules/@pi-plugins/fast-mode/dist/index.d.mts.map +1 -0
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +2026 -0
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -0
- package/node_modules/@pi-plugins/fast-mode/package.json +73 -0
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +59 -0
- package/node_modules/pi-mcp-adapter/README.md +62 -13
- package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +377 -0
- package/node_modules/pi-mcp-adapter/commands.ts +9 -7
- package/node_modules/pi-mcp-adapter/config.ts +110 -49
- package/node_modules/pi-mcp-adapter/direct-tools.ts +34 -19
- package/node_modules/pi-mcp-adapter/elicitation-handler.ts +37 -36
- package/node_modules/pi-mcp-adapter/errors.ts +21 -17
- package/node_modules/pi-mcp-adapter/host-html-template.ts +13 -7
- package/node_modules/pi-mcp-adapter/index.ts +37 -14
- package/node_modules/pi-mcp-adapter/init.ts +9 -7
- package/node_modules/pi-mcp-adapter/json-schema-validator.ts +2 -2
- package/node_modules/pi-mcp-adapter/lifecycle.ts +8 -8
- package/node_modules/pi-mcp-adapter/logger.ts +1 -1
- package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +36 -22
- package/node_modules/pi-mcp-adapter/mcp-auth.ts +120 -2
- package/node_modules/pi-mcp-adapter/mcp-code.ts +13 -11
- package/node_modules/pi-mcp-adapter/mcp-oauth-provider.ts +19 -13
- package/node_modules/pi-mcp-adapter/mcp-output-guard.ts +15 -11
- package/node_modules/pi-mcp-adapter/mcp-panel.ts +34 -15
- package/node_modules/pi-mcp-adapter/mcp-probe.ts +131 -34
- package/node_modules/pi-mcp-adapter/mcp-script-worker.mjs +2 -2
- package/node_modules/pi-mcp-adapter/mcp-setup-panel.ts +7 -4
- package/node_modules/pi-mcp-adapter/mcp-trace.ts +59 -64
- package/node_modules/pi-mcp-adapter/metadata-cache.ts +34 -26
- package/node_modules/pi-mcp-adapter/npx-resolver.ts +6 -4
- package/node_modules/pi-mcp-adapter/oauth-handler.ts +1 -1
- package/node_modules/pi-mcp-adapter/onboarding-state.ts +19 -11
- package/node_modules/pi-mcp-adapter/package.json +13 -8
- package/node_modules/pi-mcp-adapter/panel-keys.ts +20 -4
- package/node_modules/pi-mcp-adapter/prompts.ts +2 -2
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +48 -11
- package/node_modules/pi-mcp-adapter/sampling-handler.ts +22 -15
- package/node_modules/pi-mcp-adapter/search-ranking.ts +2 -1
- package/node_modules/pi-mcp-adapter/server-manager.ts +165 -113
- package/node_modules/pi-mcp-adapter/session-recovery.ts +11 -12
- package/node_modules/pi-mcp-adapter/skills/mcp-scripting/SKILL.md +3 -3
- package/node_modules/pi-mcp-adapter/state.ts +3 -1
- package/node_modules/pi-mcp-adapter/tool-approval.ts +67 -4
- package/node_modules/pi-mcp-adapter/tool-metadata.ts +6 -5
- package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +14 -2
- package/node_modules/pi-mcp-adapter/ts-shape.ts +9 -2
- package/node_modules/pi-mcp-adapter/types.ts +109 -22
- package/node_modules/pi-mcp-adapter/ui-app-bridge-helpers.ts +40 -0
- package/node_modules/pi-mcp-adapter/ui-resource-handler.ts +28 -19
- package/node_modules/pi-mcp-adapter/ui-server.ts +90 -58
- package/node_modules/pi-mcp-adapter/ui-session.ts +16 -14
- package/node_modules/pi-mcp-adapter/unix-socket-transport.ts +4 -4
- package/node_modules/pi-mcp-adapter/utils.ts +23 -9
- package/package.json +22 -7
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["Array","String","graphemeSegmenter","wordSegmenter","wordSegmenter","Tokenizer","Marked","cjsRequire","Array","String"],"sources":["../../../tooling/shared/src/config.ts","../../../tooling/shared/src/statusline.ts","../../../node_modules/.pnpm/@earendil-works+pi-tui@0.83.0/node_modules/@earendil-works/pi-tui/dist/utils.js","../../../node_modules/.pnpm/@earendil-works+pi-tui@0.83.0/node_modules/@earendil-works/pi-tui/dist/keys.js","../../../node_modules/.pnpm/@earendil-works+pi-tui@0.83.0/node_modules/@earendil-works/pi-tui/dist/word-navigation.js","../../../node_modules/.pnpm/@earendil-works+pi-tui@0.83.0/node_modules/@earendil-works/pi-tui/dist/components/editor.js","../../../node_modules/.pnpm/@earendil-works+pi-tui@0.83.0/node_modules/@earendil-works/pi-tui/dist/components/input.js","../../../node_modules/.pnpm/marked@18.0.5/node_modules/marked/lib/marked.esm.js","../../../node_modules/.pnpm/@earendil-works+pi-tui@0.83.0/node_modules/@earendil-works/pi-tui/dist/components/markdown.js","../../../node_modules/.pnpm/@earendil-works+pi-tui@0.83.0/node_modules/@earendil-works/pi-tui/dist/native-modifiers.js","../../../node_modules/.pnpm/@earendil-works+pi-tui@0.83.0/node_modules/@earendil-works/pi-tui/dist/terminal.js","../src/index.ts"],"sourcesContent":["import { getAgentDir } from '@earendil-works/pi-coding-agent'\nimport { Effect, FileSystem, Path, Schema } from 'effect'\n\n/**\n * Loads an extension's JSON config from `<agent-dir>/extensions/<name>.json` and\n * validates it with `schema`.\n */\nexport const loadExtensionConfig = Effect.fnUntraced(function* <\n S extends Schema.Top,\n>(schema: S, name: string) {\n const fs = yield* FileSystem.FileSystem\n const path = yield* Path.Path\n\n const file = path.join(getAgentDir(), 'extensions', `${name}.json`)\n return yield* fs.readFileString(file).pipe(\n Effect.flatMap(Schema.decodeEffect(Schema.fromJsonString(schema))),\n Effect.tapError((error) =>\n error._tag === 'PlatformError' && error.reason._tag === 'NotFound'\n ? Effect.void\n : Effect.logWarning(\n `Could not load ${name} config. [${error._tag}]: ${error.message}`,\n ),\n ),\n )\n})\n","import type { ExtensionContext, Theme } from '@earendil-works/pi-coding-agent'\nimport { Array, Order, pipe, String } from 'effect'\n\n/**\n * One entry on the shared status line. `text` must be plain (un-styled) text —\n * the whole row is dimmed uniformly so segments from different plugins share\n * one look.\n */\nexport interface StatuslineSegment {\n readonly text: string\n readonly align: 'left' | 'right'\n}\n\nconst WIDGET_KEY = 'pi-plugins:statusline'\n\n// Each plugin bundles its own copy of this module; `Symbol.for` on\n// `globalThis` gives them all the same registry inside one pi process.\nconst REGISTRY_KEY = Symbol.for('@pi-plugins/statusline-registry')\n\ntype Registry = Map<string, StatuslineSegment>\n\nfunction registry(): Registry {\n const store = globalThis as { [REGISTRY_KEY]?: Registry }\n store[REGISTRY_KEY] ??= new Map()\n return store[REGISTRY_KEY]\n}\n\nconst byKey = Order.mapInput(\n Order.String,\n ([key]: readonly [string, StatuslineSegment]) => key,\n)\n\nfunction side(segments: Registry, align: StatuslineSegment['align']): string {\n return pipe(\n Array.fromIterable(segments),\n Array.filter(([, segment]) => segment.align === align),\n Array.sortBy(byKey),\n Array.map(([, segment]) => segment.text),\n Array.join(' · '),\n )\n}\n\n/** Terminal columns of plain text (code points, no ANSI). */\nfunction textWidth(text: string): number {\n return Array.fromIterable(text).length\n}\n\nfunction truncate(text: string, columns: number): string {\n return pipe(Array.fromIterable(text), Array.take(columns), Array.join(''))\n}\n\n/**\n * Lays out `left ... right` across `width`: left indented one column to match\n * pi's built-in widget rows, right flush against the terminal edge to match\n * pi's footer. Falls back to one truncated `left · right` run when too narrow.\n */\nfunction renderLine(segments: Registry, width: number, theme: Theme): string {\n const left = side(segments, 'left')\n const right = side(segments, 'right')\n\n const margin = Math.min(width, 1)\n const inner = width - margin\n const gap = inner - textWidth(left) - textWidth(right)\n const minGap = String.isNonEmpty(left) && String.isNonEmpty(right) ? 2 : 0\n\n const line =\n String.isNonEmpty(right) && gap >= minGap\n ? `${left}${' '.repeat(gap)}${right}`\n : truncate(\n pipe([left, right], Array.filter(String.isNonEmpty), Array.join(' · ')),\n Math.max(inner, 0),\n )\n\n return ' '.repeat(margin) + theme.fg('dim', line)\n}\n\n/**\n * Adds, replaces (`segment`), or removes (`undefined`) a keyed segment on a\n * single status line above the editor shared across pi-plugins extensions,\n * instead of each plugin stacking its own widget row.\n */\nexport function setStatuslineSegment(\n ctx: ExtensionContext,\n key: string,\n segment: StatuslineSegment | undefined,\n): void {\n const segments = registry()\n if (segment === undefined) {\n segments.delete(key)\n } else {\n segments.set(key, segment)\n }\n\n if (!ctx.hasUI) {\n return\n }\n\n if (segments.size === 0) {\n ctx.ui.setWidget(WIDGET_KEY, undefined)\n return\n }\n\n ctx.ui.setWidget(WIDGET_KEY, (_tui, theme) => ({\n render: (width: number) => [renderLine(segments, width, theme)],\n invalidate: () => {},\n }))\n}\n","import { eastAsianWidth } from \"get-east-asian-width\";\n// segmenters (shared instance)\nconst graphemeSegmenter = new Intl.Segmenter(undefined, { granularity: \"grapheme\" });\nconst wordSegmenter = new Intl.Segmenter(undefined, { granularity: \"word\" });\n/**\n * Get the shared grapheme segmenter instance.\n */\nexport function getGraphemeSegmenter() {\n return graphemeSegmenter;\n}\n/**\n * Get the shared word segmenter instance.\n */\nexport function getWordSegmenter() {\n return wordSegmenter;\n}\n/**\n * Check if a grapheme cluster (after segmentation) could possibly be an RGI emoji.\n * This is a fast heuristic to avoid the expensive rgiEmojiRegex test.\n * The tested Unicode blocks are deliberately broad to account for future\n * Unicode additions.\n */\nfunction couldBeEmoji(segment) {\n const cp = segment.codePointAt(0);\n return ((cp >= 0x1f000 && cp <= 0x1fbff) || // Emoji and Pictograph\n (cp >= 0x2300 && cp <= 0x23ff) || // Misc technical\n (cp >= 0x2600 && cp <= 0x27bf) || // Misc symbols, dingbats\n (cp >= 0x2b50 && cp <= 0x2b55) || // Specific stars/circles\n segment.includes(\"\\uFE0F\") || // Contains VS16 (emoji presentation selector)\n segment.length > 2 // Multi-codepoint sequences (ZWJ, skin tones, etc.)\n );\n}\n// Regexes for character classification (same as string-width library)\nconst zeroWidthRegex = /^(?:\\p{Default_Ignorable_Code_Point}|\\p{Control}|\\p{Mark}|\\p{Surrogate})+$/v;\nconst leadingNonPrintingRegex = /^[\\p{Default_Ignorable_Code_Point}\\p{Control}\\p{Format}\\p{Mark}\\p{Surrogate}]+/v;\nconst rgiEmojiRegex = /^\\p{RGI_Emoji}$/v;\n// Cache for non-ASCII strings\nconst WIDTH_CACHE_SIZE = 512;\nconst widthCache = new Map();\nexport const cjkBreakRegex = /[\\p{Script_Extensions=Han}\\p{Script_Extensions=Hiragana}\\p{Script_Extensions=Katakana}\\p{Script_Extensions=Hangul}\\p{Script_Extensions=Bopomofo}]/u;\nfunction isPrintableAscii(str) {\n for (let i = 0; i < str.length; i++) {\n const code = str.charCodeAt(i);\n if (code < 0x20 || code > 0x7e) {\n return false;\n }\n }\n return true;\n}\nfunction truncateFragmentToWidth(text, maxWidth) {\n if (maxWidth <= 0 || text.length === 0) {\n return { text: \"\", width: 0 };\n }\n if (isPrintableAscii(text)) {\n const clipped = text.slice(0, maxWidth);\n return { text: clipped, width: clipped.length };\n }\n const hasAnsi = text.includes(\"\\x1b\");\n const hasTabs = text.includes(\"\\t\");\n if (!hasAnsi && !hasTabs) {\n let result = \"\";\n let width = 0;\n for (const { segment } of graphemeSegmenter.segment(text)) {\n const w = graphemeWidth(segment);\n if (width + w > maxWidth) {\n break;\n }\n result += segment;\n width += w;\n }\n return { text: result, width };\n }\n let result = \"\";\n let width = 0;\n let i = 0;\n let pendingAnsi = \"\";\n while (i < text.length) {\n const ansi = extractAnsiCode(text, i);\n if (ansi) {\n pendingAnsi += ansi.code;\n i += ansi.length;\n continue;\n }\n if (text[i] === \"\\t\") {\n if (width + 3 > maxWidth) {\n break;\n }\n if (pendingAnsi) {\n result += pendingAnsi;\n pendingAnsi = \"\";\n }\n result += \"\\t\";\n width += 3;\n i++;\n continue;\n }\n let end = i;\n while (end < text.length && text[end] !== \"\\t\") {\n const nextAnsi = extractAnsiCode(text, end);\n if (nextAnsi) {\n break;\n }\n end++;\n }\n for (const { segment } of graphemeSegmenter.segment(text.slice(i, end))) {\n const w = graphemeWidth(segment);\n if (width + w > maxWidth) {\n return { text: result, width };\n }\n if (pendingAnsi) {\n result += pendingAnsi;\n pendingAnsi = \"\";\n }\n result += segment;\n width += w;\n }\n i = end;\n }\n return { text: result, width };\n}\nfunction finalizeTruncatedResult(prefix, prefixWidth, ellipsis, ellipsisWidth, maxWidth, pad) {\n const reset = \"\\x1b[0m\";\n const visibleWidth = prefixWidth + ellipsisWidth;\n let result;\n if (ellipsis.length > 0) {\n result = `${prefix}${reset}${ellipsis}${reset}`;\n }\n else {\n result = `${prefix}${reset}`;\n }\n return pad ? result + \" \".repeat(Math.max(0, maxWidth - visibleWidth)) : result;\n}\n/**\n * Calculate the terminal width of a single grapheme cluster.\n * Based on code from the string-width library, but includes a possible-emoji\n * check to avoid running the RGI_Emoji regex unnecessarily.\n */\nfunction graphemeWidth(segment) {\n if (segment === \"\\t\") {\n return 3;\n }\n // Zero-width clusters\n if (zeroWidthRegex.test(segment)) {\n return 0;\n }\n // Emoji check with pre-filter\n if (couldBeEmoji(segment) && rgiEmojiRegex.test(segment)) {\n return 2;\n }\n // Get base visible codepoint\n const base = segment.replace(leadingNonPrintingRegex, \"\");\n const cp = base.codePointAt(0);\n if (cp === undefined) {\n return 0;\n }\n // Regional indicator symbols (U+1F1E6..U+1F1FF) are often rendered as\n // full-width emoji in terminals, even when isolated during streaming.\n // Keep width conservative (2) to avoid terminal auto-wrap drift artifacts.\n if (cp >= 0x1f1e6 && cp <= 0x1f1ff) {\n return 2;\n }\n let width = eastAsianWidth(cp);\n // Trailing halfwidth/fullwidth forms and AM vowels that segment with a base.\n if (segment.length > 1) {\n for (const char of segment.slice(1)) {\n const c = char.codePointAt(0);\n if (c >= 0xff00 && c <= 0xffef) {\n width += eastAsianWidth(c);\n }\n else if (c === 0x0e33 || c === 0x0eb3) {\n width += 1;\n }\n }\n }\n return width;\n}\n/**\n * Calculate the visible width of a string in terminal columns.\n */\nexport function visibleWidth(str) {\n if (str.length === 0) {\n return 0;\n }\n // Fast path: pure ASCII printable\n if (isPrintableAscii(str)) {\n return str.length;\n }\n // Check cache\n const cached = widthCache.get(str);\n if (cached !== undefined) {\n return cached;\n }\n // Normalize: tabs to 3 spaces, strip ANSI escape codes\n let clean = str;\n if (str.includes(\"\\t\")) {\n clean = clean.replace(/\\t/g, \" \");\n }\n if (clean.includes(\"\\x1b\")) {\n // Strip supported ANSI/OSC/APC escape sequences in one pass.\n // This covers CSI styling/cursor codes, OSC hyperlinks and prompt markers,\n // and APC sequences like CURSOR_MARKER.\n let stripped = \"\";\n let i = 0;\n while (i < clean.length) {\n const ansi = extractAnsiCode(clean, i);\n if (ansi) {\n i += ansi.length;\n continue;\n }\n stripped += clean[i];\n i++;\n }\n clean = stripped;\n }\n // Calculate width\n let width = 0;\n for (const { segment } of graphemeSegmenter.segment(clean)) {\n width += graphemeWidth(segment);\n }\n // Cache result\n if (widthCache.size >= WIDTH_CACHE_SIZE) {\n const firstKey = widthCache.keys().next().value;\n if (firstKey !== undefined) {\n widthCache.delete(firstKey);\n }\n }\n widthCache.set(str, width);\n return width;\n}\n/**\n * Normalize text for terminal output without changing logical editor content.\n * Some terminals render precomposed Thai/Lao AM vowels inconsistently during\n * differential repaint. Their compatibility decompositions have the same cell\n * width but avoid stale-cell artifacts in terminal renderers. Visible tabs are\n * expanded to the fixed width used by layout so terminal tab stops cannot wrap\n * a logical line, while tabs inside terminal string sequences stay untouched.\n */\nconst THAI_LAO_AM_REGEX = /[\\u0e33\\u0eb3]/;\nconst THAI_LAO_AM_GLOBAL_REGEX = /[\\u0e33\\u0eb3]/g;\nexport function normalizeTerminalOutput(str) {\n let normalized = str;\n if (THAI_LAO_AM_REGEX.test(normalized)) {\n normalized = normalized.replace(THAI_LAO_AM_GLOBAL_REGEX, (char) => char === \"\\u0e33\" ? \"\\u0e4d\\u0e32\" : \"\\u0ecd\\u0eb2\");\n }\n if (!normalized.includes(\"\\t\"))\n return normalized;\n let result = \"\";\n let i = 0;\n while (i < normalized.length) {\n const ansi = extractAnsiCode(normalized, i);\n if (ansi) {\n result += ansi.code;\n i += ansi.length;\n continue;\n }\n result += normalized[i] === \"\\t\" ? \" \" : normalized[i];\n i++;\n }\n return result;\n}\n/**\n * Extract ANSI escape sequences from a string at the given position.\n */\nexport function extractAnsiCode(str, pos) {\n if (pos >= str.length || str[pos] !== \"\\x1b\")\n return null;\n const next = str[pos + 1];\n // CSI sequence: ESC [ ... m/G/K/H/J\n if (next === \"[\") {\n let j = pos + 2;\n while (j < str.length && !/[mGKHJ]/.test(str[j]))\n j++;\n if (j < str.length)\n return { code: str.substring(pos, j + 1), length: j + 1 - pos };\n return null;\n }\n // OSC sequence: ESC ] ... BEL or ESC ] ... ST (ESC \\)\n // Used for hyperlinks (OSC 8), window titles, etc.\n if (next === \"]\") {\n let j = pos + 2;\n while (j < str.length) {\n if (str[j] === \"\\x07\")\n return { code: str.substring(pos, j + 1), length: j + 1 - pos };\n if (str[j] === \"\\x1b\" && str[j + 1] === \"\\\\\")\n return { code: str.substring(pos, j + 2), length: j + 2 - pos };\n j++;\n }\n return null;\n }\n // APC sequence: ESC _ ... BEL or ESC _ ... ST (ESC \\)\n // Used for cursor marker and application-specific commands\n if (next === \"_\") {\n let j = pos + 2;\n while (j < str.length) {\n if (str[j] === \"\\x07\")\n return { code: str.substring(pos, j + 1), length: j + 1 - pos };\n if (str[j] === \"\\x1b\" && str[j + 1] === \"\\\\\")\n return { code: str.substring(pos, j + 2), length: j + 2 - pos };\n j++;\n }\n return null;\n }\n return null;\n}\nfunction parseOsc8Hyperlink(ansiCode) {\n if (!ansiCode.startsWith(\"\\x1b]8;\")) {\n return undefined;\n }\n const terminator = ansiCode.endsWith(\"\\x07\") ? \"\\x07\" : \"\\x1b\\\\\";\n const body = ansiCode.slice(4, terminator === \"\\x07\" ? -1 : -2);\n const separatorIndex = body.indexOf(\";\");\n if (separatorIndex === -1) {\n return undefined;\n }\n const params = body.slice(0, separatorIndex);\n const url = body.slice(separatorIndex + 1);\n if (!url) {\n return null;\n }\n return { params, url, terminator };\n}\nfunction formatOsc8Hyperlink(hyperlink) {\n return `\\x1b]8;${hyperlink.params};${hyperlink.url}${hyperlink.terminator}`;\n}\nfunction formatOsc8Close(terminator) {\n return `\\x1b]8;;${terminator}`;\n}\n/**\n * Track active ANSI SGR codes to preserve styling across line breaks.\n */\nclass AnsiCodeTracker {\n // Track individual attributes separately so we can reset them specifically\n bold = false;\n dim = false;\n italic = false;\n underline = false;\n blink = false;\n inverse = false;\n hidden = false;\n strikethrough = false;\n fgColor = null; // Stores the full code like \"31\" or \"38;5;240\"\n bgColor = null; // Stores the full code like \"41\" or \"48;5;240\"\n activeHyperlink = null;\n process(ansiCode) {\n // OSC 8 hyperlink: \\x1b]8;;<url>\\x1b\\\\ (open) or \\x1b]8;;\\x1b\\\\ (close).\n // Preserve the original terminator because some terminals only make BEL-terminated\n // links clickable. OAuth login URLs use BEL, so reopening wrapped lines with ST\n // made only the first physical line clickable in those terminals.\n const hyperlink = parseOsc8Hyperlink(ansiCode);\n if (hyperlink !== undefined) {\n this.activeHyperlink = hyperlink;\n return;\n }\n if (!ansiCode.endsWith(\"m\")) {\n return;\n }\n // Extract the parameters between \\x1b[ and m\n const match = ansiCode.match(/\\x1b\\[([\\d;]*)m/);\n if (!match)\n return;\n const params = match[1];\n if (params === \"\" || params === \"0\") {\n // Full reset\n this.reset();\n return;\n }\n // Parse parameters (can be semicolon-separated)\n const parts = params.split(\";\");\n let i = 0;\n while (i < parts.length) {\n const code = Number.parseInt(parts[i], 10);\n // Handle 256-color and RGB codes which consume multiple parameters\n if (code === 38 || code === 48) {\n // 38;5;N (256 color fg) or 38;2;R;G;B (RGB fg)\n // 48;5;N (256 color bg) or 48;2;R;G;B (RGB bg)\n if (parts[i + 1] === \"5\" && parts[i + 2] !== undefined) {\n // 256 color: 38;5;N or 48;5;N\n const colorCode = `${parts[i]};${parts[i + 1]};${parts[i + 2]}`;\n if (code === 38) {\n this.fgColor = colorCode;\n }\n else {\n this.bgColor = colorCode;\n }\n i += 3;\n continue;\n }\n else if (parts[i + 1] === \"2\" && parts[i + 4] !== undefined) {\n // RGB color: 38;2;R;G;B or 48;2;R;G;B\n const colorCode = `${parts[i]};${parts[i + 1]};${parts[i + 2]};${parts[i + 3]};${parts[i + 4]}`;\n if (code === 38) {\n this.fgColor = colorCode;\n }\n else {\n this.bgColor = colorCode;\n }\n i += 5;\n continue;\n }\n }\n // Standard SGR codes\n switch (code) {\n case 0:\n this.reset();\n break;\n case 1:\n this.bold = true;\n break;\n case 2:\n this.dim = true;\n break;\n case 3:\n this.italic = true;\n break;\n case 4:\n this.underline = true;\n break;\n case 5:\n this.blink = true;\n break;\n case 7:\n this.inverse = true;\n break;\n case 8:\n this.hidden = true;\n break;\n case 9:\n this.strikethrough = true;\n break;\n case 21:\n this.bold = false;\n break; // Some terminals\n case 22:\n this.bold = false;\n this.dim = false;\n break;\n case 23:\n this.italic = false;\n break;\n case 24:\n this.underline = false;\n break;\n case 25:\n this.blink = false;\n break;\n case 27:\n this.inverse = false;\n break;\n case 28:\n this.hidden = false;\n break;\n case 29:\n this.strikethrough = false;\n break;\n case 39:\n this.fgColor = null;\n break; // Default fg\n case 49:\n this.bgColor = null;\n break; // Default bg\n default:\n // Standard foreground colors 30-37, 90-97\n if ((code >= 30 && code <= 37) || (code >= 90 && code <= 97)) {\n this.fgColor = String(code);\n }\n // Standard background colors 40-47, 100-107\n else if ((code >= 40 && code <= 47) || (code >= 100 && code <= 107)) {\n this.bgColor = String(code);\n }\n break;\n }\n i++;\n }\n }\n reset() {\n this.bold = false;\n this.dim = false;\n this.italic = false;\n this.underline = false;\n this.blink = false;\n this.inverse = false;\n this.hidden = false;\n this.strikethrough = false;\n this.fgColor = null;\n this.bgColor = null;\n // SGR reset does not affect OSC 8 hyperlink state\n }\n /** Clear all state for reuse. */\n clear() {\n this.reset();\n this.activeHyperlink = null;\n }\n getActiveCodes() {\n const codes = [];\n if (this.bold)\n codes.push(\"1\");\n if (this.dim)\n codes.push(\"2\");\n if (this.italic)\n codes.push(\"3\");\n if (this.underline)\n codes.push(\"4\");\n if (this.blink)\n codes.push(\"5\");\n if (this.inverse)\n codes.push(\"7\");\n if (this.hidden)\n codes.push(\"8\");\n if (this.strikethrough)\n codes.push(\"9\");\n if (this.fgColor)\n codes.push(this.fgColor);\n if (this.bgColor)\n codes.push(this.bgColor);\n let result = codes.length > 0 ? `\\x1b[${codes.join(\";\")}m` : \"\";\n if (this.activeHyperlink) {\n result += formatOsc8Hyperlink(this.activeHyperlink);\n }\n return result;\n }\n hasActiveCodes() {\n return (this.bold ||\n this.dim ||\n this.italic ||\n this.underline ||\n this.blink ||\n this.inverse ||\n this.hidden ||\n this.strikethrough ||\n this.fgColor !== null ||\n this.bgColor !== null ||\n this.activeHyperlink !== null);\n }\n /**\n * Get reset codes for attributes that need to be turned off at line end.\n * Underline must be closed to prevent bleeding into padding.\n * Active OSC 8 hyperlinks must be closed and re-opened on the next line.\n * Returns empty string if no attributes need closing.\n */\n getLineEndReset() {\n let result = \"\";\n if (this.underline) {\n result += \"\\x1b[24m\"; // Underline off only\n }\n if (this.activeHyperlink) {\n result += formatOsc8Close(this.activeHyperlink.terminator); // Re-opened at line start via getActiveCodes()\n }\n return result;\n }\n}\nfunction updateTrackerFromText(text, tracker) {\n let i = 0;\n while (i < text.length) {\n const ansiResult = extractAnsiCode(text, i);\n if (ansiResult) {\n tracker.process(ansiResult.code);\n i += ansiResult.length;\n }\n else {\n i++;\n }\n }\n}\n/**\n * Split text into words while keeping ANSI codes attached.\n */\nfunction splitIntoTokensWithAnsi(text) {\n const tokens = [];\n let current = \"\";\n let pendingAnsi = \"\"; // ANSI codes waiting to be attached to next visible content\n let currentKind = null;\n let i = 0;\n const flushCurrent = () => {\n if (!current) {\n return;\n }\n tokens.push(current);\n current = \"\";\n currentKind = null;\n };\n while (i < text.length) {\n const ansiResult = extractAnsiCode(text, i);\n if (ansiResult) {\n // Hold ANSI codes separately - they'll be attached to the next visible char\n pendingAnsi += ansiResult.code;\n i += ansiResult.length;\n continue;\n }\n let end = i;\n while (end < text.length && !extractAnsiCode(text, end)) {\n end++;\n }\n for (const { segment } of graphemeSegmenter.segment(text.slice(i, end))) {\n const segmentIsSpace = segment === \" \";\n if (!segmentIsSpace && cjkBreakRegex.test(segment)) {\n flushCurrent();\n const token = pendingAnsi + segment;\n pendingAnsi = \"\";\n tokens.push(token);\n continue;\n }\n const segmentKind = segmentIsSpace ? \"space\" : \"word\";\n if (current && currentKind !== segmentKind) {\n flushCurrent();\n }\n // Attach any pending ANSI codes to this visible character\n if (pendingAnsi) {\n current += pendingAnsi;\n pendingAnsi = \"\";\n }\n currentKind = segmentKind;\n current += segment;\n }\n i = end;\n }\n // Handle any remaining pending ANSI codes (attach to last token)\n if (pendingAnsi) {\n if (current) {\n current += pendingAnsi;\n }\n else if (tokens.length > 0) {\n tokens[tokens.length - 1] += pendingAnsi;\n }\n else {\n current = pendingAnsi;\n }\n }\n if (current) {\n tokens.push(current);\n }\n return tokens;\n}\n/**\n * Wrap text with ANSI codes preserved.\n *\n * ONLY does word wrapping - NO padding, NO background colors.\n * Returns lines where each line is <= width visible chars.\n * Active ANSI codes are preserved across line breaks.\n *\n * @param text - Text to wrap (may contain ANSI codes and newlines)\n * @param width - Maximum visible width per line\n * @returns Array of wrapped lines (NOT padded to width)\n */\nexport function wrapTextWithAnsi(text, width) {\n if (!text) {\n return [\"\"];\n }\n // Handle newlines by processing each line separately\n // Track ANSI state across lines so styles carry over after literal newlines\n const inputLines = text.split(/\\r\\n|\\r|\\n/);\n const result = [];\n const tracker = new AnsiCodeTracker();\n for (const inputLine of inputLines) {\n // Prepend active ANSI codes from previous lines (except for first line)\n const prefix = result.length > 0 ? tracker.getActiveCodes() : \"\";\n const wrappedLines = wrapSingleLine(prefix + inputLine, width);\n for (const wrappedLine of wrappedLines) {\n result.push(wrappedLine);\n }\n // Update tracker with codes from this line for next iteration\n updateTrackerFromText(inputLine, tracker);\n }\n return result.length > 0 ? result : [\"\"];\n}\nfunction wrapSingleLine(line, width) {\n if (!line) {\n return [\"\"];\n }\n const visibleLength = visibleWidth(line);\n if (visibleLength <= width) {\n return [line];\n }\n const wrapped = [];\n const tracker = new AnsiCodeTracker();\n const tokens = splitIntoTokensWithAnsi(line);\n let currentLine = \"\";\n let currentVisibleLength = 0;\n for (const token of tokens) {\n const tokenVisibleLength = visibleWidth(token);\n const isWhitespace = token.trim() === \"\";\n // Token itself is too long - break it character by character\n if (tokenVisibleLength > width && !isWhitespace) {\n if (currentLine) {\n // Add specific reset for underline only (preserves background)\n const lineEndReset = tracker.getLineEndReset();\n if (lineEndReset) {\n currentLine += lineEndReset;\n }\n wrapped.push(currentLine);\n currentLine = \"\";\n currentVisibleLength = 0;\n }\n // Break long token - breakLongWord handles its own resets\n const broken = breakLongWord(token, width, tracker);\n for (let i = 0; i < broken.length - 1; i++) {\n wrapped.push(broken[i]);\n }\n currentLine = broken[broken.length - 1];\n currentVisibleLength = visibleWidth(currentLine);\n continue;\n }\n // Check if adding this token would exceed width\n const totalNeeded = currentVisibleLength + tokenVisibleLength;\n if (totalNeeded > width && currentVisibleLength > 0) {\n // Trim trailing whitespace, then add underline reset (not full reset, to preserve background)\n let lineToWrap = currentLine.trimEnd();\n const lineEndReset = tracker.getLineEndReset();\n if (lineEndReset) {\n lineToWrap += lineEndReset;\n }\n wrapped.push(lineToWrap);\n if (isWhitespace) {\n // Don't start new line with whitespace\n currentLine = tracker.getActiveCodes();\n currentVisibleLength = 0;\n }\n else {\n currentLine = tracker.getActiveCodes() + token;\n currentVisibleLength = tokenVisibleLength;\n }\n }\n else {\n // Add to current line\n currentLine += token;\n currentVisibleLength += tokenVisibleLength;\n }\n updateTrackerFromText(token, tracker);\n }\n if (currentLine) {\n // No reset at end of final line - let caller handle it\n wrapped.push(currentLine);\n }\n // Trailing whitespace can cause lines to exceed the requested width\n return wrapped.length > 0 ? wrapped.map((line) => line.trimEnd()) : [\"\"];\n}\nexport const PUNCTUATION_REGEX = /[(){}[\\]<>.,;:'\"!?+\\-=*/\\\\|&%^$#@~`]/;\n/**\n * Check if a character is whitespace.\n */\nexport function isWhitespaceChar(char) {\n return /\\s/.test(char);\n}\n/**\n * Check if a character is punctuation.\n */\nexport function isPunctuationChar(char) {\n return PUNCTUATION_REGEX.test(char);\n}\nfunction breakLongWord(word, width, tracker) {\n const lines = [];\n let currentLine = tracker.getActiveCodes();\n let currentWidth = 0;\n // First, separate ANSI codes from visible content\n // We need to handle ANSI codes specially since they're not graphemes\n let i = 0;\n const segments = [];\n while (i < word.length) {\n const ansiResult = extractAnsiCode(word, i);\n if (ansiResult) {\n segments.push({ type: \"ansi\", value: ansiResult.code });\n i += ansiResult.length;\n }\n else {\n // Find the next ANSI code or end of string\n let end = i;\n while (end < word.length) {\n const nextAnsi = extractAnsiCode(word, end);\n if (nextAnsi)\n break;\n end++;\n }\n // Segment this non-ANSI portion into graphemes\n const textPortion = word.slice(i, end);\n for (const seg of graphemeSegmenter.segment(textPortion)) {\n segments.push({ type: \"grapheme\", value: seg.segment });\n }\n i = end;\n }\n }\n // Now process segments\n for (const seg of segments) {\n if (seg.type === \"ansi\") {\n currentLine += seg.value;\n tracker.process(seg.value);\n continue;\n }\n const grapheme = seg.value;\n // Skip empty graphemes to avoid issues with string-width calculation\n if (!grapheme)\n continue;\n const graphemeWidth = visibleWidth(grapheme);\n if (currentWidth + graphemeWidth > width) {\n // Add specific reset for underline only (preserves background)\n const lineEndReset = tracker.getLineEndReset();\n if (lineEndReset) {\n currentLine += lineEndReset;\n }\n lines.push(currentLine);\n currentLine = tracker.getActiveCodes();\n currentWidth = 0;\n }\n currentLine += grapheme;\n currentWidth += graphemeWidth;\n }\n if (currentLine) {\n // No reset at end of final segment - caller handles continuation\n lines.push(currentLine);\n }\n return lines.length > 0 ? lines : [\"\"];\n}\n/**\n * Apply background color to a line, padding to full width.\n *\n * @param line - Line of text (may contain ANSI codes)\n * @param width - Total width to pad to\n * @param bgFn - Background color function\n * @returns Line with background applied and padded to width\n */\nexport function applyBackgroundToLine(line, width, bgFn) {\n // Calculate padding needed\n const visibleLen = visibleWidth(line);\n const paddingNeeded = Math.max(0, width - visibleLen);\n const padding = \" \".repeat(paddingNeeded);\n // Apply background to content + padding\n const withPadding = line + padding;\n return bgFn(withPadding);\n}\n/**\n * Truncate text to fit within a maximum visible width, adding ellipsis if needed.\n * Optionally pad with spaces to reach exactly maxWidth.\n * Properly handles ANSI escape codes (they don't count toward width).\n *\n * @param text - Text to truncate (may contain ANSI codes)\n * @param maxWidth - Maximum visible width\n * @param ellipsis - Ellipsis string to append when truncating (default: \"...\")\n * @param pad - If true, pad result with spaces to exactly maxWidth (default: false)\n * @returns Truncated text, optionally padded to exactly maxWidth\n */\nexport function truncateToWidth(text, maxWidth, ellipsis = \"...\", pad = false) {\n if (maxWidth <= 0) {\n return \"\";\n }\n if (text.length === 0) {\n return pad ? \" \".repeat(maxWidth) : \"\";\n }\n const ellipsisWidth = visibleWidth(ellipsis);\n if (ellipsisWidth >= maxWidth) {\n const textWidth = visibleWidth(text);\n if (textWidth <= maxWidth) {\n return pad ? text + \" \".repeat(maxWidth - textWidth) : text;\n }\n const clippedEllipsis = truncateFragmentToWidth(ellipsis, maxWidth);\n if (clippedEllipsis.width === 0) {\n return pad ? \" \".repeat(maxWidth) : \"\";\n }\n return finalizeTruncatedResult(\"\", 0, clippedEllipsis.text, clippedEllipsis.width, maxWidth, pad);\n }\n if (isPrintableAscii(text)) {\n if (text.length <= maxWidth) {\n return pad ? text + \" \".repeat(maxWidth - text.length) : text;\n }\n const targetWidth = maxWidth - ellipsisWidth;\n return finalizeTruncatedResult(text.slice(0, targetWidth), targetWidth, ellipsis, ellipsisWidth, maxWidth, pad);\n }\n const targetWidth = maxWidth - ellipsisWidth;\n let result = \"\";\n let pendingAnsi = \"\";\n let visibleSoFar = 0;\n let keptWidth = 0;\n let keepContiguousPrefix = true;\n let overflowed = false;\n let exhaustedInput = false;\n const hasAnsi = text.includes(\"\\x1b\");\n const hasTabs = text.includes(\"\\t\");\n if (!hasAnsi && !hasTabs) {\n for (const { segment } of graphemeSegmenter.segment(text)) {\n const width = graphemeWidth(segment);\n if (keepContiguousPrefix && keptWidth + width <= targetWidth) {\n result += segment;\n keptWidth += width;\n }\n else {\n keepContiguousPrefix = false;\n }\n visibleSoFar += width;\n if (visibleSoFar > maxWidth) {\n overflowed = true;\n break;\n }\n }\n exhaustedInput = !overflowed;\n }\n else {\n let i = 0;\n while (i < text.length) {\n const ansi = extractAnsiCode(text, i);\n if (ansi) {\n pendingAnsi += ansi.code;\n i += ansi.length;\n continue;\n }\n if (text[i] === \"\\t\") {\n if (keepContiguousPrefix && keptWidth + 3 <= targetWidth) {\n if (pendingAnsi) {\n result += pendingAnsi;\n pendingAnsi = \"\";\n }\n result += \"\\t\";\n keptWidth += 3;\n }\n else {\n keepContiguousPrefix = false;\n pendingAnsi = \"\";\n }\n visibleSoFar += 3;\n if (visibleSoFar > maxWidth) {\n overflowed = true;\n break;\n }\n i++;\n continue;\n }\n let end = i;\n while (end < text.length && text[end] !== \"\\t\") {\n const nextAnsi = extractAnsiCode(text, end);\n if (nextAnsi) {\n break;\n }\n end++;\n }\n for (const { segment } of graphemeSegmenter.segment(text.slice(i, end))) {\n const width = graphemeWidth(segment);\n if (keepContiguousPrefix && keptWidth + width <= targetWidth) {\n if (pendingAnsi) {\n result += pendingAnsi;\n pendingAnsi = \"\";\n }\n result += segment;\n keptWidth += width;\n }\n else {\n keepContiguousPrefix = false;\n pendingAnsi = \"\";\n }\n visibleSoFar += width;\n if (visibleSoFar > maxWidth) {\n overflowed = true;\n break;\n }\n }\n if (overflowed) {\n break;\n }\n i = end;\n }\n exhaustedInput = i >= text.length;\n }\n if (!overflowed && exhaustedInput) {\n return pad ? text + \" \".repeat(Math.max(0, maxWidth - visibleSoFar)) : text;\n }\n return finalizeTruncatedResult(result, keptWidth, ellipsis, ellipsisWidth, maxWidth, pad);\n}\n/**\n * Extract a range of visible columns from a line. Handles ANSI codes and wide chars.\n * @param strict - If true, exclude wide chars at boundary that would extend past the range\n */\nexport function sliceByColumn(line, startCol, length, strict = false) {\n return sliceWithWidth(line, startCol, length, strict).text;\n}\n/** Like sliceByColumn but also returns the actual visible width of the result. */\nexport function sliceWithWidth(line, startCol, length, strict = false) {\n if (length <= 0)\n return { text: \"\", width: 0 };\n const endCol = startCol + length;\n let result = \"\", resultWidth = 0, currentCol = 0, i = 0, pendingAnsi = \"\";\n while (i < line.length) {\n const ansi = extractAnsiCode(line, i);\n if (ansi) {\n if (currentCol >= startCol && currentCol < endCol)\n result += ansi.code;\n else if (currentCol < startCol)\n pendingAnsi += ansi.code;\n i += ansi.length;\n continue;\n }\n let textEnd = i;\n while (textEnd < line.length && !extractAnsiCode(line, textEnd))\n textEnd++;\n for (const { segment } of graphemeSegmenter.segment(line.slice(i, textEnd))) {\n const w = graphemeWidth(segment);\n const inRange = currentCol >= startCol && currentCol < endCol;\n const fits = !strict || currentCol + w <= endCol;\n if (inRange && fits) {\n if (pendingAnsi) {\n result += pendingAnsi;\n pendingAnsi = \"\";\n }\n result += segment;\n resultWidth += w;\n }\n currentCol += w;\n if (currentCol >= endCol)\n break;\n }\n i = textEnd;\n if (currentCol >= endCol)\n break;\n }\n return { text: result, width: resultWidth };\n}\n// Pooled tracker instance for extractSegments (avoids allocation per call)\nconst pooledStyleTracker = new AnsiCodeTracker();\n/**\n * Extract \"before\" and \"after\" segments from a line in a single pass.\n * Used for overlay compositing where we need content before and after the overlay region.\n * Preserves styling from before the overlay that should affect content after it.\n */\nexport function extractSegments(line, beforeEnd, afterStart, afterLen, strictAfter = false) {\n let before = \"\", beforeWidth = 0, after = \"\", afterWidth = 0;\n let currentCol = 0, i = 0;\n let pendingAnsiBefore = \"\";\n let afterStarted = false;\n const afterEnd = afterStart + afterLen;\n // Track styling state so \"after\" inherits styling from before the overlay\n pooledStyleTracker.clear();\n while (i < line.length) {\n const ansi = extractAnsiCode(line, i);\n if (ansi) {\n // Track all SGR codes to know styling state at afterStart\n pooledStyleTracker.process(ansi.code);\n // Include ANSI codes in their respective segments\n if (currentCol < beforeEnd) {\n pendingAnsiBefore += ansi.code;\n }\n else if (currentCol >= afterStart && currentCol < afterEnd && afterStarted) {\n // Only include after we've started \"after\" (styling already prepended)\n after += ansi.code;\n }\n i += ansi.length;\n continue;\n }\n let textEnd = i;\n while (textEnd < line.length && !extractAnsiCode(line, textEnd))\n textEnd++;\n for (const { segment } of graphemeSegmenter.segment(line.slice(i, textEnd))) {\n const w = graphemeWidth(segment);\n if (currentCol < beforeEnd && currentCol + w <= beforeEnd) {\n if (pendingAnsiBefore) {\n before += pendingAnsiBefore;\n pendingAnsiBefore = \"\";\n }\n before += segment;\n beforeWidth += w;\n }\n else if (currentCol >= afterStart && currentCol < afterEnd) {\n const fits = !strictAfter || currentCol + w <= afterEnd;\n if (fits) {\n // On first \"after\" grapheme, prepend inherited styling from before overlay\n if (!afterStarted) {\n after += pooledStyleTracker.getActiveCodes();\n afterStarted = true;\n }\n after += segment;\n afterWidth += w;\n }\n }\n currentCol += w;\n // Early exit: done with \"before\" only, or done with both segments\n if (afterLen <= 0 ? currentCol >= beforeEnd : currentCol >= afterEnd)\n break;\n }\n i = textEnd;\n if (afterLen <= 0 ? currentCol >= beforeEnd : currentCol >= afterEnd)\n break;\n }\n return { before, beforeWidth, after, afterWidth };\n}\n//# sourceMappingURL=utils.js.map","/**\n * Keyboard input handling for terminal applications.\n *\n * Supports both legacy terminal sequences and Kitty keyboard protocol.\n * See: https://sw.kovidgoyal.net/kitty/keyboard-protocol/\n * Reference: https://github.com/sst/opentui/blob/7da92b4088aebfe27b9f691c04163a48821e49fd/packages/core/src/lib/parse.keypress.ts\n *\n * Symbol keys are also supported, however some ctrl+symbol combos\n * overlap with ASCII codes, e.g. ctrl+[ = ESC.\n * See: https://sw.kovidgoyal.net/kitty/keyboard-protocol/#legacy-ctrl-mapping-of-ascii-keys\n * Those can still be * used for ctrl+shift combos\n *\n * API:\n * - matchesKey(data, keyId) - Check if input matches a key identifier\n * - parseKey(data) - Parse input and return the key identifier\n * - Key - Helper object for creating typed key identifiers\n * - setKittyProtocolActive(active) - Set global Kitty protocol state\n * - isKittyProtocolActive() - Query global Kitty protocol state\n */\n// =============================================================================\n// Global Kitty Protocol State\n// =============================================================================\nlet _kittyProtocolActive = false;\n/**\n * Set the global Kitty keyboard protocol state.\n * Called by ProcessTerminal after detecting protocol support.\n */\nexport function setKittyProtocolActive(active) {\n _kittyProtocolActive = active;\n}\n/**\n * Query whether Kitty keyboard protocol is currently active.\n */\nexport function isKittyProtocolActive() {\n return _kittyProtocolActive;\n}\n/**\n * Helper object for creating typed key identifiers with autocomplete.\n *\n * Usage:\n * - Key.escape, Key.enter, Key.tab, etc. for special keys\n * - Key.backtick, Key.comma, Key.period, etc. for symbol keys\n * - Key.ctrl(\"c\"), Key.alt(\"x\"), Key.super(\"k\") for single modifiers\n * - Key.ctrlShift(\"p\"), Key.ctrlAlt(\"x\"), Key.ctrlSuper(\"k\") for combined modifiers\n */\nexport const Key = {\n // Special keys\n escape: \"escape\",\n esc: \"esc\",\n enter: \"enter\",\n return: \"return\",\n tab: \"tab\",\n space: \"space\",\n backspace: \"backspace\",\n delete: \"delete\",\n insert: \"insert\",\n clear: \"clear\",\n home: \"home\",\n end: \"end\",\n pageUp: \"pageUp\",\n pageDown: \"pageDown\",\n up: \"up\",\n down: \"down\",\n left: \"left\",\n right: \"right\",\n f1: \"f1\",\n f2: \"f2\",\n f3: \"f3\",\n f4: \"f4\",\n f5: \"f5\",\n f6: \"f6\",\n f7: \"f7\",\n f8: \"f8\",\n f9: \"f9\",\n f10: \"f10\",\n f11: \"f11\",\n f12: \"f12\",\n // Symbol keys\n backtick: \"`\",\n hyphen: \"-\",\n equals: \"=\",\n leftbracket: \"[\",\n rightbracket: \"]\",\n backslash: \"\\\\\",\n semicolon: \";\",\n quote: \"'\",\n comma: \",\",\n period: \".\",\n slash: \"/\",\n exclamation: \"!\",\n at: \"@\",\n hash: \"#\",\n dollar: \"$\",\n percent: \"%\",\n caret: \"^\",\n ampersand: \"&\",\n asterisk: \"*\",\n leftparen: \"(\",\n rightparen: \")\",\n underscore: \"_\",\n plus: \"+\",\n pipe: \"|\",\n tilde: \"~\",\n leftbrace: \"{\",\n rightbrace: \"}\",\n colon: \":\",\n lessthan: \"<\",\n greaterthan: \">\",\n question: \"?\",\n // Single modifiers\n ctrl: (key) => `ctrl+${key}`,\n shift: (key) => `shift+${key}`,\n alt: (key) => `alt+${key}`,\n super: (key) => `super+${key}`,\n // Combined modifiers\n ctrlShift: (key) => `ctrl+shift+${key}`,\n shiftCtrl: (key) => `shift+ctrl+${key}`,\n ctrlAlt: (key) => `ctrl+alt+${key}`,\n altCtrl: (key) => `alt+ctrl+${key}`,\n shiftAlt: (key) => `shift+alt+${key}`,\n altShift: (key) => `alt+shift+${key}`,\n ctrlSuper: (key) => `ctrl+super+${key}`,\n superCtrl: (key) => `super+ctrl+${key}`,\n shiftSuper: (key) => `shift+super+${key}`,\n superShift: (key) => `super+shift+${key}`,\n altSuper: (key) => `alt+super+${key}`,\n superAlt: (key) => `super+alt+${key}`,\n // Triple modifiers\n ctrlShiftAlt: (key) => `ctrl+shift+alt+${key}`,\n ctrlShiftSuper: (key) => `ctrl+shift+super+${key}`,\n};\n// =============================================================================\n// Constants\n// =============================================================================\nconst SYMBOL_KEYS = new Set([\n \"`\",\n \"-\",\n \"=\",\n \"[\",\n \"]\",\n \"\\\\\",\n \";\",\n \"'\",\n \",\",\n \".\",\n \"/\",\n \"!\",\n \"@\",\n \"#\",\n \"$\",\n \"%\",\n \"^\",\n \"&\",\n \"*\",\n \"(\",\n \")\",\n \"_\",\n \"+\",\n \"|\",\n \"~\",\n \"{\",\n \"}\",\n \":\",\n \"<\",\n \">\",\n \"?\",\n]);\nconst MODIFIERS = {\n shift: 1,\n alt: 2,\n ctrl: 4,\n super: 8,\n};\nconst LOCK_MASK = 64 + 128; // Caps Lock + Num Lock\nconst CODEPOINTS = {\n escape: 27,\n tab: 9,\n enter: 13,\n space: 32,\n backspace: 127,\n kpEnter: 57414, // Numpad Enter (Kitty protocol)\n};\nconst ARROW_CODEPOINTS = {\n up: -1,\n down: -2,\n right: -3,\n left: -4,\n};\nconst FUNCTIONAL_CODEPOINTS = {\n delete: -10,\n insert: -11,\n pageUp: -12,\n pageDown: -13,\n home: -14,\n end: -15,\n};\nconst KITTY_FUNCTIONAL_KEY_EQUIVALENTS = new Map([\n [57399, 48], // KP_0 -> 0\n [57400, 49], // KP_1 -> 1\n [57401, 50], // KP_2 -> 2\n [57402, 51], // KP_3 -> 3\n [57403, 52], // KP_4 -> 4\n [57404, 53], // KP_5 -> 5\n [57405, 54], // KP_6 -> 6\n [57406, 55], // KP_7 -> 7\n [57407, 56], // KP_8 -> 8\n [57408, 57], // KP_9 -> 9\n [57409, 46], // KP_DECIMAL -> .\n [57410, 47], // KP_DIVIDE -> /\n [57411, 42], // KP_MULTIPLY -> *\n [57412, 45], // KP_SUBTRACT -> -\n [57413, 43], // KP_ADD -> +\n [57415, 61], // KP_EQUAL -> =\n [57416, 44], // KP_SEPARATOR -> ,\n [57417, ARROW_CODEPOINTS.left],\n [57418, ARROW_CODEPOINTS.right],\n [57419, ARROW_CODEPOINTS.up],\n [57420, ARROW_CODEPOINTS.down],\n [57421, FUNCTIONAL_CODEPOINTS.pageUp],\n [57422, FUNCTIONAL_CODEPOINTS.pageDown],\n [57423, FUNCTIONAL_CODEPOINTS.home],\n [57424, FUNCTIONAL_CODEPOINTS.end],\n [57425, FUNCTIONAL_CODEPOINTS.insert],\n [57426, FUNCTIONAL_CODEPOINTS.delete],\n]);\nfunction normalizeKittyFunctionalCodepoint(codepoint) {\n return KITTY_FUNCTIONAL_KEY_EQUIVALENTS.get(codepoint) ?? codepoint;\n}\nfunction normalizeShiftedLetterIdentityCodepoint(codepoint, modifier) {\n const effectiveModifier = modifier & ~LOCK_MASK;\n if ((effectiveModifier & MODIFIERS.shift) !== 0 && codepoint >= 65 && codepoint <= 90) {\n return codepoint + 32;\n }\n return codepoint;\n}\nconst LEGACY_KEY_SEQUENCES = {\n up: [\"\\x1b[A\", \"\\x1bOA\"],\n down: [\"\\x1b[B\", \"\\x1bOB\"],\n right: [\"\\x1b[C\", \"\\x1bOC\"],\n left: [\"\\x1b[D\", \"\\x1bOD\"],\n home: [\"\\x1b[H\", \"\\x1bOH\", \"\\x1b[1~\", \"\\x1b[7~\"],\n end: [\"\\x1b[F\", \"\\x1bOF\", \"\\x1b[4~\", \"\\x1b[8~\"],\n insert: [\"\\x1b[2~\"],\n delete: [\"\\x1b[3~\"],\n pageUp: [\"\\x1b[5~\", \"\\x1b[[5~\"],\n pageDown: [\"\\x1b[6~\", \"\\x1b[[6~\"],\n clear: [\"\\x1b[E\", \"\\x1bOE\"],\n f1: [\"\\x1bOP\", \"\\x1b[11~\", \"\\x1b[[A\"],\n f2: [\"\\x1bOQ\", \"\\x1b[12~\", \"\\x1b[[B\"],\n f3: [\"\\x1bOR\", \"\\x1b[13~\", \"\\x1b[[C\"],\n f4: [\"\\x1bOS\", \"\\x1b[14~\", \"\\x1b[[D\"],\n f5: [\"\\x1b[15~\", \"\\x1b[[E\"],\n f6: [\"\\x1b[17~\"],\n f7: [\"\\x1b[18~\"],\n f8: [\"\\x1b[19~\"],\n f9: [\"\\x1b[20~\"],\n f10: [\"\\x1b[21~\"],\n f11: [\"\\x1b[23~\"],\n f12: [\"\\x1b[24~\"],\n};\nconst LEGACY_SHIFT_SEQUENCES = {\n up: [\"\\x1b[a\"],\n down: [\"\\x1b[b\"],\n right: [\"\\x1b[c\"],\n left: [\"\\x1b[d\"],\n clear: [\"\\x1b[e\"],\n insert: [\"\\x1b[2$\"],\n delete: [\"\\x1b[3$\"],\n pageUp: [\"\\x1b[5$\"],\n pageDown: [\"\\x1b[6$\"],\n home: [\"\\x1b[7$\"],\n end: [\"\\x1b[8$\"],\n};\nconst LEGACY_CTRL_SEQUENCES = {\n up: [\"\\x1bOa\"],\n down: [\"\\x1bOb\"],\n right: [\"\\x1bOc\"],\n left: [\"\\x1bOd\"],\n clear: [\"\\x1bOe\"],\n insert: [\"\\x1b[2^\"],\n delete: [\"\\x1b[3^\"],\n pageUp: [\"\\x1b[5^\"],\n pageDown: [\"\\x1b[6^\"],\n home: [\"\\x1b[7^\"],\n end: [\"\\x1b[8^\"],\n};\nconst LEGACY_SEQUENCE_KEY_IDS = {\n \"\\x1bOA\": \"up\",\n \"\\x1bOB\": \"down\",\n \"\\x1bOC\": \"right\",\n \"\\x1bOD\": \"left\",\n \"\\x1bOH\": \"home\",\n \"\\x1bOF\": \"end\",\n \"\\x1b[E\": \"clear\",\n \"\\x1bOE\": \"clear\",\n \"\\x1bOe\": \"ctrl+clear\",\n \"\\x1b[e\": \"shift+clear\",\n \"\\x1b[2~\": \"insert\",\n \"\\x1b[2$\": \"shift+insert\",\n \"\\x1b[2^\": \"ctrl+insert\",\n \"\\x1b[3$\": \"shift+delete\",\n \"\\x1b[3^\": \"ctrl+delete\",\n \"\\x1b[[5~\": \"pageUp\",\n \"\\x1b[[6~\": \"pageDown\",\n \"\\x1b[a\": \"shift+up\",\n \"\\x1b[b\": \"shift+down\",\n \"\\x1b[c\": \"shift+right\",\n \"\\x1b[d\": \"shift+left\",\n \"\\x1bOa\": \"ctrl+up\",\n \"\\x1bOb\": \"ctrl+down\",\n \"\\x1bOc\": \"ctrl+right\",\n \"\\x1bOd\": \"ctrl+left\",\n \"\\x1b[5$\": \"shift+pageUp\",\n \"\\x1b[6$\": \"shift+pageDown\",\n \"\\x1b[7$\": \"shift+home\",\n \"\\x1b[8$\": \"shift+end\",\n \"\\x1b[5^\": \"ctrl+pageUp\",\n \"\\x1b[6^\": \"ctrl+pageDown\",\n \"\\x1b[7^\": \"ctrl+home\",\n \"\\x1b[8^\": \"ctrl+end\",\n \"\\x1bOP\": \"f1\",\n \"\\x1bOQ\": \"f2\",\n \"\\x1bOR\": \"f3\",\n \"\\x1bOS\": \"f4\",\n \"\\x1b[11~\": \"f1\",\n \"\\x1b[12~\": \"f2\",\n \"\\x1b[13~\": \"f3\",\n \"\\x1b[14~\": \"f4\",\n \"\\x1b[[A\": \"f1\",\n \"\\x1b[[B\": \"f2\",\n \"\\x1b[[C\": \"f3\",\n \"\\x1b[[D\": \"f4\",\n \"\\x1b[[E\": \"f5\",\n \"\\x1b[15~\": \"f5\",\n \"\\x1b[17~\": \"f6\",\n \"\\x1b[18~\": \"f7\",\n \"\\x1b[19~\": \"f8\",\n \"\\x1b[20~\": \"f9\",\n \"\\x1b[21~\": \"f10\",\n \"\\x1b[23~\": \"f11\",\n \"\\x1b[24~\": \"f12\",\n \"\\x1bb\": \"alt+left\",\n \"\\x1bf\": \"alt+right\",\n \"\\x1bp\": \"alt+up\",\n \"\\x1bn\": \"alt+down\",\n};\nconst matchesLegacySequence = (data, sequences) => sequences.includes(data);\nconst matchesLegacyModifierSequence = (data, key, modifier) => {\n if (modifier === MODIFIERS.shift) {\n return matchesLegacySequence(data, LEGACY_SHIFT_SEQUENCES[key]);\n }\n if (modifier === MODIFIERS.ctrl) {\n return matchesLegacySequence(data, LEGACY_CTRL_SEQUENCES[key]);\n }\n return false;\n};\n// Store the last parsed event type for isKeyRelease() to query\nlet _lastEventType = \"press\";\n/**\n * Check if the last parsed key event was a key release.\n * Only meaningful when Kitty keyboard protocol with flag 2 is active.\n */\nexport function isKeyRelease(data) {\n // Don't treat bracketed paste content as key release, even if it contains\n // patterns like \":3F\" (e.g., bluetooth MAC addresses like \"90:62:3F:A5\").\n // Terminal.ts re-wraps paste content with bracketed paste markers before\n // passing to TUI, so pasted data will always contain \\x1b[200~.\n if (data.includes(\"\\x1b[200~\")) {\n return false;\n }\n // Quick check: release events with flag 2 contain \":3\"\n // Format: \\x1b[<codepoint>;<modifier>:3u\n if (data.includes(\":3u\") ||\n data.includes(\":3~\") ||\n data.includes(\":3A\") ||\n data.includes(\":3B\") ||\n data.includes(\":3C\") ||\n data.includes(\":3D\") ||\n data.includes(\":3H\") ||\n data.includes(\":3F\")) {\n return true;\n }\n return false;\n}\n/**\n * Check if the last parsed key event was a key repeat.\n * Only meaningful when Kitty keyboard protocol with flag 2 is active.\n */\nexport function isKeyRepeat(data) {\n // Don't treat bracketed paste content as key repeat, even if it contains\n // patterns like \":2F\". See isKeyRelease() for details.\n if (data.includes(\"\\x1b[200~\")) {\n return false;\n }\n if (data.includes(\":2u\") ||\n data.includes(\":2~\") ||\n data.includes(\":2A\") ||\n data.includes(\":2B\") ||\n data.includes(\":2C\") ||\n data.includes(\":2D\") ||\n data.includes(\":2H\") ||\n data.includes(\":2F\")) {\n return true;\n }\n return false;\n}\nfunction parseEventType(eventTypeStr) {\n if (!eventTypeStr)\n return \"press\";\n const eventType = parseInt(eventTypeStr, 10);\n if (eventType === 2)\n return \"repeat\";\n if (eventType === 3)\n return \"release\";\n return \"press\";\n}\nfunction parseKittySequence(data) {\n // CSI u format with alternate keys (flag 4):\n // \\x1b[<codepoint>u\n // \\x1b[<codepoint>;<mod>u\n // \\x1b[<codepoint>;<mod>:<event>u\n // \\x1b[<codepoint>:<shifted>;<mod>u\n // \\x1b[<codepoint>:<shifted>:<base>;<mod>u\n // \\x1b[<codepoint>::<base>;<mod>u (no shifted key, only base)\n //\n // With flag 2, event type is appended after modifier colon: 1=press, 2=repeat, 3=release\n // With flag 4, alternate keys are appended after codepoint with colons\n const csiUMatch = data.match(/^\\x1b\\[(\\d+)(?::(\\d*))?(?::(\\d+))?(?:;(\\d+))?(?::(\\d+))?u$/);\n if (csiUMatch) {\n const codepoint = parseInt(csiUMatch[1], 10);\n const shiftedKey = csiUMatch[2] && csiUMatch[2].length > 0 ? parseInt(csiUMatch[2], 10) : undefined;\n const baseLayoutKey = csiUMatch[3] ? parseInt(csiUMatch[3], 10) : undefined;\n const modValue = csiUMatch[4] ? parseInt(csiUMatch[4], 10) : 1;\n const eventType = parseEventType(csiUMatch[5]);\n _lastEventType = eventType;\n return { codepoint, shiftedKey, baseLayoutKey, modifier: modValue - 1, eventType };\n }\n // Arrow keys with modifier: \\x1b[1;<mod>A/B/C/D or \\x1b[1;<mod>:<event>A/B/C/D\n const arrowMatch = data.match(/^\\x1b\\[1;(\\d+)(?::(\\d+))?([ABCD])$/);\n if (arrowMatch) {\n const modValue = parseInt(arrowMatch[1], 10);\n const eventType = parseEventType(arrowMatch[2]);\n const arrowCodes = { A: -1, B: -2, C: -3, D: -4 };\n _lastEventType = eventType;\n return { codepoint: arrowCodes[arrowMatch[3]], modifier: modValue - 1, eventType };\n }\n // Functional keys: \\x1b[<num>~ or \\x1b[<num>;<mod>~ or \\x1b[<num>;<mod>:<event>~\n const funcMatch = data.match(/^\\x1b\\[(\\d+)(?:;(\\d+))?(?::(\\d+))?~$/);\n if (funcMatch) {\n const keyNum = parseInt(funcMatch[1], 10);\n const modValue = funcMatch[2] ? parseInt(funcMatch[2], 10) : 1;\n const eventType = parseEventType(funcMatch[3]);\n const funcCodes = {\n 2: FUNCTIONAL_CODEPOINTS.insert,\n 3: FUNCTIONAL_CODEPOINTS.delete,\n 5: FUNCTIONAL_CODEPOINTS.pageUp,\n 6: FUNCTIONAL_CODEPOINTS.pageDown,\n 7: FUNCTIONAL_CODEPOINTS.home,\n 8: FUNCTIONAL_CODEPOINTS.end,\n };\n const codepoint = funcCodes[keyNum];\n if (codepoint !== undefined) {\n _lastEventType = eventType;\n return { codepoint, modifier: modValue - 1, eventType };\n }\n }\n // Home/End with modifier: \\x1b[1;<mod>H/F or \\x1b[1;<mod>:<event>H/F\n const homeEndMatch = data.match(/^\\x1b\\[1;(\\d+)(?::(\\d+))?([HF])$/);\n if (homeEndMatch) {\n const modValue = parseInt(homeEndMatch[1], 10);\n const eventType = parseEventType(homeEndMatch[2]);\n const codepoint = homeEndMatch[3] === \"H\" ? FUNCTIONAL_CODEPOINTS.home : FUNCTIONAL_CODEPOINTS.end;\n _lastEventType = eventType;\n return { codepoint, modifier: modValue - 1, eventType };\n }\n return null;\n}\nfunction matchesKittySequence(data, expectedCodepoint, expectedModifier) {\n const parsed = parseKittySequence(data);\n if (!parsed)\n return false;\n const actualMod = parsed.modifier & ~LOCK_MASK;\n const expectedMod = expectedModifier & ~LOCK_MASK;\n // Check if modifiers match\n if (actualMod !== expectedMod)\n return false;\n const normalizedCodepoint = normalizeShiftedLetterIdentityCodepoint(normalizeKittyFunctionalCodepoint(parsed.codepoint), parsed.modifier);\n const normalizedExpectedCodepoint = normalizeShiftedLetterIdentityCodepoint(normalizeKittyFunctionalCodepoint(expectedCodepoint), expectedModifier);\n // Primary match: codepoint matches directly after normalizing functional keys\n if (normalizedCodepoint === normalizedExpectedCodepoint)\n return true;\n // Alternate match: use base layout key for non-Latin keyboard layouts.\n // This allows Ctrl+С (Cyrillic) to match Ctrl+c (Latin) when terminal reports\n // the base layout key (the key in standard PC-101 layout).\n //\n // Only fall back to base layout key when the codepoint is NOT already a\n // recognized Latin letter (a-z) or symbol (e.g., /, -, [, ;, etc.).\n // When the codepoint is a recognized key, it is authoritative regardless\n // of physical key position. This prevents remapped layouts (Dvorak, Colemak,\n // xremap, etc.) from causing false matches: both letters and symbols move\n // to different physical positions, so Ctrl+K could falsely match Ctrl+V\n // (letter remapping) and Ctrl+/ could falsely match Ctrl+[ (symbol remapping)\n // if the base layout key were always considered.\n if (parsed.baseLayoutKey !== undefined && parsed.baseLayoutKey === expectedCodepoint) {\n const cp = normalizedCodepoint;\n const isLatinLetter = cp >= 97 && cp <= 122; // a-z\n const isKnownSymbol = SYMBOL_KEYS.has(String.fromCharCode(cp));\n if (!isLatinLetter && !isKnownSymbol)\n return true;\n }\n return false;\n}\nfunction parseModifyOtherKeysSequence(data) {\n const match = data.match(/^\\x1b\\[27;(\\d+);(\\d+)~$/);\n if (!match)\n return null;\n const modValue = parseInt(match[1], 10);\n const codepoint = parseInt(match[2], 10);\n return { codepoint, modifier: modValue - 1 };\n}\n/**\n * Match xterm modifyOtherKeys format: CSI 27 ; modifiers ; keycode ~\n * This is used by terminals when Kitty protocol is not enabled.\n * Modifier values are 1-indexed: 2=shift, 3=alt, 5=ctrl, etc.\n */\nfunction matchesModifyOtherKeys(data, expectedKeycode, expectedModifier) {\n const parsed = parseModifyOtherKeysSequence(data);\n if (!parsed)\n return false;\n return parsed.codepoint === expectedKeycode && parsed.modifier === expectedModifier;\n}\nfunction isWindowsTerminalSession() {\n return (Boolean(process.env.WT_SESSION) && !process.env.SSH_CONNECTION && !process.env.SSH_CLIENT && !process.env.SSH_TTY);\n}\n/**\n * Raw 0x08 (BS) is ambiguous in legacy terminals.\n *\n * - Windows Terminal uses it for Ctrl+Backspace.\n * - Some legacy terminals and tmux setups send it for plain Backspace.\n *\n * Prefer explicit Kitty / CSI-u / modifyOtherKeys sequences whenever they are\n * available. Fall back to a Windows Terminal heuristic only for raw BS bytes.\n */\nfunction matchesRawBackspace(data, expectedModifier) {\n if (data === \"\\x7f\")\n return expectedModifier === 0;\n if (data !== \"\\x08\")\n return false;\n return isWindowsTerminalSession() ? expectedModifier === MODIFIERS.ctrl : expectedModifier === 0;\n}\n// =============================================================================\n// Generic Key Matching\n// =============================================================================\n/**\n * Get the control character for a key.\n * Uses the universal formula: code & 0x1f (mask to lower 5 bits)\n *\n * Works for:\n * - Letters a-z → 1-26\n * - Symbols [\\]_ → 27, 28, 29, 31\n * - Also maps - to same as _ (same physical key on US keyboards)\n */\nfunction rawCtrlChar(key) {\n const char = key.toLowerCase();\n const code = char.charCodeAt(0);\n if ((code >= 97 && code <= 122) || char === \"[\" || char === \"\\\\\" || char === \"]\" || char === \"_\") {\n return String.fromCharCode(code & 0x1f);\n }\n // Handle - as _ (same physical key on US keyboards)\n if (char === \"-\") {\n return String.fromCharCode(31); // Same as Ctrl+_\n }\n return null;\n}\nfunction isDigitKey(key) {\n return key >= \"0\" && key <= \"9\";\n}\nfunction matchesPrintableModifyOtherKeys(data, expectedKeycode, expectedModifier) {\n if (expectedModifier === 0)\n return false;\n const parsed = parseModifyOtherKeysSequence(data);\n if (!parsed || parsed.modifier !== expectedModifier)\n return false;\n return (normalizeShiftedLetterIdentityCodepoint(parsed.codepoint, parsed.modifier) ===\n normalizeShiftedLetterIdentityCodepoint(expectedKeycode, expectedModifier));\n}\nfunction formatKeyNameWithModifiers(keyName, modifier) {\n const mods = [];\n const effectiveMod = modifier & ~LOCK_MASK;\n const supportedModifierMask = MODIFIERS.shift | MODIFIERS.ctrl | MODIFIERS.alt | MODIFIERS.super;\n if ((effectiveMod & ~supportedModifierMask) !== 0)\n return undefined;\n if (effectiveMod & MODIFIERS.shift)\n mods.push(\"shift\");\n if (effectiveMod & MODIFIERS.ctrl)\n mods.push(\"ctrl\");\n if (effectiveMod & MODIFIERS.alt)\n mods.push(\"alt\");\n if (effectiveMod & MODIFIERS.super)\n mods.push(\"super\");\n return mods.length > 0 ? `${mods.join(\"+\")}+${keyName}` : keyName;\n}\nfunction parseKeyId(keyId) {\n const parts = keyId.toLowerCase().split(\"+\");\n const key = parts[parts.length - 1];\n if (!key)\n return null;\n return {\n key,\n ctrl: parts.includes(\"ctrl\"),\n shift: parts.includes(\"shift\"),\n alt: parts.includes(\"alt\"),\n super: parts.includes(\"super\"),\n };\n}\n/**\n * Match input data against a key identifier string.\n *\n * Supported key identifiers:\n * - Single keys: \"escape\", \"tab\", \"enter\", \"backspace\", \"delete\", \"home\", \"end\", \"space\"\n * - Arrow keys: \"up\", \"down\", \"left\", \"right\"\n * - Ctrl combinations: \"ctrl+c\", \"ctrl+z\", etc.\n * - Shift combinations: \"shift+tab\", \"shift+enter\"\n * - Alt combinations: \"alt+enter\", \"alt+backspace\"\n * - Super combinations: \"super+k\", \"super+enter\"\n * - Combined modifiers: \"shift+ctrl+p\", \"ctrl+alt+x\", \"ctrl+super+k\"\n *\n * Use the Key helper for autocomplete: Key.ctrl(\"c\"), Key.escape, Key.ctrlShift(\"p\"), Key.super(\"k\")\n *\n * @param data - Raw input data from terminal\n * @param keyId - Key identifier (e.g., \"ctrl+c\", \"escape\", Key.ctrl(\"c\"))\n */\nexport function matchesKey(data, keyId) {\n const parsed = parseKeyId(keyId);\n if (!parsed)\n return false;\n const { key, ctrl, shift, alt, super: superModifier } = parsed;\n let modifier = 0;\n if (shift)\n modifier |= MODIFIERS.shift;\n if (alt)\n modifier |= MODIFIERS.alt;\n if (ctrl)\n modifier |= MODIFIERS.ctrl;\n if (superModifier)\n modifier |= MODIFIERS.super;\n switch (key) {\n case \"escape\":\n case \"esc\":\n if (modifier !== 0)\n return false;\n return (data === \"\\x1b\" ||\n matchesKittySequence(data, CODEPOINTS.escape, 0) ||\n matchesModifyOtherKeys(data, CODEPOINTS.escape, 0));\n case \"space\":\n if (!_kittyProtocolActive) {\n if (modifier === MODIFIERS.ctrl && data === \"\\x00\") {\n return true;\n }\n if (modifier === MODIFIERS.alt && data === \"\\x1b \") {\n return true;\n }\n }\n if (modifier === 0) {\n return (data === \" \" ||\n matchesKittySequence(data, CODEPOINTS.space, 0) ||\n matchesModifyOtherKeys(data, CODEPOINTS.space, 0));\n }\n return (matchesKittySequence(data, CODEPOINTS.space, modifier) ||\n matchesModifyOtherKeys(data, CODEPOINTS.space, modifier));\n case \"tab\":\n if (modifier === MODIFIERS.shift) {\n return (data === \"\\x1b[Z\" ||\n matchesKittySequence(data, CODEPOINTS.tab, MODIFIERS.shift) ||\n matchesModifyOtherKeys(data, CODEPOINTS.tab, MODIFIERS.shift));\n }\n if (modifier === 0) {\n return data === \"\\t\" || matchesKittySequence(data, CODEPOINTS.tab, 0);\n }\n return (matchesKittySequence(data, CODEPOINTS.tab, modifier) ||\n matchesModifyOtherKeys(data, CODEPOINTS.tab, modifier));\n case \"enter\":\n case \"return\":\n if (modifier === MODIFIERS.shift) {\n // CSI u sequences (standard Kitty protocol)\n if (matchesKittySequence(data, CODEPOINTS.enter, MODIFIERS.shift) ||\n matchesKittySequence(data, CODEPOINTS.kpEnter, MODIFIERS.shift)) {\n return true;\n }\n // xterm modifyOtherKeys format (fallback when Kitty protocol not enabled)\n if (matchesModifyOtherKeys(data, CODEPOINTS.enter, MODIFIERS.shift)) {\n return true;\n }\n // When Kitty protocol is active, legacy sequences are custom terminal mappings\n // \\x1b\\r = Kitty's \"map shift+enter send_text all \\e\\r\"\n // \\n = Ghostty's \"keybind = shift+enter=text:\\n\"\n if (_kittyProtocolActive) {\n return data === \"\\x1b\\r\" || data === \"\\n\";\n }\n return false;\n }\n if (modifier === MODIFIERS.alt) {\n // CSI u sequences (standard Kitty protocol)\n if (matchesKittySequence(data, CODEPOINTS.enter, MODIFIERS.alt) ||\n matchesKittySequence(data, CODEPOINTS.kpEnter, MODIFIERS.alt)) {\n return true;\n }\n // xterm modifyOtherKeys format (fallback when Kitty protocol not enabled)\n if (matchesModifyOtherKeys(data, CODEPOINTS.enter, MODIFIERS.alt)) {\n return true;\n }\n // \\x1b\\r is alt+enter only in legacy mode (no Kitty protocol)\n // When Kitty protocol is active, alt+enter comes as CSI u sequence\n if (!_kittyProtocolActive) {\n return data === \"\\x1b\\r\";\n }\n return false;\n }\n if (modifier === 0) {\n return (data === \"\\r\" ||\n (!_kittyProtocolActive && data === \"\\n\") ||\n data === \"\\x1bOM\" || // SS3 M (numpad enter in some terminals)\n matchesKittySequence(data, CODEPOINTS.enter, 0) ||\n matchesKittySequence(data, CODEPOINTS.kpEnter, 0));\n }\n return (matchesKittySequence(data, CODEPOINTS.enter, modifier) ||\n matchesKittySequence(data, CODEPOINTS.kpEnter, modifier) ||\n matchesModifyOtherKeys(data, CODEPOINTS.enter, modifier));\n case \"backspace\":\n if (modifier === MODIFIERS.alt) {\n if (data === \"\\x1b\\x7f\" || data === \"\\x1b\\b\") {\n return true;\n }\n return (matchesKittySequence(data, CODEPOINTS.backspace, MODIFIERS.alt) ||\n matchesModifyOtherKeys(data, CODEPOINTS.backspace, MODIFIERS.alt));\n }\n if (modifier === MODIFIERS.ctrl) {\n // Legacy raw 0x08 is ambiguous: it can be Ctrl+Backspace on Windows\n // Terminal or plain Backspace on other terminals, while also\n // overlapping with Ctrl+H.\n if (matchesRawBackspace(data, MODIFIERS.ctrl))\n return true;\n return (matchesKittySequence(data, CODEPOINTS.backspace, MODIFIERS.ctrl) ||\n matchesModifyOtherKeys(data, CODEPOINTS.backspace, MODIFIERS.ctrl));\n }\n if (modifier === 0) {\n return (matchesRawBackspace(data, 0) ||\n matchesKittySequence(data, CODEPOINTS.backspace, 0) ||\n matchesModifyOtherKeys(data, CODEPOINTS.backspace, 0));\n }\n return (matchesKittySequence(data, CODEPOINTS.backspace, modifier) ||\n matchesModifyOtherKeys(data, CODEPOINTS.backspace, modifier));\n case \"insert\":\n if (modifier === 0) {\n return (matchesLegacySequence(data, LEGACY_KEY_SEQUENCES.insert) ||\n matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.insert, 0));\n }\n if (matchesLegacyModifierSequence(data, \"insert\", modifier)) {\n return true;\n }\n return matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.insert, modifier);\n case \"delete\":\n if (modifier === 0) {\n return (matchesLegacySequence(data, LEGACY_KEY_SEQUENCES.delete) ||\n matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.delete, 0));\n }\n if (matchesLegacyModifierSequence(data, \"delete\", modifier)) {\n return true;\n }\n return matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.delete, modifier);\n case \"clear\":\n if (modifier === 0) {\n return matchesLegacySequence(data, LEGACY_KEY_SEQUENCES.clear);\n }\n return matchesLegacyModifierSequence(data, \"clear\", modifier);\n case \"home\":\n if (modifier === 0) {\n return (matchesLegacySequence(data, LEGACY_KEY_SEQUENCES.home) ||\n matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.home, 0));\n }\n if (matchesLegacyModifierSequence(data, \"home\", modifier)) {\n return true;\n }\n return matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.home, modifier);\n case \"end\":\n if (modifier === 0) {\n return (matchesLegacySequence(data, LEGACY_KEY_SEQUENCES.end) ||\n matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.end, 0));\n }\n if (matchesLegacyModifierSequence(data, \"end\", modifier)) {\n return true;\n }\n return matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.end, modifier);\n case \"pageup\":\n if (modifier === 0) {\n return (matchesLegacySequence(data, LEGACY_KEY_SEQUENCES.pageUp) ||\n matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.pageUp, 0));\n }\n if (matchesLegacyModifierSequence(data, \"pageUp\", modifier)) {\n return true;\n }\n return matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.pageUp, modifier);\n case \"pagedown\":\n if (modifier === 0) {\n return (matchesLegacySequence(data, LEGACY_KEY_SEQUENCES.pageDown) ||\n matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.pageDown, 0));\n }\n if (matchesLegacyModifierSequence(data, \"pageDown\", modifier)) {\n return true;\n }\n return matchesKittySequence(data, FUNCTIONAL_CODEPOINTS.pageDown, modifier);\n case \"up\":\n if (modifier === MODIFIERS.alt) {\n return data === \"\\x1bp\" || matchesKittySequence(data, ARROW_CODEPOINTS.up, MODIFIERS.alt);\n }\n if (modifier === 0) {\n return (matchesLegacySequence(data, LEGACY_KEY_SEQUENCES.up) ||\n matchesKittySequence(data, ARROW_CODEPOINTS.up, 0));\n }\n if (matchesLegacyModifierSequence(data, \"up\", modifier)) {\n return true;\n }\n return matchesKittySequence(data, ARROW_CODEPOINTS.up, modifier);\n case \"down\":\n if (modifier === MODIFIERS.alt) {\n return data === \"\\x1bn\" || matchesKittySequence(data, ARROW_CODEPOINTS.down, MODIFIERS.alt);\n }\n if (modifier === 0) {\n return (matchesLegacySequence(data, LEGACY_KEY_SEQUENCES.down) ||\n matchesKittySequence(data, ARROW_CODEPOINTS.down, 0));\n }\n if (matchesLegacyModifierSequence(data, \"down\", modifier)) {\n return true;\n }\n return matchesKittySequence(data, ARROW_CODEPOINTS.down, modifier);\n case \"left\":\n if (modifier === MODIFIERS.alt) {\n return (data === \"\\x1b[1;3D\" ||\n (!_kittyProtocolActive && data === \"\\x1bB\") ||\n data === \"\\x1bb\" ||\n matchesKittySequence(data, ARROW_CODEPOINTS.left, MODIFIERS.alt));\n }\n if (modifier === MODIFIERS.ctrl) {\n return (data === \"\\x1b[1;5D\" ||\n matchesLegacyModifierSequence(data, \"left\", MODIFIERS.ctrl) ||\n matchesKittySequence(data, ARROW_CODEPOINTS.left, MODIFIERS.ctrl));\n }\n if (modifier === 0) {\n return (matchesLegacySequence(data, LEGACY_KEY_SEQUENCES.left) ||\n matchesKittySequence(data, ARROW_CODEPOINTS.left, 0));\n }\n if (matchesLegacyModifierSequence(data, \"left\", modifier)) {\n return true;\n }\n return matchesKittySequence(data, ARROW_CODEPOINTS.left, modifier);\n case \"right\":\n if (modifier === MODIFIERS.alt) {\n return (data === \"\\x1b[1;3C\" ||\n (!_kittyProtocolActive && data === \"\\x1bF\") ||\n data === \"\\x1bf\" ||\n matchesKittySequence(data, ARROW_CODEPOINTS.right, MODIFIERS.alt));\n }\n if (modifier === MODIFIERS.ctrl) {\n return (data === \"\\x1b[1;5C\" ||\n matchesLegacyModifierSequence(data, \"right\", MODIFIERS.ctrl) ||\n matchesKittySequence(data, ARROW_CODEPOINTS.right, MODIFIERS.ctrl));\n }\n if (modifier === 0) {\n return (matchesLegacySequence(data, LEGACY_KEY_SEQUENCES.right) ||\n matchesKittySequence(data, ARROW_CODEPOINTS.right, 0));\n }\n if (matchesLegacyModifierSequence(data, \"right\", modifier)) {\n return true;\n }\n return matchesKittySequence(data, ARROW_CODEPOINTS.right, modifier);\n case \"f1\":\n case \"f2\":\n case \"f3\":\n case \"f4\":\n case \"f5\":\n case \"f6\":\n case \"f7\":\n case \"f8\":\n case \"f9\":\n case \"f10\":\n case \"f11\":\n case \"f12\": {\n if (modifier !== 0) {\n return false;\n }\n const functionKey = key;\n return matchesLegacySequence(data, LEGACY_KEY_SEQUENCES[functionKey]);\n }\n }\n // Handle single letter/digit keys and symbols\n if (key.length === 1 && ((key >= \"a\" && key <= \"z\") || isDigitKey(key) || SYMBOL_KEYS.has(key))) {\n const codepoint = key.charCodeAt(0);\n const rawCtrl = rawCtrlChar(key);\n const isLetter = key >= \"a\" && key <= \"z\";\n const isDigit = isDigitKey(key);\n if (modifier === MODIFIERS.ctrl + MODIFIERS.alt && !_kittyProtocolActive && rawCtrl) {\n // Legacy: ctrl+alt+key is ESC followed by the control character.\n // If that legacy form does not match, continue so CSI-u and\n // modifyOtherKeys sequences from tmux can still be recognized.\n if (data === `\\x1b${rawCtrl}`)\n return true;\n }\n if (modifier === MODIFIERS.alt && !_kittyProtocolActive && (isLetter || isDigit || SYMBOL_KEYS.has(key))) {\n // Legacy: alt+printable key is ESC followed by the key\n if (data === `\\x1b${key}`)\n return true;\n }\n if (modifier === MODIFIERS.ctrl) {\n // Legacy: ctrl+key sends the control character\n if (rawCtrl && data === rawCtrl)\n return true;\n return (matchesKittySequence(data, codepoint, MODIFIERS.ctrl) ||\n matchesPrintableModifyOtherKeys(data, codepoint, MODIFIERS.ctrl));\n }\n if (modifier === MODIFIERS.shift + MODIFIERS.ctrl) {\n return (matchesKittySequence(data, codepoint, MODIFIERS.shift + MODIFIERS.ctrl) ||\n matchesPrintableModifyOtherKeys(data, codepoint, MODIFIERS.shift + MODIFIERS.ctrl));\n }\n if (modifier === MODIFIERS.shift) {\n // Legacy: shift+letter produces uppercase\n if (isLetter && data === key.toUpperCase())\n return true;\n return (matchesKittySequence(data, codepoint, MODIFIERS.shift) ||\n matchesPrintableModifyOtherKeys(data, codepoint, MODIFIERS.shift));\n }\n if (modifier !== 0) {\n return (matchesKittySequence(data, codepoint, modifier) ||\n matchesPrintableModifyOtherKeys(data, codepoint, modifier));\n }\n // Check both raw char and Kitty sequence (needed for release events)\n return data === key || matchesKittySequence(data, codepoint, 0);\n }\n return false;\n}\n/**\n * Parse input data and return the key identifier if recognized.\n *\n * @param data - Raw input data from terminal\n * @returns Key identifier string (e.g., \"ctrl+c\") or undefined\n */\nfunction formatParsedKey(codepoint, modifier, baseLayoutKey) {\n const normalizedCodepoint = normalizeKittyFunctionalCodepoint(codepoint);\n const identityCodepoint = normalizeShiftedLetterIdentityCodepoint(normalizedCodepoint, modifier);\n // Use base layout key only when codepoint is not a recognized Latin\n // letter (a-z), digit (0-9), or symbol (/, -, [, ;, etc.). For those,\n // the codepoint is authoritative regardless of physical key position.\n // This prevents remapped layouts (Dvorak, Colemak, xremap, etc.) from\n // reporting the wrong key name based on the QWERTY physical position.\n const isLatinLetter = identityCodepoint >= 97 && identityCodepoint <= 122; // a-z\n const isDigit = identityCodepoint >= 48 && identityCodepoint <= 57; // 0-9\n const isKnownSymbol = SYMBOL_KEYS.has(String.fromCharCode(identityCodepoint));\n const effectiveCodepoint = isLatinLetter || isDigit || isKnownSymbol ? identityCodepoint : (baseLayoutKey ?? identityCodepoint);\n let keyName;\n if (effectiveCodepoint === CODEPOINTS.escape)\n keyName = \"escape\";\n else if (effectiveCodepoint === CODEPOINTS.tab)\n keyName = \"tab\";\n else if (effectiveCodepoint === CODEPOINTS.enter || effectiveCodepoint === CODEPOINTS.kpEnter)\n keyName = \"enter\";\n else if (effectiveCodepoint === CODEPOINTS.space)\n keyName = \"space\";\n else if (effectiveCodepoint === CODEPOINTS.backspace)\n keyName = \"backspace\";\n else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.delete)\n keyName = \"delete\";\n else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.insert)\n keyName = \"insert\";\n else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.home)\n keyName = \"home\";\n else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.end)\n keyName = \"end\";\n else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.pageUp)\n keyName = \"pageUp\";\n else if (effectiveCodepoint === FUNCTIONAL_CODEPOINTS.pageDown)\n keyName = \"pageDown\";\n else if (effectiveCodepoint === ARROW_CODEPOINTS.up)\n keyName = \"up\";\n else if (effectiveCodepoint === ARROW_CODEPOINTS.down)\n keyName = \"down\";\n else if (effectiveCodepoint === ARROW_CODEPOINTS.left)\n keyName = \"left\";\n else if (effectiveCodepoint === ARROW_CODEPOINTS.right)\n keyName = \"right\";\n else if (effectiveCodepoint >= 48 && effectiveCodepoint <= 57)\n keyName = String.fromCharCode(effectiveCodepoint);\n else if (effectiveCodepoint >= 97 && effectiveCodepoint <= 122)\n keyName = String.fromCharCode(effectiveCodepoint);\n else if (SYMBOL_KEYS.has(String.fromCharCode(effectiveCodepoint)))\n keyName = String.fromCharCode(effectiveCodepoint);\n if (!keyName)\n return undefined;\n return formatKeyNameWithModifiers(keyName, modifier);\n}\nexport function parseKey(data) {\n const kitty = parseKittySequence(data);\n if (kitty) {\n return formatParsedKey(kitty.codepoint, kitty.modifier, kitty.baseLayoutKey);\n }\n const modifyOtherKeys = parseModifyOtherKeysSequence(data);\n if (modifyOtherKeys) {\n return formatParsedKey(modifyOtherKeys.codepoint, modifyOtherKeys.modifier);\n }\n // Mode-aware legacy sequences\n // When Kitty protocol is active, ambiguous sequences are interpreted as custom terminal mappings:\n // - \\x1b\\r = shift+enter (Kitty mapping), not alt+enter\n // - \\n = shift+enter (Ghostty mapping)\n if (_kittyProtocolActive) {\n if (data === \"\\x1b\\r\" || data === \"\\n\")\n return \"shift+enter\";\n }\n const legacySequenceKeyId = LEGACY_SEQUENCE_KEY_IDS[data];\n if (legacySequenceKeyId)\n return legacySequenceKeyId;\n // Legacy sequences (used when Kitty protocol is not active, or for unambiguous sequences)\n if (data === \"\\x1b\")\n return \"escape\";\n if (data === \"\\x1c\")\n return \"ctrl+\\\\\";\n if (data === \"\\x1d\")\n return \"ctrl+]\";\n if (data === \"\\x1f\")\n return \"ctrl+-\";\n if (data === \"\\x1b\\x1b\")\n return \"ctrl+alt+[\";\n if (data === \"\\x1b\\x1c\")\n return \"ctrl+alt+\\\\\";\n if (data === \"\\x1b\\x1d\")\n return \"ctrl+alt+]\";\n if (data === \"\\x1b\\x1f\")\n return \"ctrl+alt+-\";\n if (data === \"\\t\")\n return \"tab\";\n if (data === \"\\r\" || (!_kittyProtocolActive && data === \"\\n\") || data === \"\\x1bOM\")\n return \"enter\";\n if (data === \"\\x00\")\n return \"ctrl+space\";\n if (data === \" \")\n return \"space\";\n if (data === \"\\x7f\")\n return \"backspace\";\n if (data === \"\\x08\")\n return isWindowsTerminalSession() ? \"ctrl+backspace\" : \"backspace\";\n if (data === \"\\x1b[Z\")\n return \"shift+tab\";\n if (!_kittyProtocolActive && data === \"\\x1b\\r\")\n return \"alt+enter\";\n if (!_kittyProtocolActive && data === \"\\x1b \")\n return \"alt+space\";\n if (data === \"\\x1b\\x7f\" || data === \"\\x1b\\b\")\n return \"alt+backspace\";\n if (!_kittyProtocolActive && data === \"\\x1bB\")\n return \"alt+left\";\n if (!_kittyProtocolActive && data === \"\\x1bF\")\n return \"alt+right\";\n if (!_kittyProtocolActive && data.length === 2 && data[0] === \"\\x1b\") {\n const code = data.charCodeAt(1);\n if (code >= 1 && code <= 26) {\n return `ctrl+alt+${String.fromCharCode(code + 96)}`;\n }\n // Legacy alt+letter/digit/symbol (ESC followed by the key)\n const key = String.fromCharCode(code);\n if ((code >= 97 && code <= 122) || (code >= 48 && code <= 57) || SYMBOL_KEYS.has(key)) {\n return `alt+${key}`;\n }\n }\n if (data === \"\\x1b[A\")\n return \"up\";\n if (data === \"\\x1b[B\")\n return \"down\";\n if (data === \"\\x1b[C\")\n return \"right\";\n if (data === \"\\x1b[D\")\n return \"left\";\n if (data === \"\\x1b[H\" || data === \"\\x1bOH\")\n return \"home\";\n if (data === \"\\x1b[F\" || data === \"\\x1bOF\")\n return \"end\";\n if (data === \"\\x1b[3~\")\n return \"delete\";\n if (data === \"\\x1b[5~\")\n return \"pageUp\";\n if (data === \"\\x1b[6~\")\n return \"pageDown\";\n // Raw Ctrl+letter\n if (data.length === 1) {\n const code = data.charCodeAt(0);\n if (code >= 1 && code <= 26) {\n return `ctrl+${String.fromCharCode(code + 96)}`;\n }\n if (code >= 32 && code <= 126) {\n return data;\n }\n }\n return undefined;\n}\n// =============================================================================\n// Kitty CSI-u Printable Decoding\n// =============================================================================\nconst KITTY_CSI_U_REGEX = /^\\x1b\\[(\\d+)(?::(\\d*))?(?::(\\d+))?(?:;(\\d+))?(?::(\\d+))?u$/;\nconst KITTY_PRINTABLE_ALLOWED_MODIFIERS = MODIFIERS.shift | LOCK_MASK;\n/**\n * Decode a Kitty CSI-u sequence into a printable character, if applicable.\n *\n * When Kitty keyboard protocol flag 1 (disambiguate) is active, terminals send\n * CSI-u sequences for all keys, including plain printable characters. This\n * function extracts the printable character from such sequences.\n *\n * Only accepts plain or Shift-modified keys. Rejects Ctrl, Alt, and unsupported\n * modifier combinations (those are handled by keybinding matching instead).\n * Prefers the shifted keycode when Shift is held and a shifted key is reported.\n *\n * @param data - Raw input data from terminal\n * @returns The printable character, or undefined if not a printable CSI-u sequence\n */\nexport function decodeKittyPrintable(data) {\n const match = data.match(KITTY_CSI_U_REGEX);\n if (!match)\n return undefined;\n // CSI-u groups: <codepoint>[:<shifted>[:<base>]];<mod>[:<event>]u\n const codepoint = Number.parseInt(match[1] ?? \"\", 10);\n if (!Number.isFinite(codepoint))\n return undefined;\n const shiftedKey = match[2] && match[2].length > 0 ? Number.parseInt(match[2], 10) : undefined;\n const modValue = match[4] ? Number.parseInt(match[4], 10) : 1;\n // Modifiers are 1-indexed in CSI-u; normalize to our bitmask.\n const modifier = Number.isFinite(modValue) ? modValue - 1 : 0;\n // Only accept printable CSI-u input for plain or Shift-modified text keys.\n // Reject unsupported modifier bits (e.g. Super/Meta) to avoid inserting\n // characters from modifier-only terminal events.\n if ((modifier & ~KITTY_PRINTABLE_ALLOWED_MODIFIERS) !== 0)\n return undefined;\n if (modifier & (MODIFIERS.alt | MODIFIERS.ctrl))\n return undefined;\n // Prefer the shifted keycode when Shift is held.\n let effectiveCodepoint = codepoint;\n if (modifier & MODIFIERS.shift && typeof shiftedKey === \"number\") {\n effectiveCodepoint = shiftedKey;\n }\n effectiveCodepoint = normalizeKittyFunctionalCodepoint(effectiveCodepoint);\n // Drop control characters or invalid codepoints.\n if (!Number.isFinite(effectiveCodepoint) || effectiveCodepoint < 32)\n return undefined;\n try {\n return String.fromCodePoint(effectiveCodepoint);\n }\n catch {\n return undefined;\n }\n}\nfunction decodeModifyOtherKeysPrintable(data) {\n const parsed = parseModifyOtherKeysSequence(data);\n if (!parsed)\n return undefined;\n const modifier = parsed.modifier & ~LOCK_MASK;\n if ((modifier & ~MODIFIERS.shift) !== 0)\n return undefined;\n if (!Number.isFinite(parsed.codepoint) || parsed.codepoint < 32)\n return undefined;\n try {\n return String.fromCodePoint(parsed.codepoint);\n }\n catch {\n return undefined;\n }\n}\nexport function decodePrintableKey(data) {\n return decodeKittyPrintable(data) ?? decodeModifyOtherKeysPrintable(data);\n}\n//# sourceMappingURL=keys.js.map","import { getWordSegmenter, isWhitespaceChar, PUNCTUATION_REGEX } from \"./utils.js\";\nconst wordSegmenter = getWordSegmenter();\n/**\n * Find the cursor position after moving one word backward from `cursor` in `text`.\n * Skips trailing whitespace, then stops at the next word/punctuation boundary.\n *\n * Pure function - does not mutate any state.\n */\nexport function findWordBackward(text, cursor, options) {\n if (cursor <= 0)\n return 0;\n const textBeforeCursor = text.slice(0, cursor);\n const segmentFn = options?.segment;\n const isAtomic = options?.isAtomicSegment;\n const segments = segmentFn ? [...segmentFn(textBeforeCursor)] : [...wordSegmenter.segment(textBeforeCursor)];\n let newCursor = cursor;\n // Skip trailing whitespace\n while (segments.length > 0 &&\n !isAtomic?.(segments[segments.length - 1]?.segment || \"\") &&\n isWhitespaceChar(segments[segments.length - 1]?.segment || \"\")) {\n newCursor -= segments.pop()?.segment.length || 0;\n }\n if (segments.length === 0)\n return newCursor;\n const last = segments[segments.length - 1];\n if (isAtomic?.(last.segment)) {\n // Skip one atomic segment.\n newCursor -= last.segment.length;\n }\n else if (last.isWordLike) {\n // Skip inside one word-like segment, preserving ASCII punctuation boundaries.\n const segment = last.segment;\n const matches = [...segment.matchAll(new RegExp(PUNCTUATION_REGEX, \"g\"))];\n if (matches.length <= 0) {\n newCursor -= segment.length;\n }\n else {\n const lastMatch = matches[matches.length - 1];\n newCursor -= segment.length - (lastMatch.index + lastMatch[0].length);\n }\n }\n else {\n // Skip non-word non-whitespace run (punctuation)\n while (segments.length > 0 &&\n !isAtomic?.(segments[segments.length - 1]?.segment || \"\") &&\n !segments[segments.length - 1]?.isWordLike &&\n !isWhitespaceChar(segments[segments.length - 1]?.segment || \"\")) {\n newCursor -= segments.pop()?.segment.length || 0;\n }\n }\n return newCursor;\n}\n/**\n * Find the cursor position after moving one word forward from `cursor` in `text`.\n * Skips leading whitespace, then stops at the next word/punctuation boundary.\n *\n * Pure function - does not mutate any state.\n */\nexport function findWordForward(text, cursor, options) {\n if (cursor >= text.length)\n return text.length;\n const textAfterCursor = text.slice(cursor);\n const segmentFn = options?.segment;\n const isAtomic = options?.isAtomicSegment;\n const segments = segmentFn ? segmentFn(textAfterCursor) : wordSegmenter.segment(textAfterCursor);\n const iterator = segments[Symbol.iterator]();\n let next = iterator.next();\n let newCursor = cursor;\n // Skip leading whitespace\n while (!next.done && !isAtomic?.(next.value.segment) && isWhitespaceChar(next.value.segment)) {\n newCursor += next.value.segment.length;\n next = iterator.next();\n }\n if (next.done)\n return newCursor;\n if (isAtomic?.(next.value.segment)) {\n // Skip one atomic segment.\n newCursor += next.value.segment.length;\n }\n else if (next.value.isWordLike) {\n // Skip inside one word-like segment, preserving ASCII punctuation boundaries.\n newCursor += PUNCTUATION_REGEX.exec(next.value.segment)?.index ?? next.value.segment.length;\n }\n else {\n // Skip non-word non-whitespace run (punctuation)\n while (!next.done &&\n !isAtomic?.(next.value.segment) &&\n !next.value.isWordLike &&\n !isWhitespaceChar(next.value.segment)) {\n newCursor += next.value.segment.length;\n next = iterator.next();\n }\n }\n return newCursor;\n}\n//# sourceMappingURL=word-navigation.js.map","import { getKeybindings } from \"../keybindings.js\";\nimport { decodePrintableKey, matchesKey } from \"../keys.js\";\nimport { KillRing } from \"../kill-ring.js\";\nimport { CURSOR_MARKER } from \"../tui.js\";\nimport { UndoStack } from \"../undo-stack.js\";\nimport { cjkBreakRegex, getGraphemeSegmenter, getWordSegmenter, isWhitespaceChar, sliceByColumn, visibleWidth, } from \"../utils.js\";\nimport { findWordBackward, findWordForward } from \"../word-navigation.js\";\nimport { SelectList } from \"./select-list.js\";\nconst graphemeSegmenter = getGraphemeSegmenter();\nconst wordSegmenter = getWordSegmenter();\n/** Regex matching paste markers like `[paste #1 +123 lines]` or `[paste #2 1234 chars]`. */\nconst PASTE_MARKER_REGEX = /\\[paste #(\\d+)( (\\+\\d+ lines|\\d+ chars))?\\]/g;\n/** Non-global version for single-segment testing. */\nconst PASTE_MARKER_SINGLE = /^\\[paste #(\\d+)( (\\+\\d+ lines|\\d+ chars))?\\]$/;\n/** Check if a segment is a paste marker (i.e. was merged by segmentWithMarkers). */\nfunction isPasteMarker(segment) {\n return segment.length >= 10 && PASTE_MARKER_SINGLE.test(segment);\n}\n/**\n * A segmenter that wraps Intl.Segmenter and merges graphemes that fall\n * within paste markers into single atomic segments. This makes cursor\n * movement, deletion, word-wrap, etc. treat paste markers as single units.\n *\n * Only markers whose numeric ID exists in `validIds` are merged.\n */\nfunction segmentWithMarkers(text, baseSegmenter, validIds) {\n // Fast path: no paste markers in the text or no valid IDs.\n if (validIds.size === 0 || !text.includes(\"[paste #\")) {\n return baseSegmenter.segment(text);\n }\n // Find all marker spans with valid IDs.\n const markers = [];\n for (const m of text.matchAll(PASTE_MARKER_REGEX)) {\n const id = Number.parseInt(m[1], 10);\n if (!validIds.has(id))\n continue;\n markers.push({ start: m.index, end: m.index + m[0].length });\n }\n if (markers.length === 0) {\n return baseSegmenter.segment(text);\n }\n // Build merged segment list.\n const baseSegments = baseSegmenter.segment(text);\n const result = [];\n let markerIdx = 0;\n for (const seg of baseSegments) {\n // Skip past markers that are entirely before this segment.\n while (markerIdx < markers.length && markers[markerIdx].end <= seg.index) {\n markerIdx++;\n }\n const marker = markerIdx < markers.length ? markers[markerIdx] : null;\n if (marker && seg.index >= marker.start && seg.index < marker.end) {\n // This segment falls inside a marker.\n // If this is the first segment of the marker, emit a merged segment.\n if (seg.index === marker.start) {\n const markerText = text.slice(marker.start, marker.end);\n result.push({\n segment: markerText,\n index: marker.start,\n input: text,\n });\n }\n // Otherwise skip (already merged into the first segment).\n }\n else {\n result.push(seg);\n }\n }\n return result;\n}\n/**\n * Split a line into word-wrapped chunks.\n * Wraps at word boundaries when possible, falling back to character-level\n * wrapping for words longer than the available width.\n *\n * @param line - The text line to wrap\n * @param maxWidth - Maximum visible width per chunk\n * @param preSegmented - Optional pre-segmented graphemes (e.g. with paste-marker awareness).\n * When omitted the default Intl.Segmenter is used.\n * @returns Array of chunks with text and position information\n */\nexport function wordWrapLine(line, maxWidth, preSegmented) {\n if (!line || maxWidth <= 0) {\n return [{ text: \"\", startIndex: 0, endIndex: 0 }];\n }\n const lineWidth = visibleWidth(line);\n if (lineWidth <= maxWidth) {\n return [{ text: line, startIndex: 0, endIndex: line.length }];\n }\n const chunks = [];\n const segments = preSegmented ?? [...graphemeSegmenter.segment(line)];\n let currentWidth = 0;\n let chunkStart = 0;\n // Wrap opportunity: the position after the last whitespace before a non-whitespace\n // grapheme, i.e. where a line break is allowed.\n let wrapOppIndex = -1;\n let wrapOppWidth = 0;\n for (let i = 0; i < segments.length; i++) {\n const seg = segments[i];\n const grapheme = seg.segment;\n const gWidth = visibleWidth(grapheme);\n const charIndex = seg.index;\n const isWs = !isPasteMarker(grapheme) && isWhitespaceChar(grapheme);\n // Overflow check before advancing.\n if (currentWidth + gWidth > maxWidth) {\n if (wrapOppIndex >= 0 && currentWidth - wrapOppWidth + gWidth <= maxWidth) {\n // Backtrack to last wrap opportunity (the remaining content\n // plus the current grapheme still fits within maxWidth).\n chunks.push({ text: line.slice(chunkStart, wrapOppIndex), startIndex: chunkStart, endIndex: wrapOppIndex });\n chunkStart = wrapOppIndex;\n currentWidth -= wrapOppWidth;\n }\n else if (chunkStart < charIndex) {\n // No viable wrap opportunity: force-break at current position.\n // This also handles the case where backtracking to a word\n // boundary wouldn't help because the remaining content plus\n // the current grapheme (e.g. a wide character) still exceeds\n // maxWidth.\n chunks.push({ text: line.slice(chunkStart, charIndex), startIndex: chunkStart, endIndex: charIndex });\n chunkStart = charIndex;\n currentWidth = 0;\n }\n wrapOppIndex = -1;\n }\n if (gWidth > maxWidth) {\n // Single atomic segment wider than maxWidth (e.g. paste marker\n // in a narrow terminal). Re-wrap it at grapheme granularity.\n // The segment remains logically atomic for cursor\n // movement / editing — the split is purely visual for word-wrap layout.\n const subChunks = wordWrapLine(grapheme, maxWidth);\n for (let j = 0; j < subChunks.length - 1; j++) {\n const sc = subChunks[j];\n chunks.push({ text: sc.text, startIndex: charIndex + sc.startIndex, endIndex: charIndex + sc.endIndex });\n }\n const last = subChunks[subChunks.length - 1];\n chunkStart = charIndex + last.startIndex;\n currentWidth = visibleWidth(last.text);\n wrapOppIndex = -1;\n continue;\n }\n // Advance.\n currentWidth += gWidth;\n // Record wrap opportunity: whitespace followed by non-whitespace\n // (multiple spaces join; the break point is after the last space),\n // or at a boundary where either side is CJK (CJK allows breaking\n // between any adjacent characters).\n const next = segments[i + 1];\n if (isWs && next && (isPasteMarker(next.segment) || !isWhitespaceChar(next.segment))) {\n wrapOppIndex = next.index;\n wrapOppWidth = currentWidth;\n }\n else if (!isWs && next && !isWhitespaceChar(next.segment)) {\n const isCjk = !isPasteMarker(grapheme) && cjkBreakRegex.test(grapheme);\n const nextIsCjk = !isPasteMarker(next.segment) && cjkBreakRegex.test(next.segment);\n if (isCjk || nextIsCjk) {\n wrapOppIndex = next.index;\n wrapOppWidth = currentWidth;\n }\n }\n }\n // Push final chunk.\n chunks.push({ text: line.slice(chunkStart), startIndex: chunkStart, endIndex: line.length });\n return chunks;\n}\nconst SLASH_COMMAND_SELECT_LIST_LAYOUT = {\n minPrimaryColumnWidth: 12,\n maxPrimaryColumnWidth: 32,\n};\nconst ATTACHMENT_AUTOCOMPLETE_DEBOUNCE_MS = 20;\nconst DEFAULT_AUTOCOMPLETE_TRIGGER_CHARACTERS = [\"@\", \"#\"];\nfunction escapeCharacterClass(value) {\n return value.replace(/[\\\\^$.*+?()[\\]{}|-]/g, \"\\\\$&\");\n}\nfunction buildTriggerPattern(triggerCharacters) {\n return new RegExp(`(?:^|[\\\\s])[${triggerCharacters.map(escapeCharacterClass).join(\"\")}][^\\\\s]*$`);\n}\nfunction buildDebouncePattern(triggerCharacters) {\n const escapedWithoutAt = triggerCharacters.filter((character) => character !== \"@\").map(escapeCharacterClass);\n return new RegExp(`(?:^|[ \\\\t])(?:@(?:\"[^\"]*|[^\\\\s]*)|[${escapedWithoutAt.join(\"\")}][^\\\\s]*)$`);\n}\nfunction createScrollBorder(direction, hiddenLineCount, width) {\n const availableWidth = Math.max(0, width);\n const indicator = `─── ${direction} ${hiddenLineCount} more `;\n const remaining = availableWidth - visibleWidth(indicator);\n if (remaining >= 0)\n return indicator + \"─\".repeat(remaining);\n const ellipsis = \"...\".slice(0, availableWidth);\n const indicatorWidth = availableWidth - visibleWidth(ellipsis);\n return sliceByColumn(indicator, 0, indicatorWidth, true) + ellipsis;\n}\nexport class Editor {\n state = {\n lines: [\"\"],\n cursorLine: 0,\n cursorCol: 0,\n };\n /** Focusable interface - set by TUI when focus changes */\n focused = false;\n tui;\n theme;\n paddingX = 0;\n // Store last render width for cursor navigation\n lastWidth = 80;\n // Vertical scrolling support\n scrollOffset = 0;\n // Border color (can be changed dynamically)\n borderColor;\n // Autocomplete support\n autocompleteProvider;\n autocompleteTriggerCharacters = [...DEFAULT_AUTOCOMPLETE_TRIGGER_CHARACTERS];\n autocompleteTriggerPattern = buildTriggerPattern(this.autocompleteTriggerCharacters);\n autocompleteDebouncePattern = buildDebouncePattern(this.autocompleteTriggerCharacters);\n autocompleteList;\n autocompleteState = null;\n autocompletePrefix = \"\";\n autocompleteMaxVisible = 5;\n autocompleteAbort;\n autocompleteDebounceTimer;\n autocompleteRequestTask = Promise.resolve();\n autocompleteStartToken = 0;\n autocompleteRequestId = 0;\n // Paste tracking for large pastes\n pastes = new Map();\n pasteCounter = 0;\n // Bracketed paste mode buffering\n pasteBuffer = \"\";\n isInPaste = false;\n // Prompt history for up/down navigation\n history = [];\n historyIndex = -1; // -1 = not browsing, 0 = most recent, 1 = older, etc.\n historyDraft = null;\n // Kill ring for Emacs-style kill/yank operations\n killRing = new KillRing();\n lastAction = null;\n // Character jump mode\n jumpMode = null;\n // Preferred visual column for vertical cursor movement (sticky column)\n preferredVisualCol = null;\n // When the cursor is snapped to the start of an atomic segment, e.g. a\n // paste marker, cursorCol no longer reflects where the cursor would have\n // landed. This field stores the pre-snap cursorCol so that the next\n // vertical move can resolve it to a visual column on whatever VL it belongs\n // to.\n snappedFromCursorCol = null;\n // Undo support\n undoStack = new UndoStack();\n onSubmit;\n onChange;\n disableSubmit = false;\n constructor(tui, theme, options = {}) {\n this.tui = tui;\n this.theme = theme;\n this.borderColor = theme.borderColor;\n const paddingX = options.paddingX ?? 0;\n this.paddingX = Number.isFinite(paddingX) ? Math.max(0, Math.floor(paddingX)) : 0;\n const maxVisible = options.autocompleteMaxVisible ?? 5;\n this.autocompleteMaxVisible = Number.isFinite(maxVisible) ? Math.max(3, Math.min(20, Math.floor(maxVisible))) : 5;\n }\n /** Set of currently valid paste IDs, for marker-aware segmentation. */\n validPasteIds() {\n return new Set(this.pastes.keys());\n }\n /** Segment text with paste-marker awareness, only merging markers with valid IDs. */\n segment(text, mode) {\n return segmentWithMarkers(text, mode === \"word\" ? wordSegmenter : graphemeSegmenter, this.validPasteIds());\n }\n getPaddingX() {\n return this.paddingX;\n }\n setPaddingX(padding) {\n const newPadding = Number.isFinite(padding) ? Math.max(0, Math.floor(padding)) : 0;\n if (this.paddingX !== newPadding) {\n this.paddingX = newPadding;\n this.tui.requestRender();\n }\n }\n getAutocompleteMaxVisible() {\n return this.autocompleteMaxVisible;\n }\n setAutocompleteMaxVisible(maxVisible) {\n const newMaxVisible = Number.isFinite(maxVisible) ? Math.max(3, Math.min(20, Math.floor(maxVisible))) : 5;\n if (this.autocompleteMaxVisible !== newMaxVisible) {\n this.autocompleteMaxVisible = newMaxVisible;\n this.tui.requestRender();\n }\n }\n setAutocompleteProvider(provider) {\n this.cancelAutocomplete();\n this.autocompleteProvider = provider;\n this.setAutocompleteTriggerCharacters(provider.triggerCharacters ?? []);\n }\n /**\n * Add a prompt to history for up/down arrow navigation.\n * Called after successful submission.\n */\n addToHistory(text) {\n const trimmed = text.trim();\n if (!trimmed)\n return;\n // Don't add consecutive duplicates\n if (this.history.length > 0 && this.history[0] === trimmed)\n return;\n this.history.unshift(trimmed);\n // Limit history size\n if (this.history.length > 100) {\n this.history.pop();\n }\n }\n isEditorEmpty() {\n return this.state.lines.length === 1 && this.state.lines[0] === \"\";\n }\n isOnFirstVisualLine() {\n const visualLines = this.buildVisualLineMap(this.lastWidth);\n const currentVisualLine = this.findCurrentVisualLine(visualLines);\n return currentVisualLine === 0;\n }\n isOnLastVisualLine() {\n const visualLines = this.buildVisualLineMap(this.lastWidth);\n const currentVisualLine = this.findCurrentVisualLine(visualLines);\n return currentVisualLine === visualLines.length - 1;\n }\n navigateHistory(direction) {\n this.lastAction = null;\n if (this.history.length === 0)\n return;\n const newIndex = this.historyIndex - direction; // Up(-1) increases index, Down(1) decreases\n if (newIndex < -1 || newIndex >= this.history.length)\n return;\n // Capture state when first entering history browsing mode\n if (this.historyIndex === -1 && newIndex >= 0) {\n this.pushUndoSnapshot();\n this.historyDraft = structuredClone(this.state);\n }\n this.historyIndex = newIndex;\n if (this.historyIndex === -1) {\n const draft = this.historyDraft;\n this.historyDraft = null;\n if (draft) {\n this.state = draft;\n this.preferredVisualCol = null;\n this.snappedFromCursorCol = null;\n this.scrollOffset = 0;\n if (this.onChange)\n this.onChange(this.getText());\n }\n else {\n this.setTextInternal(\"\");\n }\n }\n else {\n this.setTextInternal(this.history[this.historyIndex] || \"\", direction === -1 ? \"start\" : \"end\");\n }\n }\n exitHistoryBrowsing() {\n this.historyIndex = -1;\n this.historyDraft = null;\n }\n /** Internal setText that doesn't reset history state - used by navigateHistory */\n setTextInternal(text, cursorPlacement = \"end\") {\n const lines = text.split(\"\\n\");\n this.state.lines = lines.length === 0 ? [\"\"] : lines;\n this.state.cursorLine = cursorPlacement === \"start\" ? 0 : this.state.lines.length - 1;\n this.setCursorCol(cursorPlacement === \"start\" ? 0 : this.state.lines[this.state.cursorLine]?.length || 0);\n // Reset scroll - render() will adjust to show cursor\n this.scrollOffset = 0;\n if (this.onChange) {\n this.onChange(this.getText());\n }\n }\n invalidate() {\n // No cached state to invalidate currently\n }\n render(width) {\n const maxPadding = Math.max(0, Math.floor((width - 1) / 2));\n const paddingX = Math.min(this.paddingX, maxPadding);\n const contentWidth = Math.max(1, width - paddingX * 2);\n // Layout width: with padding the cursor can overflow into it,\n // without padding we reserve 1 column for the cursor.\n const layoutWidth = Math.max(1, contentWidth - (paddingX ? 0 : 1));\n // Store for cursor navigation (must match wrapping width)\n this.lastWidth = layoutWidth;\n const horizontal = this.borderColor(\"─\");\n // Layout the text\n const layoutLines = this.layoutText(layoutWidth);\n // Calculate max visible lines: 30% of terminal height, minimum 5 lines\n const terminalRows = this.tui.terminal.rows;\n const maxVisibleLines = Math.max(5, Math.floor(terminalRows * 0.3));\n // Find the cursor line index in layoutLines\n let cursorLineIndex = layoutLines.findIndex((line) => line.hasCursor);\n if (cursorLineIndex === -1)\n cursorLineIndex = 0;\n // Adjust scroll offset to keep cursor visible\n if (cursorLineIndex < this.scrollOffset) {\n this.scrollOffset = cursorLineIndex;\n }\n else if (cursorLineIndex >= this.scrollOffset + maxVisibleLines) {\n this.scrollOffset = cursorLineIndex - maxVisibleLines + 1;\n }\n // Clamp scroll offset to valid range\n const maxScrollOffset = Math.max(0, layoutLines.length - maxVisibleLines);\n this.scrollOffset = Math.max(0, Math.min(this.scrollOffset, maxScrollOffset));\n // Get visible lines slice\n const visibleLines = layoutLines.slice(this.scrollOffset, this.scrollOffset + maxVisibleLines);\n const result = [];\n const leftPadding = \" \".repeat(paddingX);\n const rightPadding = leftPadding;\n // Render top border (with scroll indicator if scrolled down)\n if (this.scrollOffset > 0) {\n const border = createScrollBorder(\"↑\", this.scrollOffset, width);\n result.push(this.borderColor(border));\n }\n else {\n result.push(horizontal.repeat(width));\n }\n // Render each visible layout line\n // Emit hardware cursor marker when focused so TUI can position the\n // hardware cursor for IME candidate-window placement even while\n // autocomplete (e.g. slash-command menu) is visible.\n const emitCursorMarker = this.focused;\n for (const layoutLine of visibleLines) {\n let displayText = layoutLine.text;\n let lineVisibleWidth = visibleWidth(layoutLine.text);\n let cursorInPadding = false;\n // Add cursor if this line has it\n if (layoutLine.hasCursor && layoutLine.cursorPos !== undefined) {\n const before = displayText.slice(0, layoutLine.cursorPos);\n const after = displayText.slice(layoutLine.cursorPos);\n // Hardware cursor marker (zero-width, emitted before fake cursor for IME positioning)\n const marker = emitCursorMarker ? CURSOR_MARKER : \"\";\n if (after.length > 0) {\n // Cursor is on a character (grapheme) - replace it with highlighted version\n // Get the first grapheme from 'after'\n const afterGraphemes = [...this.segment(after, \"grapheme\")];\n const firstGrapheme = afterGraphemes[0]?.segment || \"\";\n const restAfter = after.slice(firstGrapheme.length);\n const cursor = `\\x1b[7m${firstGrapheme}\\x1b[0m`;\n displayText = before + marker + cursor + restAfter;\n // lineVisibleWidth stays the same - we're replacing, not adding\n }\n else {\n // Cursor is at the end - add highlighted space\n const cursor = \"\\x1b[7m \\x1b[0m\";\n displayText = before + marker + cursor;\n lineVisibleWidth = lineVisibleWidth + 1;\n // If cursor overflows content width into the padding, flag it\n if (lineVisibleWidth > contentWidth && paddingX > 0) {\n cursorInPadding = true;\n }\n }\n }\n // Calculate padding based on actual visible width\n const padding = \" \".repeat(Math.max(0, contentWidth - lineVisibleWidth));\n const lineRightPadding = cursorInPadding ? rightPadding.slice(1) : rightPadding;\n // Render the line (no side borders, just horizontal lines above and below)\n result.push(`${leftPadding}${displayText}${padding}${lineRightPadding}`);\n }\n // Render bottom border (with scroll indicator if more content below)\n const linesBelow = layoutLines.length - (this.scrollOffset + visibleLines.length);\n if (linesBelow > 0) {\n const border = createScrollBorder(\"↓\", linesBelow, width);\n result.push(this.borderColor(border));\n }\n else {\n result.push(horizontal.repeat(width));\n }\n // Add autocomplete list if active\n if (this.autocompleteState && this.autocompleteList) {\n const autocompleteResult = this.autocompleteList.render(contentWidth);\n for (const line of autocompleteResult) {\n const lineWidth = visibleWidth(line);\n const linePadding = \" \".repeat(Math.max(0, contentWidth - lineWidth));\n result.push(`${leftPadding}${line}${linePadding}${rightPadding}`);\n }\n }\n return result;\n }\n handleInput(data) {\n const kb = getKeybindings();\n // Handle character jump mode (awaiting next character to jump to)\n if (this.jumpMode !== null) {\n // Cancel if the hotkey is pressed again\n if (kb.matches(data, \"tui.editor.jumpForward\") || kb.matches(data, \"tui.editor.jumpBackward\")) {\n this.jumpMode = null;\n return;\n }\n const printable = decodePrintableKey(data) ?? (data.charCodeAt(0) >= 32 ? data : undefined);\n if (printable !== undefined) {\n // Printable character - perform the jump\n const direction = this.jumpMode;\n this.jumpMode = null;\n this.jumpToChar(printable, direction);\n return;\n }\n // Control character - cancel and fall through to normal handling\n this.jumpMode = null;\n }\n // Handle bracketed paste mode\n if (data.includes(\"\\x1b[200~\")) {\n this.isInPaste = true;\n this.pasteBuffer = \"\";\n data = data.replace(\"\\x1b[200~\", \"\");\n }\n if (this.isInPaste) {\n this.pasteBuffer += data;\n const endIndex = this.pasteBuffer.indexOf(\"\\x1b[201~\");\n if (endIndex !== -1) {\n const pasteContent = this.pasteBuffer.substring(0, endIndex);\n if (pasteContent.length > 0) {\n this.handlePaste(pasteContent);\n }\n this.isInPaste = false;\n const remaining = this.pasteBuffer.substring(endIndex + 6);\n this.pasteBuffer = \"\";\n if (remaining.length > 0) {\n this.handleInput(remaining);\n }\n return;\n }\n return;\n }\n // Ctrl+C - let parent handle (exit/clear)\n if (kb.matches(data, \"tui.input.copy\")) {\n return;\n }\n // Undo\n if (kb.matches(data, \"tui.editor.undo\")) {\n this.undo();\n return;\n }\n // Handle autocomplete mode\n if (this.autocompleteState && this.autocompleteList) {\n if (kb.matches(data, \"tui.select.cancel\")) {\n this.cancelAutocomplete();\n return;\n }\n if (kb.matches(data, \"tui.select.up\") || kb.matches(data, \"tui.select.down\")) {\n this.autocompleteList.handleInput(data);\n return;\n }\n if (kb.matches(data, \"tui.input.tab\")) {\n const selected = this.autocompleteList.getSelectedItem();\n if (selected && this.autocompleteProvider) {\n this.pushUndoSnapshot();\n this.lastAction = null;\n const result = this.autocompleteProvider.applyCompletion(this.state.lines, this.state.cursorLine, this.state.cursorCol, selected, this.autocompletePrefix);\n this.state.lines = result.lines;\n this.state.cursorLine = result.cursorLine;\n this.setCursorCol(result.cursorCol);\n this.cancelAutocomplete();\n if (this.onChange)\n this.onChange(this.getText());\n }\n return;\n }\n if (kb.matches(data, \"tui.select.confirm\")) {\n const selected = this.autocompleteList.getSelectedItem();\n if (selected && this.autocompleteProvider) {\n this.pushUndoSnapshot();\n this.lastAction = null;\n const result = this.autocompleteProvider.applyCompletion(this.state.lines, this.state.cursorLine, this.state.cursorCol, selected, this.autocompletePrefix);\n this.state.lines = result.lines;\n this.state.cursorLine = result.cursorLine;\n this.setCursorCol(result.cursorCol);\n if (this.autocompletePrefix.startsWith(\"/\")) {\n this.cancelAutocomplete();\n // Fall through to submit\n }\n else {\n this.cancelAutocomplete();\n if (this.onChange)\n this.onChange(this.getText());\n return;\n }\n }\n }\n }\n // Tab - trigger completion\n if (kb.matches(data, \"tui.input.tab\") && !this.autocompleteState) {\n this.handleTabCompletion();\n return;\n }\n // Deletion actions\n if (kb.matches(data, \"tui.editor.deleteToLineEnd\")) {\n this.deleteToEndOfLine();\n return;\n }\n if (kb.matches(data, \"tui.editor.deleteToLineStart\")) {\n this.deleteToStartOfLine();\n return;\n }\n if (kb.matches(data, \"tui.editor.deleteWordBackward\")) {\n this.deleteWordBackwards();\n return;\n }\n if (kb.matches(data, \"tui.editor.deleteWordForward\")) {\n this.deleteWordForward();\n return;\n }\n if (kb.matches(data, \"tui.editor.deleteCharBackward\") || matchesKey(data, \"shift+backspace\")) {\n this.handleBackspace();\n return;\n }\n if (kb.matches(data, \"tui.editor.deleteCharForward\") || matchesKey(data, \"shift+delete\")) {\n this.handleForwardDelete();\n return;\n }\n // Kill ring actions\n if (kb.matches(data, \"tui.editor.yank\")) {\n this.yank();\n return;\n }\n if (kb.matches(data, \"tui.editor.yankPop\")) {\n this.yankPop();\n return;\n }\n // Cursor movement actions\n if (kb.matches(data, \"tui.editor.cursorLineStart\")) {\n this.moveToLineStart();\n return;\n }\n if (kb.matches(data, \"tui.editor.cursorLineEnd\")) {\n this.moveToLineEnd();\n return;\n }\n if (kb.matches(data, \"tui.editor.cursorWordLeft\")) {\n this.moveWordBackwards();\n return;\n }\n if (kb.matches(data, \"tui.editor.cursorWordRight\")) {\n this.moveWordForwards();\n return;\n }\n // New line\n if (kb.matches(data, \"tui.input.newLine\") ||\n (data.charCodeAt(0) === 10 && data.length > 1) ||\n data === \"\\x1b\\r\" ||\n data === \"\\x1b[13;2~\" ||\n (data.length > 1 && data.includes(\"\\x1b\") && data.includes(\"\\r\")) ||\n (data === \"\\n\" && data.length === 1)) {\n if (this.shouldSubmitOnBackslashEnter(data, kb)) {\n this.handleBackspace();\n this.submitValue();\n return;\n }\n this.addNewLine();\n return;\n }\n // Submit (Enter)\n if (kb.matches(data, \"tui.input.submit\")) {\n if (this.disableSubmit)\n return;\n // Workaround for terminals without Shift+Enter support:\n // If char before cursor is \\, delete it and insert newline instead of submitting.\n const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n if (this.state.cursorCol > 0 && currentLine[this.state.cursorCol - 1] === \"\\\\\") {\n this.handleBackspace();\n this.addNewLine();\n return;\n }\n this.submitValue();\n return;\n }\n // Arrow key navigation (with history support)\n if (kb.matches(data, \"tui.editor.cursorUp\")) {\n if (this.isOnFirstVisualLine() &&\n (this.isEditorEmpty() || this.historyIndex > -1 || this.state.cursorCol === 0)) {\n this.navigateHistory(-1);\n }\n else if (this.isOnFirstVisualLine()) {\n // Already at top - jump to start of line\n this.moveToLineStart();\n }\n else {\n this.moveCursor(-1, 0);\n }\n return;\n }\n if (kb.matches(data, \"tui.editor.cursorDown\")) {\n if (this.historyIndex > -1 && this.isOnLastVisualLine()) {\n this.navigateHistory(1);\n }\n else if (this.isOnLastVisualLine()) {\n // Already at bottom - jump to end of line\n this.moveToLineEnd();\n }\n else {\n this.moveCursor(1, 0);\n }\n return;\n }\n if (kb.matches(data, \"tui.editor.cursorRight\")) {\n this.moveCursor(0, 1);\n return;\n }\n if (kb.matches(data, \"tui.editor.cursorLeft\")) {\n this.moveCursor(0, -1);\n return;\n }\n // Page up/down - scroll by page and move cursor\n if (kb.matches(data, \"tui.editor.pageUp\")) {\n this.pageScroll(-1);\n return;\n }\n if (kb.matches(data, \"tui.editor.pageDown\")) {\n this.pageScroll(1);\n return;\n }\n // Character jump mode triggers\n if (kb.matches(data, \"tui.editor.jumpForward\")) {\n this.jumpMode = \"forward\";\n return;\n }\n if (kb.matches(data, \"tui.editor.jumpBackward\")) {\n this.jumpMode = \"backward\";\n return;\n }\n // Shift+Space - insert regular space\n if (matchesKey(data, \"shift+space\")) {\n this.insertCharacter(\" \");\n return;\n }\n const printable = decodePrintableKey(data);\n if (printable !== undefined) {\n this.insertCharacter(printable);\n return;\n }\n // Regular characters\n if (data.charCodeAt(0) >= 32) {\n this.insertCharacter(data);\n }\n }\n layoutText(contentWidth) {\n const layoutLines = [];\n if (this.state.lines.length === 0 || (this.state.lines.length === 1 && this.state.lines[0] === \"\")) {\n // Empty editor\n layoutLines.push({\n text: \"\",\n hasCursor: true,\n cursorPos: 0,\n });\n return layoutLines;\n }\n // Process each logical line\n for (let i = 0; i < this.state.lines.length; i++) {\n const line = this.state.lines[i] || \"\";\n const isCurrentLine = i === this.state.cursorLine;\n const lineVisibleWidth = visibleWidth(line);\n if (lineVisibleWidth <= contentWidth) {\n // Line fits in one layout line\n if (isCurrentLine) {\n layoutLines.push({\n text: line,\n hasCursor: true,\n cursorPos: this.state.cursorCol,\n });\n }\n else {\n layoutLines.push({\n text: line,\n hasCursor: false,\n });\n }\n }\n else {\n // Line needs wrapping - use word-aware wrapping\n const chunks = wordWrapLine(line, contentWidth, [...this.segment(line, \"grapheme\")]);\n for (let chunkIndex = 0; chunkIndex < chunks.length; chunkIndex++) {\n const chunk = chunks[chunkIndex];\n if (!chunk)\n continue;\n const cursorPos = this.state.cursorCol;\n const isLastChunk = chunkIndex === chunks.length - 1;\n // Determine if cursor is in this chunk\n // For word-wrapped chunks, we need to handle the case where\n // cursor might be in trimmed whitespace at end of chunk\n let hasCursorInChunk = false;\n let adjustedCursorPos = 0;\n if (isCurrentLine) {\n if (isLastChunk) {\n // Last chunk: cursor belongs here if >= startIndex\n hasCursorInChunk = cursorPos >= chunk.startIndex;\n adjustedCursorPos = cursorPos - chunk.startIndex;\n }\n else {\n // Non-last chunk: cursor belongs here if in range [startIndex, endIndex)\n // But we need to handle the visual position in the trimmed text\n hasCursorInChunk = cursorPos >= chunk.startIndex && cursorPos < chunk.endIndex;\n if (hasCursorInChunk) {\n adjustedCursorPos = cursorPos - chunk.startIndex;\n // Clamp to text length (in case cursor was in trimmed whitespace)\n if (adjustedCursorPos > chunk.text.length) {\n adjustedCursorPos = chunk.text.length;\n }\n }\n }\n }\n if (hasCursorInChunk) {\n layoutLines.push({\n text: chunk.text,\n hasCursor: true,\n cursorPos: adjustedCursorPos,\n });\n }\n else {\n layoutLines.push({\n text: chunk.text,\n hasCursor: false,\n });\n }\n }\n }\n }\n return layoutLines;\n }\n getText() {\n return this.state.lines.join(\"\\n\");\n }\n expandPasteMarkers(text) {\n let result = text;\n for (const [pasteId, pasteContent] of this.pastes) {\n const markerRegex = new RegExp(`\\\\[paste #${pasteId}( (\\\\+\\\\d+ lines|\\\\d+ chars))?\\\\]`, \"g\");\n result = result.replace(markerRegex, () => pasteContent);\n }\n return result;\n }\n /**\n * Get text with paste markers expanded to their actual content.\n * Use this when you need the full content (e.g., for external editor).\n */\n getExpandedText() {\n return this.expandPasteMarkers(this.state.lines.join(\"\\n\"));\n }\n getLines() {\n return [...this.state.lines];\n }\n getCursor() {\n return { line: this.state.cursorLine, col: this.state.cursorCol };\n }\n setText(text) {\n this.cancelAutocomplete();\n this.lastAction = null;\n this.exitHistoryBrowsing();\n const normalized = this.normalizeText(text);\n // Push undo snapshot if content differs (makes programmatic changes undoable)\n if (this.getText() !== normalized) {\n this.pushUndoSnapshot();\n }\n this.pastes.clear();\n this.pasteCounter = 0;\n this.setTextInternal(normalized);\n }\n /**\n * Insert text at the current cursor position.\n * Used for programmatic insertion (e.g., clipboard image markers).\n * This is atomic for undo - single undo restores entire pre-insert state.\n */\n insertTextAtCursor(text) {\n if (!text)\n return;\n this.cancelAutocomplete();\n this.pushUndoSnapshot();\n this.lastAction = null;\n this.exitHistoryBrowsing();\n this.insertTextAtCursorInternal(text);\n }\n /**\n * Normalize text for editor storage:\n * - Normalize line endings (\\r\\n and \\r -> \\n)\n * - Expand tabs to 4 spaces\n */\n normalizeText(text) {\n return text.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\").replace(/\\t/g, \" \");\n }\n /**\n * Internal text insertion at cursor. Handles single and multi-line text.\n * Does not push undo snapshots or trigger autocomplete - caller is responsible.\n * Normalizes line endings and calls onChange once at the end.\n */\n insertTextAtCursorInternal(text) {\n if (!text)\n return;\n // Normalize line endings and tabs\n const normalized = this.normalizeText(text);\n const insertedLines = normalized.split(\"\\n\");\n const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n const beforeCursor = currentLine.slice(0, this.state.cursorCol);\n const afterCursor = currentLine.slice(this.state.cursorCol);\n if (insertedLines.length === 1) {\n // Single line - insert at cursor position\n this.state.lines[this.state.cursorLine] = beforeCursor + normalized + afterCursor;\n this.setCursorCol(this.state.cursorCol + normalized.length);\n }\n else {\n // Multi-line insertion\n this.state.lines = [\n // All lines before current line\n ...this.state.lines.slice(0, this.state.cursorLine),\n // The first inserted line merged with text before cursor\n beforeCursor + insertedLines[0],\n // All middle inserted lines\n ...insertedLines.slice(1, -1),\n // The last inserted line with text after cursor\n insertedLines[insertedLines.length - 1] + afterCursor,\n // All lines after current line\n ...this.state.lines.slice(this.state.cursorLine + 1),\n ];\n this.state.cursorLine += insertedLines.length - 1;\n this.setCursorCol((insertedLines[insertedLines.length - 1] || \"\").length);\n }\n if (this.onChange) {\n this.onChange(this.getText());\n }\n }\n // All the editor methods from before...\n insertCharacter(char, skipUndoCoalescing) {\n this.exitHistoryBrowsing();\n // Undo coalescing (fish-style):\n // - Consecutive word chars coalesce into one undo unit\n // - Space captures state before itself (so undo removes space+following word together)\n // - Each space is separately undoable\n // Skip coalescing when called from atomic operations (e.g., handlePaste)\n if (!skipUndoCoalescing) {\n if (isWhitespaceChar(char) || this.lastAction !== \"type-word\") {\n this.pushUndoSnapshot();\n }\n this.lastAction = \"type-word\";\n }\n const line = this.state.lines[this.state.cursorLine] || \"\";\n const before = line.slice(0, this.state.cursorCol);\n const after = line.slice(this.state.cursorCol);\n this.state.lines[this.state.cursorLine] = before + char + after;\n this.setCursorCol(this.state.cursorCol + char.length);\n if (this.onChange) {\n this.onChange(this.getText());\n }\n // Check if we should trigger or update autocomplete\n if (!this.autocompleteState) {\n // Auto-trigger for \"/\" at the start of a line (slash commands)\n if (char === \"/\" && this.isAtStartOfMessage()) {\n this.tryTriggerAutocomplete();\n }\n // Auto-trigger for symbol-based completion like @, #, or provider triggers at token boundaries\n else if (this.autocompleteTriggerCharacters.includes(char)) {\n const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n const textBeforeCursor = currentLine.slice(0, this.state.cursorCol);\n const charBeforeSymbol = textBeforeCursor[textBeforeCursor.length - 2];\n if (textBeforeCursor.length === 1 || charBeforeSymbol === \" \" || charBeforeSymbol === \"\\t\") {\n this.tryTriggerAutocomplete();\n }\n }\n // Also auto-trigger when typing letters in a slash command or symbol completion context\n else if (/[a-zA-Z0-9.\\-_]/.test(char)) {\n const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n const textBeforeCursor = currentLine.slice(0, this.state.cursorCol);\n // Check if we're in a slash command (with or without space for arguments)\n if (this.isInSlashCommandContext(textBeforeCursor)) {\n this.tryTriggerAutocomplete();\n }\n // Check if we're in a symbol-based completion context like @, #, or provider triggers\n else if (this.autocompleteTriggerPattern.test(textBeforeCursor)) {\n this.tryTriggerAutocomplete();\n }\n }\n }\n else {\n this.updateAutocomplete();\n }\n }\n handlePaste(pastedText) {\n this.cancelAutocomplete();\n this.exitHistoryBrowsing();\n this.lastAction = null;\n this.pushUndoSnapshot();\n // Some terminals (e.g. tmux popups with extended-keys-format=csi-u) re-encode\n // control bytes inside bracketed paste as CSI-u Ctrl+<letter> sequences\n // (ESC [ <codepoint> ; 5 u). Decode those back to their literal byte so the\n // per-char filter below preserves newlines instead of stripping ESC and\n // leaking the printable tail (e.g. \"[106;5u\") into the editor.\n const decodedText = pastedText.replace(/\\x1b\\[(\\d+);5u/g, (match, code) => {\n const cp = Number(code);\n if (cp >= 97 && cp <= 122)\n return String.fromCharCode(cp - 96);\n if (cp >= 65 && cp <= 90)\n return String.fromCharCode(cp - 64);\n return match;\n });\n // Clean the pasted text: normalize line endings, expand tabs\n const cleanText = this.normalizeText(decodedText);\n // Filter out non-printable characters except newlines\n let filteredText = cleanText\n .split(\"\")\n .filter((char) => char === \"\\n\" || char.charCodeAt(0) >= 32)\n .join(\"\");\n // If pasting a file path (starts with /, ~, or .) and the character before\n // the cursor is a word character, prepend a space for better readability\n if (/^[/~.]/.test(filteredText)) {\n const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n const charBeforeCursor = this.state.cursorCol > 0 ? currentLine[this.state.cursorCol - 1] : \"\";\n if (charBeforeCursor && /\\w/.test(charBeforeCursor)) {\n filteredText = ` ${filteredText}`;\n }\n }\n // Split into lines to check for large paste\n const pastedLines = filteredText.split(\"\\n\");\n // Check if this is a large paste (> 10 lines or > 1000 characters)\n const totalChars = filteredText.length;\n if (pastedLines.length > 10 || totalChars > 1000) {\n // Store the paste and insert a marker\n this.pasteCounter++;\n const pasteId = this.pasteCounter;\n this.pastes.set(pasteId, filteredText);\n // Insert marker like \"[paste #1 +123 lines]\" or \"[paste #1 1234 chars]\"\n const marker = pastedLines.length > 10\n ? `[paste #${pasteId} +${pastedLines.length} lines]`\n : `[paste #${pasteId} ${totalChars} chars]`;\n this.insertTextAtCursorInternal(marker);\n return;\n }\n if (pastedLines.length === 1) {\n // Single line - insert atomically (do not trigger autocomplete during paste)\n this.insertTextAtCursorInternal(filteredText);\n return;\n }\n // Multi-line paste - use direct state manipulation\n this.insertTextAtCursorInternal(filteredText);\n }\n addNewLine() {\n this.cancelAutocomplete();\n this.exitHistoryBrowsing();\n this.lastAction = null;\n this.pushUndoSnapshot();\n const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n const before = currentLine.slice(0, this.state.cursorCol);\n const after = currentLine.slice(this.state.cursorCol);\n // Split current line\n this.state.lines[this.state.cursorLine] = before;\n this.state.lines.splice(this.state.cursorLine + 1, 0, after);\n // Move cursor to start of new line\n this.state.cursorLine++;\n this.setCursorCol(0);\n if (this.onChange) {\n this.onChange(this.getText());\n }\n }\n shouldSubmitOnBackslashEnter(data, kb) {\n if (this.disableSubmit)\n return false;\n if (!matchesKey(data, \"enter\"))\n return false;\n const submitKeys = kb.getKeys(\"tui.input.submit\");\n const hasShiftEnter = submitKeys.includes(\"shift+enter\") || submitKeys.includes(\"shift+return\");\n if (!hasShiftEnter)\n return false;\n const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n return this.state.cursorCol > 0 && currentLine[this.state.cursorCol - 1] === \"\\\\\";\n }\n submitValue() {\n this.cancelAutocomplete();\n const result = this.expandPasteMarkers(this.state.lines.join(\"\\n\")).trim();\n this.state = { lines: [\"\"], cursorLine: 0, cursorCol: 0 };\n this.pastes.clear();\n this.pasteCounter = 0;\n this.exitHistoryBrowsing();\n this.scrollOffset = 0;\n this.undoStack.clear();\n this.lastAction = null;\n if (this.onChange)\n this.onChange(\"\");\n if (this.onSubmit)\n this.onSubmit(result);\n }\n handleBackspace() {\n this.exitHistoryBrowsing();\n this.lastAction = null;\n if (this.state.cursorCol > 0) {\n this.pushUndoSnapshot();\n // Delete grapheme before cursor (handles emojis, combining characters, etc.)\n let line = this.state.lines[this.state.cursorLine] || \"\";\n const beforeCursor = line.slice(0, this.state.cursorCol);\n // Find the last grapheme in the text before cursor\n const graphemes = [...this.segment(beforeCursor, \"grapheme\")];\n const lastGrapheme = graphemes[graphemes.length - 1];\n const graphemeLength = lastGrapheme ? lastGrapheme.segment.length : 1;\n const isPastedSegmented = PASTE_MARKER_SINGLE.exec(lastGrapheme.segment);\n if (isPastedSegmented) {\n // This contains the id part e.g 4 from [paste #4 +123 lines]\n const targetId = Number(isPastedSegmented[1]);\n this.pastes.delete(targetId);\n this.pasteCounter--;\n // Shift registry entries down in ascending id order, independent\n // of marker order in the text ([paste #3] becomes [paste #2] when\n // [paste #1] is removed).\n const higherIds = [...this.pastes.keys()].filter((id) => id > targetId).sort((a, b) => a - b);\n for (const id of higherIds) {\n this.pastes.set(id - 1, this.pastes.get(id));\n this.pastes.delete(id);\n }\n // Renumber markers with ids greater than the removed one.\n this.state.lines = this.state.lines.map((line) => line.replace(PASTE_MARKER_REGEX, (fullMatch, idGroup, suffixGroup) => {\n const x = Number(idGroup);\n if (x <= targetId)\n return fullMatch;\n return `[paste #${x - 1}${suffixGroup}]`;\n }));\n }\n line = this.state.lines[this.state.cursorLine] || \"\";\n const before = line.slice(0, this.state.cursorCol - graphemeLength);\n const after = line.slice(this.state.cursorCol);\n this.state.lines[this.state.cursorLine] = before + after;\n this.setCursorCol(this.state.cursorCol - graphemeLength);\n }\n else if (this.state.cursorLine > 0) {\n this.pushUndoSnapshot();\n // Merge with previous line\n const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n const previousLine = this.state.lines[this.state.cursorLine - 1] || \"\";\n this.state.lines[this.state.cursorLine - 1] = previousLine + currentLine;\n this.state.lines.splice(this.state.cursorLine, 1);\n this.state.cursorLine--;\n this.setCursorCol(previousLine.length);\n }\n if (this.onChange) {\n this.onChange(this.getText());\n }\n // Update or re-trigger autocomplete after backspace\n if (this.autocompleteState) {\n this.updateAutocomplete();\n }\n else {\n // If autocomplete was cancelled (no matches), re-trigger if we're in a completable context\n const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n const textBeforeCursor = currentLine.slice(0, this.state.cursorCol);\n // Slash command context\n if (this.isInSlashCommandContext(textBeforeCursor)) {\n this.tryTriggerAutocomplete();\n }\n // Symbol-based completion context like @, #, or provider triggers\n else if (this.autocompleteTriggerPattern.test(textBeforeCursor)) {\n this.tryTriggerAutocomplete();\n }\n }\n }\n /**\n * Set cursor column and clear preferredVisualCol.\n * Use this for all non-vertical cursor movements to reset sticky column behavior.\n */\n setCursorCol(col) {\n this.state.cursorCol = col;\n this.preferredVisualCol = null;\n this.snappedFromCursorCol = null;\n }\n /**\n * Move cursor to a target visual line, applying sticky column logic.\n * Shared by moveCursor() and pageScroll().\n */\n moveToVisualLine(visualLines, currentVisualLine, targetVisualLine) {\n const currentVL = visualLines[currentVisualLine];\n const targetVL = visualLines[targetVisualLine];\n if (!(currentVL && targetVL))\n return;\n // When the cursor was snapped to a segment start, resolve the pre-snap\n // position against the VL it belongs to. This gives the correct visual\n // column even after a resize reshuffles VLs.\n let currentVisualCol;\n if (this.snappedFromCursorCol !== null) {\n const vlIndex = this.findVisualLineAt(visualLines, currentVL.logicalLine, this.snappedFromCursorCol);\n currentVisualCol = this.snappedFromCursorCol - visualLines[vlIndex].startCol;\n }\n else {\n currentVisualCol = this.state.cursorCol - currentVL.startCol;\n }\n // For non-last segments, clamp to length-1 to stay within the segment\n const isLastSourceSegment = currentVisualLine === visualLines.length - 1 ||\n visualLines[currentVisualLine + 1]?.logicalLine !== currentVL.logicalLine;\n const sourceMaxVisualCol = isLastSourceSegment ? currentVL.length : Math.max(0, currentVL.length - 1);\n const isLastTargetSegment = targetVisualLine === visualLines.length - 1 ||\n visualLines[targetVisualLine + 1]?.logicalLine !== targetVL.logicalLine;\n const targetMaxVisualCol = isLastTargetSegment ? targetVL.length : Math.max(0, targetVL.length - 1);\n const moveToVisualCol = this.computeVerticalMoveColumn(currentVisualCol, sourceMaxVisualCol, targetMaxVisualCol);\n // Set cursor position\n this.state.cursorLine = targetVL.logicalLine;\n const targetCol = targetVL.startCol + moveToVisualCol;\n const logicalLine = this.state.lines[targetVL.logicalLine] || \"\";\n this.state.cursorCol = Math.min(targetCol, logicalLine.length);\n // Snap cursor to atomic segment boundary (e.g. paste markers)\n // so the cursor never lands in the middle of a multi-grapheme unit.\n // Single-grapheme segments don't need snapping.\n const segments = [...this.segment(logicalLine, \"grapheme\")];\n for (const seg of segments) {\n if (seg.index > this.state.cursorCol)\n break;\n if (seg.segment.length <= 1)\n continue;\n if (this.state.cursorCol < seg.index + seg.segment.length) {\n const isContinuation = seg.index < targetVL.startCol;\n const isMovingDown = targetVisualLine > currentVisualLine;\n if (isContinuation && isMovingDown) {\n // The segment started on a previous visual line, and we\n // already visited it on the way down. Skip all remaining\n // continuation VLs and land on the first VL past it.\n const segEnd = seg.index + seg.segment.length;\n let next = targetVisualLine + 1;\n while (next < visualLines.length &&\n visualLines[next].logicalLine === targetVL.logicalLine &&\n visualLines[next].startCol < segEnd) {\n next++;\n }\n if (next < visualLines.length) {\n this.moveToVisualLine(visualLines, currentVisualLine, next);\n return;\n }\n }\n // Snap to the start of the segment so it gets highlighted.\n // Store the pre-snap position so the next vertical move can\n // resolve it to the correct visual column.\n this.snappedFromCursorCol = this.state.cursorCol;\n this.state.cursorCol = seg.index;\n return;\n }\n }\n // No snap occurred – we moved out of the atomic segment.\n this.snappedFromCursorCol = null;\n }\n /**\n * Compute the target visual column for vertical cursor movement.\n * Implements the sticky column decision table:\n *\n * | P | S | T | U | Scenario | Set Preferred | Move To |\n * |---|---|---|---| ---------------------------------------------------- |---------------|-------------|\n * | 0 | * | 0 | - | Start nav, target fits | null | current |\n * | 0 | * | 1 | - | Start nav, target shorter | current | target end |\n * | 1 | 0 | 0 | 0 | Clamped, target fits preferred | null | preferred |\n * | 1 | 0 | 0 | 1 | Clamped, target longer but still can't fit preferred | keep | target end |\n * | 1 | 0 | 1 | - | Clamped, target even shorter | keep | target end |\n * | 1 | 1 | 0 | - | Rewrapped, target fits current | null | current |\n * | 1 | 1 | 1 | - | Rewrapped, target shorter than current | current | target end |\n *\n * Where:\n * - P = preferred col is set\n * - S = cursor in middle of source line (not clamped to end)\n * - T = target line shorter than current visual col\n * - U = target line shorter than preferred col\n */\n computeVerticalMoveColumn(currentVisualCol, sourceMaxVisualCol, targetMaxVisualCol) {\n const hasPreferred = this.preferredVisualCol !== null; // P\n const cursorInMiddle = currentVisualCol < sourceMaxVisualCol; // S\n const targetTooShort = targetMaxVisualCol < currentVisualCol; // T\n if (!hasPreferred || cursorInMiddle) {\n if (targetTooShort) {\n // Cases 2 and 7\n this.preferredVisualCol = currentVisualCol;\n return targetMaxVisualCol;\n }\n // Cases 1 and 6\n this.preferredVisualCol = null;\n return currentVisualCol;\n }\n const targetCantFitPreferred = targetMaxVisualCol < this.preferredVisualCol; // U\n if (targetTooShort || targetCantFitPreferred) {\n // Cases 4 and 5\n return targetMaxVisualCol;\n }\n // Case 3\n const result = this.preferredVisualCol;\n this.preferredVisualCol = null;\n return result;\n }\n moveToLineStart() {\n this.lastAction = null;\n this.setCursorCol(0);\n }\n moveToLineEnd() {\n this.lastAction = null;\n const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n this.setCursorCol(currentLine.length);\n }\n deleteToStartOfLine() {\n this.exitHistoryBrowsing();\n const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n if (this.state.cursorCol > 0) {\n this.pushUndoSnapshot();\n // Calculate text to be deleted and save to kill ring (backward deletion = prepend)\n const deletedText = currentLine.slice(0, this.state.cursorCol);\n this.killRing.push(deletedText, { prepend: true, accumulate: this.lastAction === \"kill\" });\n this.lastAction = \"kill\";\n // Delete from start of line up to cursor\n this.state.lines[this.state.cursorLine] = currentLine.slice(this.state.cursorCol);\n this.setCursorCol(0);\n }\n else if (this.state.cursorLine > 0) {\n this.pushUndoSnapshot();\n // At start of line - merge with previous line, treating newline as deleted text\n this.killRing.push(\"\\n\", { prepend: true, accumulate: this.lastAction === \"kill\" });\n this.lastAction = \"kill\";\n const previousLine = this.state.lines[this.state.cursorLine - 1] || \"\";\n this.state.lines[this.state.cursorLine - 1] = previousLine + currentLine;\n this.state.lines.splice(this.state.cursorLine, 1);\n this.state.cursorLine--;\n this.setCursorCol(previousLine.length);\n }\n if (this.onChange) {\n this.onChange(this.getText());\n }\n }\n deleteToEndOfLine() {\n this.exitHistoryBrowsing();\n const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n if (this.state.cursorCol < currentLine.length) {\n this.pushUndoSnapshot();\n // Calculate text to be deleted and save to kill ring (forward deletion = append)\n const deletedText = currentLine.slice(this.state.cursorCol);\n this.killRing.push(deletedText, { prepend: false, accumulate: this.lastAction === \"kill\" });\n this.lastAction = \"kill\";\n // Delete from cursor to end of line\n this.state.lines[this.state.cursorLine] = currentLine.slice(0, this.state.cursorCol);\n }\n else if (this.state.cursorLine < this.state.lines.length - 1) {\n this.pushUndoSnapshot();\n // At end of line - merge with next line, treating newline as deleted text\n this.killRing.push(\"\\n\", { prepend: false, accumulate: this.lastAction === \"kill\" });\n this.lastAction = \"kill\";\n const nextLine = this.state.lines[this.state.cursorLine + 1] || \"\";\n this.state.lines[this.state.cursorLine] = currentLine + nextLine;\n this.state.lines.splice(this.state.cursorLine + 1, 1);\n }\n if (this.onChange) {\n this.onChange(this.getText());\n }\n }\n deleteWordBackwards() {\n this.exitHistoryBrowsing();\n const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n // If at start of line, behave like backspace at column 0 (merge with previous line)\n if (this.state.cursorCol === 0) {\n if (this.state.cursorLine > 0) {\n this.pushUndoSnapshot();\n // Treat newline as deleted text (backward deletion = prepend)\n this.killRing.push(\"\\n\", { prepend: true, accumulate: this.lastAction === \"kill\" });\n this.lastAction = \"kill\";\n const previousLine = this.state.lines[this.state.cursorLine - 1] || \"\";\n this.state.lines[this.state.cursorLine - 1] = previousLine + currentLine;\n this.state.lines.splice(this.state.cursorLine, 1);\n this.state.cursorLine--;\n this.setCursorCol(previousLine.length);\n }\n }\n else {\n this.pushUndoSnapshot();\n // Save lastAction before cursor movement (moveWordBackwards resets it)\n const wasKill = this.lastAction === \"kill\";\n const oldCursorCol = this.state.cursorCol;\n this.moveWordBackwards();\n const deleteFrom = this.state.cursorCol;\n this.setCursorCol(oldCursorCol);\n const deletedText = currentLine.slice(deleteFrom, this.state.cursorCol);\n this.killRing.push(deletedText, { prepend: true, accumulate: wasKill });\n this.lastAction = \"kill\";\n this.state.lines[this.state.cursorLine] =\n currentLine.slice(0, deleteFrom) + currentLine.slice(this.state.cursorCol);\n this.setCursorCol(deleteFrom);\n }\n if (this.onChange) {\n this.onChange(this.getText());\n }\n }\n deleteWordForward() {\n this.exitHistoryBrowsing();\n const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n // If at end of line, merge with next line (delete the newline)\n if (this.state.cursorCol >= currentLine.length) {\n if (this.state.cursorLine < this.state.lines.length - 1) {\n this.pushUndoSnapshot();\n // Treat newline as deleted text (forward deletion = append)\n this.killRing.push(\"\\n\", { prepend: false, accumulate: this.lastAction === \"kill\" });\n this.lastAction = \"kill\";\n const nextLine = this.state.lines[this.state.cursorLine + 1] || \"\";\n this.state.lines[this.state.cursorLine] = currentLine + nextLine;\n this.state.lines.splice(this.state.cursorLine + 1, 1);\n }\n }\n else {\n this.pushUndoSnapshot();\n // Save lastAction before cursor movement (moveWordForwards resets it)\n const wasKill = this.lastAction === \"kill\";\n const oldCursorCol = this.state.cursorCol;\n this.moveWordForwards();\n const deleteTo = this.state.cursorCol;\n this.setCursorCol(oldCursorCol);\n const deletedText = currentLine.slice(this.state.cursorCol, deleteTo);\n this.killRing.push(deletedText, { prepend: false, accumulate: wasKill });\n this.lastAction = \"kill\";\n this.state.lines[this.state.cursorLine] =\n currentLine.slice(0, this.state.cursorCol) + currentLine.slice(deleteTo);\n }\n if (this.onChange) {\n this.onChange(this.getText());\n }\n }\n handleForwardDelete() {\n this.exitHistoryBrowsing();\n this.lastAction = null;\n const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n if (this.state.cursorCol < currentLine.length) {\n this.pushUndoSnapshot();\n // Delete grapheme at cursor position (handles emojis, combining characters, etc.)\n const afterCursor = currentLine.slice(this.state.cursorCol);\n // Find the first grapheme at cursor\n const graphemes = [...this.segment(afterCursor, \"grapheme\")];\n const firstGrapheme = graphemes[0];\n const graphemeLength = firstGrapheme ? firstGrapheme.segment.length : 1;\n const before = currentLine.slice(0, this.state.cursorCol);\n const after = currentLine.slice(this.state.cursorCol + graphemeLength);\n this.state.lines[this.state.cursorLine] = before + after;\n }\n else if (this.state.cursorLine < this.state.lines.length - 1) {\n this.pushUndoSnapshot();\n // At end of line - merge with next line\n const nextLine = this.state.lines[this.state.cursorLine + 1] || \"\";\n this.state.lines[this.state.cursorLine] = currentLine + nextLine;\n this.state.lines.splice(this.state.cursorLine + 1, 1);\n }\n if (this.onChange) {\n this.onChange(this.getText());\n }\n // Update or re-trigger autocomplete after forward delete\n if (this.autocompleteState) {\n this.updateAutocomplete();\n }\n else {\n const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n const textBeforeCursor = currentLine.slice(0, this.state.cursorCol);\n // Slash command context\n if (this.isInSlashCommandContext(textBeforeCursor)) {\n this.tryTriggerAutocomplete();\n }\n // Symbol-based completion context like @, #, or provider triggers\n else if (this.autocompleteTriggerPattern.test(textBeforeCursor)) {\n this.tryTriggerAutocomplete();\n }\n }\n }\n /**\n * Build a mapping from visual lines to logical positions.\n * Returns an array where each element represents a visual line with:\n * - logicalLine: index into this.state.lines\n * - startCol: starting column in the logical line\n * - length: length of this visual line segment\n */\n buildVisualLineMap(width) {\n const visualLines = [];\n for (let i = 0; i < this.state.lines.length; i++) {\n const line = this.state.lines[i] || \"\";\n const lineVisWidth = visibleWidth(line);\n if (line.length === 0) {\n // Empty line still takes one visual line\n visualLines.push({ logicalLine: i, startCol: 0, length: 0 });\n }\n else if (lineVisWidth <= width) {\n visualLines.push({ logicalLine: i, startCol: 0, length: line.length });\n }\n else {\n // Line needs wrapping - use word-aware wrapping\n const chunks = wordWrapLine(line, width, [...this.segment(line, \"grapheme\")]);\n for (const chunk of chunks) {\n visualLines.push({\n logicalLine: i,\n startCol: chunk.startIndex,\n length: chunk.endIndex - chunk.startIndex,\n });\n }\n }\n }\n return visualLines;\n }\n /**\n * Find the visual line index that contains the given logical position.\n */\n findVisualLineAt(visualLines, line, col) {\n for (let i = 0; i < visualLines.length; i++) {\n const vl = visualLines[i];\n if (!vl || vl.logicalLine !== line)\n continue;\n const offset = col - vl.startCol;\n // Cursor is in this segment if it's within range. For the last\n // segment of a logical line, cursor can be at length (end position)\n const isLastSegmentOfLine = i === visualLines.length - 1 || visualLines[i + 1]?.logicalLine !== vl.logicalLine;\n if (offset >= 0 && (offset < vl.length || (isLastSegmentOfLine && offset === vl.length))) {\n return i;\n }\n }\n return visualLines.length - 1;\n }\n /**\n * Find the visual line index for the current cursor position.\n */\n findCurrentVisualLine(visualLines) {\n return this.findVisualLineAt(visualLines, this.state.cursorLine, this.state.cursorCol);\n }\n moveCursor(deltaLine, deltaCol) {\n this.lastAction = null;\n const visualLines = this.buildVisualLineMap(this.lastWidth);\n const currentVisualLine = this.findCurrentVisualLine(visualLines);\n if (deltaLine !== 0) {\n const targetVisualLine = currentVisualLine + deltaLine;\n if (targetVisualLine >= 0 && targetVisualLine < visualLines.length) {\n this.moveToVisualLine(visualLines, currentVisualLine, targetVisualLine);\n }\n }\n if (deltaCol !== 0) {\n const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n if (deltaCol > 0) {\n // Moving right - move by one grapheme (handles emojis, combining characters, etc.)\n if (this.state.cursorCol < currentLine.length) {\n const afterCursor = currentLine.slice(this.state.cursorCol);\n const graphemes = [...this.segment(afterCursor, \"grapheme\")];\n const firstGrapheme = graphemes[0];\n this.setCursorCol(this.state.cursorCol + (firstGrapheme ? firstGrapheme.segment.length : 1));\n }\n else if (this.state.cursorLine < this.state.lines.length - 1) {\n // Wrap to start of next logical line\n this.state.cursorLine++;\n this.setCursorCol(0);\n }\n else {\n // At end of last line - can't move, but set preferredVisualCol for up/down navigation\n const currentVL = visualLines[currentVisualLine];\n if (currentVL) {\n this.preferredVisualCol = this.state.cursorCol - currentVL.startCol;\n }\n }\n }\n else {\n // Moving left - move by one grapheme (handles emojis, combining characters, etc.)\n if (this.state.cursorCol > 0) {\n const beforeCursor = currentLine.slice(0, this.state.cursorCol);\n const graphemes = [...this.segment(beforeCursor, \"grapheme\")];\n const lastGrapheme = graphemes[graphemes.length - 1];\n this.setCursorCol(this.state.cursorCol - (lastGrapheme ? lastGrapheme.segment.length : 1));\n }\n else if (this.state.cursorLine > 0) {\n // Wrap to end of previous logical line\n this.state.cursorLine--;\n const prevLine = this.state.lines[this.state.cursorLine] || \"\";\n this.setCursorCol(prevLine.length);\n }\n }\n }\n // Keep an open autocomplete picker in sync with the new cursor\n // position: cursor movement changes the text before the cursor, so a\n // picker computed for the old position is stale. Re-query so it\n // refreshes — or closes when the new position yields no suggestions —\n // mirroring insertCharacter()/handleBackspace(). Without this, arrowing\n // left from `/cmd ` back into the command name leaves the argument\n // picker showing against a `/cmd` prefix (and a Tab there would\n // concatenate the stale suggestion onto the partial command name).\n if (this.autocompleteState) {\n this.updateAutocomplete();\n }\n }\n /**\n * Scroll by a page (direction: -1 for up, 1 for down).\n * Moves cursor by the page size while keeping it in bounds.\n */\n pageScroll(direction) {\n this.lastAction = null;\n const terminalRows = this.tui.terminal.rows;\n const pageSize = Math.max(5, Math.floor(terminalRows * 0.3));\n const visualLines = this.buildVisualLineMap(this.lastWidth);\n const currentVisualLine = this.findCurrentVisualLine(visualLines);\n const targetVisualLine = Math.max(0, Math.min(visualLines.length - 1, currentVisualLine + direction * pageSize));\n this.moveToVisualLine(visualLines, currentVisualLine, targetVisualLine);\n }\n moveWordBackwards() {\n this.lastAction = null;\n const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n // If at start of line, move to end of previous line\n if (this.state.cursorCol === 0) {\n if (this.state.cursorLine > 0) {\n this.state.cursorLine--;\n const prevLine = this.state.lines[this.state.cursorLine] || \"\";\n this.setCursorCol(prevLine.length);\n }\n return;\n }\n this.setCursorCol(findWordBackward(currentLine, this.state.cursorCol, {\n segment: (text) => this.segment(text, \"word\"),\n isAtomicSegment: isPasteMarker,\n }));\n }\n /**\n * Yank (paste) the most recent kill ring entry at cursor position.\n */\n yank() {\n if (this.killRing.length === 0)\n return;\n this.pushUndoSnapshot();\n const text = this.killRing.peek();\n this.insertYankedText(text);\n this.lastAction = \"yank\";\n }\n /**\n * Cycle through kill ring (only works immediately after yank or yank-pop).\n * Replaces the last yanked text with the previous entry in the ring.\n */\n yankPop() {\n // Only works if we just yanked and have more than one entry\n if (this.lastAction !== \"yank\" || this.killRing.length <= 1)\n return;\n this.pushUndoSnapshot();\n // Delete the previously yanked text (still at end of ring before rotation)\n this.deleteYankedText();\n // Rotate the ring: move end to front\n this.killRing.rotate();\n // Insert the new most recent entry (now at end after rotation)\n const text = this.killRing.peek();\n this.insertYankedText(text);\n this.lastAction = \"yank\";\n }\n /**\n * Insert text at cursor position (used by yank operations).\n */\n insertYankedText(text) {\n this.exitHistoryBrowsing();\n const lines = text.split(\"\\n\");\n if (lines.length === 1) {\n // Single line - insert at cursor\n const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n const before = currentLine.slice(0, this.state.cursorCol);\n const after = currentLine.slice(this.state.cursorCol);\n this.state.lines[this.state.cursorLine] = before + text + after;\n this.setCursorCol(this.state.cursorCol + text.length);\n }\n else {\n // Multi-line insert\n const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n const before = currentLine.slice(0, this.state.cursorCol);\n const after = currentLine.slice(this.state.cursorCol);\n // First line merges with text before cursor\n this.state.lines[this.state.cursorLine] = before + (lines[0] || \"\");\n // Insert middle lines\n for (let i = 1; i < lines.length - 1; i++) {\n this.state.lines.splice(this.state.cursorLine + i, 0, lines[i] || \"\");\n }\n // Last line merges with text after cursor\n const lastLineIndex = this.state.cursorLine + lines.length - 1;\n this.state.lines.splice(lastLineIndex, 0, (lines[lines.length - 1] || \"\") + after);\n // Update cursor position\n this.state.cursorLine = lastLineIndex;\n this.setCursorCol((lines[lines.length - 1] || \"\").length);\n }\n if (this.onChange) {\n this.onChange(this.getText());\n }\n }\n /**\n * Delete the previously yanked text (used by yank-pop).\n * The yanked text is derived from killRing[end] since it hasn't been rotated yet.\n */\n deleteYankedText() {\n const yankedText = this.killRing.peek();\n if (!yankedText)\n return;\n const yankLines = yankedText.split(\"\\n\");\n if (yankLines.length === 1) {\n // Single line - delete backward from cursor\n const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n const deleteLen = yankedText.length;\n const before = currentLine.slice(0, this.state.cursorCol - deleteLen);\n const after = currentLine.slice(this.state.cursorCol);\n this.state.lines[this.state.cursorLine] = before + after;\n this.setCursorCol(this.state.cursorCol - deleteLen);\n }\n else {\n // Multi-line delete - cursor is at end of last yanked line\n const startLine = this.state.cursorLine - (yankLines.length - 1);\n const startCol = (this.state.lines[startLine] || \"\").length - (yankLines[0] || \"\").length;\n // Get text after cursor on current line\n const afterCursor = (this.state.lines[this.state.cursorLine] || \"\").slice(this.state.cursorCol);\n // Get text before yank start position\n const beforeYank = (this.state.lines[startLine] || \"\").slice(0, startCol);\n // Remove all lines from startLine to cursorLine and replace with merged line\n this.state.lines.splice(startLine, yankLines.length, beforeYank + afterCursor);\n // Update cursor\n this.state.cursorLine = startLine;\n this.setCursorCol(startCol);\n }\n if (this.onChange) {\n this.onChange(this.getText());\n }\n }\n pushUndoSnapshot() {\n this.undoStack.push({ state: this.state, pastes: this.pastes, pasteCounter: this.pasteCounter });\n }\n undo() {\n this.exitHistoryBrowsing();\n const snapshot = this.undoStack.pop();\n if (!snapshot)\n return;\n Object.assign(this.state, snapshot.state);\n this.pastes = snapshot.pastes;\n this.pasteCounter = snapshot.pasteCounter;\n this.lastAction = null;\n this.preferredVisualCol = null;\n if (this.onChange) {\n this.onChange(this.getText());\n }\n }\n /**\n * Jump to the first occurrence of a character in the specified direction.\n * Multi-line search. Case-sensitive. Skips the current cursor position.\n */\n jumpToChar(char, direction) {\n this.lastAction = null;\n const isForward = direction === \"forward\";\n const lines = this.state.lines;\n const end = isForward ? lines.length : -1;\n const step = isForward ? 1 : -1;\n for (let lineIdx = this.state.cursorLine; lineIdx !== end; lineIdx += step) {\n const line = lines[lineIdx] || \"\";\n const isCurrentLine = lineIdx === this.state.cursorLine;\n // Current line: start after/before cursor; other lines: search full line\n const searchFrom = isCurrentLine\n ? isForward\n ? this.state.cursorCol + 1\n : this.state.cursorCol - 1\n : undefined;\n const idx = isForward ? line.indexOf(char, searchFrom) : line.lastIndexOf(char, searchFrom);\n if (idx !== -1) {\n this.state.cursorLine = lineIdx;\n this.setCursorCol(idx);\n return;\n }\n }\n // No match found - cursor stays in place\n }\n moveWordForwards() {\n this.lastAction = null;\n const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n // If at end of line, move to start of next line\n if (this.state.cursorCol >= currentLine.length) {\n if (this.state.cursorLine < this.state.lines.length - 1) {\n this.state.cursorLine++;\n this.setCursorCol(0);\n }\n return;\n }\n this.setCursorCol(findWordForward(currentLine, this.state.cursorCol, {\n segment: (text) => this.segment(text, \"word\"),\n isAtomicSegment: isPasteMarker,\n }));\n }\n // Slash menu only allowed on the first line of the editor\n isSlashMenuAllowed() {\n return this.state.cursorLine === 0;\n }\n // Helper method to check if cursor is at start of message (for slash command detection)\n isAtStartOfMessage() {\n if (!this.isSlashMenuAllowed())\n return false;\n const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n const beforeCursor = currentLine.slice(0, this.state.cursorCol);\n return beforeCursor.trim() === \"\" || beforeCursor.trim() === \"/\";\n }\n isInSlashCommandContext(textBeforeCursor) {\n return this.isSlashMenuAllowed() && textBeforeCursor.trimStart().startsWith(\"/\");\n }\n // Autocomplete methods\n /**\n * Find the best autocomplete item index for the given prefix.\n * Returns -1 if no match is found.\n *\n * Match priority:\n * 1. Exact match (prefix === item.value) -> always selected\n * 2. Prefix match -> first item whose value starts with prefix\n * 3. No match -> -1 (keep default highlight)\n *\n * Matching is case-sensitive and checks item.value only.\n */\n getBestAutocompleteMatchIndex(items, prefix) {\n if (!prefix)\n return -1;\n let firstPrefixIndex = -1;\n for (let i = 0; i < items.length; i++) {\n const value = items[i].value;\n if (value === prefix) {\n return i; // Exact match always wins\n }\n if (firstPrefixIndex === -1 && value.startsWith(prefix)) {\n firstPrefixIndex = i;\n }\n }\n return firstPrefixIndex;\n }\n createAutocompleteList(prefix, items) {\n const layout = prefix.startsWith(\"/\") ? SLASH_COMMAND_SELECT_LIST_LAYOUT : undefined;\n return new SelectList(items, this.autocompleteMaxVisible, this.theme.selectList, layout);\n }\n tryTriggerAutocomplete(explicitTab = false) {\n this.requestAutocomplete({ force: false, explicitTab });\n }\n handleTabCompletion() {\n if (!this.autocompleteProvider)\n return;\n const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n const beforeCursor = currentLine.slice(0, this.state.cursorCol);\n if (this.isInSlashCommandContext(beforeCursor) && !beforeCursor.trimStart().includes(\" \")) {\n this.handleSlashCommandCompletion();\n }\n else {\n this.forceFileAutocomplete(true);\n }\n }\n handleSlashCommandCompletion() {\n this.requestAutocomplete({ force: false, explicitTab: true });\n }\n forceFileAutocomplete(explicitTab = false) {\n this.requestAutocomplete({ force: true, explicitTab });\n }\n requestAutocomplete(options) {\n if (!this.autocompleteProvider)\n return;\n if (options.force) {\n const shouldTrigger = !this.autocompleteProvider.shouldTriggerFileCompletion ||\n this.autocompleteProvider.shouldTriggerFileCompletion(this.state.lines, this.state.cursorLine, this.state.cursorCol);\n if (!shouldTrigger) {\n return;\n }\n }\n this.cancelAutocompleteRequest();\n const startToken = ++this.autocompleteStartToken;\n const debounceMs = this.getAutocompleteDebounceMs(options);\n if (debounceMs > 0) {\n this.autocompleteDebounceTimer = setTimeout(() => {\n this.autocompleteDebounceTimer = undefined;\n void this.startAutocompleteRequest(startToken, options);\n }, debounceMs);\n return;\n }\n void this.startAutocompleteRequest(startToken, options);\n }\n async startAutocompleteRequest(startToken, options) {\n const previousTask = this.autocompleteRequestTask;\n this.autocompleteRequestTask = (async () => {\n await previousTask;\n if (startToken !== this.autocompleteStartToken || !this.autocompleteProvider) {\n return;\n }\n const controller = new AbortController();\n this.autocompleteAbort = controller;\n const requestId = ++this.autocompleteRequestId;\n const snapshotText = this.getText();\n const snapshotLine = this.state.cursorLine;\n const snapshotCol = this.state.cursorCol;\n await this.runAutocompleteRequest(requestId, controller, snapshotText, snapshotLine, snapshotCol, options);\n })();\n await this.autocompleteRequestTask;\n }\n setAutocompleteTriggerCharacters(triggerCharacters) {\n const next = [...DEFAULT_AUTOCOMPLETE_TRIGGER_CHARACTERS];\n for (const character of triggerCharacters) {\n if (character.length !== 1 || character === \"/\" || isWhitespaceChar(character) || next.includes(character)) {\n continue;\n }\n next.push(character);\n }\n this.autocompleteTriggerCharacters = next;\n this.autocompleteTriggerPattern = buildTriggerPattern(next);\n this.autocompleteDebouncePattern = buildDebouncePattern(next);\n }\n getAutocompleteDebounceMs(options) {\n if (options.explicitTab || options.force) {\n return 0;\n }\n const currentLine = this.state.lines[this.state.cursorLine] || \"\";\n const textBeforeCursor = currentLine.slice(0, this.state.cursorCol);\n return this.autocompleteDebouncePattern.test(textBeforeCursor) ? ATTACHMENT_AUTOCOMPLETE_DEBOUNCE_MS : 0;\n }\n async runAutocompleteRequest(requestId, controller, snapshotText, snapshotLine, snapshotCol, options) {\n if (!this.autocompleteProvider)\n return;\n const suggestions = await this.autocompleteProvider.getSuggestions(this.state.lines, this.state.cursorLine, this.state.cursorCol, { signal: controller.signal, force: options.force });\n if (!this.isAutocompleteRequestCurrent(requestId, controller, snapshotText, snapshotLine, snapshotCol)) {\n return;\n }\n this.autocompleteAbort = undefined;\n if (!suggestions || !Array.isArray(suggestions.items) || suggestions.items.length === 0) {\n this.cancelAutocomplete();\n this.tui.requestRender();\n return;\n }\n if (options.force && options.explicitTab && suggestions.items.length === 1) {\n const item = suggestions.items[0];\n this.pushUndoSnapshot();\n this.lastAction = null;\n const result = this.autocompleteProvider.applyCompletion(this.state.lines, this.state.cursorLine, this.state.cursorCol, item, suggestions.prefix);\n this.state.lines = result.lines;\n this.state.cursorLine = result.cursorLine;\n this.setCursorCol(result.cursorCol);\n if (this.onChange)\n this.onChange(this.getText());\n this.tui.requestRender();\n return;\n }\n this.applyAutocompleteSuggestions(suggestions, options.force ? \"force\" : \"regular\");\n this.tui.requestRender();\n }\n isAutocompleteRequestCurrent(requestId, controller, snapshotText, snapshotLine, snapshotCol) {\n return (!controller.signal.aborted &&\n requestId === this.autocompleteRequestId &&\n this.getText() === snapshotText &&\n this.state.cursorLine === snapshotLine &&\n this.state.cursorCol === snapshotCol);\n }\n applyAutocompleteSuggestions(suggestions, state) {\n this.autocompletePrefix = suggestions.prefix;\n this.autocompleteList = this.createAutocompleteList(suggestions.prefix, suggestions.items);\n const bestMatchIndex = this.getBestAutocompleteMatchIndex(suggestions.items, suggestions.prefix);\n if (bestMatchIndex >= 0) {\n this.autocompleteList.setSelectedIndex(bestMatchIndex);\n }\n this.autocompleteState = state;\n }\n cancelAutocompleteRequest() {\n this.autocompleteStartToken += 1;\n if (this.autocompleteDebounceTimer) {\n clearTimeout(this.autocompleteDebounceTimer);\n this.autocompleteDebounceTimer = undefined;\n }\n this.autocompleteAbort?.abort();\n this.autocompleteAbort = undefined;\n }\n clearAutocompleteUi() {\n this.autocompleteState = null;\n this.autocompleteList = undefined;\n this.autocompletePrefix = \"\";\n }\n cancelAutocomplete() {\n this.cancelAutocompleteRequest();\n this.clearAutocompleteUi();\n }\n isShowingAutocomplete() {\n return this.autocompleteState !== null;\n }\n updateAutocomplete() {\n if (!this.autocompleteState || !this.autocompleteProvider)\n return;\n this.requestAutocomplete({ force: this.autocompleteState === \"force\", explicitTab: false });\n }\n}\n//# sourceMappingURL=editor.js.map","import { getKeybindings } from \"../keybindings.js\";\nimport { decodeKittyPrintable } from \"../keys.js\";\nimport { KillRing } from \"../kill-ring.js\";\nimport { CURSOR_MARKER } from \"../tui.js\";\nimport { UndoStack } from \"../undo-stack.js\";\nimport { getGraphemeSegmenter, isWhitespaceChar, sliceByColumn, visibleWidth } from \"../utils.js\";\nimport { findWordBackward, findWordForward } from \"../word-navigation.js\";\nconst segmenter = getGraphemeSegmenter();\n/**\n * Input component - single-line text input with horizontal scrolling\n */\nexport class Input {\n value = \"\";\n cursor = 0; // Cursor position in the value\n onSubmit;\n onEscape;\n /** Focusable interface - set by TUI when focus changes */\n focused = false;\n // Bracketed paste mode buffering\n pasteBuffer = \"\";\n isInPaste = false;\n // Kill ring for Emacs-style kill/yank operations\n killRing = new KillRing();\n lastAction = null;\n // Undo support\n undoStack = new UndoStack();\n getValue() {\n return this.value;\n }\n setValue(value) {\n this.value = value;\n this.cursor = Math.min(this.cursor, value.length);\n }\n handleInput(data) {\n // Handle bracketed paste mode\n // Start of paste: \\x1b[200~\n // End of paste: \\x1b[201~\n // Check if we're starting a bracketed paste\n if (data.includes(\"\\x1b[200~\")) {\n this.isInPaste = true;\n this.pasteBuffer = \"\";\n data = data.replace(\"\\x1b[200~\", \"\");\n }\n // If we're in a paste, buffer the data\n if (this.isInPaste) {\n // Check if this chunk contains the end marker\n this.pasteBuffer += data;\n const endIndex = this.pasteBuffer.indexOf(\"\\x1b[201~\");\n if (endIndex !== -1) {\n // Extract the pasted content\n const pasteContent = this.pasteBuffer.substring(0, endIndex);\n // Process the complete paste\n this.handlePaste(pasteContent);\n // Reset paste state\n this.isInPaste = false;\n // Handle any remaining input after the paste marker\n const remaining = this.pasteBuffer.substring(endIndex + 6); // 6 = length of \\x1b[201~\n this.pasteBuffer = \"\";\n if (remaining) {\n this.handleInput(remaining);\n }\n }\n return;\n }\n const kb = getKeybindings();\n // Escape/Cancel\n if (kb.matches(data, \"tui.select.cancel\")) {\n if (this.onEscape)\n this.onEscape();\n return;\n }\n // Undo\n if (kb.matches(data, \"tui.editor.undo\")) {\n this.undo();\n return;\n }\n // Submit\n if (kb.matches(data, \"tui.input.submit\") || data === \"\\n\") {\n if (this.onSubmit)\n this.onSubmit(this.value);\n return;\n }\n // Deletion\n if (kb.matches(data, \"tui.editor.deleteCharBackward\")) {\n this.handleBackspace();\n return;\n }\n if (kb.matches(data, \"tui.editor.deleteCharForward\")) {\n this.handleForwardDelete();\n return;\n }\n if (kb.matches(data, \"tui.editor.deleteWordBackward\")) {\n this.deleteWordBackwards();\n return;\n }\n if (kb.matches(data, \"tui.editor.deleteWordForward\")) {\n this.deleteWordForward();\n return;\n }\n if (kb.matches(data, \"tui.editor.deleteToLineStart\")) {\n this.deleteToLineStart();\n return;\n }\n if (kb.matches(data, \"tui.editor.deleteToLineEnd\")) {\n this.deleteToLineEnd();\n return;\n }\n // Kill ring actions\n if (kb.matches(data, \"tui.editor.yank\")) {\n this.yank();\n return;\n }\n if (kb.matches(data, \"tui.editor.yankPop\")) {\n this.yankPop();\n return;\n }\n // Cursor movement\n if (kb.matches(data, \"tui.editor.cursorLeft\")) {\n this.lastAction = null;\n if (this.cursor > 0) {\n const beforeCursor = this.value.slice(0, this.cursor);\n const graphemes = [...segmenter.segment(beforeCursor)];\n const lastGrapheme = graphemes[graphemes.length - 1];\n this.cursor -= lastGrapheme ? lastGrapheme.segment.length : 1;\n }\n return;\n }\n if (kb.matches(data, \"tui.editor.cursorRight\")) {\n this.lastAction = null;\n if (this.cursor < this.value.length) {\n const afterCursor = this.value.slice(this.cursor);\n const graphemes = [...segmenter.segment(afterCursor)];\n const firstGrapheme = graphemes[0];\n this.cursor += firstGrapheme ? firstGrapheme.segment.length : 1;\n }\n return;\n }\n if (kb.matches(data, \"tui.editor.cursorLineStart\")) {\n this.lastAction = null;\n this.cursor = 0;\n return;\n }\n if (kb.matches(data, \"tui.editor.cursorLineEnd\")) {\n this.lastAction = null;\n this.cursor = this.value.length;\n return;\n }\n if (kb.matches(data, \"tui.editor.cursorWordLeft\")) {\n this.moveWordBackwards();\n return;\n }\n if (kb.matches(data, \"tui.editor.cursorWordRight\")) {\n this.moveWordForwards();\n return;\n }\n // Kitty CSI-u printable character (e.g. \\x1b[97u for 'a').\n // Terminals with Kitty protocol flag 1 (disambiguate) send CSI-u for all keys,\n // including plain printable characters. Decode before the control-char check\n // since CSI-u sequences contain \\x1b which would be rejected.\n const kittyPrintable = decodeKittyPrintable(data);\n if (kittyPrintable !== undefined) {\n this.insertCharacter(kittyPrintable);\n return;\n }\n // Regular character input - accept printable characters including Unicode,\n // but reject control characters (C0: 0x00-0x1F, DEL: 0x7F, C1: 0x80-0x9F)\n const hasControlChars = [...data].some((ch) => {\n const code = ch.charCodeAt(0);\n return code < 32 || code === 0x7f || (code >= 0x80 && code <= 0x9f);\n });\n if (!hasControlChars) {\n this.insertCharacter(data);\n }\n }\n insertCharacter(char) {\n // Undo coalescing: consecutive word chars coalesce into one undo unit\n if (isWhitespaceChar(char) || this.lastAction !== \"type-word\") {\n this.pushUndo();\n }\n this.lastAction = \"type-word\";\n this.value = this.value.slice(0, this.cursor) + char + this.value.slice(this.cursor);\n this.cursor += char.length;\n }\n handleBackspace() {\n this.lastAction = null;\n if (this.cursor > 0) {\n this.pushUndo();\n const beforeCursor = this.value.slice(0, this.cursor);\n const graphemes = [...segmenter.segment(beforeCursor)];\n const lastGrapheme = graphemes[graphemes.length - 1];\n const graphemeLength = lastGrapheme ? lastGrapheme.segment.length : 1;\n this.value = this.value.slice(0, this.cursor - graphemeLength) + this.value.slice(this.cursor);\n this.cursor -= graphemeLength;\n }\n }\n handleForwardDelete() {\n this.lastAction = null;\n if (this.cursor < this.value.length) {\n this.pushUndo();\n const afterCursor = this.value.slice(this.cursor);\n const graphemes = [...segmenter.segment(afterCursor)];\n const firstGrapheme = graphemes[0];\n const graphemeLength = firstGrapheme ? firstGrapheme.segment.length : 1;\n this.value = this.value.slice(0, this.cursor) + this.value.slice(this.cursor + graphemeLength);\n }\n }\n deleteToLineStart() {\n if (this.cursor === 0)\n return;\n this.pushUndo();\n const deletedText = this.value.slice(0, this.cursor);\n this.killRing.push(deletedText, { prepend: true, accumulate: this.lastAction === \"kill\" });\n this.lastAction = \"kill\";\n this.value = this.value.slice(this.cursor);\n this.cursor = 0;\n }\n deleteToLineEnd() {\n if (this.cursor >= this.value.length)\n return;\n this.pushUndo();\n const deletedText = this.value.slice(this.cursor);\n this.killRing.push(deletedText, { prepend: false, accumulate: this.lastAction === \"kill\" });\n this.lastAction = \"kill\";\n this.value = this.value.slice(0, this.cursor);\n }\n deleteWordBackwards() {\n if (this.cursor === 0)\n return;\n // Save lastAction before cursor movement (moveWordBackwards resets it)\n const wasKill = this.lastAction === \"kill\";\n this.pushUndo();\n const oldCursor = this.cursor;\n this.moveWordBackwards();\n const deleteFrom = this.cursor;\n this.cursor = oldCursor;\n const deletedText = this.value.slice(deleteFrom, this.cursor);\n this.killRing.push(deletedText, { prepend: true, accumulate: wasKill });\n this.lastAction = \"kill\";\n this.value = this.value.slice(0, deleteFrom) + this.value.slice(this.cursor);\n this.cursor = deleteFrom;\n }\n deleteWordForward() {\n if (this.cursor >= this.value.length)\n return;\n // Save lastAction before cursor movement (moveWordForwards resets it)\n const wasKill = this.lastAction === \"kill\";\n this.pushUndo();\n const oldCursor = this.cursor;\n this.moveWordForwards();\n const deleteTo = this.cursor;\n this.cursor = oldCursor;\n const deletedText = this.value.slice(this.cursor, deleteTo);\n this.killRing.push(deletedText, { prepend: false, accumulate: wasKill });\n this.lastAction = \"kill\";\n this.value = this.value.slice(0, this.cursor) + this.value.slice(deleteTo);\n }\n yank() {\n const text = this.killRing.peek();\n if (!text)\n return;\n this.pushUndo();\n this.value = this.value.slice(0, this.cursor) + text + this.value.slice(this.cursor);\n this.cursor += text.length;\n this.lastAction = \"yank\";\n }\n yankPop() {\n if (this.lastAction !== \"yank\" || this.killRing.length <= 1)\n return;\n this.pushUndo();\n // Delete the previously yanked text (still at end of ring before rotation)\n const prevText = this.killRing.peek() || \"\";\n this.value = this.value.slice(0, this.cursor - prevText.length) + this.value.slice(this.cursor);\n this.cursor -= prevText.length;\n // Rotate and insert new entry\n this.killRing.rotate();\n const text = this.killRing.peek() || \"\";\n this.value = this.value.slice(0, this.cursor) + text + this.value.slice(this.cursor);\n this.cursor += text.length;\n this.lastAction = \"yank\";\n }\n pushUndo() {\n this.undoStack.push({ value: this.value, cursor: this.cursor });\n }\n undo() {\n const snapshot = this.undoStack.pop();\n if (!snapshot)\n return;\n this.value = snapshot.value;\n this.cursor = snapshot.cursor;\n this.lastAction = null;\n }\n moveWordBackwards() {\n if (this.cursor === 0)\n return;\n this.lastAction = null;\n this.cursor = findWordBackward(this.value, this.cursor);\n }\n moveWordForwards() {\n if (this.cursor >= this.value.length)\n return;\n this.lastAction = null;\n this.cursor = findWordForward(this.value, this.cursor);\n }\n handlePaste(pastedText) {\n this.lastAction = null;\n this.pushUndo();\n // Clean the pasted text - remove newlines and carriage returns\n const cleanText = pastedText.replace(/\\r\\n/g, \"\").replace(/\\r/g, \"\").replace(/\\n/g, \"\").replace(/\\t/g, \" \");\n // Insert at cursor position\n this.value = this.value.slice(0, this.cursor) + cleanText + this.value.slice(this.cursor);\n this.cursor += cleanText.length;\n }\n invalidate() {\n // No cached state to invalidate currently\n }\n render(width) {\n // Calculate visible window\n const prompt = \"> \";\n const availableWidth = width - prompt.length;\n if (availableWidth <= 0) {\n return [prompt];\n }\n let visibleText = \"\";\n let cursorDisplay = this.cursor;\n const totalWidth = visibleWidth(this.value);\n if (totalWidth < availableWidth) {\n // Everything fits (leave room for cursor at end)\n visibleText = this.value;\n }\n else {\n // Need horizontal scrolling\n // Reserve one column for cursor if it's at the end\n const scrollWidth = this.cursor === this.value.length ? availableWidth - 1 : availableWidth;\n const cursorCol = visibleWidth(this.value.slice(0, this.cursor));\n if (scrollWidth > 0) {\n const halfWidth = Math.floor(scrollWidth / 2);\n let startCol = 0;\n if (cursorCol < halfWidth) {\n // Cursor near start\n startCol = 0;\n }\n else if (cursorCol > totalWidth - halfWidth) {\n // Cursor near end\n startCol = Math.max(0, totalWidth - scrollWidth);\n }\n else {\n // Cursor in middle\n startCol = Math.max(0, cursorCol - halfWidth);\n }\n visibleText = sliceByColumn(this.value, startCol, scrollWidth, true);\n const beforeCursor = sliceByColumn(this.value, startCol, Math.max(0, cursorCol - startCol), true);\n cursorDisplay = beforeCursor.length;\n }\n else {\n visibleText = \"\";\n cursorDisplay = 0;\n }\n }\n // Build line with fake cursor\n // Insert cursor character at cursor position\n const graphemes = [...segmenter.segment(visibleText.slice(cursorDisplay))];\n const cursorGrapheme = graphemes[0];\n const beforeCursor = visibleText.slice(0, cursorDisplay);\n const atCursor = cursorGrapheme?.segment ?? \" \"; // Character at cursor, or space if at end\n const afterCursor = visibleText.slice(cursorDisplay + atCursor.length);\n // Hardware cursor marker (zero-width, emitted before fake cursor for IME positioning)\n const marker = this.focused ? CURSOR_MARKER : \"\";\n // Use inverse video to show cursor\n const cursorChar = `\\x1b[7m${atCursor}\\x1b[27m`; // ESC[7m = reverse video, ESC[27m = normal\n const textWithCursor = beforeCursor + marker + cursorChar + afterCursor;\n // Calculate visual width\n const visualLength = visibleWidth(textWithCursor);\n const padding = \" \".repeat(Math.max(0, availableWidth - visualLength));\n const line = prompt + textWithCursor + padding;\n return [line];\n }\n}\n//# sourceMappingURL=input.js.map","/**\n * marked v18.0.5 - a markdown parser\n * Copyright (c) 2018-2026, MarkedJS. (MIT License)\n * Copyright (c) 2011-2018, Christopher Jeffrey. (MIT License)\n * https://github.com/markedjs/marked\n */\n\n/**\n * DO NOT EDIT THIS FILE\n * The code in this file is generated from files in ./src/\n */\n\nfunction M(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}var T=M();function N(l){T=l}var _={exec:()=>null};function E(l){let e=[];return t=>{let n=Math.max(0,Math.min(3,t-1)),s=e[n];return s||(s=l(n),e[n]=s),s}}function d(l,e=\"\"){let t=typeof l==\"string\"?l:l.source,n={replace:(s,r)=>{let i=typeof r==\"string\"?r:r.source;return i=i.replace(m.caret,\"$1\"),t=t.replace(s,i),n},getRegex:()=>new RegExp(t,e)};return n}var Te=((l=\"\")=>{try{return!!new RegExp(\"(?<=1)(?<!1)\"+l)}catch{return!1}})(),m={codeRemoveIndent:/^(?: {1,4}| {0,3}\\t)/gm,outputLinkReplace:/\\\\([\\[\\]])/g,indentCodeCompensation:/^(\\s+)(?:```)/,beginningSpace:/^\\s+/,endingHash:/#$/,startingSpaceChar:/^ /,endingSpaceChar:/ $/,nonSpaceChar:/[^ ]/,newLineCharGlobal:/\\n/g,tabCharGlobal:/\\t/g,multipleSpaceGlobal:/\\s+/g,blankLine:/^[ \\t]*$/,doubleBlankLine:/\\n[ \\t]*\\n[ \\t]*$/,blockquoteStart:/^ {0,3}>/,blockquoteSetextReplace:/\\n {0,3}((?:=+|-+) *)(?=\\n|$)/g,blockquoteSetextReplace2:/^ {0,3}>[ \\t]?/gm,listReplaceNesting:/^ {1,4}(?=( {4})*[^ ])/g,listIsTask:/^\\[[ xX]\\] +\\S/,listReplaceTask:/^\\[[ xX]\\] +/,listTaskCheckbox:/\\[[ xX]\\]/,anyLine:/\\n.*\\n/,hrefBrackets:/^<(.*)>$/,tableDelimiter:/[:|]/,tableAlignChars:/^\\||\\| *$/g,tableRowBlankLine:/\\n[ \\t]*$/,tableAlignRight:/^ *-+: *$/,tableAlignCenter:/^ *:-+: *$/,tableAlignLeft:/^ *:-+ *$/,startATag:/^<a /i,endATag:/^<\\/a>/i,startPreScriptTag:/^<(pre|code|kbd|script)(\\s|>)/i,endPreScriptTag:/^<\\/(pre|code|kbd|script)(\\s|>)/i,startAngleBracket:/^</,endAngleBracket:/>$/,pedanticHrefTitle:/^([^'\"]*[^\\s])\\s+(['\"])(.*)\\2/,unicodeAlphaNumeric:/[\\p{L}\\p{N}]/u,escapeTest:/[&<>\"']/,escapeReplace:/[&<>\"']/g,escapeTestNoEncode:/[<>\"']|&(?!(#\\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\\w+);)/,escapeReplaceNoEncode:/[<>\"']|&(?!(#\\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\\w+);)/g,caret:/(^|[^\\[])\\^/g,percentDecode:/%25/g,findPipe:/\\|/g,splitPipe:/ \\|/,slashPipe:/\\\\\\|/g,carriageReturn:/\\r\\n|\\r/g,spaceLine:/^ +$/gm,notSpaceStart:/^\\S*/,endingNewline:/\\n$/,listItemRegex:l=>new RegExp(`^( {0,3}${l})((?:[\t ][^\\\\n]*)?(?:\\\\n|$))`),nextBulletRegex:E(l=>new RegExp(`^ {0,${l}}(?:[*+-]|\\\\d{1,9}[.)])((?:[ \t][^\\\\n]*)?(?:\\\\n|$))`)),hrRegex:E(l=>new RegExp(`^ {0,${l}}((?:- *){3,}|(?:_ *){3,}|(?:\\\\* *){3,})(?:\\\\n+|$)`)),fencesBeginRegex:E(l=>new RegExp(`^ {0,${l}}(?:\\`\\`\\`|~~~)`)),headingBeginRegex:E(l=>new RegExp(`^ {0,${l}}#`)),htmlBeginRegex:E(l=>new RegExp(`^ {0,${l}}<(?:[a-z].*>|!--)`,\"i\")),blockquoteBeginRegex:E(l=>new RegExp(`^ {0,${l}}>`))},Oe=/^(?:[ \\t]*(?:\\n|$))+/,we=/^((?: {4}| {0,3}\\t)[^\\n]+(?:\\n(?:[ \\t]*(?:\\n|$))*)?)+/,ye=/^ {0,3}(`{3,}(?=[^`\\n]*(?:\\n|$))|~{3,})([^\\n]*)(?:\\n|$)(?:|([\\s\\S]*?)(?:\\n|$))(?: {0,3}\\1[~`]* *(?=\\n|$)|$)/,B=/^ {0,3}((?:-[\\t ]*){3,}|(?:_[ \\t]*){3,}|(?:\\*[ \\t]*){3,})(?:\\n+|$)/,Pe=/^ {0,3}(#{1,6})(?=\\s|$)(.*)(?:\\n+|$)/,j=/ {0,3}(?:[*+-]|\\d{1,9}[.)])/,oe=/^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\\n(?!\\s*?\\n|bull |blockCode|fences|blockquote|heading|html|table))+?)\\n {0,3}(=+|-+) *(?:\\n+|$)/,ae=d(oe).replace(/bull/g,j).replace(/blockCode/g,/(?: {4}| {0,3}\\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\\n>]+>\\n/).replace(/\\|table/g,\"\").getRegex(),Se=d(oe).replace(/bull/g,j).replace(/blockCode/g,/(?: {4}| {0,3}\\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\\n>]+>\\n/).replace(/table/g,/ {0,3}\\|?(?:[:\\- ]*\\|)+[\\:\\- ]*\\n/).getRegex(),F=/^([^\\n]+(?:\\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\\n)[^\\n]+)*)/,$e=/^[^\\n]+/,U=/(?!\\s*\\])(?:\\\\[\\s\\S]|[^\\[\\]\\\\])+/,Le=d(/^ {0,3}\\[(label)\\]: *(?:\\n[ \\t]*)?([^<\\s][^\\s]*|<.*?>)(?:(?: +(?:\\n[ \\t]*)?| *\\n[ \\t]*)(title))? *(?:\\n+|$)/).replace(\"label\",U).replace(\"title\",/(?:\"(?:\\\\\"?|[^\"\\\\])*\"|'[^'\\n]*(?:\\n[^'\\n]+)*\\n?'|\\([^()]*\\))/).getRegex(),_e=d(/^(bull)([ \\t][^\\n]*?)?(?:\\n|$)/).replace(/bull/g,j).getRegex(),H=\"address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul\",K=/<!--(?:-?>|[\\s\\S]*?(?:-->|$))/,ze=d(\"^ {0,3}(?:<(script|pre|style|textarea)[\\\\s>][\\\\s\\\\S]*?(?:</\\\\1>[^\\\\n]*\\\\n+|$)|comment[^\\\\n]*(\\\\n+|$)|<\\\\?[\\\\s\\\\S]*?(?:\\\\?>\\\\n*|$)|<![A-Z][\\\\s\\\\S]*?(?:>\\\\n*|$)|<!\\\\[CDATA\\\\[[\\\\s\\\\S]*?(?:\\\\]\\\\]>\\\\n*|$)|</?(tag)(?: +|\\\\n|/?>)[\\\\s\\\\S]*?(?:(?:\\\\n[ \t]*)+\\\\n|$)|<(?!script|pre|style|textarea)([a-z][\\\\w-]*)(?:attribute)*? */?>(?=[ \\\\t]*(?:\\\\n|$))[\\\\s\\\\S]*?(?:(?:\\\\n[ \t]*)+\\\\n|$)|</(?!script|pre|style|textarea)[a-z][\\\\w-]*\\\\s*>(?=[ \\\\t]*(?:\\\\n|$))[\\\\s\\\\S]*?(?:(?:\\\\n[ \t]*)+\\\\n|$))\",\"i\").replace(\"comment\",K).replace(\"tag\",H).replace(\"attribute\",/ +[a-zA-Z:_][\\w.:-]*(?: *= *\"[^\"\\n]*\"| *= *'[^'\\n]*'| *= *[^\\s\"'=<>`]+)?/).getRegex(),le=d(F).replace(\"hr\",B).replace(\"heading\",\" {0,3}#{1,6}(?:\\\\s|$)\").replace(\"|lheading\",\"\").replace(\"|table\",\"\").replace(\"blockquote\",\" {0,3}>\").replace(\"fences\",\" {0,3}(?:`{3,}(?=[^`\\\\n]*\\\\n)|~{3,})[^\\\\n]*\\\\n\").replace(\"list\",\" {0,3}(?:[*+-]|1[.)])[ \\\\t]+[^ \\\\t\\\\n]\").replace(\"html\",\"</?(?:tag)(?: +|\\\\n|/?>)|<(?:script|pre|style|textarea|!--)\").replace(\"tag\",H).getRegex(),Me=d(/^( {0,3}> ?(paragraph|[^\\n]*)(?:\\n|$))+/).replace(\"paragraph\",le).getRegex(),W={blockquote:Me,code:we,def:Le,fences:ye,heading:Pe,hr:B,html:ze,lheading:ae,list:_e,newline:Oe,paragraph:le,table:_,text:$e},se=d(\"^ *([^\\\\n ].*)\\\\n {0,3}((?:\\\\| *)?:?-+:? *(?:\\\\| *:?-+:? *)*(?:\\\\| *)?)(?:\\\\n((?:(?! *\\\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\\\n|$))*)\\\\n*|$)\").replace(\"hr\",B).replace(\"heading\",\" {0,3}#{1,6}(?:\\\\s|$)\").replace(\"blockquote\",\" {0,3}>\").replace(\"code\",\"(?: {4}| {0,3}\t)[^\\\\n]\").replace(\"fences\",\" {0,3}(?:`{3,}(?=[^`\\\\n]*\\\\n)|~{3,})[^\\\\n]*\\\\n\").replace(\"list\",\" {0,3}(?:[*+-]|1[.)])[ \\\\t]\").replace(\"html\",\"</?(?:tag)(?: +|\\\\n|/?>)|<(?:script|pre|style|textarea|!--)\").replace(\"tag\",H).getRegex(),Ee={...W,lheading:Se,table:se,paragraph:d(F).replace(\"hr\",B).replace(\"heading\",\" {0,3}#{1,6}(?:\\\\s|$)\").replace(\"|lheading\",\"\").replace(\"table\",se).replace(\"blockquote\",\" {0,3}>\").replace(\"fences\",\" {0,3}(?:`{3,}(?=[^`\\\\n]*\\\\n)|~{3,})[^\\\\n]*\\\\n\").replace(\"list\",\" {0,3}(?:[*+-]|1[.)])[ \\\\t]+[^ \\\\t\\\\n]\").replace(\"html\",\"</?(?:tag)(?: +|\\\\n|/?>)|<(?:script|pre|style|textarea|!--)\").replace(\"tag\",H).getRegex()},Ie={...W,html:d(`^ *(?:comment *(?:\\\\n|\\\\s*$)|<(tag)[\\\\s\\\\S]+?</\\\\1> *(?:\\\\n{2,}|\\\\s*$)|<tag(?:\"[^\"]*\"|'[^']*'|\\\\s[^'\"/>\\\\s]*)*?/?> *(?:\\\\n{2,}|\\\\s*$))`).replace(\"comment\",K).replace(/tag/g,\"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\\\b)\\\\w+(?!:|[^\\\\w\\\\s@]*@)\\\\b\").getRegex(),def:/^ *\\[([^\\]]+)\\]: *<?([^\\s>]+)>?(?: +([\"(][^\\n]+[\")]))? *(?:\\n+|$)/,heading:/^(#{1,6})(.*)(?:\\n+|$)/,fences:_,lheading:/^(.+?)\\n {0,3}(=+|-+) *(?:\\n+|$)/,paragraph:d(F).replace(\"hr\",B).replace(\"heading\",` *#{1,6} *[^\n]`).replace(\"lheading\",ae).replace(\"|table\",\"\").replace(\"blockquote\",\" {0,3}>\").replace(\"|fences\",\"\").replace(\"|list\",\"\").replace(\"|html\",\"\").replace(\"|tag\",\"\").getRegex()},Ae=/^\\\\([!\"#$%&'()*+,\\-./:;<=>?@\\[\\]\\\\^_`{|}~])/,Ce=/^(`+)([^`]|[^`][\\s\\S]*?[^`])\\1(?!`)/,ue=/^( {2,}|\\\\)\\n(?!\\s*$)/,Be=/^(`+|[^`])(?:(?= {2,}\\n)|[\\s\\S]*?(?:(?=[\\\\<!\\[`*_]|\\b_|$)|[^ ](?= {2,}\\n)))/,I=/[\\p{P}\\p{S}]/u,Z=/[\\s\\p{P}\\p{S}]/u,X=/[^\\s\\p{P}\\p{S}]/u,De=d(/^((?![*_])punctSpace)/,\"u\").replace(/punctSpace/g,Z).getRegex(),pe=/(?!~)[\\p{P}\\p{S}]/u,qe=/(?!~)[\\s\\p{P}\\p{S}]/u,ve=/(?:[^\\s\\p{P}\\p{S}]|~)/u,He=d(/link|precode-code|html/,\"g\").replace(\"link\",/\\[(?:[^\\[\\]`]|(?<a>`+)[^`]+\\k<a>(?!`))*?\\]\\((?:\\\\[\\s\\S]|[^\\\\\\(\\)]|\\((?:\\\\[\\s\\S]|[^\\\\\\(\\)])*\\))*\\)/).replace(\"precode-\",Te?\"(?<!`)()\":\"(^^|[^`])\").replace(\"code\",/(?<b>`+)[^`]+\\k<b>(?!`)/).replace(\"html\",/<(?! )[^<>]*?>/).getRegex(),ce=/^(?:\\*+(?:((?!\\*)punct)|([^\\s*]))?)|^_+(?:((?!_)punct)|([^\\s_]))?/,Ze=d(ce,\"u\").replace(/punct/g,I).getRegex(),Ge=d(ce,\"u\").replace(/punct/g,pe).getRegex(),he=\"^[^_*]*?__[^_*]*?\\\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\\\*)punct(\\\\*+)(?=[\\\\s]|$)|notPunctSpace(\\\\*+)(?!\\\\*)(?=punctSpace|$)|(?!\\\\*)punctSpace(\\\\*+)(?=notPunctSpace)|[\\\\s](\\\\*+)(?!\\\\*)(?=punct)|(?!\\\\*)punct(\\\\*+)(?!\\\\*)(?=punct)|notPunctSpace(\\\\*+)(?=notPunctSpace)\",Ne=d(he,\"gu\").replace(/notPunctSpace/g,X).replace(/punctSpace/g,Z).replace(/punct/g,I).getRegex(),Qe=d(he,\"gu\").replace(/notPunctSpace/g,ve).replace(/punctSpace/g,qe).replace(/punct/g,pe).getRegex(),je=d(\"^[^_*]*?\\\\*\\\\*[^_*]*?_[^_*]*?(?=\\\\*\\\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)\",\"gu\").replace(/notPunctSpace/g,X).replace(/punctSpace/g,Z).replace(/punct/g,I).getRegex(),Fe=d(/^~~?(?:((?!~)punct)|[^\\s~])/,\"u\").replace(/punct/g,I).getRegex(),Ue=\"^[^~]+(?=[^~])|(?!~)punct(~~?)(?=[\\\\s]|$)|notPunctSpace(~~?)(?!~)(?=punctSpace|$)|(?!~)punctSpace(~~?)(?=notPunctSpace)|[\\\\s](~~?)(?!~)(?=punct)|(?!~)punct(~~?)(?!~)(?=punct)|notPunctSpace(~~?)(?=notPunctSpace)\",Ke=d(Ue,\"gu\").replace(/notPunctSpace/g,X).replace(/punctSpace/g,Z).replace(/punct/g,I).getRegex(),We=d(/\\\\(punct)/,\"gu\").replace(/punct/g,I).getRegex(),Xe=d(/^<(scheme:[^\\s\\x00-\\x1f<>]*|email)>/).replace(\"scheme\",/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace(\"email\",/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(),Je=d(K).replace(\"(?:-->|$)\",\"-->\").getRegex(),Ve=d(\"^comment|^</[a-zA-Z][\\\\w:-]*\\\\s*>|^<[a-zA-Z][\\\\w-]*(?:attribute)*?\\\\s*/?>|^<\\\\?[\\\\s\\\\S]*?\\\\?>|^<![a-zA-Z]+\\\\s[\\\\s\\\\S]*?>|^<!\\\\[CDATA\\\\[[\\\\s\\\\S]*?\\\\]\\\\]>\").replace(\"comment\",Je).replace(\"attribute\",/\\s+[a-zA-Z:_][\\w.:-]*(?:\\s*=\\s*\"[^\"]*\"|\\s*=\\s*'[^']*'|\\s*=\\s*[^\\s\"'=<>`]+)?/).getRegex(),v=/(?:\\[(?:\\\\[\\s\\S]|[^\\[\\]\\\\])*\\]|\\\\[\\s\\S]|`+(?!`)[^`]*?`+(?!`)|``+(?=\\])|[^\\[\\]\\\\`])*?/,Ye=d(/^!?\\[(label)\\]\\(\\s*(href)(?:(?:[ \\t]+(?:\\n[ \\t]*)?|\\n[ \\t]*)(title))?\\s*\\)/).replace(\"label\",v).replace(\"href\",/<(?:\\\\.|[^\\n<>\\\\])+>|[^ \\t\\n\\x00-\\x1f]*/).replace(\"title\",/\"(?:\\\\\"?|[^\"\\\\])*\"|'(?:\\\\'?|[^'\\\\])*'|\\((?:\\\\\\)?|[^)\\\\])*\\)/).getRegex(),ke=d(/^!?\\[(label)\\]\\[(ref)\\]/).replace(\"label\",v).replace(\"ref\",U).getRegex(),de=d(/^!?\\[(ref)\\](?:\\[\\])?/).replace(\"ref\",U).getRegex(),et=d(\"reflink|nolink(?!\\\\()\",\"g\").replace(\"reflink\",ke).replace(\"nolink\",de).getRegex(),ie=/[hH][tT][tT][pP][sS]?|[fF][tT][pP]/,J={_backpedal:_,anyPunctuation:We,autolink:Xe,blockSkip:He,br:ue,code:Ce,del:_,delLDelim:_,delRDelim:_,emStrongLDelim:Ze,emStrongRDelimAst:Ne,emStrongRDelimUnd:je,escape:Ae,link:Ye,nolink:de,punctuation:De,reflink:ke,reflinkSearch:et,tag:Ve,text:Be,url:_},tt={...J,link:d(/^!?\\[(label)\\]\\((.*?)\\)/).replace(\"label\",v).getRegex(),reflink:d(/^!?\\[(label)\\]\\s*\\[([^\\]]*)\\]/).replace(\"label\",v).getRegex()},Q={...J,emStrongRDelimAst:Qe,emStrongLDelim:Ge,delLDelim:Fe,delRDelim:Ke,url:d(/^((?:protocol):\\/\\/|www\\.)(?:[a-zA-Z0-9\\-]+\\.?)+[^\\s<]*|^email/).replace(\"protocol\",ie).replace(\"email\",/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(),_backpedal:/(?:[^?!.,:;*_'\"~()&]+|\\([^)]*\\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'\"~)]+(?!$))+/,del:/^(~~?)(?=[^\\s~])((?:\\\\[\\s\\S]|[^\\\\])*?(?:\\\\[\\s\\S]|[^\\s~\\\\]))\\1(?=[^~]|$)/,text:d(/^([`~]+|[^`~])(?:(?= {2,}\\n)|(?=[a-zA-Z0-9.!#$%&'*+\\/=?_`{\\|}~-]+@)|[\\s\\S]*?(?:(?=[\\\\<!\\[`*~_]|\\b_|protocol:\\/\\/|www\\.|$)|[^ ](?= {2,}\\n)|[^a-zA-Z0-9.!#$%&'*+\\/=?_`{\\|}~-](?=[a-zA-Z0-9.!#$%&'*+\\/=?_`{\\|}~-]+@)))/).replace(\"protocol\",ie).getRegex()},nt={...Q,br:d(ue).replace(\"{2,}\",\"*\").getRegex(),text:d(Q.text).replace(\"\\\\b_\",\"\\\\b_| {2,}\\\\n\").replace(/\\{2,\\}/g,\"*\").getRegex()},D={normal:W,gfm:Ee,pedantic:Ie},A={normal:J,gfm:Q,breaks:nt,pedantic:tt};var rt={\"&\":\"&\",\"<\":\"<\",\">\":\">\",'\"':\""\",\"'\":\"'\"},ge=l=>rt[l];function O(l,e){if(e){if(m.escapeTest.test(l))return l.replace(m.escapeReplace,ge)}else if(m.escapeTestNoEncode.test(l))return l.replace(m.escapeReplaceNoEncode,ge);return l}function V(l){try{l=encodeURI(l).replace(m.percentDecode,\"%\")}catch{return null}return l}function Y(l,e){let t=l.replace(m.findPipe,(r,i,o)=>{let u=!1,a=i;for(;--a>=0&&o[a]===\"\\\\\";)u=!u;return u?\"|\":\" |\"}),n=t.split(m.splitPipe),s=0;if(n[0].trim()||n.shift(),n.length>0&&!n.at(-1)?.trim()&&n.pop(),e)if(n.length>e)n.splice(e);else for(;n.length<e;)n.push(\"\");for(;s<n.length;s++)n[s]=n[s].trim().replace(m.slashPipe,\"|\");return n}function $(l,e,t){let n=l.length;if(n===0)return\"\";let s=0;for(;s<n;){let r=l.charAt(n-s-1);if(r===e&&!t)s++;else if(r!==e&&t)s++;else break}return l.slice(0,n-s)}function ee(l){let e=l.split(`\n`),t=e.length-1;for(;t>=0&&m.blankLine.test(e[t]);)t--;return e.length-t<=2?l:e.slice(0,t+1).join(`\n`)}function fe(l,e){if(l.indexOf(e[1])===-1)return-1;let t=0;for(let n=0;n<l.length;n++)if(l[n]===\"\\\\\")n++;else if(l[n]===e[0])t++;else if(l[n]===e[1]&&(t--,t<0))return n;return t>0?-2:-1}function me(l,e=0){let t=e,n=\"\";for(let s of l)if(s===\"\t\"){let r=4-t%4;n+=\" \".repeat(r),t+=r}else n+=s,t++;return n}function xe(l,e,t,n,s){let r=e.href,i=e.title||null,o=l[1].replace(s.other.outputLinkReplace,\"$1\");n.state.inLink=!0;let u={type:l[0].charAt(0)===\"!\"?\"image\":\"link\",raw:t,href:r,title:i,text:o,tokens:n.inlineTokens(o)};return n.state.inLink=!1,u}function st(l,e,t){let n=l.match(t.other.indentCodeCompensation);if(n===null)return e;let s=n[1];return e.split(`\n`).map(r=>{let i=r.match(t.other.beginningSpace);if(i===null)return r;let[o]=i;return o.length>=s.length?r.slice(s.length):r}).join(`\n`)}var w=class{options;rules;lexer;constructor(e){this.options=e||T}space(e){let t=this.rules.block.newline.exec(e);if(t&&t[0].length>0)return{type:\"space\",raw:t[0]}}code(e){let t=this.rules.block.code.exec(e);if(t){let n=this.options.pedantic?t[0]:ee(t[0]),s=n.replace(this.rules.other.codeRemoveIndent,\"\");return{type:\"code\",raw:n,codeBlockStyle:\"indented\",text:s}}}fences(e){let t=this.rules.block.fences.exec(e);if(t){let n=t[0],s=st(n,t[3]||\"\",this.rules);return{type:\"code\",raw:n,lang:t[2]?t[2].trim().replace(this.rules.inline.anyPunctuation,\"$1\"):t[2],text:s}}}heading(e){let t=this.rules.block.heading.exec(e);if(t){let n=t[2].trim();if(this.rules.other.endingHash.test(n)){let s=$(n,\"#\");(this.options.pedantic||!s||this.rules.other.endingSpaceChar.test(s))&&(n=s.trim())}return{type:\"heading\",raw:$(t[0],`\n`),depth:t[1].length,text:n,tokens:this.lexer.inline(n)}}}hr(e){let t=this.rules.block.hr.exec(e);if(t)return{type:\"hr\",raw:$(t[0],`\n`)}}blockquote(e){let t=this.rules.block.blockquote.exec(e);if(t){let n=$(t[0],`\n`).split(`\n`),s=\"\",r=\"\",i=[];for(;n.length>0;){let o=!1,u=[],a;for(a=0;a<n.length;a++)if(this.rules.other.blockquoteStart.test(n[a]))u.push(n[a]),o=!0;else if(!o)u.push(n[a]);else break;n=n.slice(a);let c=u.join(`\n`),p=c.replace(this.rules.other.blockquoteSetextReplace,`\n $1`).replace(this.rules.other.blockquoteSetextReplace2,\"\");s=s?`${s}\n${c}`:c,r=r?`${r}\n${p}`:p;let k=this.lexer.state.top;if(this.lexer.state.top=!0,this.lexer.blockTokens(p,i,!0),this.lexer.state.top=k,n.length===0)break;let h=i.at(-1);if(h?.type===\"code\")break;if(h?.type===\"blockquote\"){let R=h,f=R.raw+`\n`+n.join(`\n`),S=this.blockquote(f);i[i.length-1]=S,s=s.substring(0,s.length-R.raw.length)+S.raw,r=r.substring(0,r.length-R.text.length)+S.text;break}else if(h?.type===\"list\"){let R=h,f=R.raw+`\n`+n.join(`\n`),S=this.list(f);i[i.length-1]=S,s=s.substring(0,s.length-h.raw.length)+S.raw,r=r.substring(0,r.length-R.raw.length)+S.raw,n=f.substring(i.at(-1).raw.length).split(`\n`);continue}}return{type:\"blockquote\",raw:s,tokens:i,text:r}}}list(e){let t=this.rules.block.list.exec(e);if(t){let n=t[1].trim(),s=n.length>1,r={type:\"list\",raw:\"\",ordered:s,start:s?+n.slice(0,-1):\"\",loose:!1,items:[]};n=s?`\\\\d{1,9}\\\\${n.slice(-1)}`:`\\\\${n}`,this.options.pedantic&&(n=s?n:\"[*+-]\");let i=this.rules.other.listItemRegex(n),o=!1;for(;e;){let a=!1,c=\"\",p=\"\";if(!(t=i.exec(e))||this.rules.block.hr.test(e))break;c=t[0],e=e.substring(c.length);let k=me(t[2].split(`\n`,1)[0],t[1].length),h=e.split(`\n`,1)[0],R=!k.trim(),f=0;if(this.options.pedantic?(f=2,p=k.trimStart()):R?f=t[1].length+1:(f=k.search(this.rules.other.nonSpaceChar),f=f>4?1:f,p=k.slice(f),f+=t[1].length),R&&this.rules.other.blankLine.test(h)&&(c+=h+`\n`,e=e.substring(h.length+1),a=!0),!a){let S=this.rules.other.nextBulletRegex(f),te=this.rules.other.hrRegex(f),ne=this.rules.other.fencesBeginRegex(f),re=this.rules.other.headingBeginRegex(f),be=this.rules.other.htmlBeginRegex(f),Re=this.rules.other.blockquoteBeginRegex(f);for(;e;){let G=e.split(`\n`,1)[0],C;if(h=G,this.options.pedantic?(h=h.replace(this.rules.other.listReplaceNesting,\" \"),C=h):C=h.replace(this.rules.other.tabCharGlobal,\" \"),ne.test(h)||re.test(h)||be.test(h)||Re.test(h)||S.test(h)||te.test(h))break;if(C.search(this.rules.other.nonSpaceChar)>=f||!h.trim())p+=`\n`+C.slice(f);else{if(R||k.replace(this.rules.other.tabCharGlobal,\" \").search(this.rules.other.nonSpaceChar)>=4||ne.test(k)||re.test(k)||te.test(k))break;p+=`\n`+h}R=!h.trim(),c+=G+`\n`,e=e.substring(G.length+1),k=C.slice(f)}}r.loose||(o?r.loose=!0:this.rules.other.doubleBlankLine.test(c)&&(o=!0)),r.items.push({type:\"list_item\",raw:c,task:!!this.options.gfm&&this.rules.other.listIsTask.test(p),loose:!1,text:p,tokens:[]}),r.raw+=c}let u=r.items.at(-1);if(u)u.raw=u.raw.trimEnd(),u.text=u.text.trimEnd();else return;r.raw=r.raw.trimEnd();for(let a of r.items){this.lexer.state.top=!1,a.tokens=this.lexer.blockTokens(a.text,[]);let c=a.tokens[0];if(a.task&&(c?.type===\"text\"||c?.type===\"paragraph\")){a.text=a.text.replace(this.rules.other.listReplaceTask,\"\"),c.raw=c.raw.replace(this.rules.other.listReplaceTask,\"\"),c.text=c.text.replace(this.rules.other.listReplaceTask,\"\");for(let k=this.lexer.inlineQueue.length-1;k>=0;k--)if(this.rules.other.listIsTask.test(this.lexer.inlineQueue[k].src)){this.lexer.inlineQueue[k].src=this.lexer.inlineQueue[k].src.replace(this.rules.other.listReplaceTask,\"\");break}let p=this.rules.other.listTaskCheckbox.exec(a.raw);if(p){let k={type:\"checkbox\",raw:p[0]+\" \",checked:p[0]!==\"[ ]\"};a.checked=k.checked,r.loose?a.tokens[0]&&[\"paragraph\",\"text\"].includes(a.tokens[0].type)&&\"tokens\"in a.tokens[0]&&a.tokens[0].tokens?(a.tokens[0].raw=k.raw+a.tokens[0].raw,a.tokens[0].text=k.raw+a.tokens[0].text,a.tokens[0].tokens.unshift(k)):a.tokens.unshift({type:\"paragraph\",raw:k.raw,text:k.raw,tokens:[k]}):a.tokens.unshift(k)}}else a.task&&(a.task=!1);if(!r.loose){let p=a.tokens.filter(h=>h.type===\"space\"),k=p.length>0&&p.some(h=>this.rules.other.anyLine.test(h.raw));r.loose=k}}if(r.loose)for(let a of r.items){a.loose=!0;for(let c of a.tokens)c.type===\"text\"&&(c.type=\"paragraph\")}return r}}html(e){let t=this.rules.block.html.exec(e);if(t){let n=ee(t[0]);return{type:\"html\",block:!0,raw:n,pre:t[1]===\"pre\"||t[1]===\"script\"||t[1]===\"style\",text:n}}}def(e){let t=this.rules.block.def.exec(e);if(t){let n=t[1].toLowerCase().replace(this.rules.other.multipleSpaceGlobal,\" \"),s=t[2]?t[2].replace(this.rules.other.hrefBrackets,\"$1\").replace(this.rules.inline.anyPunctuation,\"$1\"):\"\",r=t[3]?t[3].substring(1,t[3].length-1).replace(this.rules.inline.anyPunctuation,\"$1\"):t[3];return{type:\"def\",tag:n,raw:$(t[0],`\n`),href:s,title:r}}}table(e){let t=this.rules.block.table.exec(e);if(!t||!this.rules.other.tableDelimiter.test(t[2]))return;let n=Y(t[1]),s=t[2].replace(this.rules.other.tableAlignChars,\"\").split(\"|\"),r=t[3]?.trim()?t[3].replace(this.rules.other.tableRowBlankLine,\"\").split(`\n`):[],i={type:\"table\",raw:$(t[0],`\n`),header:[],align:[],rows:[]};if(n.length===s.length){for(let o of s)this.rules.other.tableAlignRight.test(o)?i.align.push(\"right\"):this.rules.other.tableAlignCenter.test(o)?i.align.push(\"center\"):this.rules.other.tableAlignLeft.test(o)?i.align.push(\"left\"):i.align.push(null);for(let o=0;o<n.length;o++)i.header.push({text:n[o],tokens:this.lexer.inline(n[o]),header:!0,align:i.align[o]});for(let o of r)i.rows.push(Y(o,i.header.length).map((u,a)=>({text:u,tokens:this.lexer.inline(u),header:!1,align:i.align[a]})));return i}}lheading(e){let t=this.rules.block.lheading.exec(e);if(t){let n=t[1].trim();return{type:\"heading\",raw:$(t[0],`\n`),depth:t[2].charAt(0)===\"=\"?1:2,text:n,tokens:this.lexer.inline(n)}}}paragraph(e){let t=this.rules.block.paragraph.exec(e);if(t){let n=t[1].charAt(t[1].length-1)===`\n`?t[1].slice(0,-1):t[1];return{type:\"paragraph\",raw:t[0],text:n,tokens:this.lexer.inline(n)}}}text(e){let t=this.rules.block.text.exec(e);if(t)return{type:\"text\",raw:t[0],text:t[0],tokens:this.lexer.inline(t[0])}}escape(e){let t=this.rules.inline.escape.exec(e);if(t)return{type:\"escape\",raw:t[0],text:t[1]}}tag(e){let t=this.rules.inline.tag.exec(e);if(t)return!this.lexer.state.inLink&&this.rules.other.startATag.test(t[0])?this.lexer.state.inLink=!0:this.lexer.state.inLink&&this.rules.other.endATag.test(t[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&this.rules.other.startPreScriptTag.test(t[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&this.rules.other.endPreScriptTag.test(t[0])&&(this.lexer.state.inRawBlock=!1),{type:\"html\",raw:t[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:!1,text:t[0]}}link(e){let t=this.rules.inline.link.exec(e);if(t){let n=t[2].trim();if(!this.options.pedantic&&this.rules.other.startAngleBracket.test(n)){if(!this.rules.other.endAngleBracket.test(n))return;let i=$(n.slice(0,-1),\"\\\\\");if((n.length-i.length)%2===0)return}else{let i=fe(t[2],\"()\");if(i===-2)return;if(i>-1){let u=(t[0].indexOf(\"!\")===0?5:4)+t[1].length+i;t[2]=t[2].substring(0,i),t[0]=t[0].substring(0,u).trim(),t[3]=\"\"}}let s=t[2],r=\"\";if(this.options.pedantic){let i=this.rules.other.pedanticHrefTitle.exec(s);i&&(s=i[1],r=i[3])}else r=t[3]?t[3].slice(1,-1):\"\";return s=s.trim(),this.rules.other.startAngleBracket.test(s)&&(this.options.pedantic&&!this.rules.other.endAngleBracket.test(n)?s=s.slice(1):s=s.slice(1,-1)),xe(t,{href:s&&s.replace(this.rules.inline.anyPunctuation,\"$1\"),title:r&&r.replace(this.rules.inline.anyPunctuation,\"$1\")},t[0],this.lexer,this.rules)}}reflink(e,t){let n;if((n=this.rules.inline.reflink.exec(e))||(n=this.rules.inline.nolink.exec(e))){let s=(n[2]||n[1]).replace(this.rules.other.multipleSpaceGlobal,\" \"),r=t[s.toLowerCase()];if(!r){let i=n[0].charAt(0);return{type:\"text\",raw:i,text:i}}return xe(n,r,n[0],this.lexer,this.rules)}}emStrong(e,t,n=\"\"){let s=this.rules.inline.emStrongLDelim.exec(e);if(!s||!s[1]&&!s[2]&&!s[3]&&!s[4]||s[4]&&n.match(this.rules.other.unicodeAlphaNumeric))return;if(!(s[1]||s[3]||\"\")||!n||this.rules.inline.punctuation.exec(n)){let i=[...s[0]].length-1,o,u,a=i,c=0,p=s[0][0]===\"*\"?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(p.lastIndex=0,t=t.slice(-1*e.length+i);(s=p.exec(t))!==null;){if(o=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!o)continue;if(u=[...o].length,s[3]||s[4]){a+=u;continue}else if((s[5]||s[6])&&i%3&&!((i+u)%3)){c+=u;continue}if(a-=u,a>0)continue;u=Math.min(u,u+a+c);let k=[...s[0]][0].length,h=e.slice(0,i+s.index+k+u);if(Math.min(i,u)%2){let f=h.slice(1,-1);return{type:\"em\",raw:h,text:f,tokens:this.lexer.inlineTokens(f)}}let R=h.slice(2,-2);return{type:\"strong\",raw:h,text:R,tokens:this.lexer.inlineTokens(R)}}}}codespan(e){let t=this.rules.inline.code.exec(e);if(t){let n=t[2].replace(this.rules.other.newLineCharGlobal,\" \"),s=this.rules.other.nonSpaceChar.test(n),r=this.rules.other.startingSpaceChar.test(n)&&this.rules.other.endingSpaceChar.test(n);return s&&r&&(n=n.substring(1,n.length-1)),{type:\"codespan\",raw:t[0],text:n}}}br(e){let t=this.rules.inline.br.exec(e);if(t)return{type:\"br\",raw:t[0]}}del(e,t,n=\"\"){let s=this.rules.inline.delLDelim.exec(e);if(!s)return;if(!(s[1]||\"\")||!n||this.rules.inline.punctuation.exec(n)){let i=[...s[0]].length-1,o,u,a=i,c=this.rules.inline.delRDelim;for(c.lastIndex=0,t=t.slice(-1*e.length+i);(s=c.exec(t))!==null;){if(o=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!o||(u=[...o].length,u!==i))continue;if(s[3]||s[4]){a+=u;continue}if(a-=u,a>0)continue;u=Math.min(u,u+a);let p=[...s[0]][0].length,k=e.slice(0,i+s.index+p+u),h=k.slice(i,-i);return{type:\"del\",raw:k,text:h,tokens:this.lexer.inlineTokens(h)}}}}autolink(e){let t=this.rules.inline.autolink.exec(e);if(t){let n,s;return t[2]===\"@\"?(n=t[1],s=\"mailto:\"+n):(n=t[1],s=n),{type:\"link\",raw:t[0],text:n,href:s,tokens:[{type:\"text\",raw:n,text:n}]}}}url(e){let t;if(t=this.rules.inline.url.exec(e)){let n,s;if(t[2]===\"@\")n=t[0],s=\"mailto:\"+n;else{let r;do r=t[0],t[0]=this.rules.inline._backpedal.exec(t[0])?.[0]??\"\";while(r!==t[0]);n=t[0],t[1]===\"www.\"?s=\"http://\"+t[0]:s=t[0]}return{type:\"link\",raw:t[0],text:n,href:s,tokens:[{type:\"text\",raw:n,text:n}]}}}inlineText(e){let t=this.rules.inline.text.exec(e);if(t){let n=this.lexer.state.inRawBlock;return{type:\"text\",raw:t[0],text:t[0],escaped:n}}}};var x=class l{tokens;options;state;inlineQueue;tokenizer;constructor(e){this.tokens=[],this.tokens.links=Object.create(null),this.options=e||T,this.options.tokenizer=this.options.tokenizer||new w,this.tokenizer=this.options.tokenizer,this.tokenizer.options=this.options,this.tokenizer.lexer=this,this.inlineQueue=[],this.state={inLink:!1,inRawBlock:!1,top:!0};let t={other:m,block:D.normal,inline:A.normal};this.options.pedantic?(t.block=D.pedantic,t.inline=A.pedantic):this.options.gfm&&(t.block=D.gfm,this.options.breaks?t.inline=A.breaks:t.inline=A.gfm),this.tokenizer.rules=t}static get rules(){return{block:D,inline:A}}static lex(e,t){return new l(t).lex(e)}static lexInline(e,t){return new l(t).inlineTokens(e)}lex(e){e=e.replace(m.carriageReturn,`\n`),this.blockTokens(e,this.tokens);for(let t=0;t<this.inlineQueue.length;t++){let n=this.inlineQueue[t];this.inlineTokens(n.src,n.tokens)}return this.inlineQueue=[],this.tokens}blockTokens(e,t=[],n=!1){this.tokenizer.lexer=this,this.options.pedantic&&(e=e.replace(m.tabCharGlobal,\" \").replace(m.spaceLine,\"\"));let s=1/0;for(;e;){if(e.length<s)s=e.length;else{this.infiniteLoopError(e.charCodeAt(0));break}let r;if(this.options.extensions?.block?.some(o=>(r=o.call({lexer:this},e,t))?(e=e.substring(r.raw.length),t.push(r),!0):!1))continue;if(r=this.tokenizer.space(e)){e=e.substring(r.raw.length);let o=t.at(-1);r.raw.length===1&&o!==void 0?o.raw+=`\n`:t.push(r);continue}if(r=this.tokenizer.code(e)){e=e.substring(r.raw.length);let o=t.at(-1);o?.type===\"paragraph\"||o?.type===\"text\"?(o.raw+=(o.raw.endsWith(`\n`)?\"\":`\n`)+r.raw,o.text+=`\n`+r.text,this.inlineQueue.at(-1).src=o.text):t.push(r);continue}if(r=this.tokenizer.fences(e)){e=e.substring(r.raw.length),t.push(r);continue}if(r=this.tokenizer.heading(e)){e=e.substring(r.raw.length),t.push(r);continue}if(r=this.tokenizer.hr(e)){e=e.substring(r.raw.length),t.push(r);continue}if(r=this.tokenizer.blockquote(e)){e=e.substring(r.raw.length),t.push(r);continue}if(r=this.tokenizer.list(e)){e=e.substring(r.raw.length),t.push(r);continue}if(r=this.tokenizer.html(e)){e=e.substring(r.raw.length),t.push(r);continue}if(r=this.tokenizer.def(e)){e=e.substring(r.raw.length);let o=t.at(-1);o?.type===\"paragraph\"||o?.type===\"text\"?(o.raw+=(o.raw.endsWith(`\n`)?\"\":`\n`)+r.raw,o.text+=`\n`+r.raw,this.inlineQueue.at(-1).src=o.text):this.tokens.links[r.tag]||(this.tokens.links[r.tag]={href:r.href,title:r.title},t.push(r));continue}if(r=this.tokenizer.table(e)){e=e.substring(r.raw.length),t.push(r);continue}if(r=this.tokenizer.lheading(e)){e=e.substring(r.raw.length),t.push(r);continue}let i=e;if(this.options.extensions?.startBlock){let o=1/0,u=e.slice(1),a;this.options.extensions.startBlock.forEach(c=>{a=c.call({lexer:this},u),typeof a==\"number\"&&a>=0&&(o=Math.min(o,a))}),o<1/0&&o>=0&&(i=e.substring(0,o+1))}if(this.state.top&&(r=this.tokenizer.paragraph(i))){let o=t.at(-1);n&&o?.type===\"paragraph\"?(o.raw+=(o.raw.endsWith(`\n`)?\"\":`\n`)+r.raw,o.text+=`\n`+r.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=o.text):t.push(r),n=i.length!==e.length,e=e.substring(r.raw.length);continue}if(r=this.tokenizer.text(e)){e=e.substring(r.raw.length);let o=t.at(-1);o?.type===\"text\"?(o.raw+=(o.raw.endsWith(`\n`)?\"\":`\n`)+r.raw,o.text+=`\n`+r.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=o.text):t.push(r);continue}if(e){this.infiniteLoopError(e.charCodeAt(0));break}}return this.state.top=!0,t}inline(e,t=[]){return this.inlineQueue.push({src:e,tokens:t}),t}inlineTokens(e,t=[]){this.tokenizer.lexer=this;let n=e,s=null;if(this.tokens.links){let a=Object.keys(this.tokens.links);if(a.length>0)for(;(s=this.tokenizer.rules.inline.reflinkSearch.exec(n))!==null;)a.includes(s[0].slice(s[0].lastIndexOf(\"[\")+1,-1))&&(n=n.slice(0,s.index)+\"[\"+\"a\".repeat(s[0].length-2)+\"]\"+n.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex))}for(;(s=this.tokenizer.rules.inline.anyPunctuation.exec(n))!==null;)n=n.slice(0,s.index)+\"++\"+n.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);let r;for(;(s=this.tokenizer.rules.inline.blockSkip.exec(n))!==null;)r=s[2]?s[2].length:0,n=n.slice(0,s.index+r)+\"[\"+\"a\".repeat(s[0].length-r-2)+\"]\"+n.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);n=this.options.hooks?.emStrongMask?.call({lexer:this},n)??n;let i=!1,o=\"\",u=1/0;for(;e;){if(e.length<u)u=e.length;else{this.infiniteLoopError(e.charCodeAt(0));break}i||(o=\"\"),i=!1;let a;if(this.options.extensions?.inline?.some(p=>(a=p.call({lexer:this},e,t))?(e=e.substring(a.raw.length),t.push(a),!0):!1))continue;if(a=this.tokenizer.escape(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.tag(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.link(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.reflink(e,this.tokens.links)){e=e.substring(a.raw.length);let p=t.at(-1);a.type===\"text\"&&p?.type===\"text\"?(p.raw+=a.raw,p.text+=a.text):t.push(a);continue}if(a=this.tokenizer.emStrong(e,n,o)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.codespan(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.br(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.del(e,n,o)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.autolink(e)){e=e.substring(a.raw.length),t.push(a);continue}if(!this.state.inLink&&(a=this.tokenizer.url(e))){e=e.substring(a.raw.length),t.push(a);continue}let c=e;if(this.options.extensions?.startInline){let p=1/0,k=e.slice(1),h;this.options.extensions.startInline.forEach(R=>{h=R.call({lexer:this},k),typeof h==\"number\"&&h>=0&&(p=Math.min(p,h))}),p<1/0&&p>=0&&(c=e.substring(0,p+1))}if(a=this.tokenizer.inlineText(c)){e=e.substring(a.raw.length),a.raw.slice(-1)!==\"_\"&&(o=a.raw.slice(-1)),i=!0;let p=t.at(-1);p?.type===\"text\"?(p.raw+=a.raw,p.text+=a.text):t.push(a);continue}if(e){this.infiniteLoopError(e.charCodeAt(0));break}}return t}infiniteLoopError(e){let t=\"Infinite loop on byte: \"+e;if(this.options.silent)console.error(t);else throw new Error(t)}};var y=class{options;parser;constructor(e){this.options=e||T}space(e){return\"\"}code({text:e,lang:t,escaped:n}){let s=(t||\"\").match(m.notSpaceStart)?.[0],r=e.replace(m.endingNewline,\"\")+`\n`;return s?'<pre><code class=\"language-'+O(s)+'\">'+(n?r:O(r,!0))+`</code></pre>\n`:\"<pre><code>\"+(n?r:O(r,!0))+`</code></pre>\n`}blockquote({tokens:e}){return`<blockquote>\n${this.parser.parse(e)}</blockquote>\n`}html({text:e}){return e}def(e){return\"\"}heading({tokens:e,depth:t}){return`<h${t}>${this.parser.parseInline(e)}</h${t}>\n`}hr(e){return`<hr>\n`}list(e){let t=e.ordered,n=e.start,s=\"\";for(let o=0;o<e.items.length;o++){let u=e.items[o];s+=this.listitem(u)}let r=t?\"ol\":\"ul\",i=t&&n!==1?' start=\"'+n+'\"':\"\";return\"<\"+r+i+`>\n`+s+\"</\"+r+`>\n`}listitem(e){return`<li>${this.parser.parse(e.tokens)}</li>\n`}checkbox({checked:e}){return\"<input \"+(e?'checked=\"\" ':\"\")+'disabled=\"\" type=\"checkbox\"> '}paragraph({tokens:e}){return`<p>${this.parser.parseInline(e)}</p>\n`}table(e){let t=\"\",n=\"\";for(let r=0;r<e.header.length;r++)n+=this.tablecell(e.header[r]);t+=this.tablerow({text:n});let s=\"\";for(let r=0;r<e.rows.length;r++){let i=e.rows[r];n=\"\";for(let o=0;o<i.length;o++)n+=this.tablecell(i[o]);s+=this.tablerow({text:n})}return s&&(s=`<tbody>${s}</tbody>`),`<table>\n<thead>\n`+t+`</thead>\n`+s+`</table>\n`}tablerow({text:e}){return`<tr>\n${e}</tr>\n`}tablecell(e){let t=this.parser.parseInline(e.tokens),n=e.header?\"th\":\"td\";return(e.align?`<${n} align=\"${e.align}\">`:`<${n}>`)+t+`</${n}>\n`}strong({tokens:e}){return`<strong>${this.parser.parseInline(e)}</strong>`}em({tokens:e}){return`<em>${this.parser.parseInline(e)}</em>`}codespan({text:e}){return`<code>${O(e,!0)}</code>`}br(e){return\"<br>\"}del({tokens:e}){return`<del>${this.parser.parseInline(e)}</del>`}link({href:e,title:t,tokens:n}){let s=this.parser.parseInline(n),r=V(e);if(r===null)return s;e=r;let i='<a href=\"'+e+'\"';return t&&(i+=' title=\"'+O(t)+'\"'),i+=\">\"+s+\"</a>\",i}image({href:e,title:t,text:n,tokens:s}){s&&(n=this.parser.parseInline(s,this.parser.textRenderer));let r=V(e);if(r===null)return O(n);e=r;let i=`<img src=\"${e}\" alt=\"${O(n)}\"`;return t&&(i+=` title=\"${O(t)}\"`),i+=\">\",i}text(e){return\"tokens\"in e&&e.tokens?this.parser.parseInline(e.tokens):\"escaped\"in e&&e.escaped?e.text:O(e.text)}};var L=class{strong({text:e}){return e}em({text:e}){return e}codespan({text:e}){return e}del({text:e}){return e}html({text:e}){return e}text({text:e}){return e}link({text:e}){return\"\"+e}image({text:e}){return\"\"+e}br(){return\"\"}checkbox({raw:e}){return e}};var b=class l{options;renderer;textRenderer;constructor(e){this.options=e||T,this.options.renderer=this.options.renderer||new y,this.renderer=this.options.renderer,this.renderer.options=this.options,this.renderer.parser=this,this.textRenderer=new L}static parse(e,t){return new l(t).parse(e)}static parseInline(e,t){return new l(t).parseInline(e)}parse(e){this.renderer.parser=this;let t=\"\";for(let n=0;n<e.length;n++){let s=e[n];if(this.options.extensions?.renderers?.[s.type]){let i=s,o=this.options.extensions.renderers[i.type].call({parser:this},i);if(o!==!1||![\"space\",\"hr\",\"heading\",\"code\",\"table\",\"blockquote\",\"list\",\"html\",\"def\",\"paragraph\",\"text\"].includes(i.type)){t+=o||\"\";continue}}let r=s;switch(r.type){case\"space\":{t+=this.renderer.space(r);break}case\"hr\":{t+=this.renderer.hr(r);break}case\"heading\":{t+=this.renderer.heading(r);break}case\"code\":{t+=this.renderer.code(r);break}case\"table\":{t+=this.renderer.table(r);break}case\"blockquote\":{t+=this.renderer.blockquote(r);break}case\"list\":{t+=this.renderer.list(r);break}case\"checkbox\":{t+=this.renderer.checkbox(r);break}case\"html\":{t+=this.renderer.html(r);break}case\"def\":{t+=this.renderer.def(r);break}case\"paragraph\":{t+=this.renderer.paragraph(r);break}case\"text\":{t+=this.renderer.text(r);break}default:{let i='Token with \"'+r.type+'\" type was not found.';if(this.options.silent)return console.error(i),\"\";throw new Error(i)}}}return t}parseInline(e,t=this.renderer){this.renderer.parser=this;let n=\"\";for(let s=0;s<e.length;s++){let r=e[s];if(this.options.extensions?.renderers?.[r.type]){let o=this.options.extensions.renderers[r.type].call({parser:this},r);if(o!==!1||![\"escape\",\"html\",\"link\",\"image\",\"strong\",\"em\",\"codespan\",\"br\",\"del\",\"text\"].includes(r.type)){n+=o||\"\";continue}}let i=r;switch(i.type){case\"escape\":{n+=t.text(i);break}case\"html\":{n+=t.html(i);break}case\"link\":{n+=t.link(i);break}case\"image\":{n+=t.image(i);break}case\"checkbox\":{n+=t.checkbox(i);break}case\"strong\":{n+=t.strong(i);break}case\"em\":{n+=t.em(i);break}case\"codespan\":{n+=t.codespan(i);break}case\"br\":{n+=t.br(i);break}case\"del\":{n+=t.del(i);break}case\"text\":{n+=t.text(i);break}default:{let o='Token with \"'+i.type+'\" type was not found.';if(this.options.silent)return console.error(o),\"\";throw new Error(o)}}}return n}};var P=class{options;block;constructor(e){this.options=e||T}static passThroughHooks=new Set([\"preprocess\",\"postprocess\",\"processAllTokens\",\"emStrongMask\"]);static passThroughHooksRespectAsync=new Set([\"preprocess\",\"postprocess\",\"processAllTokens\"]);preprocess(e){return e}postprocess(e){return e}processAllTokens(e){return e}emStrongMask(e){return e}provideLexer(e=this.block){return e?x.lex:x.lexInline}provideParser(e=this.block){return e?b.parse:b.parseInline}};var q=class{defaults=M();options=this.setOptions;parse=this.parseMarkdown(!0);parseInline=this.parseMarkdown(!1);Parser=b;Renderer=y;TextRenderer=L;Lexer=x;Tokenizer=w;Hooks=P;constructor(...e){this.use(...e)}walkTokens(e,t){let n=[];for(let s of e)switch(n=n.concat(t.call(this,s)),s.type){case\"table\":{let r=s;for(let i of r.header)n=n.concat(this.walkTokens(i.tokens,t));for(let i of r.rows)for(let o of i)n=n.concat(this.walkTokens(o.tokens,t));break}case\"list\":{let r=s;n=n.concat(this.walkTokens(r.items,t));break}default:{let r=s;this.defaults.extensions?.childTokens?.[r.type]?this.defaults.extensions.childTokens[r.type].forEach(i=>{let o=r[i].flat(1/0);n=n.concat(this.walkTokens(o,t))}):r.tokens&&(n=n.concat(this.walkTokens(r.tokens,t)))}}return n}use(...e){let t=this.defaults.extensions||{renderers:{},childTokens:{}};return e.forEach(n=>{let s={...n};if(s.async=this.defaults.async||s.async||!1,n.extensions&&(n.extensions.forEach(r=>{if(!r.name)throw new Error(\"extension name required\");if(\"renderer\"in r){let i=t.renderers[r.name];i?t.renderers[r.name]=function(...o){let u=r.renderer.apply(this,o);return u===!1&&(u=i.apply(this,o)),u}:t.renderers[r.name]=r.renderer}if(\"tokenizer\"in r){if(!r.level||r.level!==\"block\"&&r.level!==\"inline\")throw new Error(\"extension level must be 'block' or 'inline'\");let i=t[r.level];i?i.unshift(r.tokenizer):t[r.level]=[r.tokenizer],r.start&&(r.level===\"block\"?t.startBlock?t.startBlock.push(r.start):t.startBlock=[r.start]:r.level===\"inline\"&&(t.startInline?t.startInline.push(r.start):t.startInline=[r.start]))}\"childTokens\"in r&&r.childTokens&&(t.childTokens[r.name]=r.childTokens)}),s.extensions=t),n.renderer){let r=this.defaults.renderer||new y(this.defaults);for(let i in n.renderer){if(!(i in r))throw new Error(`renderer '${i}' does not exist`);if([\"options\",\"parser\"].includes(i))continue;let o=i,u=n.renderer[o],a=r[o];r[o]=(...c)=>{let p=u.apply(r,c);return p===!1&&(p=a.apply(r,c)),p||\"\"}}s.renderer=r}if(n.tokenizer){let r=this.defaults.tokenizer||new w(this.defaults);for(let i in n.tokenizer){if(!(i in r))throw new Error(`tokenizer '${i}' does not exist`);if([\"options\",\"rules\",\"lexer\"].includes(i))continue;let o=i,u=n.tokenizer[o],a=r[o];r[o]=(...c)=>{let p=u.apply(r,c);return p===!1&&(p=a.apply(r,c)),p}}s.tokenizer=r}if(n.hooks){let r=this.defaults.hooks||new P;for(let i in n.hooks){if(!(i in r))throw new Error(`hook '${i}' does not exist`);if([\"options\",\"block\"].includes(i))continue;let o=i,u=n.hooks[o],a=r[o];P.passThroughHooks.has(i)?r[o]=c=>{if(this.defaults.async&&P.passThroughHooksRespectAsync.has(i))return(async()=>{let k=await u.call(r,c);return a.call(r,k)})();let p=u.call(r,c);return a.call(r,p)}:r[o]=(...c)=>{if(this.defaults.async)return(async()=>{let k=await u.apply(r,c);return k===!1&&(k=await a.apply(r,c)),k})();let p=u.apply(r,c);return p===!1&&(p=a.apply(r,c)),p}}s.hooks=r}if(n.walkTokens){let r=this.defaults.walkTokens,i=n.walkTokens;s.walkTokens=function(o){let u=[];return u.push(i.call(this,o)),r&&(u=u.concat(r.call(this,o))),u}}this.defaults={...this.defaults,...s}}),this}setOptions(e){return this.defaults={...this.defaults,...e},this}lexer(e,t){return x.lex(e,t??this.defaults)}parser(e,t){return b.parse(e,t??this.defaults)}parseMarkdown(e){return(n,s)=>{let r={...s},i={...this.defaults,...r},o=this.onError(!!i.silent,!!i.async);if(this.defaults.async===!0&&r.async===!1)return o(new Error(\"marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise.\"));if(typeof n>\"u\"||n===null)return o(new Error(\"marked(): input parameter is undefined or null\"));if(typeof n!=\"string\")return o(new Error(\"marked(): input parameter is of type \"+Object.prototype.toString.call(n)+\", string expected\"));if(i.hooks&&(i.hooks.options=i,i.hooks.block=e),i.async)return(async()=>{let u=i.hooks?await i.hooks.preprocess(n):n,c=await(i.hooks?await i.hooks.provideLexer(e):e?x.lex:x.lexInline)(u,i),p=i.hooks?await i.hooks.processAllTokens(c):c;i.walkTokens&&await Promise.all(this.walkTokens(p,i.walkTokens));let h=await(i.hooks?await i.hooks.provideParser(e):e?b.parse:b.parseInline)(p,i);return i.hooks?await i.hooks.postprocess(h):h})().catch(o);try{i.hooks&&(n=i.hooks.preprocess(n));let a=(i.hooks?i.hooks.provideLexer(e):e?x.lex:x.lexInline)(n,i);i.hooks&&(a=i.hooks.processAllTokens(a)),i.walkTokens&&this.walkTokens(a,i.walkTokens);let p=(i.hooks?i.hooks.provideParser(e):e?b.parse:b.parseInline)(a,i);return i.hooks&&(p=i.hooks.postprocess(p)),p}catch(u){return o(u)}}}onError(e,t){return n=>{if(n.message+=`\nPlease report this to https://github.com/markedjs/marked.`,e){let s=\"<p>An error occurred:</p><pre>\"+O(n.message+\"\",!0)+\"</pre>\";return t?Promise.resolve(s):s}if(t)return Promise.reject(n);throw n}}};var z=new q;function g(l,e){return z.parse(l,e)}g.options=g.setOptions=function(l){return z.setOptions(l),g.defaults=z.defaults,N(g.defaults),g};g.getDefaults=M;g.defaults=T;g.use=function(...l){return z.use(...l),g.defaults=z.defaults,N(g.defaults),g};g.walkTokens=function(l,e){return z.walkTokens(l,e)};g.parseInline=z.parseInline;g.Parser=b;g.parser=b.parse;g.Renderer=y;g.TextRenderer=L;g.Lexer=x;g.lexer=x.lex;g.Tokenizer=w;g.Hooks=P;g.parse=g;var Ft=g.options,Ut=g.setOptions,Kt=g.use,Wt=g.walkTokens,Xt=g.parseInline,Jt=g,Vt=b.parse,Yt=x.lex;export{P as Hooks,x as Lexer,q as Marked,b as Parser,y as Renderer,L as TextRenderer,w as Tokenizer,T as defaults,M as getDefaults,Yt as lexer,g as marked,Ft as options,Jt as parse,Xt as parseInline,Vt as parser,Ut as setOptions,Kt as use,Wt as walkTokens};\n//# sourceMappingURL=marked.esm.js.map\n","import { Marked, Tokenizer } from \"marked\";\nimport { getCapabilities, hyperlink, isImageLine } from \"../terminal-image.js\";\nimport { applyBackgroundToLine, visibleWidth, wrapTextWithAnsi } from \"../utils.js\";\nconst STRICT_STRIKETHROUGH_REGEX = /^(~~)(?=[^\\s~])((?:\\\\.|[^\\\\])*?(?:\\\\.|[^\\s~\\\\]))\\1(?=[^~]|$)/;\nclass StrictStrikethroughTokenizer extends Tokenizer {\n del(src) {\n const match = STRICT_STRIKETHROUGH_REGEX.exec(src);\n if (!match) {\n return undefined;\n }\n const text = match[2];\n return {\n type: \"del\",\n raw: match[0],\n text,\n tokens: this.lexer.inlineTokens(text),\n };\n }\n}\nfunction trimPartialClosingFences(tokens) {\n const token = tokens[tokens.length - 1];\n if (token?.type === \"list\") {\n trimPartialClosingFences(token.items[token.items.length - 1]?.tokens ?? []);\n return;\n }\n if (token?.type === \"blockquote\") {\n trimPartialClosingFences(token.tokens ?? []);\n return;\n }\n if (token?.type !== \"code\") {\n return;\n }\n // Trim streamed partial closing fences so code blocks do not shrink/flicker\n // when the final fence character arrives. See https://github.com/earendil-works/pi/issues/5825.\n const marker = /^(`{3,}|~{3,})/.exec(token.raw)?.[1];\n const lastLine = token.raw.split(\"\\n\").pop();\n if (!marker || !lastLine || lastLine.length >= marker.length || lastLine !== marker[0]?.repeat(lastLine.length)) {\n return;\n }\n token.text = token.text.slice(0, -lastLine.length).replace(/\\n$/, \"\");\n}\nconst markdownParser = new Marked();\nmarkdownParser.setOptions({\n tokenizer: new StrictStrikethroughTokenizer(),\n});\nexport class Markdown {\n text;\n paddingX; // Left/right padding\n paddingY; // Top/bottom padding\n defaultTextStyle;\n theme;\n options;\n defaultStylePrefix;\n // Cache for rendered output\n cachedText;\n cachedWidth;\n cachedLines;\n constructor(text, paddingX, paddingY, theme, defaultTextStyle, options) {\n this.text = text;\n this.paddingX = paddingX;\n this.paddingY = paddingY;\n this.theme = theme;\n this.defaultTextStyle = defaultTextStyle;\n this.options = options ? { ...options } : {};\n }\n setText(text) {\n this.text = text;\n this.invalidate();\n }\n invalidate() {\n this.cachedText = undefined;\n this.cachedWidth = undefined;\n this.cachedLines = undefined;\n }\n render(width) {\n // Check cache\n if (this.cachedLines && this.cachedText === this.text && this.cachedWidth === width) {\n return this.cachedLines;\n }\n // Calculate available width for content (subtract horizontal padding)\n const contentWidth = Math.max(1, width - this.paddingX * 2);\n // Don't render anything if there's no actual text\n if (!this.text || this.text.trim() === \"\") {\n const result = [];\n // Update cache\n this.cachedText = this.text;\n this.cachedWidth = width;\n this.cachedLines = result;\n return result;\n }\n // Replace tabs with 3 spaces for consistent rendering\n const normalizedText = this.text.replace(/\\t/g, \" \");\n // Parse markdown to HTML-like tokens\n const tokens = markdownParser.lexer(normalizedText);\n trimPartialClosingFences(tokens);\n // Convert tokens to styled terminal output\n const renderedLines = [];\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i];\n const nextToken = tokens[i + 1];\n const tokenLines = this.renderToken(token, contentWidth, nextToken?.type);\n for (const tokenLine of tokenLines) {\n renderedLines.push(tokenLine);\n }\n }\n // Wrap lines (NO padding, NO background yet)\n const wrappedLines = [];\n for (const line of renderedLines) {\n if (isImageLine(line)) {\n wrappedLines.push(line);\n }\n else {\n for (const wrappedLine of wrapTextWithAnsi(line, contentWidth)) {\n wrappedLines.push(wrappedLine);\n }\n }\n }\n // Add margins and background to each wrapped line\n const leftMargin = \" \".repeat(this.paddingX);\n const rightMargin = \" \".repeat(this.paddingX);\n const bgFn = this.defaultTextStyle?.bgColor;\n const contentLines = [];\n for (const line of wrappedLines) {\n if (isImageLine(line)) {\n contentLines.push(line);\n continue;\n }\n const lineWithMargins = leftMargin + line + rightMargin;\n if (bgFn) {\n contentLines.push(applyBackgroundToLine(lineWithMargins, width, bgFn));\n }\n else {\n // No background - just pad to width\n const visibleLen = visibleWidth(lineWithMargins);\n const paddingNeeded = Math.max(0, width - visibleLen);\n contentLines.push(lineWithMargins + \" \".repeat(paddingNeeded));\n }\n }\n // Add top/bottom padding (empty lines)\n const emptyLine = \" \".repeat(width);\n const emptyLines = [];\n for (let i = 0; i < this.paddingY; i++) {\n const line = bgFn ? applyBackgroundToLine(emptyLine, width, bgFn) : emptyLine;\n emptyLines.push(line);\n }\n // Combine top padding, content, and bottom padding\n const result = emptyLines.concat(contentLines, emptyLines);\n // Update cache\n this.cachedText = this.text;\n this.cachedWidth = width;\n this.cachedLines = result;\n return result.length > 0 ? result : [\"\"];\n }\n /**\n * Apply default text style to a string.\n * This is the base styling applied to all text content.\n * NOTE: Background color is NOT applied here - it's applied at the padding stage\n * to ensure it extends to the full line width.\n */\n applyDefaultStyle(text) {\n if (!this.defaultTextStyle) {\n return text;\n }\n let styled = text;\n // Apply foreground color (NOT background - that's applied at padding stage)\n if (this.defaultTextStyle.color) {\n styled = this.defaultTextStyle.color(styled);\n }\n // Apply text decorations using this.theme\n if (this.defaultTextStyle.bold) {\n styled = this.theme.bold(styled);\n }\n if (this.defaultTextStyle.italic) {\n styled = this.theme.italic(styled);\n }\n if (this.defaultTextStyle.strikethrough) {\n styled = this.theme.strikethrough(styled);\n }\n if (this.defaultTextStyle.underline) {\n styled = this.theme.underline(styled);\n }\n return styled;\n }\n getDefaultStylePrefix() {\n if (!this.defaultTextStyle) {\n return \"\";\n }\n if (this.defaultStylePrefix !== undefined) {\n return this.defaultStylePrefix;\n }\n const sentinel = \"\\u0000\";\n let styled = sentinel;\n if (this.defaultTextStyle.color) {\n styled = this.defaultTextStyle.color(styled);\n }\n if (this.defaultTextStyle.bold) {\n styled = this.theme.bold(styled);\n }\n if (this.defaultTextStyle.italic) {\n styled = this.theme.italic(styled);\n }\n if (this.defaultTextStyle.strikethrough) {\n styled = this.theme.strikethrough(styled);\n }\n if (this.defaultTextStyle.underline) {\n styled = this.theme.underline(styled);\n }\n const sentinelIndex = styled.indexOf(sentinel);\n this.defaultStylePrefix = sentinelIndex >= 0 ? styled.slice(0, sentinelIndex) : \"\";\n return this.defaultStylePrefix;\n }\n getStylePrefix(styleFn) {\n const sentinel = \"\\u0000\";\n const styled = styleFn(sentinel);\n const sentinelIndex = styled.indexOf(sentinel);\n return sentinelIndex >= 0 ? styled.slice(0, sentinelIndex) : \"\";\n }\n getDefaultInlineStyleContext() {\n return {\n applyText: (text) => this.applyDefaultStyle(text),\n stylePrefix: this.getDefaultStylePrefix(),\n };\n }\n renderToken(token, width, nextTokenType, styleContext) {\n const lines = [];\n switch (token.type) {\n case \"heading\": {\n const headingLevel = token.depth;\n const headingPrefix = `${\"#\".repeat(headingLevel)} `;\n // Build a heading-specific style context so inline tokens (codespan, bold, etc.)\n // restore heading styling after their own ANSI resets instead of falling back to\n // the default text style.\n let headingStyleFn;\n if (headingLevel === 1) {\n headingStyleFn = (text) => this.theme.heading(this.theme.bold(this.theme.underline(text)));\n }\n else {\n headingStyleFn = (text) => this.theme.heading(this.theme.bold(text));\n }\n const headingStyleContext = {\n applyText: headingStyleFn,\n stylePrefix: this.getStylePrefix(headingStyleFn),\n };\n const headingText = this.renderInlineTokens(token.tokens || [], headingStyleContext);\n const styledHeading = headingLevel >= 3 ? headingStyleFn(headingPrefix) + headingText : headingText;\n lines.push(styledHeading);\n if (nextTokenType && nextTokenType !== \"space\") {\n lines.push(\"\"); // Add spacing after headings (unless space token follows)\n }\n break;\n }\n case \"paragraph\": {\n const paragraphText = this.renderInlineTokens(token.tokens || [], styleContext);\n lines.push(paragraphText);\n // Don't add spacing if next token is space or list\n if (nextTokenType && nextTokenType !== \"list\" && nextTokenType !== \"space\") {\n lines.push(\"\");\n }\n break;\n }\n case \"text\":\n lines.push(this.renderInlineTokens([token], styleContext));\n break;\n case \"code\": {\n const indent = this.theme.codeBlockIndent ?? \" \";\n lines.push(this.theme.codeBlockBorder(`\\`\\`\\`${token.lang || \"\"}`));\n if (this.theme.highlightCode) {\n const highlightedLines = this.theme.highlightCode(token.text, token.lang);\n for (const hlLine of highlightedLines) {\n lines.push(`${indent}${hlLine}`);\n }\n }\n else {\n // Split code by newlines and style each line\n const codeLines = token.text.split(\"\\n\");\n for (const codeLine of codeLines) {\n lines.push(`${indent}${this.theme.codeBlock(codeLine)}`);\n }\n }\n lines.push(this.theme.codeBlockBorder(\"```\"));\n if (nextTokenType && nextTokenType !== \"space\") {\n lines.push(\"\"); // Add spacing after code blocks (unless space token follows)\n }\n break;\n }\n case \"list\": {\n const listLines = this.renderList(token, 0, width, styleContext);\n lines.push(...listLines);\n // Don't add spacing after lists if a space token follows\n // (the space token will handle it)\n break;\n }\n case \"table\": {\n const tableLines = this.renderTable(token, width, nextTokenType, styleContext);\n lines.push(...tableLines);\n break;\n }\n case \"blockquote\": {\n const quoteStyle = (text) => this.theme.quote(this.theme.italic(text));\n const quoteStylePrefix = this.getStylePrefix(quoteStyle);\n const applyQuoteStyle = (line) => {\n if (!quoteStylePrefix) {\n return quoteStyle(line);\n }\n const lineWithReappliedStyle = line.replace(/\\x1b\\[0m/g, `\\x1b[0m${quoteStylePrefix}`);\n return quoteStyle(lineWithReappliedStyle);\n };\n // Calculate available width for quote content (subtract border \"│ \" = 2 chars)\n const quoteContentWidth = Math.max(1, width - 2);\n // Blockquotes contain block-level tokens (paragraph, list, code, etc.), so render\n // children with renderToken() instead of renderInlineTokens().\n // Default message style should not apply inside blockquotes.\n const quoteInlineStyleContext = {\n applyText: (text) => text,\n stylePrefix: quoteStylePrefix,\n };\n const quoteTokens = token.tokens || [];\n const renderedQuoteLines = [];\n for (let i = 0; i < quoteTokens.length; i++) {\n const quoteToken = quoteTokens[i];\n const nextQuoteToken = quoteTokens[i + 1];\n renderedQuoteLines.push(...this.renderToken(quoteToken, quoteContentWidth, nextQuoteToken?.type, quoteInlineStyleContext));\n }\n // Avoid rendering an extra empty quote line before the outer blockquote spacing.\n while (renderedQuoteLines.length > 0 && renderedQuoteLines[renderedQuoteLines.length - 1] === \"\") {\n renderedQuoteLines.pop();\n }\n for (const quoteLine of renderedQuoteLines) {\n const styledLine = applyQuoteStyle(quoteLine);\n const wrappedLines = wrapTextWithAnsi(styledLine, quoteContentWidth);\n for (const wrappedLine of wrappedLines) {\n lines.push(this.theme.quoteBorder(\"│ \") + wrappedLine);\n }\n }\n if (nextTokenType && nextTokenType !== \"space\") {\n lines.push(\"\"); // Add spacing after blockquotes (unless space token follows)\n }\n break;\n }\n case \"hr\":\n lines.push(this.theme.hr(\"─\".repeat(Math.min(width, 80))));\n if (nextTokenType && nextTokenType !== \"space\") {\n lines.push(\"\"); // Add spacing after horizontal rules (unless space token follows)\n }\n break;\n case \"html\":\n // Render HTML as plain text (escaped for terminal)\n if (\"raw\" in token && typeof token.raw === \"string\") {\n lines.push(this.applyDefaultStyle(token.raw.trim()));\n }\n break;\n case \"space\":\n // Space tokens represent blank lines in markdown\n lines.push(\"\");\n break;\n default:\n // Handle any other token types as plain text\n if (\"text\" in token && typeof token.text === \"string\") {\n lines.push(token.text);\n }\n }\n return lines;\n }\n renderInlineTokens(tokens, styleContext) {\n let result = \"\";\n const resolvedStyleContext = styleContext ?? this.getDefaultInlineStyleContext();\n const { applyText, stylePrefix } = resolvedStyleContext;\n const applyTextWithNewlines = (text) => {\n const segments = text.split(\"\\n\");\n return segments.map((segment) => applyText(segment)).join(\"\\n\");\n };\n for (const token of tokens) {\n switch (token.type) {\n case \"escape\":\n result += applyTextWithNewlines(this.options.preserveBackslashEscapes ? token.raw : token.text);\n break;\n case \"text\":\n // Text tokens in list items can have nested tokens for inline formatting\n if (token.tokens && token.tokens.length > 0) {\n result += this.renderInlineTokens(token.tokens, resolvedStyleContext);\n }\n else {\n result += applyTextWithNewlines(token.text);\n }\n break;\n case \"paragraph\":\n // Paragraph tokens contain nested inline tokens\n result += this.renderInlineTokens(token.tokens || [], resolvedStyleContext);\n break;\n case \"strong\": {\n const boldContent = this.renderInlineTokens(token.tokens || [], resolvedStyleContext);\n result += this.theme.bold(boldContent) + stylePrefix;\n break;\n }\n case \"em\": {\n const italicContent = this.renderInlineTokens(token.tokens || [], resolvedStyleContext);\n result += this.theme.italic(italicContent) + stylePrefix;\n break;\n }\n case \"codespan\":\n result += this.theme.code(token.text) + stylePrefix;\n break;\n case \"link\": {\n const linkText = this.renderInlineTokens(token.tokens || [], resolvedStyleContext);\n const styledLink = this.theme.link(this.theme.underline(linkText));\n if (getCapabilities().hyperlinks) {\n // OSC 8: render as a clickable hyperlink. The URL is not printed inline,\n // so we always show only the link text regardless of whether it matches href.\n result += hyperlink(styledLink, token.href) + stylePrefix;\n }\n else {\n // Fallback: print URL in parentheses when text differs from href.\n // Compare raw token.text (not styled) against href for the equality check.\n // For mailto: links strip the prefix (autolinked emails use text=\"foo@bar.com\"\n // but href=\"mailto:foo@bar.com\").\n const hrefForComparison = token.href.startsWith(\"mailto:\") ? token.href.slice(7) : token.href;\n if (token.text === token.href || token.text === hrefForComparison) {\n result += styledLink + stylePrefix;\n }\n else {\n result += styledLink + this.theme.linkUrl(` (${token.href})`) + stylePrefix;\n }\n }\n break;\n }\n case \"br\":\n result += \"\\n\";\n break;\n case \"del\": {\n const delContent = this.renderInlineTokens(token.tokens || [], resolvedStyleContext);\n result += this.theme.strikethrough(delContent) + stylePrefix;\n break;\n }\n case \"html\":\n // Render inline HTML as plain text\n if (\"raw\" in token && typeof token.raw === \"string\") {\n result += applyTextWithNewlines(token.raw);\n }\n break;\n default:\n // Handle any other inline token types as plain text\n if (\"text\" in token && typeof token.text === \"string\") {\n result += applyTextWithNewlines(token.text);\n }\n }\n }\n while (stylePrefix && result.endsWith(stylePrefix)) {\n result = result.slice(0, -stylePrefix.length);\n }\n return result;\n }\n getOrderedListMarker(item) {\n const match = /^(?: {0,3})(\\d{1,9}[.)])[ \\t]+/.exec(item.raw);\n return match ? `${match[1]} ` : undefined;\n }\n getUnorderedListMarker(item) {\n const match = /^(?: {0,3})([-+*])(?:[ \\t]+|(?=\\r?\\n|$))/.exec(item.raw);\n return match ? `${match[1]} ` : undefined;\n }\n /**\n * Render a list with proper nesting support\n */\n renderList(token, depth, width, styleContext) {\n const lines = [];\n const indent = \" \".repeat(depth);\n // Use the list's start property (defaults to 1 for ordered lists)\n const startNumber = typeof token.start === \"number\" ? token.start : 1;\n for (let i = 0; i < token.items.length; i++) {\n const item = token.items[i];\n const isLastItem = i === token.items.length - 1;\n const bullet = token.ordered\n ? this.options.preserveOrderedListMarkers\n ? (this.getOrderedListMarker(item) ?? `${startNumber + i}. `)\n : `${startNumber + i}. `\n : this.options.preserveOrderedListMarkers\n ? (this.getUnorderedListMarker(item) ?? \"- \")\n : \"- \";\n const taskMarker = item.task ? `[${item.checked ? \"x\" : \" \"}] ` : \"\";\n const marker = bullet + taskMarker;\n const firstPrefix = indent + this.theme.listBullet(marker);\n const continuationPrefix = indent + \" \".repeat(visibleWidth(marker));\n const itemWidth = Math.max(1, width - visibleWidth(firstPrefix));\n let renderedAnyLine = false;\n for (const itemToken of item.tokens) {\n if (itemToken.type === \"list\") {\n lines.push(...this.renderList(itemToken, depth + 1, width, styleContext));\n renderedAnyLine = true;\n continue;\n }\n const itemLines = this.renderToken(itemToken, itemWidth, undefined, styleContext);\n for (const line of itemLines) {\n for (const wrappedLine of wrapTextWithAnsi(line, itemWidth)) {\n const linePrefix = renderedAnyLine ? continuationPrefix : firstPrefix;\n lines.push(linePrefix + wrappedLine);\n renderedAnyLine = true;\n }\n }\n }\n if (!renderedAnyLine) {\n lines.push(firstPrefix);\n }\n if (token.loose && !isLastItem) {\n lines.push(\"\");\n }\n }\n return lines;\n }\n /**\n * Get the visible width of the longest word in a string.\n */\n getLongestWordWidth(text, maxWidth) {\n const words = text.split(/\\s+/).filter((word) => word.length > 0);\n let longest = 0;\n for (const word of words) {\n longest = Math.max(longest, visibleWidth(word));\n }\n if (maxWidth === undefined) {\n return longest;\n }\n return Math.min(longest, maxWidth);\n }\n /**\n * Wrap a table cell to fit into a column.\n *\n * Delegates to wrapTextWithAnsi() so ANSI codes + long tokens are handled\n * consistently with the rest of the renderer.\n */\n wrapCellText(text, maxWidth) {\n return wrapTextWithAnsi(text, Math.max(1, maxWidth));\n }\n /**\n * Render a table with width-aware cell wrapping.\n * Cells that don't fit are wrapped to multiple lines.\n */\n renderTable(token, availableWidth, nextTokenType, styleContext) {\n const lines = [];\n const numCols = token.header.length;\n if (numCols === 0) {\n return lines;\n }\n // Calculate border overhead: \"│ \" + (n-1) * \" │ \" + \" │\"\n // = 2 + (n-1) * 3 + 2 = 3n + 1\n const borderOverhead = 3 * numCols + 1;\n const availableForCells = availableWidth - borderOverhead;\n if (availableForCells < numCols) {\n // Too narrow to render a stable table. Fall back to raw markdown.\n const fallbackLines = token.raw ? wrapTextWithAnsi(token.raw, availableWidth) : [];\n if (nextTokenType && nextTokenType !== \"space\") {\n fallbackLines.push(\"\");\n }\n return fallbackLines;\n }\n const maxUnbrokenWordWidth = 30;\n // Calculate natural column widths (what each column needs without constraints)\n const naturalWidths = [];\n const minWordWidths = [];\n for (let i = 0; i < numCols; i++) {\n const headerText = this.renderInlineTokens(token.header[i].tokens || [], styleContext);\n naturalWidths[i] = visibleWidth(headerText);\n minWordWidths[i] = Math.max(1, this.getLongestWordWidth(headerText, maxUnbrokenWordWidth));\n }\n for (const row of token.rows) {\n for (let i = 0; i < row.length; i++) {\n const cellText = this.renderInlineTokens(row[i].tokens || [], styleContext);\n naturalWidths[i] = Math.max(naturalWidths[i] || 0, visibleWidth(cellText));\n minWordWidths[i] = Math.max(minWordWidths[i] || 1, this.getLongestWordWidth(cellText, maxUnbrokenWordWidth));\n }\n }\n let minColumnWidths = minWordWidths;\n let minCellsWidth = minColumnWidths.reduce((a, b) => a + b, 0);\n if (minCellsWidth > availableForCells) {\n minColumnWidths = new Array(numCols).fill(1);\n const remaining = availableForCells - numCols;\n if (remaining > 0) {\n const totalWeight = minWordWidths.reduce((total, width) => total + Math.max(0, width - 1), 0);\n const growth = minWordWidths.map((width) => {\n const weight = Math.max(0, width - 1);\n return totalWeight > 0 ? Math.floor((weight / totalWeight) * remaining) : 0;\n });\n for (let i = 0; i < numCols; i++) {\n minColumnWidths[i] += growth[i] ?? 0;\n }\n const allocated = growth.reduce((total, width) => total + width, 0);\n let leftover = remaining - allocated;\n for (let i = 0; leftover > 0 && i < numCols; i++) {\n minColumnWidths[i]++;\n leftover--;\n }\n }\n minCellsWidth = minColumnWidths.reduce((a, b) => a + b, 0);\n }\n // Calculate column widths that fit within available width\n const totalNaturalWidth = naturalWidths.reduce((a, b) => a + b, 0) + borderOverhead;\n let columnWidths;\n if (totalNaturalWidth <= availableWidth) {\n // Everything fits naturally\n columnWidths = naturalWidths.map((width, index) => Math.max(width, minColumnWidths[index]));\n }\n else {\n // Need to shrink columns to fit\n const totalGrowPotential = naturalWidths.reduce((total, width, index) => {\n return total + Math.max(0, width - minColumnWidths[index]);\n }, 0);\n const extraWidth = Math.max(0, availableForCells - minCellsWidth);\n columnWidths = minColumnWidths.map((minWidth, index) => {\n const naturalWidth = naturalWidths[index];\n const minWidthDelta = Math.max(0, naturalWidth - minWidth);\n let grow = 0;\n if (totalGrowPotential > 0) {\n grow = Math.floor((minWidthDelta / totalGrowPotential) * extraWidth);\n }\n return minWidth + grow;\n });\n // Adjust for rounding errors - distribute remaining space\n const allocated = columnWidths.reduce((a, b) => a + b, 0);\n let remaining = availableForCells - allocated;\n while (remaining > 0) {\n let grew = false;\n for (let i = 0; i < numCols && remaining > 0; i++) {\n if (columnWidths[i] < naturalWidths[i]) {\n columnWidths[i]++;\n remaining--;\n grew = true;\n }\n }\n if (!grew) {\n break;\n }\n }\n }\n // Render top border\n const topBorderCells = columnWidths.map((w) => \"─\".repeat(w));\n lines.push(`┌─${topBorderCells.join(\"─┬─\")}─┐`);\n // Render header with wrapping\n const headerCellLines = token.header.map((cell, i) => {\n const text = this.renderInlineTokens(cell.tokens || [], styleContext);\n return this.wrapCellText(text, columnWidths[i]);\n });\n const headerLineCount = Math.max(...headerCellLines.map((c) => c.length));\n for (let lineIdx = 0; lineIdx < headerLineCount; lineIdx++) {\n const rowParts = headerCellLines.map((cellLines, colIdx) => {\n const text = cellLines[lineIdx] || \"\";\n const padded = text + \" \".repeat(Math.max(0, columnWidths[colIdx] - visibleWidth(text)));\n return this.theme.bold(padded);\n });\n lines.push(`│ ${rowParts.join(\" │ \")} │`);\n }\n // Render separator\n const separatorCells = columnWidths.map((w) => \"─\".repeat(w));\n const separatorLine = `├─${separatorCells.join(\"─┼─\")}─┤`;\n lines.push(separatorLine);\n // Render rows with wrapping\n for (let rowIndex = 0; rowIndex < token.rows.length; rowIndex++) {\n const row = token.rows[rowIndex];\n const rowCellLines = row.map((cell, i) => {\n const text = this.renderInlineTokens(cell.tokens || [], styleContext);\n return this.wrapCellText(text, columnWidths[i]);\n });\n const rowLineCount = Math.max(...rowCellLines.map((c) => c.length));\n for (let lineIdx = 0; lineIdx < rowLineCount; lineIdx++) {\n const rowParts = rowCellLines.map((cellLines, colIdx) => {\n const text = cellLines[lineIdx] || \"\";\n return text + \" \".repeat(Math.max(0, columnWidths[colIdx] - visibleWidth(text)));\n });\n lines.push(`│ ${rowParts.join(\" │ \")} │`);\n }\n if (rowIndex < token.rows.length - 1) {\n lines.push(separatorLine);\n }\n }\n // Render bottom border\n const bottomBorderCells = columnWidths.map((w) => \"─\".repeat(w));\n lines.push(`└─${bottomBorderCells.join(\"─┴─\")}─┘`);\n if (nextTokenType && nextTokenType !== \"space\") {\n lines.push(\"\"); // Add spacing after table\n }\n return lines;\n }\n}\n//# sourceMappingURL=markdown.js.map","import { createRequire } from \"node:module\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nconst cjsRequire = createRequire(import.meta.url);\nlet nativeModifiersHelper;\nfunction isNativeModifiersHelper(value) {\n if (typeof value !== \"object\" || value === null)\n return false;\n const candidate = value.isModifierPressed;\n return typeof candidate === \"function\";\n}\nfunction loadNativeModifiersHelper() {\n if (nativeModifiersHelper !== undefined)\n return nativeModifiersHelper ?? undefined;\n nativeModifiersHelper = null;\n if (process.platform !== \"darwin\")\n return undefined;\n const arch = process.arch;\n if (arch !== \"x64\" && arch !== \"arm64\")\n return undefined;\n const moduleDir = path.dirname(fileURLToPath(import.meta.url));\n const nativePath = path.join(\"native\", \"darwin\", \"prebuilds\", `darwin-${arch}`, \"darwin-modifiers.node\");\n const candidates = [\n path.join(moduleDir, \"..\", nativePath),\n path.join(moduleDir, nativePath),\n path.join(path.dirname(process.execPath), nativePath),\n ];\n for (const modulePath of candidates) {\n try {\n const helper = cjsRequire(modulePath);\n if (isNativeModifiersHelper(helper)) {\n nativeModifiersHelper = helper;\n return helper;\n }\n }\n catch {\n // Try the next possible packaging location.\n }\n }\n return undefined;\n}\nexport function isNativeModifierPressed(key) {\n const helper = loadNativeModifiersHelper();\n if (!helper)\n return false;\n try {\n return helper.isModifierPressed(key) === true;\n }\n catch {\n return false;\n }\n}\n//# sourceMappingURL=native-modifiers.js.map","import * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { setKittyProtocolActive } from \"./keys.js\";\nimport { isNativeModifierPressed } from \"./native-modifiers.js\";\nimport { StdinBuffer } from \"./stdin-buffer.js\";\nconst cjsRequire = createRequire(import.meta.url);\nconst TERMINAL_PROGRESS_KEEPALIVE_MS = 1000;\nconst TERMINAL_PROGRESS_ACTIVE_SEQUENCE = \"\\x1b]9;4;3\\x07\";\nconst TERMINAL_PROGRESS_CLEAR_SEQUENCE = \"\\x1b]9;4;0;\\x07\";\nconst APPLE_TERMINAL_SHIFT_ENTER_SEQUENCE = \"\\x1b[13;2u\";\nconst DESIRED_KITTY_KEYBOARD_PROTOCOL_FLAGS = 7;\nconst KEYBOARD_PROTOCOL_RESPONSE_FRAGMENT_TIMEOUT_MS = 150;\nconst KITTY_KEYBOARD_PROTOCOL_QUERY = `\\x1b[>${DESIRED_KITTY_KEYBOARD_PROTOCOL_FLAGS}u\\x1b[?u\\x1b[c`;\nexport function parseKeyboardProtocolNegotiationSequence(sequence) {\n const kittyFlags = sequence.match(/^\\x1b\\[\\?(\\d+)u$/);\n if (kittyFlags) {\n return { type: \"kitty-flags\", flags: Number.parseInt(kittyFlags[1], 10) };\n }\n if (/^\\x1b\\[\\?[\\d;]*c$/.test(sequence)) {\n return { type: \"device-attributes\" };\n }\n return undefined;\n}\nfunction isKeyboardProtocolNegotiationSequencePrefix(sequence) {\n return sequence === \"\\x1b[\" || /^\\x1b\\[\\?[\\d;]*$/.test(sequence);\n}\nexport function isAppleTerminalSession() {\n return process.platform === \"darwin\" && process.env.TERM_PROGRAM === \"Apple_Terminal\";\n}\nexport function normalizeAppleTerminalInput(data, isAppleTerminal, isShiftPressed) {\n if (isAppleTerminal && data === \"\\r\" && isShiftPressed)\n return APPLE_TERMINAL_SHIFT_ENTER_SEQUENCE;\n return data;\n}\n/**\n * Real terminal using process.stdin/stdout\n */\nexport class ProcessTerminal {\n wasRaw = false;\n inputHandler;\n resizeHandler;\n _kittyProtocolActive = false;\n _modifyOtherKeysActive = false;\n keyboardProtocolPushed = false;\n keyboardProtocolNegotiationBuffer = \"\";\n keyboardProtocolBufferFlushTimer;\n stdinBuffer;\n stdinDataHandler;\n progressInterval;\n writeLogPath = (() => {\n const env = process.env.PI_TUI_WRITE_LOG || \"\";\n if (!env)\n return \"\";\n try {\n if (fs.statSync(env).isDirectory()) {\n const now = new Date();\n const ts = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, \"0\")}-${String(now.getDate()).padStart(2, \"0\")}_${String(now.getHours()).padStart(2, \"0\")}-${String(now.getMinutes()).padStart(2, \"0\")}-${String(now.getSeconds()).padStart(2, \"0\")}`;\n return path.join(env, `tui-${ts}-${process.pid}.log`);\n }\n }\n catch {\n // Not an existing directory - use as-is (file path)\n }\n return env;\n })();\n get kittyProtocolActive() {\n return this._kittyProtocolActive;\n }\n get modifyOtherKeysActive() {\n return this._modifyOtherKeysActive;\n }\n start(onInput, onResize) {\n this.inputHandler = onInput;\n this.resizeHandler = onResize;\n // Save previous state and enable raw mode\n this.wasRaw = process.stdin.isRaw || false;\n if (process.stdin.setRawMode) {\n process.stdin.setRawMode(true);\n }\n process.stdin.setEncoding(\"utf8\");\n process.stdin.resume();\n // Enable bracketed paste mode - terminal will wrap pastes in \\x1b[200~ ... \\x1b[201~\n process.stdout.write(\"\\x1b[?2004h\");\n // Set up resize handler immediately\n process.stdout.on(\"resize\", this.resizeHandler);\n // Refresh terminal dimensions - they may be stale after suspend/resume\n // (SIGWINCH is lost while process is stopped). Unix only.\n if (process.platform !== \"win32\") {\n process.kill(process.pid, \"SIGWINCH\");\n }\n // On Windows, enable ENABLE_VIRTUAL_TERMINAL_INPUT so the console sends\n // VT escape sequences (e.g. \\x1b[Z for Shift+Tab) instead of raw console\n // events that lose modifier information. Must run AFTER setRawMode(true)\n // since that resets console mode flags.\n this.enableWindowsVTInput();\n // Query Kitty keyboard protocol and fall back to modifyOtherKeys when DA confirms no Kitty response.\n // See: https://sw.kovidgoyal.net/kitty/keyboard-protocol/\n this.queryAndEnableKittyProtocol();\n }\n /**\n * Set up StdinBuffer to split batched input into individual sequences.\n * This ensures components receive single events, making matchesKey/isKeyRelease work correctly.\n *\n * Also watches for Kitty protocol response and enables it when detected.\n * This is done here (after stdinBuffer parsing) rather than on raw stdin\n * to handle the case where the response arrives split across multiple events.\n */\n setupStdinBuffer() {\n this.stdinBuffer = new StdinBuffer({ timeout: 10 });\n // Forward individual sequences to the input handler\n this.stdinBuffer.on(\"data\", (sequence) => {\n const negotiationSequence = this.readKeyboardProtocolNegotiationSequence(sequence);\n if (negotiationSequence === \"pending\") {\n this.scheduleKeyboardProtocolNegotiationBufferFlush();\n return; // Wait briefly for the rest of a split Kitty response.\n }\n if (this.handleKeyboardProtocolNegotiationSequence(negotiationSequence)) {\n return;\n }\n this.forwardInputSequence(sequence);\n });\n // Re-wrap paste content with bracketed paste markers for existing editor handling\n this.stdinBuffer.on(\"paste\", (content) => {\n if (this.inputHandler) {\n this.inputHandler(`\\x1b[200~${content}\\x1b[201~`);\n }\n });\n // Handler that pipes stdin data through the buffer\n this.stdinDataHandler = (data) => {\n this.stdinBuffer.process(data);\n };\n }\n /**\n * Query terminal for Kitty keyboard protocol support and enable it if available.\n *\n * Kitty's progressive enhancement detection requires requesting the desired\n * flags before querying them. The trailing DA query is a sentinel supported by\n * terminals that do not know Kitty keyboard protocol; receiving DA before a\n * Kitty response enables modifyOtherKeys fallback without a startup timeout.\n *\n * The requested flags are:\n * - 1 = disambiguate escape codes\n * - 2 = report event types (press/repeat/release)\n * - 4 = report alternate keys (shifted key, base layout key)\n */\n queryAndEnableKittyProtocol() {\n this.setupStdinBuffer();\n process.stdin.on(\"data\", this.stdinDataHandler);\n this.keyboardProtocolPushed = true;\n this.clearKeyboardProtocolNegotiationBuffer();\n process.stdout.write(KITTY_KEYBOARD_PROTOCOL_QUERY);\n }\n handleKeyboardProtocolNegotiationSequence(negotiationSequence) {\n if (!negotiationSequence)\n return false;\n this.clearKeyboardProtocolNegotiationBuffer();\n if (negotiationSequence.type === \"kitty-flags\") {\n if (negotiationSequence.flags !== 0) {\n this.disableModifyOtherKeys();\n if (!this._kittyProtocolActive) {\n this._kittyProtocolActive = true;\n setKittyProtocolActive(true);\n }\n }\n else {\n this.enableModifyOtherKeys();\n }\n return true;\n }\n if (!this._kittyProtocolActive) {\n this.enableModifyOtherKeys();\n }\n return true;\n }\n readKeyboardProtocolNegotiationSequence(sequence) {\n if (this.keyboardProtocolNegotiationBuffer) {\n const bufferedSequence = this.keyboardProtocolNegotiationBuffer + sequence;\n const negotiationSequence = parseKeyboardProtocolNegotiationSequence(bufferedSequence);\n if (negotiationSequence) {\n this.clearKeyboardProtocolNegotiationBuffer();\n return negotiationSequence;\n }\n if (isKeyboardProtocolNegotiationSequencePrefix(bufferedSequence)) {\n this.setKeyboardProtocolNegotiationBuffer(bufferedSequence);\n return \"pending\";\n }\n this.flushKeyboardProtocolNegotiationBufferAsInput();\n }\n const negotiationSequence = parseKeyboardProtocolNegotiationSequence(sequence);\n if (negotiationSequence)\n return negotiationSequence;\n if (isKeyboardProtocolNegotiationSequencePrefix(sequence)) {\n this.setKeyboardProtocolNegotiationBuffer(sequence);\n return \"pending\";\n }\n return undefined;\n }\n setKeyboardProtocolNegotiationBuffer(sequence) {\n this.clearKeyboardProtocolNegotiationBufferFlushTimer();\n this.keyboardProtocolNegotiationBuffer = sequence;\n }\n clearKeyboardProtocolNegotiationBuffer() {\n this.clearKeyboardProtocolNegotiationBufferFlushTimer();\n this.keyboardProtocolNegotiationBuffer = \"\";\n }\n flushKeyboardProtocolNegotiationBufferAsInput() {\n if (!this.keyboardProtocolNegotiationBuffer)\n return;\n const sequence = this.keyboardProtocolNegotiationBuffer;\n this.clearKeyboardProtocolNegotiationBuffer();\n this.forwardInputSequence(sequence);\n }\n scheduleKeyboardProtocolNegotiationBufferFlush() {\n if (!this.keyboardProtocolNegotiationBuffer || this.keyboardProtocolBufferFlushTimer)\n return;\n this.keyboardProtocolBufferFlushTimer = setTimeout(() => {\n this.keyboardProtocolBufferFlushTimer = undefined;\n this.flushKeyboardProtocolNegotiationBufferAsInput();\n }, KEYBOARD_PROTOCOL_RESPONSE_FRAGMENT_TIMEOUT_MS);\n }\n clearKeyboardProtocolNegotiationBufferFlushTimer() {\n if (!this.keyboardProtocolBufferFlushTimer)\n return;\n clearTimeout(this.keyboardProtocolBufferFlushTimer);\n this.keyboardProtocolBufferFlushTimer = undefined;\n }\n forwardInputSequence(sequence) {\n if (!this.inputHandler)\n return;\n const isAppleTerminal = sequence === \"\\r\" && isAppleTerminalSession();\n const input = normalizeAppleTerminalInput(sequence, isAppleTerminal, isAppleTerminal && isNativeModifierPressed(\"shift\"));\n this.inputHandler(input);\n }\n enableModifyOtherKeys() {\n if (this._kittyProtocolActive || this._modifyOtherKeysActive)\n return;\n process.stdout.write(\"\\x1b[>4;2m\");\n this._modifyOtherKeysActive = true;\n }\n disableModifyOtherKeys() {\n if (!this._modifyOtherKeysActive)\n return;\n process.stdout.write(\"\\x1b[>4;0m\");\n this._modifyOtherKeysActive = false;\n }\n /**\n * On Windows, add ENABLE_VIRTUAL_TERMINAL_INPUT (0x0200) to the stdin\n * console handle so the terminal sends VT sequences for modified keys\n * (e.g. \\x1b[Z for Shift+Tab). Without this, libuv's ReadConsoleInputW\n * discards modifier state and Shift+Tab arrives as plain \\t.\n */\n enableWindowsVTInput() {\n if (process.platform !== \"win32\")\n return;\n try {\n const arch = process.arch;\n if (arch !== \"x64\" && arch !== \"arm64\")\n return;\n // Dynamic require so non-Windows and bundled/browser paths never load the\n // native helper. In the npm package native/ is next to dist/; in compiled\n // binary archives native/ is copied next to the executable.\n const moduleDir = path.dirname(fileURLToPath(import.meta.url));\n const nativePath = path.join(\"native\", \"win32\", \"prebuilds\", `win32-${arch}`, \"win32-console-mode.node\");\n const candidates = [\n path.join(moduleDir, \"..\", nativePath),\n path.join(moduleDir, nativePath),\n path.join(path.dirname(process.execPath), nativePath),\n ];\n for (const modulePath of candidates) {\n try {\n const helper = cjsRequire(modulePath);\n helper.enableVirtualTerminalInput?.();\n return;\n }\n catch {\n // Try the next possible packaging location.\n }\n }\n }\n catch {\n // Native helper not available — Shift+Tab won't be distinguishable from Tab.\n }\n }\n async drainInput(maxMs = 1000, idleMs = 50) {\n const shouldDisableKittyProtocol = this.keyboardProtocolPushed || this._kittyProtocolActive;\n this.clearKeyboardProtocolNegotiationBuffer();\n if (shouldDisableKittyProtocol) {\n // Disable Kitty keyboard protocol first so any late key releases\n // do not generate new Kitty escape sequences.\n process.stdout.write(\"\\x1b[<u\");\n this.keyboardProtocolPushed = false;\n this._kittyProtocolActive = false;\n setKittyProtocolActive(false);\n }\n this.disableModifyOtherKeys();\n const previousHandler = this.inputHandler;\n this.inputHandler = undefined;\n let lastDataTime = Date.now();\n const onData = () => {\n lastDataTime = Date.now();\n };\n process.stdin.on(\"data\", onData);\n const endTime = Date.now() + maxMs;\n try {\n while (true) {\n const now = Date.now();\n const timeLeft = endTime - now;\n if (timeLeft <= 0)\n break;\n if (now - lastDataTime >= idleMs)\n break;\n await new Promise((resolve) => setTimeout(resolve, Math.min(idleMs, timeLeft)));\n }\n }\n finally {\n process.stdin.removeListener(\"data\", onData);\n this.inputHandler = previousHandler;\n }\n }\n stop() {\n if (this.clearProgressInterval()) {\n process.stdout.write(TERMINAL_PROGRESS_CLEAR_SEQUENCE);\n }\n // Disable bracketed paste mode\n process.stdout.write(\"\\x1b[?2004l\");\n const shouldDisableKittyProtocol = this.keyboardProtocolPushed || this._kittyProtocolActive;\n this.clearKeyboardProtocolNegotiationBuffer();\n // Disable Kitty keyboard protocol if not already done by drainInput()\n if (shouldDisableKittyProtocol) {\n process.stdout.write(\"\\x1b[<u\");\n this.keyboardProtocolPushed = false;\n this._kittyProtocolActive = false;\n setKittyProtocolActive(false);\n }\n this.disableModifyOtherKeys();\n // Clean up StdinBuffer\n if (this.stdinBuffer) {\n this.stdinBuffer.destroy();\n this.stdinBuffer = undefined;\n }\n // Remove event handlers\n if (this.stdinDataHandler) {\n process.stdin.removeListener(\"data\", this.stdinDataHandler);\n this.stdinDataHandler = undefined;\n }\n this.inputHandler = undefined;\n if (this.resizeHandler) {\n process.stdout.removeListener(\"resize\", this.resizeHandler);\n this.resizeHandler = undefined;\n }\n // Pause stdin to prevent any buffered input (e.g., Ctrl+D) from being\n // re-interpreted after raw mode is disabled. This fixes a race condition\n // where Ctrl+D could close the parent shell over SSH.\n process.stdin.pause();\n // Restore raw mode state\n if (process.stdin.setRawMode) {\n process.stdin.setRawMode(this.wasRaw);\n }\n }\n write(data) {\n process.stdout.write(data);\n if (this.writeLogPath) {\n try {\n fs.appendFileSync(this.writeLogPath, data, { encoding: \"utf8\" });\n }\n catch {\n // Ignore logging errors\n }\n }\n }\n get columns() {\n return process.stdout.columns || Number(process.env.COLUMNS) || 80;\n }\n get rows() {\n return process.stdout.rows || Number(process.env.LINES) || 24;\n }\n moveBy(lines) {\n if (lines > 0) {\n // Move down\n process.stdout.write(`\\x1b[${lines}B`);\n }\n else if (lines < 0) {\n // Move up\n process.stdout.write(`\\x1b[${-lines}A`);\n }\n // lines === 0: no movement\n }\n hideCursor() {\n process.stdout.write(\"\\x1b[?25l\");\n }\n showCursor() {\n process.stdout.write(\"\\x1b[?25h\");\n }\n clearLine() {\n process.stdout.write(\"\\x1b[K\");\n }\n clearFromCursor() {\n process.stdout.write(\"\\x1b[J\");\n }\n clearScreen() {\n process.stdout.write(\"\\x1b[2J\\x1b[H\"); // Clear screen and move to home (1,1)\n }\n setTitle(title) {\n // OSC 0;title BEL - set terminal window title\n process.stdout.write(`\\x1b]0;${title}\\x07`);\n }\n setProgress(active) {\n if (active) {\n // OSC 9;4;3 - indeterminate progress\n process.stdout.write(TERMINAL_PROGRESS_ACTIVE_SEQUENCE);\n if (!this.progressInterval) {\n this.progressInterval = setInterval(() => {\n process.stdout.write(TERMINAL_PROGRESS_ACTIVE_SEQUENCE);\n }, TERMINAL_PROGRESS_KEEPALIVE_MS);\n }\n }\n else {\n this.clearProgressInterval();\n // OSC 9;4;0 - clear progress\n process.stdout.write(TERMINAL_PROGRESS_CLEAR_SEQUENCE);\n }\n }\n clearProgressInterval() {\n if (!this.progressInterval)\n return false;\n clearInterval(this.progressInterval);\n this.progressInterval = undefined;\n return true;\n }\n}\n//# sourceMappingURL=terminal.js.map","import type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent'\nimport * as NodeServices from '@effect/platform-node/NodeServices'\nimport { loadExtensionConfig, setStatuslineSegment } from '@pi-plugins/shared'\nimport {\n Array,\n Data,\n Effect,\n Match,\n pipe,\n Predicate,\n Record,\n Schema,\n String,\n} from 'effect'\n\nconst EXTENSION_ID = 'fast-mode'\nconst COMMAND_ARGS = ['on', 'off', 'status'] as const\n/** Status-line segment shown above the editor while fast mode is active. */\nconst SEGMENT_KEY = EXTENSION_ID\nconst SEGMENT_LABEL = '[fast mode]'\n\nconst FastModeConfig = Schema.Struct({\n enabled: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(false))),\n /** `provider/model-id` keys that fast mode applies to. */\n models: Schema.Array(Schema.String).pipe(\n Schema.withDecodingDefault(\n Effect.succeed([\n 'openai/gpt-5.4',\n 'openai/gpt-5.5',\n 'openai/gpt-5.6-sol',\n 'openai/gpt-5.6-terra',\n 'openai/gpt-5.6-luna',\n 'openai-codex/gpt-5.4',\n 'openai-codex/gpt-5.5',\n 'openai-codex/gpt-5.6-sol',\n 'openai-codex/gpt-5.6-terra',\n 'openai-codex/gpt-5.6-luna',\n ]),\n ),\n ),\n /** Show a `fast mode` indicator above the editor while active. */\n showStatus: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(true))),\n})\ntype FastModeConfig = typeof FastModeConfig.Type\n\ntype ActiveModel = NonNullable<ExtensionContext['model']>\ntype FastModeApi = 'openai-responses' | 'openai-codex-responses'\n\nfunction modelKey(model: ActiveModel): string {\n return `${model.provider}/${model.id}`\n}\n\n/**\n * Rewrites a provider request payload to ask for fast inference, returning the\n * replacement payload — or `undefined` to leave the request untouched.\n */\ntype Applicator = (\n payload: Record<string, unknown>,\n model: ActiveModel,\n) => Record<string, unknown> | undefined\n\n/** Whether fast mode can apply to the active model. */\ntype Eligibility = Data.TaggedEnum<{\n Eligible: { readonly apply: Applicator }\n Ineligible: { readonly message: string }\n}>\nconst Eligibility = Data.taggedEnum<Eligibility>()\n\nconst FAST_APPLICATORS: Record<string, Applicator> = {\n 'openai-responses': applyOpenAIPriorityTier,\n 'openai-codex-responses': applyOpenAIPriorityTier,\n} satisfies Record<FastModeApi, Applicator>\n\nfunction applyOpenAIPriorityTier(\n payload: Record<string, unknown>,\n): Record<string, unknown> | undefined {\n // If the request already has a `service_tier`, leave it untouched.\n return Record.has(payload, 'service_tier')\n ? undefined\n : { ...payload, service_tier: 'priority' }\n}\n\nexport default function fastMode(pi: ExtensionAPI) {\n let config = Schema.decodeUnknownSync(FastModeConfig)({})\n let enabled = false\n\n function checkEligibility(model: ExtensionContext['model']): Eligibility {\n if (!model) {\n return Eligibility.Ineligible({ message: 'no model is selected' })\n }\n\n const key = modelKey(model)\n if (!config.models.includes(key)) {\n return Eligibility.Ineligible({\n message: `${key} is not in the configured models`,\n })\n }\n\n const apply = FAST_APPLICATORS[model.api]\n if (!apply) {\n return Eligibility.Ineligible({\n message: `the ${model.api} API has no fast-mode support`,\n })\n }\n\n return Eligibility.Eligible({ apply })\n }\n\n function updateStatus(ctx: ExtensionContext): void {\n if (!ctx.hasUI) {\n return\n }\n\n const active =\n config.showStatus &&\n enabled &&\n Eligibility.$is('Eligible')(checkEligibility(ctx.model))\n\n setStatuslineSegment(\n ctx,\n SEGMENT_KEY,\n active ? { text: SEGMENT_LABEL, align: 'right' } : undefined,\n )\n }\n\n function notifyState(ctx: ExtensionContext): void {\n const model = ctx.model\n const name = model?.name ?? '(none)'\n const message = !enabled\n ? `Fast mode is off. Current model: ${name}.`\n : Eligibility.$match(checkEligibility(model), {\n Eligible: () => `Fast mode is on for ${name}.`,\n Ineligible: ({ message: reason }) => {\n const models = config.models.join(', ') || 'none'\n return `Fast mode is on, but inactive: ${reason}. Configured models: ${models}.`\n },\n })\n\n ctx.ui.notify(message, 'info')\n }\n\n pi.on('session_start', async (_event, ctx) => {\n config = await Effect.runPromise(\n loadExtensionConfig(FastModeConfig, EXTENSION_ID).pipe(\n Effect.orElseSucceed(() => config),\n Effect.provide(NodeServices.layer),\n ),\n )\n enabled = pi.getFlag('fast') === true || config.enabled\n updateStatus(ctx)\n })\n\n pi.on('model_select', (_event, ctx) => {\n updateStatus(ctx)\n })\n\n pi.on('before_provider_request', (event, ctx) => {\n const model = ctx.model\n if (!enabled || !model) {\n return undefined\n }\n\n const eligibility = checkEligibility(model)\n if (\n Eligibility.$is('Ineligible')(eligibility) ||\n !Predicate.isObject(event.payload) ||\n event.payload['model'] !== model.id\n ) {\n return undefined\n }\n\n return eligibility.apply(event.payload, model)\n })\n\n pi.registerFlag('fast', {\n description: 'Start with fast mode enabled',\n type: 'boolean',\n default: false,\n })\n\n pi.registerCommand('fast', {\n description:\n 'Toggle fast mode (faster, costlier inference) for configured models',\n getArgumentCompletions: (prefix) => {\n const items = pipe(\n COMMAND_ARGS,\n Array.filter(String.startsWith(prefix)),\n Array.map((arg) => ({ value: arg, label: arg })),\n )\n\n return Array.match(items, {\n onNonEmpty: (matched) => [...matched],\n onEmpty: () => null,\n })\n },\n handler: async (args, ctx) => {\n Match.value(args.trim().toLowerCase()).pipe(\n Match.whenOr('', 'on', 'off', (cmd) => {\n enabled = cmd === '' ? !enabled : cmd === 'on'\n updateStatus(ctx)\n notifyState(ctx)\n }),\n Match.when('status', () => notifyState(ctx)),\n Match.orElse(() => ctx.ui.notify('Usage: /fast [on|off|status]', 'warning')),\n )\n },\n })\n}\n"],"x_google_ignoreList":[2,3,4,5,6,7,8,9,10],"mappings":"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"}
|