Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
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
9 changes: 9 additions & 0 deletions packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,14 @@ export function Prompt(props: PromptProps) {
return !!current
})

const cursorStyle = createMemo(() => {
const tui = sync.data.config.tui
return {
style: (tui?.cursor_style ?? "block") as "block" | "line" | "underline",
blinking: tui?.cursor_blink ?? true,
}
})

const spinnerDef = createMemo(() => {
const color = local.agent.color(local.agent.current().name)
return {
Expand Down Expand Up @@ -948,6 +956,7 @@ export function Prompt(props: PromptProps) {
onMouseDown={(r: MouseEvent) => r.target?.focus()}
focusedBackgroundColor={theme.backgroundElement}
cursorColor={theme.text}
cursorStyle={cursorStyle()}
syntaxStyle={syntax()}
/>
<box flexDirection="row" flexShrink={0} paddingTop={1} gap={1}>
Expand Down
10 changes: 10 additions & 0 deletions packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,15 @@ function RejectPrompt(props: { onConfirm: (message: string) => void; onCancel: (
const dimensions = useTerminalDimensions()
const narrow = createMemo(() => dimensions().width < 80)
const dialog = useDialog()
const sync = useSync()

const cursorStyle = createMemo(() => {
const tui = sync.data.config.tui
return {
style: (tui?.cursor_style ?? "block") as "block" | "line" | "underline",
blinking: tui?.cursor_blink ?? true,
}
})

useKeyboard((evt) => {
if (dialog.stack.length > 0) return
Expand Down Expand Up @@ -355,6 +364,7 @@ function RejectPrompt(props: { onConfirm: (message: string) => void; onCancel: (
textColor={theme.text}
focusedTextColor={theme.text}
cursorColor={theme.primary}
cursorStyle={cursorStyle()}
keyBindings={textareaKeybindings()}
/>
<box flexDirection="row" gap={2} flexShrink={0}>
Expand Down
10 changes: 10 additions & 0 deletions packages/opencode/src/cli/cmd/tui/routes/session/question.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useKeyboard } from "@opentui/solid"
import type { TextareaRenderable } from "@opentui/core"
import { useKeybind } from "../../context/keybind"
import { selectedForeground, tint, useTheme } from "../../context/theme"
import { useSync } from "../../context/sync"
import type { QuestionAnswer, QuestionRequest } from "@opencode-ai/sdk/v2"
import { useSDK } from "../../context/sdk"
import { SplitBorder } from "../../component/border"
Expand All @@ -15,6 +16,7 @@ export function QuestionPrompt(props: { request: QuestionRequest }) {
const { theme } = useTheme()
const keybind = useKeybind()
const bindings = useTextareaKeybindings()
const sync = useSync()

const questions = createMemo(() => props.request.questions)
const single = createMemo(() => questions().length === 1 && questions()[0]?.multiple !== true)
Expand All @@ -41,6 +43,13 @@ export function QuestionPrompt(props: { request: QuestionRequest }) {
if (!value) return false
return store.answers[store.tab]?.includes(value) ?? false
})
const cursorStyle = createMemo(() => {
const tui = sync.data.config.tui
return {
style: (tui?.cursor_style ?? "block") as "block" | "line" | "underline",
blinking: tui?.cursor_blink ?? true,
}
})

function submit() {
const answers = questions().map((_, i) => store.answers[i] ?? [])
Expand Down Expand Up @@ -379,6 +388,7 @@ export function QuestionPrompt(props: { request: QuestionRequest }) {
textColor={theme.text}
focusedTextColor={theme.text}
cursorColor={theme.primary}
cursorStyle={cursorStyle()}
keyBindings={bindings()}
/>
</box>
Expand Down
14 changes: 13 additions & 1 deletion packages/opencode/src/cli/cmd/tui/ui/dialog-export-options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { TextareaRenderable, TextAttributes } from "@opentui/core"
import { useTheme } from "../context/theme"
import { useDialog, type DialogContext } from "./dialog"
import { createStore } from "solid-js/store"
import { onMount, Show, type JSX } from "solid-js"
import { createMemo, onMount, Show, type JSX } from "solid-js"
import { useKeyboard } from "@opentui/solid"
import { useSync } from "../context/sync"

export type DialogExportOptionsProps = {
defaultFilename: string
Expand All @@ -24,7 +25,17 @@ export type DialogExportOptionsProps = {
export function DialogExportOptions(props: DialogExportOptionsProps) {
const dialog = useDialog()
const { theme } = useTheme()
const sync = useSync()
let textarea: TextareaRenderable

const cursorStyle = createMemo(() => {
const tui = sync.data.config.tui
return {
style: (tui?.cursor_style ?? "block") as "block" | "line" | "underline",
blinking: tui?.cursor_blink ?? true,
}
})

const [store, setStore] = createStore({
thinking: props.defaultThinking,
toolDetails: props.defaultToolDetails,
Expand Down Expand Up @@ -104,6 +115,7 @@ export function DialogExportOptions(props: DialogExportOptionsProps) {
textColor={theme.text}
focusedTextColor={theme.text}
cursorColor={theme.text}
cursorStyle={cursorStyle()}
/>
</box>
<box flexDirection="column">
Expand Down
13 changes: 12 additions & 1 deletion packages/opencode/src/cli/cmd/tui/ui/dialog-prompt.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { TextareaRenderable, TextAttributes } from "@opentui/core"
import { useTheme } from "../context/theme"
import { useDialog, type DialogContext } from "./dialog"
import { onMount, type JSX } from "solid-js"
import { createMemo, onMount, type JSX } from "solid-js"
import { useKeyboard } from "@opentui/solid"
import { useSync } from "../context/sync"

export type DialogPromptProps = {
title: string
Expand All @@ -16,8 +17,17 @@ export type DialogPromptProps = {
export function DialogPrompt(props: DialogPromptProps) {
const dialog = useDialog()
const { theme } = useTheme()
const sync = useSync()
let textarea: TextareaRenderable

const cursorStyle = createMemo(() => {
const tui = sync.data.config.tui
return {
style: (tui?.cursor_style ?? "block") as "block" | "line" | "underline",
blinking: tui?.cursor_blink ?? true,
}
})

useKeyboard((evt) => {
if (evt.name === "return") {
props.onConfirm?.(textarea.plainText)
Expand Down Expand Up @@ -55,6 +65,7 @@ export function DialogPrompt(props: DialogPromptProps) {
textColor={theme.text}
focusedTextColor={theme.text}
cursorColor={theme.text}
cursorStyle={cursorStyle()}
/>
</box>
<box paddingBottom={1} gap={1} flexDirection="row">
Expand Down
7 changes: 7 additions & 0 deletions packages/opencode/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -829,6 +829,11 @@ export namespace Config {
ref: "KeybindsConfig",
})

export const CursorStyle = z.enum(["block", "line", "underline"]).meta({
ref: "CursorStyleConfig",
})
export type CursorStyle = z.infer<typeof CursorStyle>

export const TUI = z.object({
scroll_speed: z.number().min(0.001).optional().describe("TUI scroll speed"),
scroll_acceleration: z
Expand All @@ -841,6 +846,8 @@ export namespace Config {
.enum(["auto", "stacked"])
.optional()
.describe("Control diff rendering style: 'auto' adapts to terminal width, 'stacked' always shows single column"),
cursor_style: CursorStyle.optional().describe("Cursor shape in text inputs: 'block', 'line', or 'underline'"),
cursor_blink: z.boolean().optional().describe("Enable cursor blinking in text inputs"),
})

export const Server = z
Expand Down
10 changes: 10 additions & 0 deletions packages/sdk/js/src/v2/gen/types.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1315,6 +1315,11 @@ export type KeybindsConfig = {
*/
export type LogLevel = "DEBUG" | "INFO" | "WARN" | "ERROR"

/**
* Cursor shape in text inputs: 'block', 'line', or 'underline'
*/
export type CursorStyleConfig = "block" | "line" | "underline"

/**
* Server configuration for opencode serve and web commands
*/
Expand Down Expand Up @@ -1620,6 +1625,11 @@ export type Config = {
* Control diff rendering style: 'auto' adapts to terminal width, 'stacked' always shows single column
*/
diff_style?: "auto" | "stacked"
cursor_style?: CursorStyleConfig
/**
* Enable cursor blinking in text inputs
*/
cursor_blink?: boolean
}
server?: ServerConfig
/**
Expand Down
Loading