@draht/tui 2026.3.2-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 +761 -0
- package/dist/autocomplete.d.ts +50 -0
- package/dist/autocomplete.d.ts.map +1 -0
- package/dist/autocomplete.js +596 -0
- package/dist/autocomplete.js.map +1 -0
- package/dist/components/box.d.ts +22 -0
- package/dist/components/box.d.ts.map +1 -0
- package/dist/components/box.js +104 -0
- package/dist/components/box.js.map +1 -0
- package/dist/components/cancellable-loader.d.ts +22 -0
- package/dist/components/cancellable-loader.d.ts.map +1 -0
- package/dist/components/cancellable-loader.js +35 -0
- package/dist/components/cancellable-loader.js.map +1 -0
- package/dist/components/editor.d.ts +205 -0
- package/dist/components/editor.d.ts.map +1 -0
- package/dist/components/editor.js +1679 -0
- package/dist/components/editor.js.map +1 -0
- package/dist/components/image.d.ts +28 -0
- package/dist/components/image.d.ts.map +1 -0
- package/dist/components/image.js +69 -0
- package/dist/components/image.js.map +1 -0
- package/dist/components/input.d.ts +37 -0
- package/dist/components/input.d.ts.map +1 -0
- package/dist/components/input.js +433 -0
- package/dist/components/input.js.map +1 -0
- package/dist/components/loader.d.ts +21 -0
- package/dist/components/loader.d.ts.map +1 -0
- package/dist/components/loader.js +49 -0
- package/dist/components/loader.js.map +1 -0
- package/dist/components/markdown.d.ts +95 -0
- package/dist/components/markdown.d.ts.map +1 -0
- package/dist/components/markdown.js +629 -0
- package/dist/components/markdown.js.map +1 -0
- package/dist/components/select-list.d.ts +32 -0
- package/dist/components/select-list.d.ts.map +1 -0
- package/dist/components/select-list.js +152 -0
- package/dist/components/select-list.js.map +1 -0
- package/dist/components/settings-list.d.ts +50 -0
- package/dist/components/settings-list.d.ts.map +1 -0
- package/dist/components/settings-list.js +185 -0
- package/dist/components/settings-list.js.map +1 -0
- package/dist/components/spacer.d.ts +12 -0
- package/dist/components/spacer.d.ts.map +1 -0
- package/dist/components/spacer.js +23 -0
- package/dist/components/spacer.js.map +1 -0
- package/dist/components/text.d.ts +19 -0
- package/dist/components/text.d.ts.map +1 -0
- package/dist/components/text.js +89 -0
- package/dist/components/text.js.map +1 -0
- package/dist/components/truncated-text.d.ts +13 -0
- package/dist/components/truncated-text.d.ts.map +1 -0
- package/dist/components/truncated-text.js +51 -0
- package/dist/components/truncated-text.js.map +1 -0
- package/dist/editor-component.d.ts +39 -0
- package/dist/editor-component.d.ts.map +1 -0
- package/dist/editor-component.js +2 -0
- package/dist/editor-component.js.map +1 -0
- package/dist/fuzzy.d.ts +16 -0
- package/dist/fuzzy.d.ts.map +1 -0
- package/dist/fuzzy.js +107 -0
- package/dist/fuzzy.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/keybindings.d.ts +39 -0
- package/dist/keybindings.d.ts.map +1 -0
- package/dist/keybindings.js +114 -0
- package/dist/keybindings.js.map +1 -0
- package/dist/keys.d.ts +160 -0
- package/dist/keys.d.ts.map +1 -0
- package/dist/keys.js +959 -0
- package/dist/keys.js.map +1 -0
- package/dist/kill-ring.d.ts +28 -0
- package/dist/kill-ring.d.ts.map +1 -0
- package/dist/kill-ring.js +44 -0
- package/dist/kill-ring.js.map +1 -0
- package/dist/stdin-buffer.d.ts +48 -0
- package/dist/stdin-buffer.d.ts.map +1 -0
- package/dist/stdin-buffer.js +317 -0
- package/dist/stdin-buffer.js.map +1 -0
- package/dist/terminal-image.d.ts +68 -0
- package/dist/terminal-image.d.ts.map +1 -0
- package/dist/terminal-image.js +288 -0
- package/dist/terminal-image.js.map +1 -0
- package/dist/terminal.d.ts +78 -0
- package/dist/terminal.d.ts.map +1 -0
- package/dist/terminal.js +249 -0
- package/dist/terminal.js.map +1 -0
- package/dist/tui.d.ts +210 -0
- package/dist/tui.d.ts.map +1 -0
- package/dist/tui.js +955 -0
- package/dist/tui.js.map +1 -0
- package/dist/undo-stack.d.ts +17 -0
- package/dist/undo-stack.d.ts.map +1 -0
- package/dist/undo-stack.js +25 -0
- package/dist/undo-stack.js.map +1 -0
- package/dist/utils.d.ts +78 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +800 -0
- package/dist/utils.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/components/markdown.ts"],"names":[],"mappings":"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","sourcesContent":["import { marked, type Token } from \"marked\";\nimport { isImageLine } from \"../terminal-image.js\";\nimport type { Component } from \"../tui.js\";\nimport { applyBackgroundToLine, visibleWidth, wrapTextWithAnsi } from \"../utils.js\";\n\n/**\n * Default text styling for markdown content.\n * Applied to all text unless overridden by markdown formatting.\n */\nexport interface DefaultTextStyle {\n\t/** Foreground color function */\n\tcolor?: (text: string) => string;\n\t/** Background color function */\n\tbgColor?: (text: string) => string;\n\t/** Bold text */\n\tbold?: boolean;\n\t/** Italic text */\n\titalic?: boolean;\n\t/** Strikethrough text */\n\tstrikethrough?: boolean;\n\t/** Underline text */\n\tunderline?: boolean;\n}\n\n/**\n * Theme functions for markdown elements.\n * Each function takes text and returns styled text with ANSI codes.\n */\nexport interface MarkdownTheme {\n\theading: (text: string) => string;\n\tlink: (text: string) => string;\n\tlinkUrl: (text: string) => string;\n\tcode: (text: string) => string;\n\tcodeBlock: (text: string) => string;\n\tcodeBlockBorder: (text: string) => string;\n\tquote: (text: string) => string;\n\tquoteBorder: (text: string) => string;\n\thr: (text: string) => string;\n\tlistBullet: (text: string) => string;\n\tbold: (text: string) => string;\n\titalic: (text: string) => string;\n\tstrikethrough: (text: string) => string;\n\tunderline: (text: string) => string;\n\thighlightCode?: (code: string, lang?: string) => string[];\n\t/** Prefix applied to each rendered code block line (default: \" \") */\n\tcodeBlockIndent?: string;\n}\n\ninterface InlineStyleContext {\n\tapplyText: (text: string) => string;\n\tstylePrefix: string;\n}\n\nexport class Markdown implements Component {\n\tprivate text: string;\n\tprivate paddingX: number; // Left/right padding\n\tprivate paddingY: number; // Top/bottom padding\n\tprivate defaultTextStyle?: DefaultTextStyle;\n\tprivate theme: MarkdownTheme;\n\tprivate defaultStylePrefix?: string;\n\n\t// Cache for rendered output\n\tprivate cachedText?: string;\n\tprivate cachedWidth?: number;\n\tprivate cachedLines?: string[];\n\n\tconstructor(\n\t\ttext: string,\n\t\tpaddingX: number,\n\t\tpaddingY: number,\n\t\ttheme: MarkdownTheme,\n\t\tdefaultTextStyle?: DefaultTextStyle,\n\t) {\n\t\tthis.text = text;\n\t\tthis.paddingX = paddingX;\n\t\tthis.paddingY = paddingY;\n\t\tthis.theme = theme;\n\t\tthis.defaultTextStyle = defaultTextStyle;\n\t}\n\n\tsetText(text: string): void {\n\t\tthis.text = text;\n\t\tthis.invalidate();\n\t}\n\n\tinvalidate(): void {\n\t\tthis.cachedText = undefined;\n\t\tthis.cachedWidth = undefined;\n\t\tthis.cachedLines = undefined;\n\t}\n\n\trender(width: number): string[] {\n\t\t// Check cache\n\t\tif (this.cachedLines && this.cachedText === this.text && this.cachedWidth === width) {\n\t\t\treturn this.cachedLines;\n\t\t}\n\n\t\t// Calculate available width for content (subtract horizontal padding)\n\t\tconst contentWidth = Math.max(1, width - this.paddingX * 2);\n\n\t\t// Don't render anything if there's no actual text\n\t\tif (!this.text || this.text.trim() === \"\") {\n\t\t\tconst result: string[] = [];\n\t\t\t// Update cache\n\t\t\tthis.cachedText = this.text;\n\t\t\tthis.cachedWidth = width;\n\t\t\tthis.cachedLines = result;\n\t\t\treturn result;\n\t\t}\n\n\t\t// Replace tabs with 3 spaces for consistent rendering\n\t\tconst normalizedText = this.text.replace(/\\t/g, \" \");\n\n\t\t// Parse markdown to HTML-like tokens\n\t\tconst tokens = marked.lexer(normalizedText);\n\n\t\t// Convert tokens to styled terminal output\n\t\tconst renderedLines: string[] = [];\n\n\t\tfor (let i = 0; i < tokens.length; i++) {\n\t\t\tconst token = tokens[i];\n\t\t\tconst nextToken = tokens[i + 1];\n\t\t\tconst tokenLines = this.renderToken(token, contentWidth, nextToken?.type);\n\t\t\trenderedLines.push(...tokenLines);\n\t\t}\n\n\t\t// Wrap lines (NO padding, NO background yet)\n\t\tconst wrappedLines: string[] = [];\n\t\tfor (const line of renderedLines) {\n\t\t\tif (isImageLine(line)) {\n\t\t\t\twrappedLines.push(line);\n\t\t\t} else {\n\t\t\t\twrappedLines.push(...wrapTextWithAnsi(line, contentWidth));\n\t\t\t}\n\t\t}\n\n\t\t// Add margins and background to each wrapped line\n\t\tconst leftMargin = \" \".repeat(this.paddingX);\n\t\tconst rightMargin = \" \".repeat(this.paddingX);\n\t\tconst bgFn = this.defaultTextStyle?.bgColor;\n\t\tconst contentLines: string[] = [];\n\n\t\tfor (const line of wrappedLines) {\n\t\t\tif (isImageLine(line)) {\n\t\t\t\tcontentLines.push(line);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst lineWithMargins = leftMargin + line + rightMargin;\n\n\t\t\tif (bgFn) {\n\t\t\t\tcontentLines.push(applyBackgroundToLine(lineWithMargins, width, bgFn));\n\t\t\t} else {\n\t\t\t\t// No background - just pad to width\n\t\t\t\tconst visibleLen = visibleWidth(lineWithMargins);\n\t\t\t\tconst paddingNeeded = Math.max(0, width - visibleLen);\n\t\t\t\tcontentLines.push(lineWithMargins + \" \".repeat(paddingNeeded));\n\t\t\t}\n\t\t}\n\n\t\t// Add top/bottom padding (empty lines)\n\t\tconst emptyLine = \" \".repeat(width);\n\t\tconst emptyLines: string[] = [];\n\t\tfor (let i = 0; i < this.paddingY; i++) {\n\t\t\tconst line = bgFn ? applyBackgroundToLine(emptyLine, width, bgFn) : emptyLine;\n\t\t\temptyLines.push(line);\n\t\t}\n\n\t\t// Combine top padding, content, and bottom padding\n\t\tconst result = [...emptyLines, ...contentLines, ...emptyLines];\n\n\t\t// Update cache\n\t\tthis.cachedText = this.text;\n\t\tthis.cachedWidth = width;\n\t\tthis.cachedLines = result;\n\n\t\treturn result.length > 0 ? result : [\"\"];\n\t}\n\n\t/**\n\t * Apply default text style to a string.\n\t * This is the base styling applied to all text content.\n\t * NOTE: Background color is NOT applied here - it's applied at the padding stage\n\t * to ensure it extends to the full line width.\n\t */\n\tprivate applyDefaultStyle(text: string): string {\n\t\tif (!this.defaultTextStyle) {\n\t\t\treturn text;\n\t\t}\n\n\t\tlet styled = text;\n\n\t\t// Apply foreground color (NOT background - that's applied at padding stage)\n\t\tif (this.defaultTextStyle.color) {\n\t\t\tstyled = this.defaultTextStyle.color(styled);\n\t\t}\n\n\t\t// Apply text decorations using this.theme\n\t\tif (this.defaultTextStyle.bold) {\n\t\t\tstyled = this.theme.bold(styled);\n\t\t}\n\t\tif (this.defaultTextStyle.italic) {\n\t\t\tstyled = this.theme.italic(styled);\n\t\t}\n\t\tif (this.defaultTextStyle.strikethrough) {\n\t\t\tstyled = this.theme.strikethrough(styled);\n\t\t}\n\t\tif (this.defaultTextStyle.underline) {\n\t\t\tstyled = this.theme.underline(styled);\n\t\t}\n\n\t\treturn styled;\n\t}\n\n\tprivate getDefaultStylePrefix(): string {\n\t\tif (!this.defaultTextStyle) {\n\t\t\treturn \"\";\n\t\t}\n\n\t\tif (this.defaultStylePrefix !== undefined) {\n\t\t\treturn this.defaultStylePrefix;\n\t\t}\n\n\t\tconst sentinel = \"\\u0000\";\n\t\tlet styled = sentinel;\n\n\t\tif (this.defaultTextStyle.color) {\n\t\t\tstyled = this.defaultTextStyle.color(styled);\n\t\t}\n\n\t\tif (this.defaultTextStyle.bold) {\n\t\t\tstyled = this.theme.bold(styled);\n\t\t}\n\t\tif (this.defaultTextStyle.italic) {\n\t\t\tstyled = this.theme.italic(styled);\n\t\t}\n\t\tif (this.defaultTextStyle.strikethrough) {\n\t\t\tstyled = this.theme.strikethrough(styled);\n\t\t}\n\t\tif (this.defaultTextStyle.underline) {\n\t\t\tstyled = this.theme.underline(styled);\n\t\t}\n\n\t\tconst sentinelIndex = styled.indexOf(sentinel);\n\t\tthis.defaultStylePrefix = sentinelIndex >= 0 ? styled.slice(0, sentinelIndex) : \"\";\n\t\treturn this.defaultStylePrefix;\n\t}\n\n\tprivate getStylePrefix(styleFn: (text: string) => string): string {\n\t\tconst sentinel = \"\\u0000\";\n\t\tconst styled = styleFn(sentinel);\n\t\tconst sentinelIndex = styled.indexOf(sentinel);\n\t\treturn sentinelIndex >= 0 ? styled.slice(0, sentinelIndex) : \"\";\n\t}\n\n\tprivate getDefaultInlineStyleContext(): InlineStyleContext {\n\t\treturn {\n\t\t\tapplyText: (text: string) => this.applyDefaultStyle(text),\n\t\t\tstylePrefix: this.getDefaultStylePrefix(),\n\t\t};\n\t}\n\n\tprivate renderToken(token: Token, width: number, nextTokenType?: string): string[] {\n\t\tconst lines: string[] = [];\n\n\t\tswitch (token.type) {\n\t\t\tcase \"heading\": {\n\t\t\t\tconst headingLevel = token.depth;\n\t\t\t\tconst headingPrefix = `${\"#\".repeat(headingLevel)} `;\n\t\t\t\tconst headingText = this.renderInlineTokens(token.tokens || []);\n\t\t\t\tlet styledHeading: string;\n\t\t\t\tif (headingLevel === 1) {\n\t\t\t\t\tstyledHeading = this.theme.heading(this.theme.bold(this.theme.underline(headingText)));\n\t\t\t\t} else if (headingLevel === 2) {\n\t\t\t\t\tstyledHeading = this.theme.heading(this.theme.bold(headingText));\n\t\t\t\t} else {\n\t\t\t\t\tstyledHeading = this.theme.heading(this.theme.bold(headingPrefix + headingText));\n\t\t\t\t}\n\t\t\t\tlines.push(styledHeading);\n\t\t\t\tif (nextTokenType !== \"space\") {\n\t\t\t\t\tlines.push(\"\"); // Add spacing after headings (unless space token follows)\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"paragraph\": {\n\t\t\t\tconst paragraphText = this.renderInlineTokens(token.tokens || []);\n\t\t\t\tlines.push(paragraphText);\n\t\t\t\t// Don't add spacing if next token is space or list\n\t\t\t\tif (nextTokenType && nextTokenType !== \"list\" && nextTokenType !== \"space\") {\n\t\t\t\t\tlines.push(\"\");\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"code\": {\n\t\t\t\tconst indent = this.theme.codeBlockIndent ?? \" \";\n\t\t\t\tlines.push(this.theme.codeBlockBorder(`\\`\\`\\`${token.lang || \"\"}`));\n\t\t\t\tif (this.theme.highlightCode) {\n\t\t\t\t\tconst highlightedLines = this.theme.highlightCode(token.text, token.lang);\n\t\t\t\t\tfor (const hlLine of highlightedLines) {\n\t\t\t\t\t\tlines.push(`${indent}${hlLine}`);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Split code by newlines and style each line\n\t\t\t\t\tconst codeLines = token.text.split(\"\\n\");\n\t\t\t\t\tfor (const codeLine of codeLines) {\n\t\t\t\t\t\tlines.push(`${indent}${this.theme.codeBlock(codeLine)}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlines.push(this.theme.codeBlockBorder(\"```\"));\n\t\t\t\tif (nextTokenType !== \"space\") {\n\t\t\t\t\tlines.push(\"\"); // Add spacing after code blocks (unless space token follows)\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"list\": {\n\t\t\t\tconst listLines = this.renderList(token as any, 0);\n\t\t\t\tlines.push(...listLines);\n\t\t\t\t// Don't add spacing after lists if a space token follows\n\t\t\t\t// (the space token will handle it)\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"table\": {\n\t\t\t\tconst tableLines = this.renderTable(token as any, width);\n\t\t\t\tlines.push(...tableLines);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"blockquote\": {\n\t\t\t\tconst quoteStyle = (text: string) => this.theme.quote(this.theme.italic(text));\n\t\t\t\tconst quoteStyleContext: InlineStyleContext = {\n\t\t\t\t\tapplyText: quoteStyle,\n\t\t\t\t\tstylePrefix: this.getStylePrefix(quoteStyle),\n\t\t\t\t};\n\t\t\t\tconst quoteText = this.renderInlineTokens(token.tokens || [], quoteStyleContext);\n\t\t\t\tconst quoteLines = quoteText.split(\"\\n\");\n\n\t\t\t\t// Calculate available width for quote content (subtract border \"│ \" = 2 chars)\n\t\t\t\tconst quoteContentWidth = Math.max(1, width - 2);\n\n\t\t\t\tfor (const quoteLine of quoteLines) {\n\t\t\t\t\t// Wrap the styled line, then add border to each wrapped line\n\t\t\t\t\tconst wrappedLines = wrapTextWithAnsi(quoteLine, quoteContentWidth);\n\t\t\t\t\tfor (const wrappedLine of wrappedLines) {\n\t\t\t\t\t\tlines.push(this.theme.quoteBorder(\"│ \") + wrappedLine);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (nextTokenType !== \"space\") {\n\t\t\t\t\tlines.push(\"\"); // Add spacing after blockquotes (unless space token follows)\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"hr\":\n\t\t\t\tlines.push(this.theme.hr(\"─\".repeat(Math.min(width, 80))));\n\t\t\t\tif (nextTokenType !== \"space\") {\n\t\t\t\t\tlines.push(\"\"); // Add spacing after horizontal rules (unless space token follows)\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase \"html\":\n\t\t\t\t// Render HTML as plain text (escaped for terminal)\n\t\t\t\tif (\"raw\" in token && typeof token.raw === \"string\") {\n\t\t\t\t\tlines.push(this.applyDefaultStyle(token.raw.trim()));\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase \"space\":\n\t\t\t\t// Space tokens represent blank lines in markdown\n\t\t\t\tlines.push(\"\");\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\t// Handle any other token types as plain text\n\t\t\t\tif (\"text\" in token && typeof token.text === \"string\") {\n\t\t\t\t\tlines.push(token.text);\n\t\t\t\t}\n\t\t}\n\n\t\treturn lines;\n\t}\n\n\tprivate renderInlineTokens(tokens: Token[], styleContext?: InlineStyleContext): string {\n\t\tlet result = \"\";\n\t\tconst resolvedStyleContext = styleContext ?? this.getDefaultInlineStyleContext();\n\t\tconst { applyText, stylePrefix } = resolvedStyleContext;\n\t\tconst applyTextWithNewlines = (text: string): string => {\n\t\t\tconst segments: string[] = text.split(\"\\n\");\n\t\t\treturn segments.map((segment: string) => applyText(segment)).join(\"\\n\");\n\t\t};\n\n\t\tfor (const token of tokens) {\n\t\t\tswitch (token.type) {\n\t\t\t\tcase \"text\":\n\t\t\t\t\t// Text tokens in list items can have nested tokens for inline formatting\n\t\t\t\t\tif (token.tokens && token.tokens.length > 0) {\n\t\t\t\t\t\tresult += this.renderInlineTokens(token.tokens, resolvedStyleContext);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult += applyTextWithNewlines(token.text);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase \"paragraph\":\n\t\t\t\t\t// Paragraph tokens contain nested inline tokens\n\t\t\t\t\tresult += this.renderInlineTokens(token.tokens || [], resolvedStyleContext);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase \"strong\": {\n\t\t\t\t\tconst boldContent = this.renderInlineTokens(token.tokens || [], resolvedStyleContext);\n\t\t\t\t\tresult += this.theme.bold(boldContent) + stylePrefix;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"em\": {\n\t\t\t\t\tconst italicContent = this.renderInlineTokens(token.tokens || [], resolvedStyleContext);\n\t\t\t\t\tresult += this.theme.italic(italicContent) + stylePrefix;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"codespan\":\n\t\t\t\t\tresult += this.theme.code(token.text) + stylePrefix;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase \"link\": {\n\t\t\t\t\tconst linkText = this.renderInlineTokens(token.tokens || [], resolvedStyleContext);\n\t\t\t\t\t// If link text matches href, only show the link once\n\t\t\t\t\t// Compare raw text (token.text) not styled text (linkText) since linkText has ANSI codes\n\t\t\t\t\t// For mailto: links, strip the prefix before comparing (autolinked emails have\n\t\t\t\t\t// text=\"foo@bar.com\" but href=\"mailto:foo@bar.com\")\n\t\t\t\t\tconst hrefForComparison = token.href.startsWith(\"mailto:\") ? token.href.slice(7) : token.href;\n\t\t\t\t\tif (token.text === token.href || token.text === hrefForComparison) {\n\t\t\t\t\t\tresult += this.theme.link(this.theme.underline(linkText)) + stylePrefix;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult +=\n\t\t\t\t\t\t\tthis.theme.link(this.theme.underline(linkText)) +\n\t\t\t\t\t\t\tthis.theme.linkUrl(` (${token.href})`) +\n\t\t\t\t\t\t\tstylePrefix;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"br\":\n\t\t\t\t\tresult += \"\\n\";\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase \"del\": {\n\t\t\t\t\tconst delContent = this.renderInlineTokens(token.tokens || [], resolvedStyleContext);\n\t\t\t\t\tresult += this.theme.strikethrough(delContent) + stylePrefix;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"html\":\n\t\t\t\t\t// Render inline HTML as plain text\n\t\t\t\t\tif (\"raw\" in token && typeof token.raw === \"string\") {\n\t\t\t\t\t\tresult += applyTextWithNewlines(token.raw);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\t// Handle any other inline token types as plain text\n\t\t\t\t\tif (\"text\" in token && typeof token.text === \"string\") {\n\t\t\t\t\t\tresult += applyTextWithNewlines(token.text);\n\t\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Render a list with proper nesting support\n\t */\n\tprivate renderList(token: Token & { items: any[]; ordered: boolean; start?: number }, depth: number): string[] {\n\t\tconst lines: string[] = [];\n\t\tconst indent = \" \".repeat(depth);\n\t\t// Use the list's start property (defaults to 1 for ordered lists)\n\t\tconst startNumber = token.start ?? 1;\n\n\t\tfor (let i = 0; i < token.items.length; i++) {\n\t\t\tconst item = token.items[i];\n\t\t\tconst bullet = token.ordered ? `${startNumber + i}. ` : \"- \";\n\n\t\t\t// Process item tokens to handle nested lists\n\t\t\tconst itemLines = this.renderListItem(item.tokens || [], depth);\n\n\t\t\tif (itemLines.length > 0) {\n\t\t\t\t// First line - check if it's a nested list\n\t\t\t\t// A nested list will start with indent (spaces) followed by cyan bullet\n\t\t\t\tconst firstLine = itemLines[0];\n\t\t\t\tconst isNestedList = /^\\s+\\x1b\\[36m[-\\d]/.test(firstLine); // starts with spaces + cyan + bullet char\n\n\t\t\t\tif (isNestedList) {\n\t\t\t\t\t// This is a nested list, just add it as-is (already has full indent)\n\t\t\t\t\tlines.push(firstLine);\n\t\t\t\t} else {\n\t\t\t\t\t// Regular text content - add indent and bullet\n\t\t\t\t\tlines.push(indent + this.theme.listBullet(bullet) + firstLine);\n\t\t\t\t}\n\n\t\t\t\t// Rest of the lines\n\t\t\t\tfor (let j = 1; j < itemLines.length; j++) {\n\t\t\t\t\tconst line = itemLines[j];\n\t\t\t\t\tconst isNestedListLine = /^\\s+\\x1b\\[36m[-\\d]/.test(line); // starts with spaces + cyan + bullet char\n\n\t\t\t\t\tif (isNestedListLine) {\n\t\t\t\t\t\t// Nested list line - already has full indent\n\t\t\t\t\t\tlines.push(line);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Regular content - add parent indent + 2 spaces for continuation\n\t\t\t\t\t\tlines.push(`${indent} ${line}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlines.push(indent + this.theme.listBullet(bullet));\n\t\t\t}\n\t\t}\n\n\t\treturn lines;\n\t}\n\n\t/**\n\t * Render list item tokens, handling nested lists\n\t * Returns lines WITHOUT the parent indent (renderList will add it)\n\t */\n\tprivate renderListItem(tokens: Token[], parentDepth: number): string[] {\n\t\tconst lines: string[] = [];\n\n\t\tfor (const token of tokens) {\n\t\t\tif (token.type === \"list\") {\n\t\t\t\t// Nested list - render with one additional indent level\n\t\t\t\t// These lines will have their own indent, so we just add them as-is\n\t\t\t\tconst nestedLines = this.renderList(token as any, parentDepth + 1);\n\t\t\t\tlines.push(...nestedLines);\n\t\t\t} else if (token.type === \"text\") {\n\t\t\t\t// Text content (may have inline tokens)\n\t\t\t\tconst text =\n\t\t\t\t\ttoken.tokens && token.tokens.length > 0 ? this.renderInlineTokens(token.tokens) : token.text || \"\";\n\t\t\t\tlines.push(text);\n\t\t\t} else if (token.type === \"paragraph\") {\n\t\t\t\t// Paragraph in list item\n\t\t\t\tconst text = this.renderInlineTokens(token.tokens || []);\n\t\t\t\tlines.push(text);\n\t\t\t} else if (token.type === \"code\") {\n\t\t\t\t// Code block in list item\n\t\t\t\tconst indent = this.theme.codeBlockIndent ?? \" \";\n\t\t\t\tlines.push(this.theme.codeBlockBorder(`\\`\\`\\`${token.lang || \"\"}`));\n\t\t\t\tif (this.theme.highlightCode) {\n\t\t\t\t\tconst highlightedLines = this.theme.highlightCode(token.text, token.lang);\n\t\t\t\t\tfor (const hlLine of highlightedLines) {\n\t\t\t\t\t\tlines.push(`${indent}${hlLine}`);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tconst codeLines = token.text.split(\"\\n\");\n\t\t\t\t\tfor (const codeLine of codeLines) {\n\t\t\t\t\t\tlines.push(`${indent}${this.theme.codeBlock(codeLine)}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlines.push(this.theme.codeBlockBorder(\"```\"));\n\t\t\t} else {\n\t\t\t\t// Other token types - try to render as inline\n\t\t\t\tconst text = this.renderInlineTokens([token]);\n\t\t\t\tif (text) {\n\t\t\t\t\tlines.push(text);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn lines;\n\t}\n\n\t/**\n\t * Get the visible width of the longest word in a string.\n\t */\n\tprivate getLongestWordWidth(text: string, maxWidth?: number): number {\n\t\tconst words = text.split(/\\s+/).filter((word) => word.length > 0);\n\t\tlet longest = 0;\n\t\tfor (const word of words) {\n\t\t\tlongest = Math.max(longest, visibleWidth(word));\n\t\t}\n\t\tif (maxWidth === undefined) {\n\t\t\treturn longest;\n\t\t}\n\t\treturn Math.min(longest, maxWidth);\n\t}\n\n\t/**\n\t * Wrap a table cell to fit into a column.\n\t *\n\t * Delegates to wrapTextWithAnsi() so ANSI codes + long tokens are handled\n\t * consistently with the rest of the renderer.\n\t */\n\tprivate wrapCellText(text: string, maxWidth: number): string[] {\n\t\treturn wrapTextWithAnsi(text, Math.max(1, maxWidth));\n\t}\n\n\t/**\n\t * Render a table with width-aware cell wrapping.\n\t * Cells that don't fit are wrapped to multiple lines.\n\t */\n\tprivate renderTable(\n\t\ttoken: Token & { header: any[]; rows: any[][]; raw?: string },\n\t\tavailableWidth: number,\n\t): string[] {\n\t\tconst lines: string[] = [];\n\t\tconst numCols = token.header.length;\n\n\t\tif (numCols === 0) {\n\t\t\treturn lines;\n\t\t}\n\n\t\t// Calculate border overhead: \"│ \" + (n-1) * \" │ \" + \" │\"\n\t\t// = 2 + (n-1) * 3 + 2 = 3n + 1\n\t\tconst borderOverhead = 3 * numCols + 1;\n\t\tconst availableForCells = availableWidth - borderOverhead;\n\t\tif (availableForCells < numCols) {\n\t\t\t// Too narrow to render a stable table. Fall back to raw markdown.\n\t\t\tconst fallbackLines = token.raw ? wrapTextWithAnsi(token.raw, availableWidth) : [];\n\t\t\tfallbackLines.push(\"\");\n\t\t\treturn fallbackLines;\n\t\t}\n\n\t\tconst maxUnbrokenWordWidth = 30;\n\n\t\t// Calculate natural column widths (what each column needs without constraints)\n\t\tconst naturalWidths: number[] = [];\n\t\tconst minWordWidths: number[] = [];\n\t\tfor (let i = 0; i < numCols; i++) {\n\t\t\tconst headerText = this.renderInlineTokens(token.header[i].tokens || []);\n\t\t\tnaturalWidths[i] = visibleWidth(headerText);\n\t\t\tminWordWidths[i] = Math.max(1, this.getLongestWordWidth(headerText, maxUnbrokenWordWidth));\n\t\t}\n\t\tfor (const row of token.rows) {\n\t\t\tfor (let i = 0; i < row.length; i++) {\n\t\t\t\tconst cellText = this.renderInlineTokens(row[i].tokens || []);\n\t\t\t\tnaturalWidths[i] = Math.max(naturalWidths[i] || 0, visibleWidth(cellText));\n\t\t\t\tminWordWidths[i] = Math.max(\n\t\t\t\t\tminWordWidths[i] || 1,\n\t\t\t\t\tthis.getLongestWordWidth(cellText, maxUnbrokenWordWidth),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tlet minColumnWidths = minWordWidths;\n\t\tlet minCellsWidth = minColumnWidths.reduce((a, b) => a + b, 0);\n\n\t\tif (minCellsWidth > availableForCells) {\n\t\t\tminColumnWidths = new Array(numCols).fill(1);\n\t\t\tconst remaining = availableForCells - numCols;\n\n\t\t\tif (remaining > 0) {\n\t\t\t\tconst totalWeight = minWordWidths.reduce((total, width) => total + Math.max(0, width - 1), 0);\n\t\t\t\tconst growth = minWordWidths.map((width) => {\n\t\t\t\t\tconst weight = Math.max(0, width - 1);\n\t\t\t\t\treturn totalWeight > 0 ? Math.floor((weight / totalWeight) * remaining) : 0;\n\t\t\t\t});\n\n\t\t\t\tfor (let i = 0; i < numCols; i++) {\n\t\t\t\t\tminColumnWidths[i] += growth[i] ?? 0;\n\t\t\t\t}\n\n\t\t\t\tconst allocated = growth.reduce((total, width) => total + width, 0);\n\t\t\t\tlet leftover = remaining - allocated;\n\t\t\t\tfor (let i = 0; leftover > 0 && i < numCols; i++) {\n\t\t\t\t\tminColumnWidths[i]++;\n\t\t\t\t\tleftover--;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tminCellsWidth = minColumnWidths.reduce((a, b) => a + b, 0);\n\t\t}\n\n\t\t// Calculate column widths that fit within available width\n\t\tconst totalNaturalWidth = naturalWidths.reduce((a, b) => a + b, 0) + borderOverhead;\n\t\tlet columnWidths: number[];\n\n\t\tif (totalNaturalWidth <= availableWidth) {\n\t\t\t// Everything fits naturally\n\t\t\tcolumnWidths = naturalWidths.map((width, index) => Math.max(width, minColumnWidths[index]));\n\t\t} else {\n\t\t\t// Need to shrink columns to fit\n\t\t\tconst totalGrowPotential = naturalWidths.reduce((total, width, index) => {\n\t\t\t\treturn total + Math.max(0, width - minColumnWidths[index]);\n\t\t\t}, 0);\n\t\t\tconst extraWidth = Math.max(0, availableForCells - minCellsWidth);\n\t\t\tcolumnWidths = minColumnWidths.map((minWidth, index) => {\n\t\t\t\tconst naturalWidth = naturalWidths[index];\n\t\t\t\tconst minWidthDelta = Math.max(0, naturalWidth - minWidth);\n\t\t\t\tlet grow = 0;\n\t\t\t\tif (totalGrowPotential > 0) {\n\t\t\t\t\tgrow = Math.floor((minWidthDelta / totalGrowPotential) * extraWidth);\n\t\t\t\t}\n\t\t\t\treturn minWidth + grow;\n\t\t\t});\n\n\t\t\t// Adjust for rounding errors - distribute remaining space\n\t\t\tconst allocated = columnWidths.reduce((a, b) => a + b, 0);\n\t\t\tlet remaining = availableForCells - allocated;\n\t\t\twhile (remaining > 0) {\n\t\t\t\tlet grew = false;\n\t\t\t\tfor (let i = 0; i < numCols && remaining > 0; i++) {\n\t\t\t\t\tif (columnWidths[i] < naturalWidths[i]) {\n\t\t\t\t\t\tcolumnWidths[i]++;\n\t\t\t\t\t\tremaining--;\n\t\t\t\t\t\tgrew = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!grew) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Render top border\n\t\tconst topBorderCells = columnWidths.map((w) => \"─\".repeat(w));\n\t\tlines.push(`┌─${topBorderCells.join(\"─┬─\")}─┐`);\n\n\t\t// Render header with wrapping\n\t\tconst headerCellLines: string[][] = token.header.map((cell, i) => {\n\t\t\tconst text = this.renderInlineTokens(cell.tokens || []);\n\t\t\treturn this.wrapCellText(text, columnWidths[i]);\n\t\t});\n\t\tconst headerLineCount = Math.max(...headerCellLines.map((c) => c.length));\n\n\t\tfor (let lineIdx = 0; lineIdx < headerLineCount; lineIdx++) {\n\t\t\tconst rowParts = headerCellLines.map((cellLines, colIdx) => {\n\t\t\t\tconst text = cellLines[lineIdx] || \"\";\n\t\t\t\tconst padded = text + \" \".repeat(Math.max(0, columnWidths[colIdx] - visibleWidth(text)));\n\t\t\t\treturn this.theme.bold(padded);\n\t\t\t});\n\t\t\tlines.push(`│ ${rowParts.join(\" │ \")} │`);\n\t\t}\n\n\t\t// Render separator\n\t\tconst separatorCells = columnWidths.map((w) => \"─\".repeat(w));\n\t\tconst separatorLine = `├─${separatorCells.join(\"─┼─\")}─┤`;\n\t\tlines.push(separatorLine);\n\n\t\t// Render rows with wrapping\n\t\tfor (let rowIndex = 0; rowIndex < token.rows.length; rowIndex++) {\n\t\t\tconst row = token.rows[rowIndex];\n\t\t\tconst rowCellLines: string[][] = row.map((cell, i) => {\n\t\t\t\tconst text = this.renderInlineTokens(cell.tokens || []);\n\t\t\t\treturn this.wrapCellText(text, columnWidths[i]);\n\t\t\t});\n\t\t\tconst rowLineCount = Math.max(...rowCellLines.map((c) => c.length));\n\n\t\t\tfor (let lineIdx = 0; lineIdx < rowLineCount; lineIdx++) {\n\t\t\t\tconst rowParts = rowCellLines.map((cellLines, colIdx) => {\n\t\t\t\t\tconst text = cellLines[lineIdx] || \"\";\n\t\t\t\t\treturn text + \" \".repeat(Math.max(0, columnWidths[colIdx] - visibleWidth(text)));\n\t\t\t\t});\n\t\t\t\tlines.push(`│ ${rowParts.join(\" │ \")} │`);\n\t\t\t}\n\n\t\t\tif (rowIndex < token.rows.length - 1) {\n\t\t\t\tlines.push(separatorLine);\n\t\t\t}\n\t\t}\n\n\t\t// Render bottom border\n\t\tconst bottomBorderCells = columnWidths.map((w) => \"─\".repeat(w));\n\t\tlines.push(`└─${bottomBorderCells.join(\"─┴─\")}─┘`);\n\n\t\tlines.push(\"\"); // Add spacing after table\n\t\treturn lines;\n\t}\n}\n"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Component } from "../tui.js";
|
|
2
|
+
export interface SelectItem {
|
|
3
|
+
value: string;
|
|
4
|
+
label: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface SelectListTheme {
|
|
8
|
+
selectedPrefix: (text: string) => string;
|
|
9
|
+
selectedText: (text: string) => string;
|
|
10
|
+
description: (text: string) => string;
|
|
11
|
+
scrollInfo: (text: string) => string;
|
|
12
|
+
noMatch: (text: string) => string;
|
|
13
|
+
}
|
|
14
|
+
export declare class SelectList implements Component {
|
|
15
|
+
private items;
|
|
16
|
+
private filteredItems;
|
|
17
|
+
private selectedIndex;
|
|
18
|
+
private maxVisible;
|
|
19
|
+
private theme;
|
|
20
|
+
onSelect?: (item: SelectItem) => void;
|
|
21
|
+
onCancel?: () => void;
|
|
22
|
+
onSelectionChange?: (item: SelectItem) => void;
|
|
23
|
+
constructor(items: SelectItem[], maxVisible: number, theme: SelectListTheme);
|
|
24
|
+
setFilter(filter: string): void;
|
|
25
|
+
setSelectedIndex(index: number): void;
|
|
26
|
+
invalidate(): void;
|
|
27
|
+
render(width: number): string[];
|
|
28
|
+
handleInput(keyData: string): void;
|
|
29
|
+
private notifySelectionChange;
|
|
30
|
+
getSelectedItem(): SelectItem | null;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=select-list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select-list.d.ts","sourceRoot":"","sources":["../../src/components/select-list.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAK3C,MAAM,WAAW,UAAU;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC/B,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACzC,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACvC,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACtC,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACrC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CAClC;AAED,qBAAa,UAAW,YAAW,SAAS;IAC3C,OAAO,CAAC,KAAK,CAAoB;IACjC,OAAO,CAAC,aAAa,CAAoB;IACzC,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,KAAK,CAAkB;IAExB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;IAEtD,YAAY,KAAK,EAAE,UAAU,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,EAK1E;IAED,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAI9B;IAED,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAEpC;IAED,UAAU,IAAI,IAAI,CAEjB;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CA+F9B;IAED,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAyBjC;IAED,OAAO,CAAC,qBAAqB;IAO7B,eAAe,IAAI,UAAU,GAAG,IAAI,CAGnC;CACD","sourcesContent":["import { getEditorKeybindings } from \"../keybindings.js\";\nimport type { Component } from \"../tui.js\";\nimport { truncateToWidth } from \"../utils.js\";\n\nconst normalizeToSingleLine = (text: string): string => text.replace(/[\\r\\n]+/g, \" \").trim();\n\nexport interface SelectItem {\n\tvalue: string;\n\tlabel: string;\n\tdescription?: string;\n}\n\nexport interface SelectListTheme {\n\tselectedPrefix: (text: string) => string;\n\tselectedText: (text: string) => string;\n\tdescription: (text: string) => string;\n\tscrollInfo: (text: string) => string;\n\tnoMatch: (text: string) => string;\n}\n\nexport class SelectList implements Component {\n\tprivate items: SelectItem[] = [];\n\tprivate filteredItems: SelectItem[] = [];\n\tprivate selectedIndex: number = 0;\n\tprivate maxVisible: number = 5;\n\tprivate theme: SelectListTheme;\n\n\tpublic onSelect?: (item: SelectItem) => void;\n\tpublic onCancel?: () => void;\n\tpublic onSelectionChange?: (item: SelectItem) => void;\n\n\tconstructor(items: SelectItem[], maxVisible: number, theme: SelectListTheme) {\n\t\tthis.items = items;\n\t\tthis.filteredItems = items;\n\t\tthis.maxVisible = maxVisible;\n\t\tthis.theme = theme;\n\t}\n\n\tsetFilter(filter: string): void {\n\t\tthis.filteredItems = this.items.filter((item) => item.value.toLowerCase().startsWith(filter.toLowerCase()));\n\t\t// Reset selection when filter changes\n\t\tthis.selectedIndex = 0;\n\t}\n\n\tsetSelectedIndex(index: number): void {\n\t\tthis.selectedIndex = Math.max(0, Math.min(index, this.filteredItems.length - 1));\n\t}\n\n\tinvalidate(): void {\n\t\t// No cached state to invalidate currently\n\t}\n\n\trender(width: number): string[] {\n\t\tconst lines: string[] = [];\n\n\t\t// If no items match filter, show message\n\t\tif (this.filteredItems.length === 0) {\n\t\t\tlines.push(this.theme.noMatch(\" No matching commands\"));\n\t\t\treturn lines;\n\t\t}\n\n\t\t// Calculate visible range with scrolling\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.filteredItems.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.filteredItems.length);\n\n\t\t// Render visible items\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst item = this.filteredItems[i];\n\t\t\tif (!item) continue;\n\n\t\t\tconst isSelected = i === this.selectedIndex;\n\t\t\tconst descriptionSingleLine = item.description ? normalizeToSingleLine(item.description) : undefined;\n\n\t\t\tlet line = \"\";\n\t\t\tif (isSelected) {\n\t\t\t\t// Use arrow indicator for selection - entire line uses selectedText color\n\t\t\t\tconst prefixWidth = 2; // \"→ \" is 2 characters visually\n\t\t\t\tconst displayValue = item.label || item.value;\n\n\t\t\t\tif (descriptionSingleLine && width > 40) {\n\t\t\t\t\t// Calculate how much space we have for value + description\n\t\t\t\t\tconst maxValueWidth = Math.min(30, width - prefixWidth - 4);\n\t\t\t\t\tconst truncatedValue = truncateToWidth(displayValue, maxValueWidth, \"\");\n\t\t\t\t\tconst spacing = \" \".repeat(Math.max(1, 32 - truncatedValue.length));\n\n\t\t\t\t\t// Calculate remaining space for description using visible widths\n\t\t\t\t\tconst descriptionStart = prefixWidth + truncatedValue.length + spacing.length;\n\t\t\t\t\tconst remainingWidth = width - descriptionStart - 2; // -2 for safety\n\n\t\t\t\t\tif (remainingWidth > 10) {\n\t\t\t\t\t\tconst truncatedDesc = truncateToWidth(descriptionSingleLine, remainingWidth, \"\");\n\t\t\t\t\t\t// Apply selectedText to entire line content\n\t\t\t\t\t\tline = this.theme.selectedText(`→ ${truncatedValue}${spacing}${truncatedDesc}`);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Not enough space for description\n\t\t\t\t\t\tconst maxWidth = width - prefixWidth - 2;\n\t\t\t\t\t\tline = this.theme.selectedText(`→ ${truncateToWidth(displayValue, maxWidth, \"\")}`);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// No description or not enough width\n\t\t\t\t\tconst maxWidth = width - prefixWidth - 2;\n\t\t\t\t\tline = this.theme.selectedText(`→ ${truncateToWidth(displayValue, maxWidth, \"\")}`);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst displayValue = item.label || item.value;\n\t\t\t\tconst prefix = \" \";\n\n\t\t\t\tif (descriptionSingleLine && width > 40) {\n\t\t\t\t\t// Calculate how much space we have for value + description\n\t\t\t\t\tconst maxValueWidth = Math.min(30, width - prefix.length - 4);\n\t\t\t\t\tconst truncatedValue = truncateToWidth(displayValue, maxValueWidth, \"\");\n\t\t\t\t\tconst spacing = \" \".repeat(Math.max(1, 32 - truncatedValue.length));\n\n\t\t\t\t\t// Calculate remaining space for description\n\t\t\t\t\tconst descriptionStart = prefix.length + truncatedValue.length + spacing.length;\n\t\t\t\t\tconst remainingWidth = width - descriptionStart - 2; // -2 for safety\n\n\t\t\t\t\tif (remainingWidth > 10) {\n\t\t\t\t\t\tconst truncatedDesc = truncateToWidth(descriptionSingleLine, remainingWidth, \"\");\n\t\t\t\t\t\tconst descText = this.theme.description(spacing + truncatedDesc);\n\t\t\t\t\t\tline = prefix + truncatedValue + descText;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Not enough space for description\n\t\t\t\t\t\tconst maxWidth = width - prefix.length - 2;\n\t\t\t\t\t\tline = prefix + truncateToWidth(displayValue, maxWidth, \"\");\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// No description or not enough width\n\t\t\t\t\tconst maxWidth = width - prefix.length - 2;\n\t\t\t\t\tline = prefix + truncateToWidth(displayValue, maxWidth, \"\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlines.push(line);\n\t\t}\n\n\t\t// Add scroll indicators if needed\n\t\tif (startIndex > 0 || endIndex < this.filteredItems.length) {\n\t\t\tconst scrollText = ` (${this.selectedIndex + 1}/${this.filteredItems.length})`;\n\t\t\t// Truncate if too long for terminal\n\t\t\tlines.push(this.theme.scrollInfo(truncateToWidth(scrollText, width - 2, \"\")));\n\t\t}\n\n\t\treturn lines;\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getEditorKeybindings();\n\t\t// Up arrow - wrap to bottom when at top\n\t\tif (kb.matches(keyData, \"selectUp\")) {\n\t\t\tthis.selectedIndex = this.selectedIndex === 0 ? this.filteredItems.length - 1 : this.selectedIndex - 1;\n\t\t\tthis.notifySelectionChange();\n\t\t}\n\t\t// Down arrow - wrap to top when at bottom\n\t\telse if (kb.matches(keyData, \"selectDown\")) {\n\t\t\tthis.selectedIndex = this.selectedIndex === this.filteredItems.length - 1 ? 0 : this.selectedIndex + 1;\n\t\t\tthis.notifySelectionChange();\n\t\t}\n\t\t// Enter\n\t\telse if (kb.matches(keyData, \"selectConfirm\")) {\n\t\t\tconst selectedItem = this.filteredItems[this.selectedIndex];\n\t\t\tif (selectedItem && this.onSelect) {\n\t\t\t\tthis.onSelect(selectedItem);\n\t\t\t}\n\t\t}\n\t\t// Escape or Ctrl+C\n\t\telse if (kb.matches(keyData, \"selectCancel\")) {\n\t\t\tif (this.onCancel) {\n\t\t\t\tthis.onCancel();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate notifySelectionChange(): void {\n\t\tconst selectedItem = this.filteredItems[this.selectedIndex];\n\t\tif (selectedItem && this.onSelectionChange) {\n\t\t\tthis.onSelectionChange(selectedItem);\n\t\t}\n\t}\n\n\tgetSelectedItem(): SelectItem | null {\n\t\tconst item = this.filteredItems[this.selectedIndex];\n\t\treturn item || null;\n\t}\n}\n"]}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { getEditorKeybindings } from "../keybindings.js";
|
|
2
|
+
import { truncateToWidth } from "../utils.js";
|
|
3
|
+
const normalizeToSingleLine = (text) => text.replace(/[\r\n]+/g, " ").trim();
|
|
4
|
+
export class SelectList {
|
|
5
|
+
items = [];
|
|
6
|
+
filteredItems = [];
|
|
7
|
+
selectedIndex = 0;
|
|
8
|
+
maxVisible = 5;
|
|
9
|
+
theme;
|
|
10
|
+
onSelect;
|
|
11
|
+
onCancel;
|
|
12
|
+
onSelectionChange;
|
|
13
|
+
constructor(items, maxVisible, theme) {
|
|
14
|
+
this.items = items;
|
|
15
|
+
this.filteredItems = items;
|
|
16
|
+
this.maxVisible = maxVisible;
|
|
17
|
+
this.theme = theme;
|
|
18
|
+
}
|
|
19
|
+
setFilter(filter) {
|
|
20
|
+
this.filteredItems = this.items.filter((item) => item.value.toLowerCase().startsWith(filter.toLowerCase()));
|
|
21
|
+
// Reset selection when filter changes
|
|
22
|
+
this.selectedIndex = 0;
|
|
23
|
+
}
|
|
24
|
+
setSelectedIndex(index) {
|
|
25
|
+
this.selectedIndex = Math.max(0, Math.min(index, this.filteredItems.length - 1));
|
|
26
|
+
}
|
|
27
|
+
invalidate() {
|
|
28
|
+
// No cached state to invalidate currently
|
|
29
|
+
}
|
|
30
|
+
render(width) {
|
|
31
|
+
const lines = [];
|
|
32
|
+
// If no items match filter, show message
|
|
33
|
+
if (this.filteredItems.length === 0) {
|
|
34
|
+
lines.push(this.theme.noMatch(" No matching commands"));
|
|
35
|
+
return lines;
|
|
36
|
+
}
|
|
37
|
+
// Calculate visible range with scrolling
|
|
38
|
+
const startIndex = Math.max(0, Math.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.filteredItems.length - this.maxVisible));
|
|
39
|
+
const endIndex = Math.min(startIndex + this.maxVisible, this.filteredItems.length);
|
|
40
|
+
// Render visible items
|
|
41
|
+
for (let i = startIndex; i < endIndex; i++) {
|
|
42
|
+
const item = this.filteredItems[i];
|
|
43
|
+
if (!item)
|
|
44
|
+
continue;
|
|
45
|
+
const isSelected = i === this.selectedIndex;
|
|
46
|
+
const descriptionSingleLine = item.description ? normalizeToSingleLine(item.description) : undefined;
|
|
47
|
+
let line = "";
|
|
48
|
+
if (isSelected) {
|
|
49
|
+
// Use arrow indicator for selection - entire line uses selectedText color
|
|
50
|
+
const prefixWidth = 2; // "→ " is 2 characters visually
|
|
51
|
+
const displayValue = item.label || item.value;
|
|
52
|
+
if (descriptionSingleLine && width > 40) {
|
|
53
|
+
// Calculate how much space we have for value + description
|
|
54
|
+
const maxValueWidth = Math.min(30, width - prefixWidth - 4);
|
|
55
|
+
const truncatedValue = truncateToWidth(displayValue, maxValueWidth, "");
|
|
56
|
+
const spacing = " ".repeat(Math.max(1, 32 - truncatedValue.length));
|
|
57
|
+
// Calculate remaining space for description using visible widths
|
|
58
|
+
const descriptionStart = prefixWidth + truncatedValue.length + spacing.length;
|
|
59
|
+
const remainingWidth = width - descriptionStart - 2; // -2 for safety
|
|
60
|
+
if (remainingWidth > 10) {
|
|
61
|
+
const truncatedDesc = truncateToWidth(descriptionSingleLine, remainingWidth, "");
|
|
62
|
+
// Apply selectedText to entire line content
|
|
63
|
+
line = this.theme.selectedText(`→ ${truncatedValue}${spacing}${truncatedDesc}`);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
// Not enough space for description
|
|
67
|
+
const maxWidth = width - prefixWidth - 2;
|
|
68
|
+
line = this.theme.selectedText(`→ ${truncateToWidth(displayValue, maxWidth, "")}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
// No description or not enough width
|
|
73
|
+
const maxWidth = width - prefixWidth - 2;
|
|
74
|
+
line = this.theme.selectedText(`→ ${truncateToWidth(displayValue, maxWidth, "")}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
const displayValue = item.label || item.value;
|
|
79
|
+
const prefix = " ";
|
|
80
|
+
if (descriptionSingleLine && width > 40) {
|
|
81
|
+
// Calculate how much space we have for value + description
|
|
82
|
+
const maxValueWidth = Math.min(30, width - prefix.length - 4);
|
|
83
|
+
const truncatedValue = truncateToWidth(displayValue, maxValueWidth, "");
|
|
84
|
+
const spacing = " ".repeat(Math.max(1, 32 - truncatedValue.length));
|
|
85
|
+
// Calculate remaining space for description
|
|
86
|
+
const descriptionStart = prefix.length + truncatedValue.length + spacing.length;
|
|
87
|
+
const remainingWidth = width - descriptionStart - 2; // -2 for safety
|
|
88
|
+
if (remainingWidth > 10) {
|
|
89
|
+
const truncatedDesc = truncateToWidth(descriptionSingleLine, remainingWidth, "");
|
|
90
|
+
const descText = this.theme.description(spacing + truncatedDesc);
|
|
91
|
+
line = prefix + truncatedValue + descText;
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
// Not enough space for description
|
|
95
|
+
const maxWidth = width - prefix.length - 2;
|
|
96
|
+
line = prefix + truncateToWidth(displayValue, maxWidth, "");
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
// No description or not enough width
|
|
101
|
+
const maxWidth = width - prefix.length - 2;
|
|
102
|
+
line = prefix + truncateToWidth(displayValue, maxWidth, "");
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
lines.push(line);
|
|
106
|
+
}
|
|
107
|
+
// Add scroll indicators if needed
|
|
108
|
+
if (startIndex > 0 || endIndex < this.filteredItems.length) {
|
|
109
|
+
const scrollText = ` (${this.selectedIndex + 1}/${this.filteredItems.length})`;
|
|
110
|
+
// Truncate if too long for terminal
|
|
111
|
+
lines.push(this.theme.scrollInfo(truncateToWidth(scrollText, width - 2, "")));
|
|
112
|
+
}
|
|
113
|
+
return lines;
|
|
114
|
+
}
|
|
115
|
+
handleInput(keyData) {
|
|
116
|
+
const kb = getEditorKeybindings();
|
|
117
|
+
// Up arrow - wrap to bottom when at top
|
|
118
|
+
if (kb.matches(keyData, "selectUp")) {
|
|
119
|
+
this.selectedIndex = this.selectedIndex === 0 ? this.filteredItems.length - 1 : this.selectedIndex - 1;
|
|
120
|
+
this.notifySelectionChange();
|
|
121
|
+
}
|
|
122
|
+
// Down arrow - wrap to top when at bottom
|
|
123
|
+
else if (kb.matches(keyData, "selectDown")) {
|
|
124
|
+
this.selectedIndex = this.selectedIndex === this.filteredItems.length - 1 ? 0 : this.selectedIndex + 1;
|
|
125
|
+
this.notifySelectionChange();
|
|
126
|
+
}
|
|
127
|
+
// Enter
|
|
128
|
+
else if (kb.matches(keyData, "selectConfirm")) {
|
|
129
|
+
const selectedItem = this.filteredItems[this.selectedIndex];
|
|
130
|
+
if (selectedItem && this.onSelect) {
|
|
131
|
+
this.onSelect(selectedItem);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// Escape or Ctrl+C
|
|
135
|
+
else if (kb.matches(keyData, "selectCancel")) {
|
|
136
|
+
if (this.onCancel) {
|
|
137
|
+
this.onCancel();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
notifySelectionChange() {
|
|
142
|
+
const selectedItem = this.filteredItems[this.selectedIndex];
|
|
143
|
+
if (selectedItem && this.onSelectionChange) {
|
|
144
|
+
this.onSelectionChange(selectedItem);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
getSelectedItem() {
|
|
148
|
+
const item = this.filteredItems[this.selectedIndex];
|
|
149
|
+
return item || null;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=select-list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select-list.js","sourceRoot":"","sources":["../../src/components/select-list.ts"],"names":[],"mappings":"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","sourcesContent":["import { getEditorKeybindings } from \"../keybindings.js\";\nimport type { Component } from \"../tui.js\";\nimport { truncateToWidth } from \"../utils.js\";\n\nconst normalizeToSingleLine = (text: string): string => text.replace(/[\\r\\n]+/g, \" \").trim();\n\nexport interface SelectItem {\n\tvalue: string;\n\tlabel: string;\n\tdescription?: string;\n}\n\nexport interface SelectListTheme {\n\tselectedPrefix: (text: string) => string;\n\tselectedText: (text: string) => string;\n\tdescription: (text: string) => string;\n\tscrollInfo: (text: string) => string;\n\tnoMatch: (text: string) => string;\n}\n\nexport class SelectList implements Component {\n\tprivate items: SelectItem[] = [];\n\tprivate filteredItems: SelectItem[] = [];\n\tprivate selectedIndex: number = 0;\n\tprivate maxVisible: number = 5;\n\tprivate theme: SelectListTheme;\n\n\tpublic onSelect?: (item: SelectItem) => void;\n\tpublic onCancel?: () => void;\n\tpublic onSelectionChange?: (item: SelectItem) => void;\n\n\tconstructor(items: SelectItem[], maxVisible: number, theme: SelectListTheme) {\n\t\tthis.items = items;\n\t\tthis.filteredItems = items;\n\t\tthis.maxVisible = maxVisible;\n\t\tthis.theme = theme;\n\t}\n\n\tsetFilter(filter: string): void {\n\t\tthis.filteredItems = this.items.filter((item) => item.value.toLowerCase().startsWith(filter.toLowerCase()));\n\t\t// Reset selection when filter changes\n\t\tthis.selectedIndex = 0;\n\t}\n\n\tsetSelectedIndex(index: number): void {\n\t\tthis.selectedIndex = Math.max(0, Math.min(index, this.filteredItems.length - 1));\n\t}\n\n\tinvalidate(): void {\n\t\t// No cached state to invalidate currently\n\t}\n\n\trender(width: number): string[] {\n\t\tconst lines: string[] = [];\n\n\t\t// If no items match filter, show message\n\t\tif (this.filteredItems.length === 0) {\n\t\t\tlines.push(this.theme.noMatch(\" No matching commands\"));\n\t\t\treturn lines;\n\t\t}\n\n\t\t// Calculate visible range with scrolling\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.filteredItems.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.filteredItems.length);\n\n\t\t// Render visible items\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst item = this.filteredItems[i];\n\t\t\tif (!item) continue;\n\n\t\t\tconst isSelected = i === this.selectedIndex;\n\t\t\tconst descriptionSingleLine = item.description ? normalizeToSingleLine(item.description) : undefined;\n\n\t\t\tlet line = \"\";\n\t\t\tif (isSelected) {\n\t\t\t\t// Use arrow indicator for selection - entire line uses selectedText color\n\t\t\t\tconst prefixWidth = 2; // \"→ \" is 2 characters visually\n\t\t\t\tconst displayValue = item.label || item.value;\n\n\t\t\t\tif (descriptionSingleLine && width > 40) {\n\t\t\t\t\t// Calculate how much space we have for value + description\n\t\t\t\t\tconst maxValueWidth = Math.min(30, width - prefixWidth - 4);\n\t\t\t\t\tconst truncatedValue = truncateToWidth(displayValue, maxValueWidth, \"\");\n\t\t\t\t\tconst spacing = \" \".repeat(Math.max(1, 32 - truncatedValue.length));\n\n\t\t\t\t\t// Calculate remaining space for description using visible widths\n\t\t\t\t\tconst descriptionStart = prefixWidth + truncatedValue.length + spacing.length;\n\t\t\t\t\tconst remainingWidth = width - descriptionStart - 2; // -2 for safety\n\n\t\t\t\t\tif (remainingWidth > 10) {\n\t\t\t\t\t\tconst truncatedDesc = truncateToWidth(descriptionSingleLine, remainingWidth, \"\");\n\t\t\t\t\t\t// Apply selectedText to entire line content\n\t\t\t\t\t\tline = this.theme.selectedText(`→ ${truncatedValue}${spacing}${truncatedDesc}`);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Not enough space for description\n\t\t\t\t\t\tconst maxWidth = width - prefixWidth - 2;\n\t\t\t\t\t\tline = this.theme.selectedText(`→ ${truncateToWidth(displayValue, maxWidth, \"\")}`);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// No description or not enough width\n\t\t\t\t\tconst maxWidth = width - prefixWidth - 2;\n\t\t\t\t\tline = this.theme.selectedText(`→ ${truncateToWidth(displayValue, maxWidth, \"\")}`);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst displayValue = item.label || item.value;\n\t\t\t\tconst prefix = \" \";\n\n\t\t\t\tif (descriptionSingleLine && width > 40) {\n\t\t\t\t\t// Calculate how much space we have for value + description\n\t\t\t\t\tconst maxValueWidth = Math.min(30, width - prefix.length - 4);\n\t\t\t\t\tconst truncatedValue = truncateToWidth(displayValue, maxValueWidth, \"\");\n\t\t\t\t\tconst spacing = \" \".repeat(Math.max(1, 32 - truncatedValue.length));\n\n\t\t\t\t\t// Calculate remaining space for description\n\t\t\t\t\tconst descriptionStart = prefix.length + truncatedValue.length + spacing.length;\n\t\t\t\t\tconst remainingWidth = width - descriptionStart - 2; // -2 for safety\n\n\t\t\t\t\tif (remainingWidth > 10) {\n\t\t\t\t\t\tconst truncatedDesc = truncateToWidth(descriptionSingleLine, remainingWidth, \"\");\n\t\t\t\t\t\tconst descText = this.theme.description(spacing + truncatedDesc);\n\t\t\t\t\t\tline = prefix + truncatedValue + descText;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Not enough space for description\n\t\t\t\t\t\tconst maxWidth = width - prefix.length - 2;\n\t\t\t\t\t\tline = prefix + truncateToWidth(displayValue, maxWidth, \"\");\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// No description or not enough width\n\t\t\t\t\tconst maxWidth = width - prefix.length - 2;\n\t\t\t\t\tline = prefix + truncateToWidth(displayValue, maxWidth, \"\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlines.push(line);\n\t\t}\n\n\t\t// Add scroll indicators if needed\n\t\tif (startIndex > 0 || endIndex < this.filteredItems.length) {\n\t\t\tconst scrollText = ` (${this.selectedIndex + 1}/${this.filteredItems.length})`;\n\t\t\t// Truncate if too long for terminal\n\t\t\tlines.push(this.theme.scrollInfo(truncateToWidth(scrollText, width - 2, \"\")));\n\t\t}\n\n\t\treturn lines;\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getEditorKeybindings();\n\t\t// Up arrow - wrap to bottom when at top\n\t\tif (kb.matches(keyData, \"selectUp\")) {\n\t\t\tthis.selectedIndex = this.selectedIndex === 0 ? this.filteredItems.length - 1 : this.selectedIndex - 1;\n\t\t\tthis.notifySelectionChange();\n\t\t}\n\t\t// Down arrow - wrap to top when at bottom\n\t\telse if (kb.matches(keyData, \"selectDown\")) {\n\t\t\tthis.selectedIndex = this.selectedIndex === this.filteredItems.length - 1 ? 0 : this.selectedIndex + 1;\n\t\t\tthis.notifySelectionChange();\n\t\t}\n\t\t// Enter\n\t\telse if (kb.matches(keyData, \"selectConfirm\")) {\n\t\t\tconst selectedItem = this.filteredItems[this.selectedIndex];\n\t\t\tif (selectedItem && this.onSelect) {\n\t\t\t\tthis.onSelect(selectedItem);\n\t\t\t}\n\t\t}\n\t\t// Escape or Ctrl+C\n\t\telse if (kb.matches(keyData, \"selectCancel\")) {\n\t\t\tif (this.onCancel) {\n\t\t\t\tthis.onCancel();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate notifySelectionChange(): void {\n\t\tconst selectedItem = this.filteredItems[this.selectedIndex];\n\t\tif (selectedItem && this.onSelectionChange) {\n\t\t\tthis.onSelectionChange(selectedItem);\n\t\t}\n\t}\n\n\tgetSelectedItem(): SelectItem | null {\n\t\tconst item = this.filteredItems[this.selectedIndex];\n\t\treturn item || null;\n\t}\n}\n"]}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Component } from "../tui.js";
|
|
2
|
+
export interface SettingItem {
|
|
3
|
+
/** Unique identifier for this setting */
|
|
4
|
+
id: string;
|
|
5
|
+
/** Display label (left side) */
|
|
6
|
+
label: string;
|
|
7
|
+
/** Optional description shown when selected */
|
|
8
|
+
description?: string;
|
|
9
|
+
/** Current value to display (right side) */
|
|
10
|
+
currentValue: string;
|
|
11
|
+
/** If provided, Enter/Space cycles through these values */
|
|
12
|
+
values?: string[];
|
|
13
|
+
/** If provided, Enter opens this submenu. Receives current value and done callback. */
|
|
14
|
+
submenu?: (currentValue: string, done: (selectedValue?: string) => void) => Component;
|
|
15
|
+
}
|
|
16
|
+
export interface SettingsListTheme {
|
|
17
|
+
label: (text: string, selected: boolean) => string;
|
|
18
|
+
value: (text: string, selected: boolean) => string;
|
|
19
|
+
description: (text: string) => string;
|
|
20
|
+
cursor: string;
|
|
21
|
+
hint: (text: string) => string;
|
|
22
|
+
}
|
|
23
|
+
export interface SettingsListOptions {
|
|
24
|
+
enableSearch?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export declare class SettingsList implements Component {
|
|
27
|
+
private items;
|
|
28
|
+
private filteredItems;
|
|
29
|
+
private theme;
|
|
30
|
+
private selectedIndex;
|
|
31
|
+
private maxVisible;
|
|
32
|
+
private onChange;
|
|
33
|
+
private onCancel;
|
|
34
|
+
private searchInput?;
|
|
35
|
+
private searchEnabled;
|
|
36
|
+
private submenuComponent;
|
|
37
|
+
private submenuItemIndex;
|
|
38
|
+
constructor(items: SettingItem[], maxVisible: number, theme: SettingsListTheme, onChange: (id: string, newValue: string) => void, onCancel: () => void, options?: SettingsListOptions);
|
|
39
|
+
/** Update an item's currentValue */
|
|
40
|
+
updateValue(id: string, newValue: string): void;
|
|
41
|
+
invalidate(): void;
|
|
42
|
+
render(width: number): string[];
|
|
43
|
+
private renderMainList;
|
|
44
|
+
handleInput(data: string): void;
|
|
45
|
+
private activateItem;
|
|
46
|
+
private closeSubmenu;
|
|
47
|
+
private applyFilter;
|
|
48
|
+
private addHintLine;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=settings-list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings-list.d.ts","sourceRoot":"","sources":["../../src/components/settings-list.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAI3C,MAAM,WAAW,WAAW;IAC3B,yCAAyC;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4CAA4C;IAC5C,YAAY,EAAE,MAAM,CAAC;IACrB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,uFAAuF;IACvF,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,aAAa,CAAC,EAAE,MAAM,KAAK,IAAI,KAAK,SAAS,CAAC;CACtF;AAED,MAAM,WAAW,iBAAiB;IACjC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,KAAK,MAAM,CAAC;IACnD,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,KAAK,MAAM,CAAC;IACnD,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,mBAAmB;IACnC,YAAY,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,qBAAa,YAAa,YAAW,SAAS;IAC7C,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,KAAK,CAAoB;IACjC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAyC;IACzD,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,WAAW,CAAC,CAAQ;IAC5B,OAAO,CAAC,aAAa,CAAU;IAG/B,OAAO,CAAC,gBAAgB,CAA0B;IAClD,OAAO,CAAC,gBAAgB,CAAuB;IAE/C,YACC,KAAK,EAAE,WAAW,EAAE,EACpB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,iBAAiB,EACxB,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,EAChD,QAAQ,EAAE,MAAM,IAAI,EACpB,OAAO,GAAE,mBAAwB,EAYjC;IAED,oCAAoC;IACpC,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAK9C;IAED,UAAU,IAAI,IAAI,CAEjB;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAO9B;IAED,OAAO,CAAC,cAAc;IA8EtB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CA6B9B;IAED,OAAO,CAAC,YAAY;IAwBpB,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,WAAW;CAanB","sourcesContent":["import { fuzzyFilter } from \"../fuzzy.js\";\nimport { getEditorKeybindings } from \"../keybindings.js\";\nimport type { Component } from \"../tui.js\";\nimport { truncateToWidth, visibleWidth, wrapTextWithAnsi } from \"../utils.js\";\nimport { Input } from \"./input.js\";\n\nexport interface SettingItem {\n\t/** Unique identifier for this setting */\n\tid: string;\n\t/** Display label (left side) */\n\tlabel: string;\n\t/** Optional description shown when selected */\n\tdescription?: string;\n\t/** Current value to display (right side) */\n\tcurrentValue: string;\n\t/** If provided, Enter/Space cycles through these values */\n\tvalues?: string[];\n\t/** If provided, Enter opens this submenu. Receives current value and done callback. */\n\tsubmenu?: (currentValue: string, done: (selectedValue?: string) => void) => Component;\n}\n\nexport interface SettingsListTheme {\n\tlabel: (text: string, selected: boolean) => string;\n\tvalue: (text: string, selected: boolean) => string;\n\tdescription: (text: string) => string;\n\tcursor: string;\n\thint: (text: string) => string;\n}\n\nexport interface SettingsListOptions {\n\tenableSearch?: boolean;\n}\n\nexport class SettingsList implements Component {\n\tprivate items: SettingItem[];\n\tprivate filteredItems: SettingItem[];\n\tprivate theme: SettingsListTheme;\n\tprivate selectedIndex = 0;\n\tprivate maxVisible: number;\n\tprivate onChange: (id: string, newValue: string) => void;\n\tprivate onCancel: () => void;\n\tprivate searchInput?: Input;\n\tprivate searchEnabled: boolean;\n\n\t// Submenu state\n\tprivate submenuComponent: Component | null = null;\n\tprivate submenuItemIndex: number | null = null;\n\n\tconstructor(\n\t\titems: SettingItem[],\n\t\tmaxVisible: number,\n\t\ttheme: SettingsListTheme,\n\t\tonChange: (id: string, newValue: string) => void,\n\t\tonCancel: () => void,\n\t\toptions: SettingsListOptions = {},\n\t) {\n\t\tthis.items = items;\n\t\tthis.filteredItems = items;\n\t\tthis.maxVisible = maxVisible;\n\t\tthis.theme = theme;\n\t\tthis.onChange = onChange;\n\t\tthis.onCancel = onCancel;\n\t\tthis.searchEnabled = options.enableSearch ?? false;\n\t\tif (this.searchEnabled) {\n\t\t\tthis.searchInput = new Input();\n\t\t}\n\t}\n\n\t/** Update an item's currentValue */\n\tupdateValue(id: string, newValue: string): void {\n\t\tconst item = this.items.find((i) => i.id === id);\n\t\tif (item) {\n\t\t\titem.currentValue = newValue;\n\t\t}\n\t}\n\n\tinvalidate(): void {\n\t\tthis.submenuComponent?.invalidate?.();\n\t}\n\n\trender(width: number): string[] {\n\t\t// If submenu is active, render it instead\n\t\tif (this.submenuComponent) {\n\t\t\treturn this.submenuComponent.render(width);\n\t\t}\n\n\t\treturn this.renderMainList(width);\n\t}\n\n\tprivate renderMainList(width: number): string[] {\n\t\tconst lines: string[] = [];\n\n\t\tif (this.searchEnabled && this.searchInput) {\n\t\t\tlines.push(...this.searchInput.render(width));\n\t\t\tlines.push(\"\");\n\t\t}\n\n\t\tif (this.items.length === 0) {\n\t\t\tlines.push(this.theme.hint(\" No settings available\"));\n\t\t\tif (this.searchEnabled) {\n\t\t\t\tthis.addHintLine(lines, width);\n\t\t\t}\n\t\t\treturn lines;\n\t\t}\n\n\t\tconst displayItems = this.searchEnabled ? this.filteredItems : this.items;\n\t\tif (displayItems.length === 0) {\n\t\t\tlines.push(truncateToWidth(this.theme.hint(\" No matching settings\"), width));\n\t\t\tthis.addHintLine(lines, width);\n\t\t\treturn lines;\n\t\t}\n\n\t\t// Calculate visible range with scrolling\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.selectedIndex - Math.floor(this.maxVisible / 2), displayItems.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, displayItems.length);\n\n\t\t// Calculate max label width for alignment\n\t\tconst maxLabelWidth = Math.min(30, Math.max(...this.items.map((item) => visibleWidth(item.label))));\n\n\t\t// Render visible items\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst item = displayItems[i];\n\t\t\tif (!item) continue;\n\n\t\t\tconst isSelected = i === this.selectedIndex;\n\t\t\tconst prefix = isSelected ? this.theme.cursor : \" \";\n\t\t\tconst prefixWidth = visibleWidth(prefix);\n\n\t\t\t// Pad label to align values\n\t\t\tconst labelPadded = item.label + \" \".repeat(Math.max(0, maxLabelWidth - visibleWidth(item.label)));\n\t\t\tconst labelText = this.theme.label(labelPadded, isSelected);\n\n\t\t\t// Calculate space for value\n\t\t\tconst separator = \" \";\n\t\t\tconst usedWidth = prefixWidth + maxLabelWidth + visibleWidth(separator);\n\t\t\tconst valueMaxWidth = width - usedWidth - 2;\n\n\t\t\tconst valueText = this.theme.value(truncateToWidth(item.currentValue, valueMaxWidth, \"\"), isSelected);\n\n\t\t\tlines.push(truncateToWidth(prefix + labelText + separator + valueText, width));\n\t\t}\n\n\t\t// Add scroll indicator if needed\n\t\tif (startIndex > 0 || endIndex < displayItems.length) {\n\t\t\tconst scrollText = ` (${this.selectedIndex + 1}/${displayItems.length})`;\n\t\t\tlines.push(this.theme.hint(truncateToWidth(scrollText, width - 2, \"\")));\n\t\t}\n\n\t\t// Add description for selected item\n\t\tconst selectedItem = displayItems[this.selectedIndex];\n\t\tif (selectedItem?.description) {\n\t\t\tlines.push(\"\");\n\t\t\tconst wrappedDesc = wrapTextWithAnsi(selectedItem.description, width - 4);\n\t\t\tfor (const line of wrappedDesc) {\n\t\t\t\tlines.push(this.theme.description(` ${line}`));\n\t\t\t}\n\t\t}\n\n\t\t// Add hint\n\t\tthis.addHintLine(lines, width);\n\n\t\treturn lines;\n\t}\n\n\thandleInput(data: string): void {\n\t\t// If submenu is active, delegate all input to it\n\t\t// The submenu's onCancel (triggered by escape) will call done() which closes it\n\t\tif (this.submenuComponent) {\n\t\t\tthis.submenuComponent.handleInput?.(data);\n\t\t\treturn;\n\t\t}\n\n\t\t// Main list input handling\n\t\tconst kb = getEditorKeybindings();\n\t\tconst displayItems = this.searchEnabled ? this.filteredItems : this.items;\n\t\tif (kb.matches(data, \"selectUp\")) {\n\t\t\tif (displayItems.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === 0 ? displayItems.length - 1 : this.selectedIndex - 1;\n\t\t} else if (kb.matches(data, \"selectDown\")) {\n\t\t\tif (displayItems.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === displayItems.length - 1 ? 0 : this.selectedIndex + 1;\n\t\t} else if (kb.matches(data, \"selectConfirm\") || data === \" \") {\n\t\t\tthis.activateItem();\n\t\t} else if (kb.matches(data, \"selectCancel\")) {\n\t\t\tthis.onCancel();\n\t\t} else if (this.searchEnabled && this.searchInput) {\n\t\t\tconst sanitized = data.replace(/ /g, \"\");\n\t\t\tif (!sanitized) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.searchInput.handleInput(sanitized);\n\t\t\tthis.applyFilter(this.searchInput.getValue());\n\t\t}\n\t}\n\n\tprivate activateItem(): void {\n\t\tconst item = this.searchEnabled ? this.filteredItems[this.selectedIndex] : this.items[this.selectedIndex];\n\t\tif (!item) return;\n\n\t\tif (item.submenu) {\n\t\t\t// Open submenu, passing current value so it can pre-select correctly\n\t\t\tthis.submenuItemIndex = this.selectedIndex;\n\t\t\tthis.submenuComponent = item.submenu(item.currentValue, (selectedValue?: string) => {\n\t\t\t\tif (selectedValue !== undefined) {\n\t\t\t\t\titem.currentValue = selectedValue;\n\t\t\t\t\tthis.onChange(item.id, selectedValue);\n\t\t\t\t}\n\t\t\t\tthis.closeSubmenu();\n\t\t\t});\n\t\t} else if (item.values && item.values.length > 0) {\n\t\t\t// Cycle through values\n\t\t\tconst currentIndex = item.values.indexOf(item.currentValue);\n\t\t\tconst nextIndex = (currentIndex + 1) % item.values.length;\n\t\t\tconst newValue = item.values[nextIndex];\n\t\t\titem.currentValue = newValue;\n\t\t\tthis.onChange(item.id, newValue);\n\t\t}\n\t}\n\n\tprivate closeSubmenu(): void {\n\t\tthis.submenuComponent = null;\n\t\t// Restore selection to the item that opened the submenu\n\t\tif (this.submenuItemIndex !== null) {\n\t\t\tthis.selectedIndex = this.submenuItemIndex;\n\t\t\tthis.submenuItemIndex = null;\n\t\t}\n\t}\n\n\tprivate applyFilter(query: string): void {\n\t\tthis.filteredItems = fuzzyFilter(this.items, query, (item) => item.label);\n\t\tthis.selectedIndex = 0;\n\t}\n\n\tprivate addHintLine(lines: string[], width: number): void {\n\t\tlines.push(\"\");\n\t\tlines.push(\n\t\t\ttruncateToWidth(\n\t\t\t\tthis.theme.hint(\n\t\t\t\t\tthis.searchEnabled\n\t\t\t\t\t\t? \" Type to search · Enter/Space to change · Esc to cancel\"\n\t\t\t\t\t\t: \" Enter/Space to change · Esc to cancel\",\n\t\t\t\t),\n\t\t\t\twidth,\n\t\t\t),\n\t\t);\n\t}\n}\n"]}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { fuzzyFilter } from "../fuzzy.js";
|
|
2
|
+
import { getEditorKeybindings } from "../keybindings.js";
|
|
3
|
+
import { truncateToWidth, visibleWidth, wrapTextWithAnsi } from "../utils.js";
|
|
4
|
+
import { Input } from "./input.js";
|
|
5
|
+
export class SettingsList {
|
|
6
|
+
items;
|
|
7
|
+
filteredItems;
|
|
8
|
+
theme;
|
|
9
|
+
selectedIndex = 0;
|
|
10
|
+
maxVisible;
|
|
11
|
+
onChange;
|
|
12
|
+
onCancel;
|
|
13
|
+
searchInput;
|
|
14
|
+
searchEnabled;
|
|
15
|
+
// Submenu state
|
|
16
|
+
submenuComponent = null;
|
|
17
|
+
submenuItemIndex = null;
|
|
18
|
+
constructor(items, maxVisible, theme, onChange, onCancel, options = {}) {
|
|
19
|
+
this.items = items;
|
|
20
|
+
this.filteredItems = items;
|
|
21
|
+
this.maxVisible = maxVisible;
|
|
22
|
+
this.theme = theme;
|
|
23
|
+
this.onChange = onChange;
|
|
24
|
+
this.onCancel = onCancel;
|
|
25
|
+
this.searchEnabled = options.enableSearch ?? false;
|
|
26
|
+
if (this.searchEnabled) {
|
|
27
|
+
this.searchInput = new Input();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** Update an item's currentValue */
|
|
31
|
+
updateValue(id, newValue) {
|
|
32
|
+
const item = this.items.find((i) => i.id === id);
|
|
33
|
+
if (item) {
|
|
34
|
+
item.currentValue = newValue;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
invalidate() {
|
|
38
|
+
this.submenuComponent?.invalidate?.();
|
|
39
|
+
}
|
|
40
|
+
render(width) {
|
|
41
|
+
// If submenu is active, render it instead
|
|
42
|
+
if (this.submenuComponent) {
|
|
43
|
+
return this.submenuComponent.render(width);
|
|
44
|
+
}
|
|
45
|
+
return this.renderMainList(width);
|
|
46
|
+
}
|
|
47
|
+
renderMainList(width) {
|
|
48
|
+
const lines = [];
|
|
49
|
+
if (this.searchEnabled && this.searchInput) {
|
|
50
|
+
lines.push(...this.searchInput.render(width));
|
|
51
|
+
lines.push("");
|
|
52
|
+
}
|
|
53
|
+
if (this.items.length === 0) {
|
|
54
|
+
lines.push(this.theme.hint(" No settings available"));
|
|
55
|
+
if (this.searchEnabled) {
|
|
56
|
+
this.addHintLine(lines, width);
|
|
57
|
+
}
|
|
58
|
+
return lines;
|
|
59
|
+
}
|
|
60
|
+
const displayItems = this.searchEnabled ? this.filteredItems : this.items;
|
|
61
|
+
if (displayItems.length === 0) {
|
|
62
|
+
lines.push(truncateToWidth(this.theme.hint(" No matching settings"), width));
|
|
63
|
+
this.addHintLine(lines, width);
|
|
64
|
+
return lines;
|
|
65
|
+
}
|
|
66
|
+
// Calculate visible range with scrolling
|
|
67
|
+
const startIndex = Math.max(0, Math.min(this.selectedIndex - Math.floor(this.maxVisible / 2), displayItems.length - this.maxVisible));
|
|
68
|
+
const endIndex = Math.min(startIndex + this.maxVisible, displayItems.length);
|
|
69
|
+
// Calculate max label width for alignment
|
|
70
|
+
const maxLabelWidth = Math.min(30, Math.max(...this.items.map((item) => visibleWidth(item.label))));
|
|
71
|
+
// Render visible items
|
|
72
|
+
for (let i = startIndex; i < endIndex; i++) {
|
|
73
|
+
const item = displayItems[i];
|
|
74
|
+
if (!item)
|
|
75
|
+
continue;
|
|
76
|
+
const isSelected = i === this.selectedIndex;
|
|
77
|
+
const prefix = isSelected ? this.theme.cursor : " ";
|
|
78
|
+
const prefixWidth = visibleWidth(prefix);
|
|
79
|
+
// Pad label to align values
|
|
80
|
+
const labelPadded = item.label + " ".repeat(Math.max(0, maxLabelWidth - visibleWidth(item.label)));
|
|
81
|
+
const labelText = this.theme.label(labelPadded, isSelected);
|
|
82
|
+
// Calculate space for value
|
|
83
|
+
const separator = " ";
|
|
84
|
+
const usedWidth = prefixWidth + maxLabelWidth + visibleWidth(separator);
|
|
85
|
+
const valueMaxWidth = width - usedWidth - 2;
|
|
86
|
+
const valueText = this.theme.value(truncateToWidth(item.currentValue, valueMaxWidth, ""), isSelected);
|
|
87
|
+
lines.push(truncateToWidth(prefix + labelText + separator + valueText, width));
|
|
88
|
+
}
|
|
89
|
+
// Add scroll indicator if needed
|
|
90
|
+
if (startIndex > 0 || endIndex < displayItems.length) {
|
|
91
|
+
const scrollText = ` (${this.selectedIndex + 1}/${displayItems.length})`;
|
|
92
|
+
lines.push(this.theme.hint(truncateToWidth(scrollText, width - 2, "")));
|
|
93
|
+
}
|
|
94
|
+
// Add description for selected item
|
|
95
|
+
const selectedItem = displayItems[this.selectedIndex];
|
|
96
|
+
if (selectedItem?.description) {
|
|
97
|
+
lines.push("");
|
|
98
|
+
const wrappedDesc = wrapTextWithAnsi(selectedItem.description, width - 4);
|
|
99
|
+
for (const line of wrappedDesc) {
|
|
100
|
+
lines.push(this.theme.description(` ${line}`));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// Add hint
|
|
104
|
+
this.addHintLine(lines, width);
|
|
105
|
+
return lines;
|
|
106
|
+
}
|
|
107
|
+
handleInput(data) {
|
|
108
|
+
// If submenu is active, delegate all input to it
|
|
109
|
+
// The submenu's onCancel (triggered by escape) will call done() which closes it
|
|
110
|
+
if (this.submenuComponent) {
|
|
111
|
+
this.submenuComponent.handleInput?.(data);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
// Main list input handling
|
|
115
|
+
const kb = getEditorKeybindings();
|
|
116
|
+
const displayItems = this.searchEnabled ? this.filteredItems : this.items;
|
|
117
|
+
if (kb.matches(data, "selectUp")) {
|
|
118
|
+
if (displayItems.length === 0)
|
|
119
|
+
return;
|
|
120
|
+
this.selectedIndex = this.selectedIndex === 0 ? displayItems.length - 1 : this.selectedIndex - 1;
|
|
121
|
+
}
|
|
122
|
+
else if (kb.matches(data, "selectDown")) {
|
|
123
|
+
if (displayItems.length === 0)
|
|
124
|
+
return;
|
|
125
|
+
this.selectedIndex = this.selectedIndex === displayItems.length - 1 ? 0 : this.selectedIndex + 1;
|
|
126
|
+
}
|
|
127
|
+
else if (kb.matches(data, "selectConfirm") || data === " ") {
|
|
128
|
+
this.activateItem();
|
|
129
|
+
}
|
|
130
|
+
else if (kb.matches(data, "selectCancel")) {
|
|
131
|
+
this.onCancel();
|
|
132
|
+
}
|
|
133
|
+
else if (this.searchEnabled && this.searchInput) {
|
|
134
|
+
const sanitized = data.replace(/ /g, "");
|
|
135
|
+
if (!sanitized) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
this.searchInput.handleInput(sanitized);
|
|
139
|
+
this.applyFilter(this.searchInput.getValue());
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
activateItem() {
|
|
143
|
+
const item = this.searchEnabled ? this.filteredItems[this.selectedIndex] : this.items[this.selectedIndex];
|
|
144
|
+
if (!item)
|
|
145
|
+
return;
|
|
146
|
+
if (item.submenu) {
|
|
147
|
+
// Open submenu, passing current value so it can pre-select correctly
|
|
148
|
+
this.submenuItemIndex = this.selectedIndex;
|
|
149
|
+
this.submenuComponent = item.submenu(item.currentValue, (selectedValue) => {
|
|
150
|
+
if (selectedValue !== undefined) {
|
|
151
|
+
item.currentValue = selectedValue;
|
|
152
|
+
this.onChange(item.id, selectedValue);
|
|
153
|
+
}
|
|
154
|
+
this.closeSubmenu();
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
else if (item.values && item.values.length > 0) {
|
|
158
|
+
// Cycle through values
|
|
159
|
+
const currentIndex = item.values.indexOf(item.currentValue);
|
|
160
|
+
const nextIndex = (currentIndex + 1) % item.values.length;
|
|
161
|
+
const newValue = item.values[nextIndex];
|
|
162
|
+
item.currentValue = newValue;
|
|
163
|
+
this.onChange(item.id, newValue);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
closeSubmenu() {
|
|
167
|
+
this.submenuComponent = null;
|
|
168
|
+
// Restore selection to the item that opened the submenu
|
|
169
|
+
if (this.submenuItemIndex !== null) {
|
|
170
|
+
this.selectedIndex = this.submenuItemIndex;
|
|
171
|
+
this.submenuItemIndex = null;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
applyFilter(query) {
|
|
175
|
+
this.filteredItems = fuzzyFilter(this.items, query, (item) => item.label);
|
|
176
|
+
this.selectedIndex = 0;
|
|
177
|
+
}
|
|
178
|
+
addHintLine(lines, width) {
|
|
179
|
+
lines.push("");
|
|
180
|
+
lines.push(truncateToWidth(this.theme.hint(this.searchEnabled
|
|
181
|
+
? " Type to search · Enter/Space to change · Esc to cancel"
|
|
182
|
+
: " Enter/Space to change · Esc to cancel"), width));
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=settings-list.js.map
|