Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 37 additions & 7 deletions packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
import { BoxRenderable, TextareaRenderable, MouseEvent, PasteEvent, decodePasteBytes } from "@opentui/core"
import { createEffect, createMemo, onMount, createSignal, onCleanup, on, Show, Switch, Match } from "solid-js"
import { BoxRenderable, RGBA, TextareaRenderable, MouseEvent, PasteEvent, decodePasteBytes } from "@opentui/core"
import {
createEffect,
createMemo,
onMount,
createSignal,
onCleanup,
on,
Show,
Switch,
Match,
} from "solid-js"
import "opentui-spinner/solid"
import path from "path"
import { fileURLToPath } from "url"
Expand Down Expand Up @@ -35,6 +45,7 @@ import { DialogProvider as DialogProviderConnect } from "../dialog-provider"
import { DialogAlert } from "../../ui/dialog-alert"
import { useToast } from "../../ui/toast"
import { useKV } from "../../context/kv"
import { createFadeIn } from "../../util/signal"
import { useTextareaKeybindings } from "../textarea-keybindings"
import { DialogSkill } from "../dialog-skill"
import { useArgs } from "@tui/context/args"
Expand Down Expand Up @@ -75,6 +86,10 @@ function randomIndex(count: number) {
return Math.floor(Math.random() * count)
}

function fadeColor(color: RGBA, alpha: number) {
return RGBA.fromValues(color.r, color.g, color.b, color.a * alpha)
}

let stashed: { prompt: PromptInfo; cursor: number } | undefined

export function Prompt(props: PromptProps) {
Expand All @@ -97,6 +112,7 @@ export function Prompt(props: PromptProps) {
const renderer = useRenderer()
const { theme, syntax } = useTheme()
const kv = useKV()
const animationsEnabled = createMemo(() => kv.get("animations_enabled", true))
const list = createMemo(() => props.placeholders?.normal ?? [])
const shell = createMemo(() => props.placeholders?.shell ?? [])
const [auto, setAuto] = createSignal<AutocompleteRef>()
Expand Down Expand Up @@ -858,6 +874,13 @@ export function Prompt(props: PromptProps) {
return !!current
})

const agentMetaAlpha = createFadeIn(() => !!local.agent.current(), animationsEnabled)
const modelMetaAlpha = createFadeIn(() => !!local.agent.current() && store.mode === "normal", animationsEnabled)
const variantMetaAlpha = createFadeIn(
() => !!local.agent.current() && store.mode === "normal" && showVariant(),
animationsEnabled,
)

const placeholderText = createMemo(() => {
if (props.showPlaceholder === false) return undefined
if (store.mode === "shell") {
Expand Down Expand Up @@ -1133,17 +1156,24 @@ export function Prompt(props: PromptProps) {
<Show when={local.agent.current()} fallback={<box height={1} />}>
{(agent) => (
<>
<text fg={highlight()}>{store.mode === "shell" ? "Shell" : Locale.titlecase(agent().name)} </text>
<text fg={fadeColor(highlight(), agentMetaAlpha())}>
{store.mode === "shell" ? "Shell" : Locale.titlecase(agent().name)}{" "}
</text>
<Show when={store.mode === "normal"}>
<box flexDirection="row" gap={1}>
<text flexShrink={0} fg={keybind.leader ? theme.textMuted : theme.text}>
<text
flexShrink={0}
fg={fadeColor(keybind.leader ? theme.textMuted : theme.text, modelMetaAlpha())}
>
{local.model.parsed().model}
</text>
<text fg={theme.textMuted}>{currentProviderLabel()}</text>
<text fg={fadeColor(theme.textMuted, modelMetaAlpha())}>{currentProviderLabel()}</text>
<Show when={showVariant()}>
<text fg={theme.textMuted}>·</text>
<text fg={fadeColor(theme.textMuted, variantMetaAlpha())}>·</text>
<text>
<span style={{ fg: theme.warning, bold: true }}>{local.model.variant.current()}</span>
<span style={{ fg: fadeColor(theme.warning, variantMetaAlpha()), bold: true }}>
{local.model.variant.current()}
</span>
</text>
</Show>
</box>
Expand Down
33 changes: 32 additions & 1 deletion packages/opencode/src/cli/cmd/tui/util/signal.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,38 @@
import { createSignal, type Accessor } from "solid-js"
import { createEffect, createSignal, on, onCleanup, type Accessor } from "solid-js"
import { debounce, type Scheduled } from "@solid-primitives/scheduled"

export function createDebouncedSignal<T>(value: T, ms: number): [Accessor<T>, Scheduled<[value: T]>] {
const [get, set] = createSignal(value)
return [get, debounce((v: T) => set(() => v), ms)]
}

export function createFadeIn(show: Accessor<boolean>, enabled: Accessor<boolean>) {
const [alpha, setAlpha] = createSignal(show() ? 1 : 0)

createEffect(
on([show, enabled], ([visible, animate], previous) => {
if (!visible) {
setAlpha(0)
return
}

if (!animate || !previous) {
setAlpha(1)
return
}

const start = performance.now()
setAlpha(0)

const timer = setInterval(() => {
const progress = Math.min((performance.now() - start) / 160, 1)
setAlpha(progress * progress * (3 - 2 * progress))
if (progress >= 1) clearInterval(timer)
}, 16)

onCleanup(() => clearInterval(timer))
}),
)

return alpha
}
Loading