Skip to content
Open
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
7 changes: 4 additions & 3 deletions packages/opencode/src/cli/cmd/tui/component/dialog-model.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { map, pipe, flatMap, entries, filter, sortBy, take } from "remeda"
import { DialogSelect, type DialogSelectRef } from "@tui/ui/dialog-select"
import { useDialog } from "@tui/ui/dialog"
import { createDialogProviderOptions, DialogProvider } from "./dialog-provider"
import { Keybind } from "@/util/keybind"
import { useKeybind } from "../context/keybind"
import * as fuzzysort from "fuzzysort"

export function useConnected() {
Expand All @@ -19,6 +19,7 @@ export function DialogModel(props: { providerID?: string }) {
const local = useLocal()
const sync = useSync()
const dialog = useDialog()
const keybind = useKeybind()
const [ref, setRef] = createSignal<DialogSelectRef<unknown>>()
const [query, setQuery] = createSignal("")

Expand Down Expand Up @@ -204,14 +205,14 @@ export function DialogModel(props: { providerID?: string }) {
<DialogSelect
keybind={[
{
keybind: Keybind.parse("ctrl+a")[0],
keybind: keybind.all.model_provider_list?.[0],
title: connected() ? "Connect provider" : "View all providers",
onTrigger() {
dialog.replace(() => <DialogProvider />)
},
},
{
keybind: Keybind.parse("ctrl+f")[0],
keybind: keybind.all.model_favorite_toggle?.[0],
title: "Favorite",
disabled: !connected(),
onTrigger: (option) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { useRoute } from "@tui/context/route"
import { useSync } from "@tui/context/sync"
import { createEffect, createMemo, createSignal, onMount } from "solid-js"
import { Locale } from "@/util/locale"
import { Keybind } from "@/util/keybind"
import { useTheme } from "../context/theme"
import { useSDK } from "../context/sdk"
import { useKeybind } from "../context/keybind"
import { DialogSessionRename } from "./dialog-session-rename"
import "opentui-spinner/solid"

Expand All @@ -16,11 +16,10 @@ export function DialogSessionList() {
const { theme } = useTheme()
const route = useRoute()
const sdk = useSDK()
const keybind = useKeybind()

const [toDelete, setToDelete] = createSignal<string>()

const deleteKeybind = "ctrl+d"

const currentSessionID = createMemo(() => (route.data.type === "session" ? route.data.sessionID : undefined))

const spinnerFrames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
Expand All @@ -40,7 +39,7 @@ export function DialogSessionList() {
const status = sync.data.session_status?.[x.id]
const isWorking = status?.type === "busy"
return {
title: isDeleting ? `Press ${deleteKeybind} again to confirm` : x.title,
title: isDeleting ? `Press ${keybind.print("session_delete")} again to confirm` : x.title,
bg: isDeleting ? theme.error : undefined,
value: x.id,
category,
Expand Down Expand Up @@ -76,7 +75,7 @@ export function DialogSessionList() {
}}
keybind={[
{
keybind: Keybind.parse(deleteKeybind)[0],
keybind: keybind.all.session_delete?.[0],
title: "delete",
onTrigger: async (option) => {
if (toDelete() === option.value) {
Expand All @@ -90,7 +89,7 @@ export function DialogSessionList() {
},
},
{
keybind: Keybind.parse("ctrl+r")[0],
keybind: keybind.all.session_rename?.[0],
title: "rename",
onTrigger: async (option) => {
dialog.replace(() => <DialogSessionRename session={option.value} />)
Expand Down
7 changes: 4 additions & 3 deletions packages/opencode/src/cli/cmd/tui/component/dialog-stash.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { useDialog } from "@tui/ui/dialog"
import { DialogSelect } from "@tui/ui/dialog-select"
import { createMemo, createSignal } from "solid-js"
import { Locale } from "@/util/locale"
import { Keybind } from "@/util/keybind"
import { useTheme } from "../context/theme"
import { useKeybind } from "../context/keybind"
import { usePromptStash, type StashEntry } from "./prompt/stash"

function getRelativeTime(timestamp: number): string {
Expand All @@ -30,6 +30,7 @@ export function DialogStash(props: { onSelect: (entry: StashEntry) => void }) {
const dialog = useDialog()
const stash = usePromptStash()
const { theme } = useTheme()
const keybind = useKeybind()

const [toDelete, setToDelete] = createSignal<number>()

Expand All @@ -41,7 +42,7 @@ export function DialogStash(props: { onSelect: (entry: StashEntry) => void }) {
const isDeleting = toDelete() === index
const lineCount = (entry.input.match(/\n/g)?.length ?? 0) + 1
return {
title: isDeleting ? "Press ctrl+d again to confirm" : getStashPreview(entry.input),
title: isDeleting ? `Press ${keybind.print("stash_delete")} again to confirm` : getStashPreview(entry.input),
bg: isDeleting ? theme.error : undefined,
value: index,
description: getRelativeTime(entry.timestamp),
Expand Down Expand Up @@ -69,7 +70,7 @@ export function DialogStash(props: { onSelect: (entry: StashEntry) => void }) {
}}
keybind={[
{
keybind: Keybind.parse("ctrl+d")[0],
keybind: keybind.all.stash_delete?.[0],
title: "delete",
onTrigger: (option) => {
if (toDelete() === option.value) {
Expand Down
6 changes: 3 additions & 3 deletions packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export interface DialogSelectProps<T> {
onSelect?: (option: DialogSelectOption<T>) => void
skipFilter?: boolean
keybind?: {
keybind: Keybind.Info
keybind?: Keybind.Info
title: string
disabled?: boolean
onTrigger: (option: DialogSelectOption<T>) => void
Expand Down Expand Up @@ -161,7 +161,7 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
}

for (const item of props.keybind ?? []) {
if (item.disabled) continue
if (item.disabled || !item.keybind) continue
if (Keybind.match(item.keybind, keybind.parse(evt))) {
const s = selected()
if (s) {
Expand All @@ -183,7 +183,7 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
}
props.ref?.(ref)

const keybinds = createMemo(() => props.keybind?.filter((x) => !x.disabled) ?? [])
const keybinds = createMemo(() => props.keybind?.filter((x) => !x.disabled && x.keybind) ?? [])

return (
<box gap={1} paddingBottom={1}>
Expand Down
6 changes: 5 additions & 1 deletion packages/opencode/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,11 @@ export namespace Config {
session_list: z.string().optional().default("<leader>l").describe("List all sessions"),
session_timeline: z.string().optional().default("<leader>g").describe("Show session timeline"),
session_fork: z.string().optional().default("none").describe("Fork session from message"),
session_rename: z.string().optional().default("none").describe("Rename session"),
session_rename: z.string().optional().default("ctrl+r").describe("Rename session"),
session_delete: z.string().optional().default("ctrl+d").describe("Delete session"),
stash_delete: z.string().optional().default("ctrl+d").describe("Delete stash entry"),
model_provider_list: z.string().optional().default("ctrl+a").describe("Open provider list from model dialog"),
model_favorite_toggle: z.string().optional().default("ctrl+f").describe("Toggle model favorite status"),
session_share: z.string().optional().default("none").describe("Share current session"),
session_unshare: z.string().optional().default("none").describe("Unshare current session"),
session_interrupt: z.string().optional().default("escape").describe("Interrupt current session"),
Expand Down
7 changes: 4 additions & 3 deletions packages/opencode/src/util/keybind.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ export namespace Keybind {
leader: boolean // our custom field
}

export function match(a: Info, b: Info): boolean {
// Normalize super field (undefined and false are equivalent)
export function match(a: Info | undefined, b: Info): boolean {
if (!a) return false
const normalizedA = { ...a, super: a.super ?? false }
const normalizedB = { ...b, super: b.super ?? false }
return isDeepEqual(normalizedA, normalizedB)
Expand All @@ -32,7 +32,8 @@ export namespace Keybind {
}
}

export function toString(info: Info): string {
export function toString(info: Info | undefined): string {
if (!info) return ""
const parts: string[] = []

if (info.ctrl) parts.push("ctrl")
Expand Down
2 changes: 1 addition & 1 deletion packages/plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@
"typescript": "catalog:",
"@typescript/native-preview": "catalog:"
}
}
}
2 changes: 1 addition & 1 deletion packages/sdk/js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@
"publishConfig": {
"directory": "dist"
}
}
}
16 changes: 16 additions & 0 deletions packages/sdk/js/src/v2/gen/types.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,22 @@ export type KeybindsConfig = {
* Rename session
*/
session_rename?: string
/**
* Delete session
*/
session_delete?: string
/**
* Delete stash entry
*/
stash_delete?: string
/**
* Open provider list from model dialog
*/
model_provider_list?: string
/**
* Toggle model favorite status
*/
model_favorite_toggle?: string
/**
* Share current session
*/
Expand Down
22 changes: 21 additions & 1 deletion packages/sdk/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -7321,7 +7321,27 @@
},
"session_rename": {
"description": "Rename session",
"default": "none",
"default": "ctrl+r",
"type": "string"
},
"session_delete": {
"description": "Delete session",
"default": "ctrl+d",
"type": "string"
},
"stash_delete": {
"description": "Delete stash entry",
"default": "ctrl+d",
"type": "string"
},
"model_provider_list": {
"description": "Open provider list from model dialog",
"default": "ctrl+a",
"type": "string"
},
"model_favorite_toggle": {
"description": "Toggle model favorite status",
"default": "ctrl+f",
"type": "string"
},
"session_share": {
Expand Down