Browse Source

feat(tui): support cycling recent models in reverse (#1953)

Yihui Khuu 6 months ago
parent
commit
92d4366a20

+ 18 - 4
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 {

+ 46 - 40
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,9 +267,14 @@ 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",

+ 4 - 0
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