feat(tui): make prompt size responsive and configurable (#28255)

This commit is contained in:
Braxton Schafer
2026-05-25 09:24:19 -05:00
committed by GitHub
parent 7703786498
commit 0de5f1ff36
3 changed files with 29 additions and 4 deletions
@@ -1464,11 +1464,15 @@ export function Prompt(props: PromptProps) {
}), }),
} }
}) })
const maxHeight = createMemo(
() => tuiConfig.prompt?.max_height ?? Math.max(6, Math.floor(dimensions().height / 3)),
)
return ( return (
<> <>
<box ref={(r: BoxRenderable) => (anchor = r)} visible={props.visible !== false}> <box ref={(r: BoxRenderable) => (anchor = r)} visible={props.visible !== false} width="100%">
<box <box
width="100%"
border={["left"]} border={["left"]}
borderColor={borderHighlight()} borderColor={borderHighlight()}
customBorderChars={{ customBorderChars={{
@@ -1483,14 +1487,16 @@ export function Prompt(props: PromptProps) {
flexShrink={0} flexShrink={0}
backgroundColor={theme.backgroundElement} backgroundColor={theme.backgroundElement}
flexGrow={1} flexGrow={1}
width="100%"
> >
<textarea <textarea
width="100%"
placeholder={placeholderText()} placeholder={placeholderText()}
placeholderColor={theme.textMuted} placeholderColor={theme.textMuted}
textColor={leader() ? theme.textMuted : theme.text} textColor={leader() ? theme.textMuted : theme.text}
focusedTextColor={leader() ? theme.textMuted : theme.text} focusedTextColor={leader() ? theme.textMuted : theme.text}
minHeight={1} minHeight={1}
maxHeight={6} maxHeight={maxHeight()}
onContentChange={() => { onContentChange={() => {
const value = input.plainText const value = input.plainText
setStore("prompt", "input", value) setStore("prompt", "input", value)
@@ -61,6 +61,15 @@ export const Attention = Schema.Struct({
sounds: Schema.optional(TuiAttentionSounds), sounds: Schema.optional(TuiAttentionSounds),
}).annotate({ description: "Attention notification and sound settings" }) }).annotate({ description: "Attention notification and sound settings" })
const PromptSize = Schema.Int.check(Schema.isGreaterThan(0))
export const Prompt = Schema.Struct({
max_height: Schema.optional(PromptSize).annotate({ description: "Prompt textarea max height" }),
max_width: Schema.optional(Schema.Union([PromptSize, Schema.Literal("auto")])).annotate({
description: "Home prompt max width: a positive integer for a fixed cap, or 'auto' to scale with terminal width",
}),
}).annotate({ description: "Prompt size settings" })
export const TuiInfo = Schema.Struct({ export const TuiInfo = Schema.Struct({
$schema: Schema.optional(Schema.String), $schema: Schema.optional(Schema.String),
theme: Schema.optional(Schema.String), theme: Schema.optional(Schema.String),
@@ -69,6 +78,7 @@ export const TuiInfo = Schema.Struct({
plugin_enabled: Schema.optional(Schema.Record(Schema.String, Schema.Boolean)), plugin_enabled: Schema.optional(Schema.Record(Schema.String, Schema.Boolean)),
leader_timeout: Schema.optional(KeymapLeaderTimeout), leader_timeout: Schema.optional(KeymapLeaderTimeout),
attention: Schema.optional(Attention), attention: Schema.optional(Attention),
prompt: Schema.optional(Prompt),
scroll_speed: Schema.optional(ScrollSpeed).annotate({ scroll_speed: Schema.optional(ScrollSpeed).annotate({
description: "TUI scroll speed", description: "TUI scroll speed",
}), }),
@@ -1,5 +1,5 @@
import { Prompt, type PromptRef } from "@tui/component/prompt" import { Prompt, type PromptRef } from "@tui/component/prompt"
import { createEffect, createSignal, onMount } from "solid-js" import { createEffect, createMemo, createSignal, onMount } from "solid-js"
import { Logo } from "../component/logo" import { Logo } from "../component/logo"
import { useSync } from "../context/sync" import { useSync } from "../context/sync"
import { Toast } from "../ui/toast" import { Toast } from "../ui/toast"
@@ -9,6 +9,8 @@ import { usePromptRef } from "../context/prompt"
import { useLocal } from "../context/local" import { useLocal } from "../context/local"
import { TuiPluginRuntime } from "@/cli/cmd/tui/plugin/runtime" import { TuiPluginRuntime } from "@/cli/cmd/tui/plugin/runtime"
import { useEditorContext } from "@tui/context/editor" import { useEditorContext } from "@tui/context/editor"
import { useTerminalDimensions } from "@opentui/solid"
import { useTuiConfig } from "../context/tui-config"
let once = false let once = false
const placeholder = { const placeholder = {
@@ -24,6 +26,13 @@ export function Home() {
const args = useArgs() const args = useArgs()
const local = useLocal() const local = useLocal()
const editor = useEditorContext() const editor = useEditorContext()
const dimensions = useTerminalDimensions()
const tuiConfig = useTuiConfig()
const promptMaxWidth = createMemo(() => {
const configured = tuiConfig.prompt?.max_width
if (configured === "auto") return Math.max(75, Math.floor(dimensions().width * 0.7))
return configured ?? 75
})
let sent = false let sent = false
onMount(() => { onMount(() => {
@@ -67,7 +76,7 @@ export function Home() {
</TuiPluginRuntime.Slot> </TuiPluginRuntime.Slot>
</box> </box>
<box height={1} minHeight={0} flexShrink={1} /> <box height={1} minHeight={0} flexShrink={1} />
<box width="100%" maxWidth={75} zIndex={1000} paddingTop={1} flexShrink={0}> <box width="100%" maxWidth={promptMaxWidth()} zIndex={1000} paddingTop={1} flexShrink={0}>
<TuiPluginRuntime.Slot name="home_prompt" mode="replace" ref={bind}> <TuiPluginRuntime.Slot name="home_prompt" mode="replace" ref={bind}>
<Prompt ref={bind} right={<TuiPluginRuntime.Slot name="home_prompt_right" />} placeholders={placeholder} /> <Prompt ref={bind} right={<TuiPluginRuntime.Slot name="home_prompt_right" />} placeholders={placeholder} />
</TuiPluginRuntime.Slot> </TuiPluginRuntime.Slot>