summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorYihui Khuu <[email protected]>2025-08-15 21:20:07 +1000
committerGitHub <[email protected]>2025-08-15 06:20:07 -0500
commit92d4366a20b4499b8e4817df442d67d021949feb (patch)
tree955d36b9911eb34ebc2deec1d5135cf56b25d2b4
parent17a7c824b848240c777469ff670a1189445ba5bd (diff)
downloadopencode-92d4366a20b4499b8e4817df442d67d021949feb.tar.gz
opencode-92d4366a20b4499b8e4817df442d67d021949feb.zip
feat(tui): support cycling recent models in reverse (#1953)
-rw-r--r--packages/tui/internal/app/app.go22
-rw-r--r--packages/tui/internal/commands/command.go86
-rw-r--r--packages/tui/internal/tui/tui.go4
3 files changed, 68 insertions, 44 deletions
diff --git a/packages/tui/internal/app/app.go b/packages/tui/internal/app/app.go
index 023b799d5..eff00f296 100644
--- a/packages/tui/internal/app/app.go
+++ b/packages/tui/internal/app/app.go
@@ -290,7 +290,7 @@ func (a *App) SwitchAgentReverse() (*App, tea.Cmd) {
return a.cycleMode(false)
}
-func (a *App) CycleRecentModel() (*App, tea.Cmd) {
+func (a *App) cycleRecentModel(forward bool) (*App, tea.Cmd) {
recentModels := a.State.RecentlyUsedModels
if len(recentModels) > 5 {
recentModels = recentModels[:5]
@@ -299,15 +299,21 @@ func (a *App) CycleRecentModel() (*App, tea.Cmd) {
return a, toast.NewInfoToast("Need at least 2 recent models to cycle")
}
nextIndex := 0
+ prevIndex := 0
for i, recentModel := range recentModels {
if a.Provider != nil && a.Model != nil && recentModel.ProviderID == a.Provider.ID &&
recentModel.ModelID == a.Model.ID {
nextIndex = (i + 1) % len(recentModels)
+ prevIndex = (i - 1 + len(recentModels)) % len(recentModels)
break
}
}
+ targetIndex := nextIndex
+ if !forward {
+ targetIndex = prevIndex
+ }
for range recentModels {
- currentRecentModel := recentModels[nextIndex%len(recentModels)]
+ currentRecentModel := recentModels[targetIndex%len(recentModels)]
provider, model := findModelByProviderAndModelID(
a.Providers,
currentRecentModel.ProviderID,
@@ -327,8 +333,8 @@ func (a *App) CycleRecentModel() (*App, tea.Cmd) {
)
}
recentModels = append(
- recentModels[:nextIndex%len(recentModels)],
- recentModels[nextIndex%len(recentModels)+1:]...)
+ recentModels[:targetIndex%len(recentModels)],
+ recentModels[targetIndex%len(recentModels)+1:]...)
if len(recentModels) < 2 {
a.State.RecentlyUsedModels = recentModels
return a, tea.Sequence(
@@ -341,6 +347,14 @@ func (a *App) CycleRecentModel() (*App, tea.Cmd) {
return a, toast.NewErrorToast("Recent model not found")
}
+func (a *App) CycleRecentModel() (*App, tea.Cmd) {
+ return a.cycleRecentModel(true)
+}
+
+func (a *App) CycleRecentModelReverse() (*App, tea.Cmd) {
+ return a.cycleRecentModel(false)
+}
+
func (a *App) SwitchToAgent(agentName string) (*App, tea.Cmd) {
// Find the agent index by name
for i, agent := range a.Agents {
diff --git a/packages/tui/internal/commands/command.go b/packages/tui/internal/commands/command.go
index fff547543..ebb468d2c 100644
--- a/packages/tui/internal/commands/command.go
+++ b/packages/tui/internal/commands/command.go
@@ -107,45 +107,46 @@ func (r CommandRegistry) Matches(msg tea.KeyPressMsg, leader bool) []Command {
}
const (
- AppHelpCommand CommandName = "app_help"
- SwitchAgentCommand CommandName = "switch_agent"
- SwitchAgentReverseCommand CommandName = "switch_agent_reverse"
- EditorOpenCommand CommandName = "editor_open"
- SessionNewCommand CommandName = "session_new"
- SessionListCommand CommandName = "session_list"
- SessionShareCommand CommandName = "session_share"
- SessionUnshareCommand CommandName = "session_unshare"
- SessionInterruptCommand CommandName = "session_interrupt"
- SessionCompactCommand CommandName = "session_compact"
- SessionExportCommand CommandName = "session_export"
- ToolDetailsCommand CommandName = "tool_details"
- ThinkingBlocksCommand CommandName = "thinking_blocks"
- ModelListCommand CommandName = "model_list"
- AgentListCommand CommandName = "agent_list"
- ModelCycleRecentCommand CommandName = "model_cycle_recent"
- ThemeListCommand CommandName = "theme_list"
- FileListCommand CommandName = "file_list"
- FileCloseCommand CommandName = "file_close"
- FileSearchCommand CommandName = "file_search"
- FileDiffToggleCommand CommandName = "file_diff_toggle"
- ProjectInitCommand CommandName = "project_init"
- InputClearCommand CommandName = "input_clear"
- InputPasteCommand CommandName = "input_paste"
- InputSubmitCommand CommandName = "input_submit"
- InputNewlineCommand CommandName = "input_newline"
- MessagesPageUpCommand CommandName = "messages_page_up"
- MessagesPageDownCommand CommandName = "messages_page_down"
- MessagesHalfPageUpCommand CommandName = "messages_half_page_up"
- MessagesHalfPageDownCommand CommandName = "messages_half_page_down"
- MessagesPreviousCommand CommandName = "messages_previous"
- MessagesNextCommand CommandName = "messages_next"
- MessagesFirstCommand CommandName = "messages_first"
- MessagesLastCommand CommandName = "messages_last"
- MessagesLayoutToggleCommand CommandName = "messages_layout_toggle"
- MessagesCopyCommand CommandName = "messages_copy"
- MessagesUndoCommand CommandName = "messages_undo"
- MessagesRedoCommand CommandName = "messages_redo"
- AppExitCommand CommandName = "app_exit"
+ AppHelpCommand CommandName = "app_help"
+ SwitchAgentCommand CommandName = "switch_agent"
+ SwitchAgentReverseCommand CommandName = "switch_agent_reverse"
+ EditorOpenCommand CommandName = "editor_open"
+ SessionNewCommand CommandName = "session_new"
+ SessionListCommand CommandName = "session_list"
+ SessionShareCommand CommandName = "session_share"
+ SessionUnshareCommand CommandName = "session_unshare"
+ SessionInterruptCommand CommandName = "session_interrupt"
+ SessionCompactCommand CommandName = "session_compact"
+ SessionExportCommand CommandName = "session_export"
+ ToolDetailsCommand CommandName = "tool_details"
+ ThinkingBlocksCommand CommandName = "thinking_blocks"
+ ModelListCommand CommandName = "model_list"
+ AgentListCommand CommandName = "agent_list"
+ ModelCycleRecentCommand CommandName = "model_cycle_recent"
+ ModelCycleRecentReverseCommand CommandName = "model_cycle_recent_reverse"
+ ThemeListCommand CommandName = "theme_list"
+ FileListCommand CommandName = "file_list"
+ FileCloseCommand CommandName = "file_close"
+ FileSearchCommand CommandName = "file_search"
+ FileDiffToggleCommand CommandName = "file_diff_toggle"
+ ProjectInitCommand CommandName = "project_init"
+ InputClearCommand CommandName = "input_clear"
+ InputPasteCommand CommandName = "input_paste"
+ InputSubmitCommand CommandName = "input_submit"
+ InputNewlineCommand CommandName = "input_newline"
+ MessagesPageUpCommand CommandName = "messages_page_up"
+ MessagesPageDownCommand CommandName = "messages_page_down"
+ MessagesHalfPageUpCommand CommandName = "messages_half_page_up"
+ MessagesHalfPageDownCommand CommandName = "messages_half_page_down"
+ MessagesPreviousCommand CommandName = "messages_previous"
+ MessagesNextCommand CommandName = "messages_next"
+ MessagesFirstCommand CommandName = "messages_first"
+ MessagesLastCommand CommandName = "messages_last"
+ MessagesLayoutToggleCommand CommandName = "messages_layout_toggle"
+ MessagesCopyCommand CommandName = "messages_copy"
+ MessagesUndoCommand CommandName = "messages_undo"
+ MessagesRedoCommand CommandName = "messages_redo"
+ AppExitCommand CommandName = "app_exit"
)
func (k Command) Matches(msg tea.KeyPressMsg, leader bool) bool {
@@ -266,10 +267,15 @@ func LoadFromConfig(config *opencode.Config) CommandRegistry {
},
{
Name: ModelCycleRecentCommand,
- Description: "cycle recent models",
+ Description: "next recent model",
Keybindings: parseBindings("f2"),
},
{
+ Name: ModelCycleRecentReverseCommand,
+ Description: "previous recent model",
+ Keybindings: parseBindings("shift+f2"),
+ },
+ {
Name: ThemeListCommand,
Description: "list themes",
Keybindings: parseBindings("<leader>t"),
diff --git a/packages/tui/internal/tui/tui.go b/packages/tui/internal/tui/tui.go
index f9a014ddb..dcbdd2b5d 100644
--- a/packages/tui/internal/tui/tui.go
+++ b/packages/tui/internal/tui/tui.go
@@ -1190,6 +1190,10 @@ func (a Model) executeCommand(command commands.Command) (tea.Model, tea.Cmd) {
updated, cmd := a.app.CycleRecentModel()
a.app = updated
cmds = append(cmds, cmd)
+ case commands.ModelCycleRecentReverseCommand:
+ updated, cmd := a.app.CycleRecentModelReverse()
+ a.app = updated
+ cmds = append(cmds, cmd)
case commands.ThemeListCommand:
themeDialog := dialog.NewThemeDialog()
a.modal = themeDialog