mirror of
https://github.com/aljazceru/opencode.git
synced 2025-12-21 01:34:22 +01:00
tui: add keyboard shortcuts to cycle through recently used models
Users can now press F2 to cycle forward and Shift+F2 to cycle backward through their recently used models, making it faster to switch between commonly used AI models without opening the model selection dialog.
This commit is contained in:
@@ -162,10 +162,32 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
|
||||
const recent = createMemo(() => store.recent.map(find).filter(Boolean))
|
||||
|
||||
const cycle = (direction: 1 | -1) => {
|
||||
const recentList = recent()
|
||||
const current = currentModel()
|
||||
if (!current) return
|
||||
|
||||
const index = recentList.findIndex((x) => x?.provider.id === current.provider.id && x?.id === current.id)
|
||||
if (index === -1) return
|
||||
|
||||
let next = index + direction
|
||||
if (next < 0) next = recentList.length - 1
|
||||
if (next >= recentList.length) next = 0
|
||||
|
||||
const val = recentList[next]
|
||||
if (!val) return
|
||||
|
||||
model.set({
|
||||
providerID: val.provider.id,
|
||||
modelID: val.id,
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
current: currentModel,
|
||||
recent,
|
||||
list,
|
||||
cycle,
|
||||
set(model: ModelKey | undefined, options?: { recent?: boolean }) {
|
||||
batch(() => {
|
||||
setStore("model", agent.current().name, model ?? fallbackModel())
|
||||
|
||||
@@ -172,6 +172,24 @@ function App() {
|
||||
dialog.replace(() => <DialogModel />)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Model cycle",
|
||||
value: "model.cycle_recent",
|
||||
keybind: "model_cycle_recent",
|
||||
category: "Agent",
|
||||
onSelect: () => {
|
||||
local.model.cycle(1)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Model cycle reverse",
|
||||
value: "model.cycle_recent_reverse",
|
||||
keybind: "model_cycle_recent_reverse",
|
||||
category: "Agent",
|
||||
onSelect: () => {
|
||||
local.model.cycle(-1)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Switch agent",
|
||||
value: "agent.list",
|
||||
|
||||
@@ -147,15 +147,6 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
setModelStore("ready", true)
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
Bun.write(
|
||||
file,
|
||||
JSON.stringify({
|
||||
recent: modelStore.recent,
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
const fallbackModel = createMemo(() => {
|
||||
if (sync.data.config.model) {
|
||||
const [providerID, modelID] = sync.data.config.model.split("/")
|
||||
@@ -206,6 +197,21 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
model: model.name ?? value.modelID,
|
||||
}
|
||||
}),
|
||||
cycle(direction: 1 | -1) {
|
||||
const current = currentModel()
|
||||
if (!current) return
|
||||
const recent = modelStore.recent
|
||||
const index = recent.findIndex(
|
||||
(x) => x.providerID === current.providerID && x.modelID === current.modelID,
|
||||
)
|
||||
if (index === -1) return
|
||||
let next = index + direction
|
||||
if (next < 0) next = recent.length - 1
|
||||
if (next >= recent.length) next = 0
|
||||
const val = recent[next]
|
||||
if (!val) return
|
||||
setModelStore("model", agent.current().name, { ...val })
|
||||
},
|
||||
set(model: { providerID: string; modelID: string }, options?: { recent?: boolean }) {
|
||||
batch(() => {
|
||||
if (!isModelValid(model)) {
|
||||
@@ -216,12 +222,17 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
setModelStore("model", agent.current().name, model)
|
||||
if (options?.recent) {
|
||||
const uniq = uniqueBy([model, ...modelStore.recent], (x) => x.providerID + x.modelID)
|
||||
if (uniq.length > 5) uniq.pop()
|
||||
setModelStore("recent", uniq)
|
||||
Bun.write(
|
||||
file,
|
||||
JSON.stringify({
|
||||
recent: modelStore.recent,
|
||||
}),
|
||||
)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@@ -453,6 +453,12 @@ export namespace Config {
|
||||
.default("<leader>h")
|
||||
.describe("Toggle code block concealment in messages"),
|
||||
model_list: z.string().optional().default("<leader>m").describe("List available models"),
|
||||
model_cycle_recent: z.string().optional().default("f2").describe("Next recently used model"),
|
||||
model_cycle_recent_reverse: z
|
||||
.string()
|
||||
.optional()
|
||||
.default("shift+f2")
|
||||
.describe("Previous recently used model"),
|
||||
command_list: z.string().optional().default("ctrl+p").describe("List available commands"),
|
||||
agent_list: z.string().optional().default("<leader>a").describe("List agents"),
|
||||
agent_cycle: z.string().optional().default("tab").describe("Next agent"),
|
||||
|
||||
@@ -114,6 +114,14 @@ export type KeybindsConfig = {
|
||||
* List available models
|
||||
*/
|
||||
model_list?: string
|
||||
/**
|
||||
* Next recently used model
|
||||
*/
|
||||
model_cycle_recent?: string
|
||||
/**
|
||||
* Previous recently used model
|
||||
*/
|
||||
model_cycle_recent_reverse?: string
|
||||
/**
|
||||
* List available commands
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user