mirror of
https://github.com/aljazceru/opencode.git
synced 2025-12-19 16:54:22 +01:00
fix: more commands cleanup
This commit is contained in:
@@ -127,6 +127,12 @@ export namespace Config {
|
|||||||
if (result.keybinds?.switch_mode_reverse && !result.keybinds.switch_agent_reverse) {
|
if (result.keybinds?.switch_mode_reverse && !result.keybinds.switch_agent_reverse) {
|
||||||
result.keybinds.switch_agent_reverse = result.keybinds.switch_mode_reverse
|
result.keybinds.switch_agent_reverse = result.keybinds.switch_mode_reverse
|
||||||
}
|
}
|
||||||
|
if (result.keybinds?.switch_agent && !result.keybinds.agent_cycle) {
|
||||||
|
result.keybinds.agent_cycle = result.keybinds.switch_agent
|
||||||
|
}
|
||||||
|
if (result.keybinds?.switch_agent_reverse && !result.keybinds.agent_cycle_reverse) {
|
||||||
|
result.keybinds.agent_cycle_reverse = result.keybinds.switch_agent_reverse
|
||||||
|
}
|
||||||
|
|
||||||
if (!result.username) {
|
if (!result.username) {
|
||||||
const os = await import("os")
|
const os = await import("os")
|
||||||
@@ -199,9 +205,12 @@ export namespace Config {
|
|||||||
.object({
|
.object({
|
||||||
leader: z.string().optional().default("ctrl+x").describe("Leader key for keybind combinations"),
|
leader: z.string().optional().default("ctrl+x").describe("Leader key for keybind combinations"),
|
||||||
app_help: z.string().optional().default("<leader>h").describe("Show help dialog"),
|
app_help: z.string().optional().default("<leader>h").describe("Show help dialog"),
|
||||||
switch_agent: z.string().optional().default("tab").describe("Next agent"),
|
app_exit: z.string().optional().default("ctrl+c,<leader>q").describe("Exit the application"),
|
||||||
switch_agent_reverse: z.string().optional().default("shift+tab").describe("Previous agent"),
|
|
||||||
editor_open: z.string().optional().default("<leader>e").describe("Open external editor"),
|
editor_open: z.string().optional().default("<leader>e").describe("Open external editor"),
|
||||||
|
theme_list: z.string().optional().default("<leader>t").describe("List available themes"),
|
||||||
|
project_init: z.string().optional().default("<leader>i").describe("Create/update AGENTS.md"),
|
||||||
|
tool_details: z.string().optional().default("<leader>d").describe("Toggle tool details"),
|
||||||
|
thinking_blocks: z.string().optional().default("<leader>b").describe("Toggle thinking blocks"),
|
||||||
session_export: z.string().optional().default("<leader>x").describe("Export session to editor"),
|
session_export: z.string().optional().default("<leader>x").describe("Export session to editor"),
|
||||||
session_new: z.string().optional().default("<leader>n").describe("Create a new session"),
|
session_new: z.string().optional().default("<leader>n").describe("Create a new session"),
|
||||||
session_list: z.string().optional().default("<leader>l").describe("List all sessions"),
|
session_list: z.string().optional().default("<leader>l").describe("List all sessions"),
|
||||||
@@ -209,18 +218,6 @@ export namespace Config {
|
|||||||
session_unshare: z.string().optional().default("none").describe("Unshare current session"),
|
session_unshare: z.string().optional().default("none").describe("Unshare current session"),
|
||||||
session_interrupt: z.string().optional().default("esc").describe("Interrupt current session"),
|
session_interrupt: z.string().optional().default("esc").describe("Interrupt current session"),
|
||||||
session_compact: z.string().optional().default("<leader>c").describe("Compact the session"),
|
session_compact: z.string().optional().default("<leader>c").describe("Compact the session"),
|
||||||
tool_details: z.string().optional().default("<leader>d").describe("Toggle tool details"),
|
|
||||||
thinking_blocks: z.string().optional().default("<leader>b").describe("Toggle thinking blocks"),
|
|
||||||
model_list: z.string().optional().default("<leader>m").describe("List available models"),
|
|
||||||
agent_list: z.string().optional().default("<leader>a").describe("List agents"),
|
|
||||||
model_cycle_recent: z.string().optional().default("f2").describe("Next recent model"),
|
|
||||||
model_cycle_recent_reverse: z.string().optional().default("shift+f2").describe("Previous recent model"),
|
|
||||||
theme_list: z.string().optional().default("<leader>t").describe("List available themes"),
|
|
||||||
project_init: z.string().optional().default("<leader>i").describe("Create/update AGENTS.md"),
|
|
||||||
input_clear: z.string().optional().default("ctrl+c").describe("Clear input field"),
|
|
||||||
input_paste: z.string().optional().default("ctrl+v").describe("Paste from clipboard"),
|
|
||||||
input_submit: z.string().optional().default("enter").describe("Submit input"),
|
|
||||||
input_newline: z.string().optional().default("shift+enter,ctrl+j").describe("Insert newline in input"),
|
|
||||||
messages_page_up: z.string().optional().default("pgup").describe("Scroll messages up by one page"),
|
messages_page_up: z.string().optional().default("pgup").describe("Scroll messages up by one page"),
|
||||||
messages_page_down: z.string().optional().default("pgdown").describe("Scroll messages down by one page"),
|
messages_page_down: z.string().optional().default("pgdown").describe("Scroll messages down by one page"),
|
||||||
messages_half_page_up: z.string().optional().default("ctrl+alt+u").describe("Scroll messages up by half page"),
|
messages_half_page_up: z.string().optional().default("ctrl+alt+u").describe("Scroll messages up by half page"),
|
||||||
@@ -234,14 +231,29 @@ export namespace Config {
|
|||||||
messages_copy: z.string().optional().default("<leader>y").describe("Copy message"),
|
messages_copy: z.string().optional().default("<leader>y").describe("Copy message"),
|
||||||
messages_undo: z.string().optional().default("<leader>u").describe("Undo message"),
|
messages_undo: z.string().optional().default("<leader>u").describe("Undo message"),
|
||||||
messages_redo: z.string().optional().default("<leader>r").describe("Redo message"),
|
messages_redo: z.string().optional().default("<leader>r").describe("Redo message"),
|
||||||
app_exit: z.string().optional().default("ctrl+c,<leader>q").describe("Exit the application"),
|
model_list: z.string().optional().default("<leader>m").describe("List available models"),
|
||||||
|
model_cycle_recent: z.string().optional().default("f2").describe("Next recent model"),
|
||||||
|
model_cycle_recent_reverse: z.string().optional().default("shift+f2").describe("Previous recent model"),
|
||||||
|
agent_list: z.string().optional().default("<leader>a").describe("List agents"),
|
||||||
|
agent_cycle: z.string().optional().default("tab").describe("Next agent"),
|
||||||
|
agent_cycle_reverse: z.string().optional().default("shift+tab").describe("Previous agent"),
|
||||||
|
input_clear: z.string().optional().default("ctrl+c").describe("Clear input field"),
|
||||||
|
input_paste: z.string().optional().default("ctrl+v").describe("Paste from clipboard"),
|
||||||
|
input_submit: z.string().optional().default("enter").describe("Submit input"),
|
||||||
|
input_newline: z.string().optional().default("shift+enter,ctrl+j").describe("Insert newline in input"),
|
||||||
// Deprecated commands
|
// Deprecated commands
|
||||||
switch_mode: z.string().optional().default("none").describe("@deprecated use switch_agent. Next mode"),
|
switch_mode: z.string().optional().default("none").describe("@deprecated use agent_cycle. Next mode"),
|
||||||
switch_mode_reverse: z
|
switch_mode_reverse: z
|
||||||
.string()
|
.string()
|
||||||
.optional()
|
.optional()
|
||||||
.default("none")
|
.default("none")
|
||||||
.describe("@deprecated use switch_agent_reverse. Previous mode"),
|
.describe("@deprecated use agent_cycle_reverse. Previous mode"),
|
||||||
|
switch_agent: z.string().optional().default("tab").describe("@deprecated use agent_cycle. Next agent"),
|
||||||
|
switch_agent_reverse: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.default("shift+tab")
|
||||||
|
.describe("@deprecated use agent_cycle_reverse. Previous agent"),
|
||||||
file_list: z.string().optional().default("none").describe("@deprecated Currently not available. List files"),
|
file_list: z.string().optional().default("none").describe("@deprecated Currently not available. List files"),
|
||||||
file_close: z.string().optional().default("none").describe("@deprecated Close file"),
|
file_close: z.string().optional().default("none").describe("@deprecated Close file"),
|
||||||
file_search: z.string().optional().default("none").describe("@deprecated Search file"),
|
file_search: z.string().optional().default("none").describe("@deprecated Search file"),
|
||||||
|
|||||||
@@ -1099,7 +1099,7 @@ export namespace Server {
|
|||||||
.post(
|
.post(
|
||||||
"/tui/execute-command",
|
"/tui/execute-command",
|
||||||
describeRoute({
|
describeRoute({
|
||||||
description: "Execute a TUI command (e.g. switch_agent)",
|
description: "Execute a TUI command (e.g. agent_cycle)",
|
||||||
operationId: "tui.executeCommand",
|
operationId: "tui.executeCommand",
|
||||||
responses: {
|
responses: {
|
||||||
200: {
|
200: {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
configured_endpoints: 36
|
configured_endpoints: 36
|
||||||
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-a881262c7de4ab59bdfbfc6e30a23c47dee465d7270ffb867b760b0103aff8ed.yml
|
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-d0eaf92deaa53a25bbbc3181540ad73ed5a4aec6381ac08d8122e24318e5e455.yml
|
||||||
openapi_spec_hash: 7dbb6f96f5c26a25c849e50298f58586
|
openapi_spec_hash: 22196d859c0711e564b9538d988abda6
|
||||||
config_hash: 8d85a768523cff92b85ef06c443d49fa
|
config_hash: 8d85a768523cff92b85ef06c443d49fa
|
||||||
|
|||||||
@@ -1655,19 +1655,25 @@ func (r ConfigShare) IsKnown() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type KeybindsConfig struct {
|
type KeybindsConfig struct {
|
||||||
|
// Next agent
|
||||||
|
AgentCycle string `json:"agent_cycle,required"`
|
||||||
|
// Previous agent
|
||||||
|
AgentCycleReverse string `json:"agent_cycle_reverse,required"`
|
||||||
|
// List agents
|
||||||
|
AgentList string `json:"agent_list,required"`
|
||||||
// Exit the application
|
// Exit the application
|
||||||
AppExit string `json:"app_exit,required"`
|
AppExit string `json:"app_exit,required"`
|
||||||
// Show help dialog
|
// Show help dialog
|
||||||
AppHelp string `json:"app_help,required"`
|
AppHelp string `json:"app_help,required"`
|
||||||
// Open external editor
|
// Open external editor
|
||||||
EditorOpen string `json:"editor_open,required"`
|
EditorOpen string `json:"editor_open,required"`
|
||||||
// Close file
|
// @deprecated Close file
|
||||||
FileClose string `json:"file_close,required"`
|
FileClose string `json:"file_close,required"`
|
||||||
// Split/unified diff
|
// @deprecated Split/unified diff
|
||||||
FileDiffToggle string `json:"file_diff_toggle,required"`
|
FileDiffToggle string `json:"file_diff_toggle,required"`
|
||||||
// List files
|
// @deprecated Currently not available. List files
|
||||||
FileList string `json:"file_list,required"`
|
FileList string `json:"file_list,required"`
|
||||||
// Search file
|
// @deprecated Search file
|
||||||
FileSearch string `json:"file_search,required"`
|
FileSearch string `json:"file_search,required"`
|
||||||
// Clear input field
|
// Clear input field
|
||||||
InputClear string `json:"input_clear,required"`
|
InputClear string `json:"input_clear,required"`
|
||||||
@@ -1689,15 +1695,15 @@ type KeybindsConfig struct {
|
|||||||
MessagesHalfPageUp string `json:"messages_half_page_up,required"`
|
MessagesHalfPageUp string `json:"messages_half_page_up,required"`
|
||||||
// Navigate to last message
|
// Navigate to last message
|
||||||
MessagesLast string `json:"messages_last,required"`
|
MessagesLast string `json:"messages_last,required"`
|
||||||
// Toggle layout
|
// @deprecated Toggle layout
|
||||||
MessagesLayoutToggle string `json:"messages_layout_toggle,required"`
|
MessagesLayoutToggle string `json:"messages_layout_toggle,required"`
|
||||||
// Navigate to next message
|
// @deprecated Navigate to next message
|
||||||
MessagesNext string `json:"messages_next,required"`
|
MessagesNext string `json:"messages_next,required"`
|
||||||
// Scroll messages down by one page
|
// Scroll messages down by one page
|
||||||
MessagesPageDown string `json:"messages_page_down,required"`
|
MessagesPageDown string `json:"messages_page_down,required"`
|
||||||
// Scroll messages up by one page
|
// Scroll messages up by one page
|
||||||
MessagesPageUp string `json:"messages_page_up,required"`
|
MessagesPageUp string `json:"messages_page_up,required"`
|
||||||
// Navigate to previous message
|
// @deprecated Navigate to previous message
|
||||||
MessagesPrevious string `json:"messages_previous,required"`
|
MessagesPrevious string `json:"messages_previous,required"`
|
||||||
// Redo message
|
// Redo message
|
||||||
MessagesRedo string `json:"messages_redo,required"`
|
MessagesRedo string `json:"messages_redo,required"`
|
||||||
@@ -1705,6 +1711,10 @@ type KeybindsConfig struct {
|
|||||||
MessagesRevert string `json:"messages_revert,required"`
|
MessagesRevert string `json:"messages_revert,required"`
|
||||||
// Undo message
|
// Undo message
|
||||||
MessagesUndo string `json:"messages_undo,required"`
|
MessagesUndo string `json:"messages_undo,required"`
|
||||||
|
// Next recent model
|
||||||
|
ModelCycleRecent string `json:"model_cycle_recent,required"`
|
||||||
|
// Previous recent model
|
||||||
|
ModelCycleRecentReverse string `json:"model_cycle_recent_reverse,required"`
|
||||||
// List available models
|
// List available models
|
||||||
ModelList string `json:"model_list,required"`
|
ModelList string `json:"model_list,required"`
|
||||||
// Create/update AGENTS.md
|
// Create/update AGENTS.md
|
||||||
@@ -1723,13 +1733,13 @@ type KeybindsConfig struct {
|
|||||||
SessionShare string `json:"session_share,required"`
|
SessionShare string `json:"session_share,required"`
|
||||||
// Unshare current session
|
// Unshare current session
|
||||||
SessionUnshare string `json:"session_unshare,required"`
|
SessionUnshare string `json:"session_unshare,required"`
|
||||||
// Next agent
|
// @deprecated use agent_cycle. Next agent
|
||||||
SwitchAgent string `json:"switch_agent,required"`
|
SwitchAgent string `json:"switch_agent,required"`
|
||||||
// Previous agent
|
// @deprecated use agent_cycle_reverse. Previous agent
|
||||||
SwitchAgentReverse string `json:"switch_agent_reverse,required"`
|
SwitchAgentReverse string `json:"switch_agent_reverse,required"`
|
||||||
// @deprecated use switch_agent. Next mode
|
// @deprecated use agent_cycle. Next mode
|
||||||
SwitchMode string `json:"switch_mode,required"`
|
SwitchMode string `json:"switch_mode,required"`
|
||||||
// @deprecated use switch_agent_reverse. Previous mode
|
// @deprecated use agent_cycle_reverse. Previous mode
|
||||||
SwitchModeReverse string `json:"switch_mode_reverse,required"`
|
SwitchModeReverse string `json:"switch_mode_reverse,required"`
|
||||||
// List available themes
|
// List available themes
|
||||||
ThemeList string `json:"theme_list,required"`
|
ThemeList string `json:"theme_list,required"`
|
||||||
@@ -1742,49 +1752,54 @@ type KeybindsConfig struct {
|
|||||||
|
|
||||||
// keybindsConfigJSON contains the JSON metadata for the struct [KeybindsConfig]
|
// keybindsConfigJSON contains the JSON metadata for the struct [KeybindsConfig]
|
||||||
type keybindsConfigJSON struct {
|
type keybindsConfigJSON struct {
|
||||||
AppExit apijson.Field
|
AgentCycle apijson.Field
|
||||||
AppHelp apijson.Field
|
AgentCycleReverse apijson.Field
|
||||||
EditorOpen apijson.Field
|
AgentList apijson.Field
|
||||||
FileClose apijson.Field
|
AppExit apijson.Field
|
||||||
FileDiffToggle apijson.Field
|
AppHelp apijson.Field
|
||||||
FileList apijson.Field
|
EditorOpen apijson.Field
|
||||||
FileSearch apijson.Field
|
FileClose apijson.Field
|
||||||
InputClear apijson.Field
|
FileDiffToggle apijson.Field
|
||||||
InputNewline apijson.Field
|
FileList apijson.Field
|
||||||
InputPaste apijson.Field
|
FileSearch apijson.Field
|
||||||
InputSubmit apijson.Field
|
InputClear apijson.Field
|
||||||
Leader apijson.Field
|
InputNewline apijson.Field
|
||||||
MessagesCopy apijson.Field
|
InputPaste apijson.Field
|
||||||
MessagesFirst apijson.Field
|
InputSubmit apijson.Field
|
||||||
MessagesHalfPageDown apijson.Field
|
Leader apijson.Field
|
||||||
MessagesHalfPageUp apijson.Field
|
MessagesCopy apijson.Field
|
||||||
MessagesLast apijson.Field
|
MessagesFirst apijson.Field
|
||||||
MessagesLayoutToggle apijson.Field
|
MessagesHalfPageDown apijson.Field
|
||||||
MessagesNext apijson.Field
|
MessagesHalfPageUp apijson.Field
|
||||||
MessagesPageDown apijson.Field
|
MessagesLast apijson.Field
|
||||||
MessagesPageUp apijson.Field
|
MessagesLayoutToggle apijson.Field
|
||||||
MessagesPrevious apijson.Field
|
MessagesNext apijson.Field
|
||||||
MessagesRedo apijson.Field
|
MessagesPageDown apijson.Field
|
||||||
MessagesRevert apijson.Field
|
MessagesPageUp apijson.Field
|
||||||
MessagesUndo apijson.Field
|
MessagesPrevious apijson.Field
|
||||||
ModelList apijson.Field
|
MessagesRedo apijson.Field
|
||||||
ProjectInit apijson.Field
|
MessagesRevert apijson.Field
|
||||||
SessionCompact apijson.Field
|
MessagesUndo apijson.Field
|
||||||
SessionExport apijson.Field
|
ModelCycleRecent apijson.Field
|
||||||
SessionInterrupt apijson.Field
|
ModelCycleRecentReverse apijson.Field
|
||||||
SessionList apijson.Field
|
ModelList apijson.Field
|
||||||
SessionNew apijson.Field
|
ProjectInit apijson.Field
|
||||||
SessionShare apijson.Field
|
SessionCompact apijson.Field
|
||||||
SessionUnshare apijson.Field
|
SessionExport apijson.Field
|
||||||
SwitchAgent apijson.Field
|
SessionInterrupt apijson.Field
|
||||||
SwitchAgentReverse apijson.Field
|
SessionList apijson.Field
|
||||||
SwitchMode apijson.Field
|
SessionNew apijson.Field
|
||||||
SwitchModeReverse apijson.Field
|
SessionShare apijson.Field
|
||||||
ThemeList apijson.Field
|
SessionUnshare apijson.Field
|
||||||
ThinkingBlocks apijson.Field
|
SwitchAgent apijson.Field
|
||||||
ToolDetails apijson.Field
|
SwitchAgentReverse apijson.Field
|
||||||
raw string
|
SwitchMode apijson.Field
|
||||||
ExtraFields map[string]apijson.Field
|
SwitchModeReverse apijson.Field
|
||||||
|
ThemeList apijson.Field
|
||||||
|
ThinkingBlocks apijson.Field
|
||||||
|
ToolDetails apijson.Field
|
||||||
|
raw string
|
||||||
|
ExtraFields map[string]apijson.Field
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *KeybindsConfig) UnmarshalJSON(data []byte) (err error) {
|
func (r *KeybindsConfig) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
|||||||
@@ -54,13 +54,13 @@ type EventListResponse struct {
|
|||||||
// [EventListResponseEventMessageRemovedProperties],
|
// [EventListResponseEventMessageRemovedProperties],
|
||||||
// [EventListResponseEventMessagePartUpdatedProperties],
|
// [EventListResponseEventMessagePartUpdatedProperties],
|
||||||
// [EventListResponseEventMessagePartRemovedProperties],
|
// [EventListResponseEventMessagePartRemovedProperties],
|
||||||
// [EventListResponseEventStorageWriteProperties],
|
// [EventListResponseEventStorageWriteProperties], [Permission],
|
||||||
// [EventListResponseEventFileEditedProperties], [interface{}], [Permission],
|
|
||||||
// [EventListResponseEventPermissionRepliedProperties],
|
// [EventListResponseEventPermissionRepliedProperties],
|
||||||
|
// [EventListResponseEventFileEditedProperties],
|
||||||
// [EventListResponseEventSessionUpdatedProperties],
|
// [EventListResponseEventSessionUpdatedProperties],
|
||||||
// [EventListResponseEventSessionDeletedProperties],
|
// [EventListResponseEventSessionDeletedProperties],
|
||||||
// [EventListResponseEventSessionIdleProperties],
|
// [EventListResponseEventSessionIdleProperties],
|
||||||
// [EventListResponseEventSessionErrorProperties],
|
// [EventListResponseEventSessionErrorProperties], [interface{}],
|
||||||
// [EventListResponseEventFileWatcherUpdatedProperties],
|
// [EventListResponseEventFileWatcherUpdatedProperties],
|
||||||
// [EventListResponseEventIdeInstalledProperties].
|
// [EventListResponseEventIdeInstalledProperties].
|
||||||
Properties interface{} `json:"properties,required"`
|
Properties interface{} `json:"properties,required"`
|
||||||
@@ -100,12 +100,11 @@ func (r *EventListResponse) UnmarshalJSON(data []byte) (err error) {
|
|||||||
// [EventListResponseEventMessageUpdated], [EventListResponseEventMessageRemoved],
|
// [EventListResponseEventMessageUpdated], [EventListResponseEventMessageRemoved],
|
||||||
// [EventListResponseEventMessagePartUpdated],
|
// [EventListResponseEventMessagePartUpdated],
|
||||||
// [EventListResponseEventMessagePartRemoved],
|
// [EventListResponseEventMessagePartRemoved],
|
||||||
// [EventListResponseEventStorageWrite], [EventListResponseEventFileEdited],
|
// [EventListResponseEventStorageWrite], [EventListResponseEventPermissionUpdated],
|
||||||
// [EventListResponseEventServerConnected],
|
// [EventListResponseEventPermissionReplied], [EventListResponseEventFileEdited],
|
||||||
// [EventListResponseEventPermissionUpdated],
|
|
||||||
// [EventListResponseEventPermissionReplied],
|
|
||||||
// [EventListResponseEventSessionUpdated], [EventListResponseEventSessionDeleted],
|
// [EventListResponseEventSessionUpdated], [EventListResponseEventSessionDeleted],
|
||||||
// [EventListResponseEventSessionIdle], [EventListResponseEventSessionError],
|
// [EventListResponseEventSessionIdle], [EventListResponseEventSessionError],
|
||||||
|
// [EventListResponseEventServerConnected],
|
||||||
// [EventListResponseEventFileWatcherUpdated],
|
// [EventListResponseEventFileWatcherUpdated],
|
||||||
// [EventListResponseEventIdeInstalled].
|
// [EventListResponseEventIdeInstalled].
|
||||||
func (r EventListResponse) AsUnion() EventListResponseUnion {
|
func (r EventListResponse) AsUnion() EventListResponseUnion {
|
||||||
@@ -117,12 +116,11 @@ func (r EventListResponse) AsUnion() EventListResponseUnion {
|
|||||||
// [EventListResponseEventMessageUpdated], [EventListResponseEventMessageRemoved],
|
// [EventListResponseEventMessageUpdated], [EventListResponseEventMessageRemoved],
|
||||||
// [EventListResponseEventMessagePartUpdated],
|
// [EventListResponseEventMessagePartUpdated],
|
||||||
// [EventListResponseEventMessagePartRemoved],
|
// [EventListResponseEventMessagePartRemoved],
|
||||||
// [EventListResponseEventStorageWrite], [EventListResponseEventFileEdited],
|
// [EventListResponseEventStorageWrite], [EventListResponseEventPermissionUpdated],
|
||||||
// [EventListResponseEventServerConnected],
|
// [EventListResponseEventPermissionReplied], [EventListResponseEventFileEdited],
|
||||||
// [EventListResponseEventPermissionUpdated],
|
|
||||||
// [EventListResponseEventPermissionReplied],
|
|
||||||
// [EventListResponseEventSessionUpdated], [EventListResponseEventSessionDeleted],
|
// [EventListResponseEventSessionUpdated], [EventListResponseEventSessionDeleted],
|
||||||
// [EventListResponseEventSessionIdle], [EventListResponseEventSessionError],
|
// [EventListResponseEventSessionIdle], [EventListResponseEventSessionError],
|
||||||
|
// [EventListResponseEventServerConnected],
|
||||||
// [EventListResponseEventFileWatcherUpdated] or
|
// [EventListResponseEventFileWatcherUpdated] or
|
||||||
// [EventListResponseEventIdeInstalled].
|
// [EventListResponseEventIdeInstalled].
|
||||||
type EventListResponseUnion interface {
|
type EventListResponseUnion interface {
|
||||||
@@ -168,16 +166,6 @@ func init() {
|
|||||||
Type: reflect.TypeOf(EventListResponseEventStorageWrite{}),
|
Type: reflect.TypeOf(EventListResponseEventStorageWrite{}),
|
||||||
DiscriminatorValue: "storage.write",
|
DiscriminatorValue: "storage.write",
|
||||||
},
|
},
|
||||||
apijson.UnionVariant{
|
|
||||||
TypeFilter: gjson.JSON,
|
|
||||||
Type: reflect.TypeOf(EventListResponseEventFileEdited{}),
|
|
||||||
DiscriminatorValue: "file.edited",
|
|
||||||
},
|
|
||||||
apijson.UnionVariant{
|
|
||||||
TypeFilter: gjson.JSON,
|
|
||||||
Type: reflect.TypeOf(EventListResponseEventServerConnected{}),
|
|
||||||
DiscriminatorValue: "server.connected",
|
|
||||||
},
|
|
||||||
apijson.UnionVariant{
|
apijson.UnionVariant{
|
||||||
TypeFilter: gjson.JSON,
|
TypeFilter: gjson.JSON,
|
||||||
Type: reflect.TypeOf(EventListResponseEventPermissionUpdated{}),
|
Type: reflect.TypeOf(EventListResponseEventPermissionUpdated{}),
|
||||||
@@ -188,6 +176,11 @@ func init() {
|
|||||||
Type: reflect.TypeOf(EventListResponseEventPermissionReplied{}),
|
Type: reflect.TypeOf(EventListResponseEventPermissionReplied{}),
|
||||||
DiscriminatorValue: "permission.replied",
|
DiscriminatorValue: "permission.replied",
|
||||||
},
|
},
|
||||||
|
apijson.UnionVariant{
|
||||||
|
TypeFilter: gjson.JSON,
|
||||||
|
Type: reflect.TypeOf(EventListResponseEventFileEdited{}),
|
||||||
|
DiscriminatorValue: "file.edited",
|
||||||
|
},
|
||||||
apijson.UnionVariant{
|
apijson.UnionVariant{
|
||||||
TypeFilter: gjson.JSON,
|
TypeFilter: gjson.JSON,
|
||||||
Type: reflect.TypeOf(EventListResponseEventSessionUpdated{}),
|
Type: reflect.TypeOf(EventListResponseEventSessionUpdated{}),
|
||||||
@@ -208,6 +201,11 @@ func init() {
|
|||||||
Type: reflect.TypeOf(EventListResponseEventSessionError{}),
|
Type: reflect.TypeOf(EventListResponseEventSessionError{}),
|
||||||
DiscriminatorValue: "session.error",
|
DiscriminatorValue: "session.error",
|
||||||
},
|
},
|
||||||
|
apijson.UnionVariant{
|
||||||
|
TypeFilter: gjson.JSON,
|
||||||
|
Type: reflect.TypeOf(EventListResponseEventServerConnected{}),
|
||||||
|
DiscriminatorValue: "server.connected",
|
||||||
|
},
|
||||||
apijson.UnionVariant{
|
apijson.UnionVariant{
|
||||||
TypeFilter: gjson.JSON,
|
TypeFilter: gjson.JSON,
|
||||||
Type: reflect.TypeOf(EventListResponseEventFileWatcherUpdated{}),
|
Type: reflect.TypeOf(EventListResponseEventFileWatcherUpdated{}),
|
||||||
@@ -651,105 +649,6 @@ func (r EventListResponseEventStorageWriteType) IsKnown() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
type EventListResponseEventFileEdited struct {
|
|
||||||
Properties EventListResponseEventFileEditedProperties `json:"properties,required"`
|
|
||||||
Type EventListResponseEventFileEditedType `json:"type,required"`
|
|
||||||
JSON eventListResponseEventFileEditedJSON `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// eventListResponseEventFileEditedJSON contains the JSON metadata for the struct
|
|
||||||
// [EventListResponseEventFileEdited]
|
|
||||||
type eventListResponseEventFileEditedJSON struct {
|
|
||||||
Properties apijson.Field
|
|
||||||
Type apijson.Field
|
|
||||||
raw string
|
|
||||||
ExtraFields map[string]apijson.Field
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *EventListResponseEventFileEdited) UnmarshalJSON(data []byte) (err error) {
|
|
||||||
return apijson.UnmarshalRoot(data, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r eventListResponseEventFileEditedJSON) RawJSON() string {
|
|
||||||
return r.raw
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r EventListResponseEventFileEdited) implementsEventListResponse() {}
|
|
||||||
|
|
||||||
type EventListResponseEventFileEditedProperties struct {
|
|
||||||
File string `json:"file,required"`
|
|
||||||
JSON eventListResponseEventFileEditedPropertiesJSON `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// eventListResponseEventFileEditedPropertiesJSON contains the JSON metadata for
|
|
||||||
// the struct [EventListResponseEventFileEditedProperties]
|
|
||||||
type eventListResponseEventFileEditedPropertiesJSON struct {
|
|
||||||
File apijson.Field
|
|
||||||
raw string
|
|
||||||
ExtraFields map[string]apijson.Field
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *EventListResponseEventFileEditedProperties) UnmarshalJSON(data []byte) (err error) {
|
|
||||||
return apijson.UnmarshalRoot(data, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r eventListResponseEventFileEditedPropertiesJSON) RawJSON() string {
|
|
||||||
return r.raw
|
|
||||||
}
|
|
||||||
|
|
||||||
type EventListResponseEventFileEditedType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
EventListResponseEventFileEditedTypeFileEdited EventListResponseEventFileEditedType = "file.edited"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (r EventListResponseEventFileEditedType) IsKnown() bool {
|
|
||||||
switch r {
|
|
||||||
case EventListResponseEventFileEditedTypeFileEdited:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type EventListResponseEventServerConnected struct {
|
|
||||||
Properties interface{} `json:"properties,required"`
|
|
||||||
Type EventListResponseEventServerConnectedType `json:"type,required"`
|
|
||||||
JSON eventListResponseEventServerConnectedJSON `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// eventListResponseEventServerConnectedJSON contains the JSON metadata for the
|
|
||||||
// struct [EventListResponseEventServerConnected]
|
|
||||||
type eventListResponseEventServerConnectedJSON struct {
|
|
||||||
Properties apijson.Field
|
|
||||||
Type apijson.Field
|
|
||||||
raw string
|
|
||||||
ExtraFields map[string]apijson.Field
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *EventListResponseEventServerConnected) UnmarshalJSON(data []byte) (err error) {
|
|
||||||
return apijson.UnmarshalRoot(data, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r eventListResponseEventServerConnectedJSON) RawJSON() string {
|
|
||||||
return r.raw
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r EventListResponseEventServerConnected) implementsEventListResponse() {}
|
|
||||||
|
|
||||||
type EventListResponseEventServerConnectedType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
EventListResponseEventServerConnectedTypeServerConnected EventListResponseEventServerConnectedType = "server.connected"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (r EventListResponseEventServerConnectedType) IsKnown() bool {
|
|
||||||
switch r {
|
|
||||||
case EventListResponseEventServerConnectedTypeServerConnected:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type EventListResponseEventPermissionUpdated struct {
|
type EventListResponseEventPermissionUpdated struct {
|
||||||
Properties Permission `json:"properties,required"`
|
Properties Permission `json:"properties,required"`
|
||||||
Type EventListResponseEventPermissionUpdatedType `json:"type,required"`
|
Type EventListResponseEventPermissionUpdatedType `json:"type,required"`
|
||||||
@@ -853,6 +752,66 @@ func (r EventListResponseEventPermissionRepliedType) IsKnown() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type EventListResponseEventFileEdited struct {
|
||||||
|
Properties EventListResponseEventFileEditedProperties `json:"properties,required"`
|
||||||
|
Type EventListResponseEventFileEditedType `json:"type,required"`
|
||||||
|
JSON eventListResponseEventFileEditedJSON `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// eventListResponseEventFileEditedJSON contains the JSON metadata for the struct
|
||||||
|
// [EventListResponseEventFileEdited]
|
||||||
|
type eventListResponseEventFileEditedJSON struct {
|
||||||
|
Properties apijson.Field
|
||||||
|
Type apijson.Field
|
||||||
|
raw string
|
||||||
|
ExtraFields map[string]apijson.Field
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *EventListResponseEventFileEdited) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
return apijson.UnmarshalRoot(data, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r eventListResponseEventFileEditedJSON) RawJSON() string {
|
||||||
|
return r.raw
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r EventListResponseEventFileEdited) implementsEventListResponse() {}
|
||||||
|
|
||||||
|
type EventListResponseEventFileEditedProperties struct {
|
||||||
|
File string `json:"file,required"`
|
||||||
|
JSON eventListResponseEventFileEditedPropertiesJSON `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// eventListResponseEventFileEditedPropertiesJSON contains the JSON metadata for
|
||||||
|
// the struct [EventListResponseEventFileEditedProperties]
|
||||||
|
type eventListResponseEventFileEditedPropertiesJSON struct {
|
||||||
|
File apijson.Field
|
||||||
|
raw string
|
||||||
|
ExtraFields map[string]apijson.Field
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *EventListResponseEventFileEditedProperties) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
return apijson.UnmarshalRoot(data, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r eventListResponseEventFileEditedPropertiesJSON) RawJSON() string {
|
||||||
|
return r.raw
|
||||||
|
}
|
||||||
|
|
||||||
|
type EventListResponseEventFileEditedType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
EventListResponseEventFileEditedTypeFileEdited EventListResponseEventFileEditedType = "file.edited"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r EventListResponseEventFileEditedType) IsKnown() bool {
|
||||||
|
switch r {
|
||||||
|
case EventListResponseEventFileEditedTypeFileEdited:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
type EventListResponseEventSessionUpdated struct {
|
type EventListResponseEventSessionUpdated struct {
|
||||||
Properties EventListResponseEventSessionUpdatedProperties `json:"properties,required"`
|
Properties EventListResponseEventSessionUpdatedProperties `json:"properties,required"`
|
||||||
Type EventListResponseEventSessionUpdatedType `json:"type,required"`
|
Type EventListResponseEventSessionUpdatedType `json:"type,required"`
|
||||||
@@ -1229,6 +1188,45 @@ func (r EventListResponseEventSessionErrorType) IsKnown() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type EventListResponseEventServerConnected struct {
|
||||||
|
Properties interface{} `json:"properties,required"`
|
||||||
|
Type EventListResponseEventServerConnectedType `json:"type,required"`
|
||||||
|
JSON eventListResponseEventServerConnectedJSON `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// eventListResponseEventServerConnectedJSON contains the JSON metadata for the
|
||||||
|
// struct [EventListResponseEventServerConnected]
|
||||||
|
type eventListResponseEventServerConnectedJSON struct {
|
||||||
|
Properties apijson.Field
|
||||||
|
Type apijson.Field
|
||||||
|
raw string
|
||||||
|
ExtraFields map[string]apijson.Field
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *EventListResponseEventServerConnected) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
return apijson.UnmarshalRoot(data, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r eventListResponseEventServerConnectedJSON) RawJSON() string {
|
||||||
|
return r.raw
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r EventListResponseEventServerConnected) implementsEventListResponse() {}
|
||||||
|
|
||||||
|
type EventListResponseEventServerConnectedType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
EventListResponseEventServerConnectedTypeServerConnected EventListResponseEventServerConnectedType = "server.connected"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r EventListResponseEventServerConnectedType) IsKnown() bool {
|
||||||
|
switch r {
|
||||||
|
case EventListResponseEventServerConnectedTypeServerConnected:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
type EventListResponseEventFileWatcherUpdated struct {
|
type EventListResponseEventFileWatcherUpdated struct {
|
||||||
Properties EventListResponseEventFileWatcherUpdatedProperties `json:"properties,required"`
|
Properties EventListResponseEventFileWatcherUpdatedProperties `json:"properties,required"`
|
||||||
Type EventListResponseEventFileWatcherUpdatedType `json:"type,required"`
|
Type EventListResponseEventFileWatcherUpdatedType `json:"type,required"`
|
||||||
@@ -1376,21 +1374,21 @@ const (
|
|||||||
EventListResponseTypeMessagePartUpdated EventListResponseType = "message.part.updated"
|
EventListResponseTypeMessagePartUpdated EventListResponseType = "message.part.updated"
|
||||||
EventListResponseTypeMessagePartRemoved EventListResponseType = "message.part.removed"
|
EventListResponseTypeMessagePartRemoved EventListResponseType = "message.part.removed"
|
||||||
EventListResponseTypeStorageWrite EventListResponseType = "storage.write"
|
EventListResponseTypeStorageWrite EventListResponseType = "storage.write"
|
||||||
EventListResponseTypeFileEdited EventListResponseType = "file.edited"
|
|
||||||
EventListResponseTypeServerConnected EventListResponseType = "server.connected"
|
|
||||||
EventListResponseTypePermissionUpdated EventListResponseType = "permission.updated"
|
EventListResponseTypePermissionUpdated EventListResponseType = "permission.updated"
|
||||||
EventListResponseTypePermissionReplied EventListResponseType = "permission.replied"
|
EventListResponseTypePermissionReplied EventListResponseType = "permission.replied"
|
||||||
|
EventListResponseTypeFileEdited EventListResponseType = "file.edited"
|
||||||
EventListResponseTypeSessionUpdated EventListResponseType = "session.updated"
|
EventListResponseTypeSessionUpdated EventListResponseType = "session.updated"
|
||||||
EventListResponseTypeSessionDeleted EventListResponseType = "session.deleted"
|
EventListResponseTypeSessionDeleted EventListResponseType = "session.deleted"
|
||||||
EventListResponseTypeSessionIdle EventListResponseType = "session.idle"
|
EventListResponseTypeSessionIdle EventListResponseType = "session.idle"
|
||||||
EventListResponseTypeSessionError EventListResponseType = "session.error"
|
EventListResponseTypeSessionError EventListResponseType = "session.error"
|
||||||
|
EventListResponseTypeServerConnected EventListResponseType = "server.connected"
|
||||||
EventListResponseTypeFileWatcherUpdated EventListResponseType = "file.watcher.updated"
|
EventListResponseTypeFileWatcherUpdated EventListResponseType = "file.watcher.updated"
|
||||||
EventListResponseTypeIdeInstalled EventListResponseType = "ide.installed"
|
EventListResponseTypeIdeInstalled EventListResponseType = "ide.installed"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r EventListResponseType) IsKnown() bool {
|
func (r EventListResponseType) IsKnown() bool {
|
||||||
switch r {
|
switch r {
|
||||||
case EventListResponseTypeInstallationUpdated, EventListResponseTypeLspClientDiagnostics, EventListResponseTypeMessageUpdated, EventListResponseTypeMessageRemoved, EventListResponseTypeMessagePartUpdated, EventListResponseTypeMessagePartRemoved, EventListResponseTypeStorageWrite, EventListResponseTypeFileEdited, EventListResponseTypeServerConnected, EventListResponseTypePermissionUpdated, EventListResponseTypePermissionReplied, EventListResponseTypeSessionUpdated, EventListResponseTypeSessionDeleted, EventListResponseTypeSessionIdle, EventListResponseTypeSessionError, EventListResponseTypeFileWatcherUpdated, EventListResponseTypeIdeInstalled:
|
case EventListResponseTypeInstallationUpdated, EventListResponseTypeLspClientDiagnostics, EventListResponseTypeMessageUpdated, EventListResponseTypeMessageRemoved, EventListResponseTypeMessagePartUpdated, EventListResponseTypeMessagePartRemoved, EventListResponseTypeStorageWrite, EventListResponseTypePermissionUpdated, EventListResponseTypePermissionReplied, EventListResponseTypeFileEdited, EventListResponseTypeSessionUpdated, EventListResponseTypeSessionDeleted, EventListResponseTypeSessionIdle, EventListResponseTypeSessionError, EventListResponseTypeServerConnected, EventListResponseTypeFileWatcherUpdated, EventListResponseTypeIdeInstalled:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -2025,9 +2025,9 @@ func (r toolStateCompletedTimeJSON) RawJSON() string {
|
|||||||
type ToolStateError struct {
|
type ToolStateError struct {
|
||||||
Error string `json:"error,required"`
|
Error string `json:"error,required"`
|
||||||
Input map[string]interface{} `json:"input,required"`
|
Input map[string]interface{} `json:"input,required"`
|
||||||
Metadata map[string]interface{} `json:"metadata"`
|
|
||||||
Status ToolStateErrorStatus `json:"status,required"`
|
Status ToolStateErrorStatus `json:"status,required"`
|
||||||
Time ToolStateErrorTime `json:"time,required"`
|
Time ToolStateErrorTime `json:"time,required"`
|
||||||
|
Metadata map[string]interface{} `json:"metadata"`
|
||||||
JSON toolStateErrorJSON `json:"-"`
|
JSON toolStateErrorJSON `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2035,9 +2035,9 @@ type ToolStateError struct {
|
|||||||
type toolStateErrorJSON struct {
|
type toolStateErrorJSON struct {
|
||||||
Error apijson.Field
|
Error apijson.Field
|
||||||
Input apijson.Field
|
Input apijson.Field
|
||||||
Metadata apijson.Field
|
|
||||||
Status apijson.Field
|
Status apijson.Field
|
||||||
Time apijson.Field
|
Time apijson.Field
|
||||||
|
Metadata apijson.Field
|
||||||
raw string
|
raw string
|
||||||
ExtraFields map[string]apijson.Field
|
ExtraFields map[string]apijson.Field
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ func (r *TuiService) ClearPrompt(ctx context.Context, opts ...option.RequestOpti
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute a TUI command (e.g. switch_agent)
|
// Execute a TUI command (e.g. agent_cycle)
|
||||||
func (r *TuiService) ExecuteCommand(ctx context.Context, body TuiExecuteCommandParams, opts ...option.RequestOption) (res *bool, err error) {
|
func (r *TuiService) ExecuteCommand(ctx context.Context, body TuiExecuteCommandParams, opts ...option.RequestOption) (res *bool, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
path := "tui/execute-command"
|
path := "tui/execute-command"
|
||||||
|
|||||||
@@ -506,7 +506,7 @@ class Tui extends _HeyApiClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute a TUI command (e.g. switch_agent)
|
* Execute a TUI command (e.g. agent_cycle)
|
||||||
*/
|
*/
|
||||||
public executeCommand<ThrowOnError extends boolean = false>(options?: Options<TuiExecuteCommandData, ThrowOnError>) {
|
public executeCommand<ThrowOnError extends boolean = false>(options?: Options<TuiExecuteCommandData, ThrowOnError>) {
|
||||||
return (options?.client ?? this._client).post<TuiExecuteCommandResponses, unknown, ThrowOnError>({
|
return (options?.client ?? this._client).post<TuiExecuteCommandResponses, unknown, ThrowOnError>({
|
||||||
|
|||||||
@@ -347,10 +347,10 @@ export type ToolStateError = {
|
|||||||
input: {
|
input: {
|
||||||
[key: string]: unknown
|
[key: string]: unknown
|
||||||
}
|
}
|
||||||
metadata: {
|
error: string
|
||||||
|
metadata?: {
|
||||||
[key: string]: unknown
|
[key: string]: unknown
|
||||||
}
|
}
|
||||||
error: string
|
|
||||||
time: {
|
time: {
|
||||||
start: number
|
start: number
|
||||||
end: number
|
end: number
|
||||||
@@ -750,25 +750,29 @@ export type KeybindsConfig = {
|
|||||||
*/
|
*/
|
||||||
app_help: string
|
app_help: string
|
||||||
/**
|
/**
|
||||||
* @deprecated use switch_agent. Next mode
|
* Exit the application
|
||||||
*/
|
*/
|
||||||
switch_mode: string
|
app_exit: string
|
||||||
/**
|
|
||||||
* @deprecated use switch_agent_reverse. Previous mode
|
|
||||||
*/
|
|
||||||
switch_mode_reverse: string
|
|
||||||
/**
|
|
||||||
* Next agent
|
|
||||||
*/
|
|
||||||
switch_agent: string
|
|
||||||
/**
|
|
||||||
* Previous agent
|
|
||||||
*/
|
|
||||||
switch_agent_reverse: string
|
|
||||||
/**
|
/**
|
||||||
* Open external editor
|
* Open external editor
|
||||||
*/
|
*/
|
||||||
editor_open: string
|
editor_open: string
|
||||||
|
/**
|
||||||
|
* List available themes
|
||||||
|
*/
|
||||||
|
theme_list: string
|
||||||
|
/**
|
||||||
|
* Create/update AGENTS.md
|
||||||
|
*/
|
||||||
|
project_init: string
|
||||||
|
/**
|
||||||
|
* Toggle tool details
|
||||||
|
*/
|
||||||
|
tool_details: string
|
||||||
|
/**
|
||||||
|
* Toggle thinking blocks
|
||||||
|
*/
|
||||||
|
thinking_blocks: string
|
||||||
/**
|
/**
|
||||||
* Export session to editor
|
* Export session to editor
|
||||||
*/
|
*/
|
||||||
@@ -798,41 +802,65 @@ export type KeybindsConfig = {
|
|||||||
*/
|
*/
|
||||||
session_compact: string
|
session_compact: string
|
||||||
/**
|
/**
|
||||||
* Toggle tool details
|
* Scroll messages up by one page
|
||||||
*/
|
*/
|
||||||
tool_details: string
|
messages_page_up: string
|
||||||
/**
|
/**
|
||||||
* Toggle thinking blocks
|
* Scroll messages down by one page
|
||||||
*/
|
*/
|
||||||
thinking_blocks: string
|
messages_page_down: string
|
||||||
|
/**
|
||||||
|
* Scroll messages up by half page
|
||||||
|
*/
|
||||||
|
messages_half_page_up: string
|
||||||
|
/**
|
||||||
|
* Scroll messages down by half page
|
||||||
|
*/
|
||||||
|
messages_half_page_down: string
|
||||||
|
/**
|
||||||
|
* Navigate to first message
|
||||||
|
*/
|
||||||
|
messages_first: string
|
||||||
|
/**
|
||||||
|
* Navigate to last message
|
||||||
|
*/
|
||||||
|
messages_last: string
|
||||||
|
/**
|
||||||
|
* Copy message
|
||||||
|
*/
|
||||||
|
messages_copy: string
|
||||||
|
/**
|
||||||
|
* Undo message
|
||||||
|
*/
|
||||||
|
messages_undo: string
|
||||||
|
/**
|
||||||
|
* Redo message
|
||||||
|
*/
|
||||||
|
messages_redo: string
|
||||||
/**
|
/**
|
||||||
* List available models
|
* List available models
|
||||||
*/
|
*/
|
||||||
model_list: string
|
model_list: string
|
||||||
/**
|
/**
|
||||||
* List available themes
|
* Next recent model
|
||||||
*/
|
*/
|
||||||
theme_list: string
|
model_cycle_recent: string
|
||||||
/**
|
/**
|
||||||
* List files
|
* Previous recent model
|
||||||
*/
|
*/
|
||||||
file_list: string
|
model_cycle_recent_reverse: string
|
||||||
/**
|
/**
|
||||||
* Close file
|
* List agents
|
||||||
*/
|
*/
|
||||||
file_close: string
|
agent_list: string
|
||||||
/**
|
/**
|
||||||
* Search file
|
* Next agent
|
||||||
*/
|
*/
|
||||||
file_search: string
|
agent_cycle: string
|
||||||
/**
|
/**
|
||||||
* Split/unified diff
|
* Previous agent
|
||||||
*/
|
*/
|
||||||
file_diff_toggle: string
|
agent_cycle_reverse: string
|
||||||
/**
|
|
||||||
* Create/update AGENTS.md
|
|
||||||
*/
|
|
||||||
project_init: string
|
|
||||||
/**
|
/**
|
||||||
* Clear input field
|
* Clear input field
|
||||||
*/
|
*/
|
||||||
@@ -850,61 +878,53 @@ export type KeybindsConfig = {
|
|||||||
*/
|
*/
|
||||||
input_newline: string
|
input_newline: string
|
||||||
/**
|
/**
|
||||||
* Scroll messages up by one page
|
* @deprecated use agent_cycle. Next mode
|
||||||
*/
|
*/
|
||||||
messages_page_up: string
|
switch_mode: string
|
||||||
/**
|
/**
|
||||||
* Scroll messages down by one page
|
* @deprecated use agent_cycle_reverse. Previous mode
|
||||||
*/
|
*/
|
||||||
messages_page_down: string
|
switch_mode_reverse: string
|
||||||
/**
|
/**
|
||||||
* Scroll messages up by half page
|
* @deprecated use agent_cycle. Next agent
|
||||||
*/
|
*/
|
||||||
messages_half_page_up: string
|
switch_agent: string
|
||||||
/**
|
/**
|
||||||
* Scroll messages down by half page
|
* @deprecated use agent_cycle_reverse. Previous agent
|
||||||
*/
|
*/
|
||||||
messages_half_page_down: string
|
switch_agent_reverse: string
|
||||||
/**
|
/**
|
||||||
* Navigate to previous message
|
* @deprecated Currently not available. List files
|
||||||
|
*/
|
||||||
|
file_list: string
|
||||||
|
/**
|
||||||
|
* @deprecated Close file
|
||||||
|
*/
|
||||||
|
file_close: string
|
||||||
|
/**
|
||||||
|
* @deprecated Search file
|
||||||
|
*/
|
||||||
|
file_search: string
|
||||||
|
/**
|
||||||
|
* @deprecated Split/unified diff
|
||||||
|
*/
|
||||||
|
file_diff_toggle: string
|
||||||
|
/**
|
||||||
|
* @deprecated Navigate to previous message
|
||||||
*/
|
*/
|
||||||
messages_previous: string
|
messages_previous: string
|
||||||
/**
|
/**
|
||||||
* Navigate to next message
|
* @deprecated Navigate to next message
|
||||||
*/
|
*/
|
||||||
messages_next: string
|
messages_next: string
|
||||||
/**
|
/**
|
||||||
* Navigate to first message
|
* @deprecated Toggle layout
|
||||||
*/
|
|
||||||
messages_first: string
|
|
||||||
/**
|
|
||||||
* Navigate to last message
|
|
||||||
*/
|
|
||||||
messages_last: string
|
|
||||||
/**
|
|
||||||
* Toggle layout
|
|
||||||
*/
|
*/
|
||||||
messages_layout_toggle: string
|
messages_layout_toggle: string
|
||||||
/**
|
|
||||||
* Copy message
|
|
||||||
*/
|
|
||||||
messages_copy: string
|
|
||||||
/**
|
/**
|
||||||
* @deprecated use messages_undo. Revert message
|
* @deprecated use messages_undo. Revert message
|
||||||
*/
|
*/
|
||||||
messages_revert: string
|
messages_revert: string
|
||||||
/**
|
|
||||||
* Undo message
|
|
||||||
*/
|
|
||||||
messages_undo: string
|
|
||||||
/**
|
|
||||||
* Redo message
|
|
||||||
*/
|
|
||||||
messages_redo: string
|
|
||||||
/**
|
|
||||||
* Exit the application
|
|
||||||
*/
|
|
||||||
app_exit: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AgentConfig = {
|
export type AgentConfig = {
|
||||||
@@ -1086,6 +1106,7 @@ export type Agent = {
|
|||||||
name: string
|
name: string
|
||||||
description?: string
|
description?: string
|
||||||
mode: "subagent" | "primary" | "all"
|
mode: "subagent" | "primary" | "all"
|
||||||
|
builtIn: boolean
|
||||||
topP?: number
|
topP?: number
|
||||||
temperature?: number
|
temperature?: number
|
||||||
permission: {
|
permission: {
|
||||||
|
|||||||
@@ -35,8 +35,6 @@ type State struct {
|
|||||||
Agent string `toml:"agent"`
|
Agent string `toml:"agent"`
|
||||||
RecentlyUsedModels []ModelUsage `toml:"recently_used_models"`
|
RecentlyUsedModels []ModelUsage `toml:"recently_used_models"`
|
||||||
RecentlyUsedAgents []AgentUsage `toml:"recently_used_agents"`
|
RecentlyUsedAgents []AgentUsage `toml:"recently_used_agents"`
|
||||||
MessagesRight bool `toml:"messages_right"`
|
|
||||||
SplitDiff bool `toml:"split_diff"`
|
|
||||||
MessageHistory []Prompt `toml:"message_history"`
|
MessageHistory []Prompt `toml:"message_history"`
|
||||||
ShowToolDetails *bool `toml:"show_tool_details"`
|
ShowToolDetails *bool `toml:"show_tool_details"`
|
||||||
ShowThinkingBlocks *bool `toml:"show_thinking_blocks"`
|
ShowThinkingBlocks *bool `toml:"show_thinking_blocks"`
|
||||||
|
|||||||
@@ -108,9 +108,12 @@ func (r CommandRegistry) Matches(msg tea.KeyPressMsg, leader bool) []Command {
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
AppHelpCommand CommandName = "app_help"
|
AppHelpCommand CommandName = "app_help"
|
||||||
SwitchAgentCommand CommandName = "switch_agent"
|
AppExitCommand CommandName = "app_exit"
|
||||||
SwitchAgentReverseCommand CommandName = "switch_agent_reverse"
|
ThemeListCommand CommandName = "theme_list"
|
||||||
|
ProjectInitCommand CommandName = "project_init"
|
||||||
EditorOpenCommand CommandName = "editor_open"
|
EditorOpenCommand CommandName = "editor_open"
|
||||||
|
ToolDetailsCommand CommandName = "tool_details"
|
||||||
|
ThinkingBlocksCommand CommandName = "thinking_blocks"
|
||||||
SessionNewCommand CommandName = "session_new"
|
SessionNewCommand CommandName = "session_new"
|
||||||
SessionListCommand CommandName = "session_list"
|
SessionListCommand CommandName = "session_list"
|
||||||
SessionShareCommand CommandName = "session_share"
|
SessionShareCommand CommandName = "session_share"
|
||||||
@@ -118,34 +121,25 @@ const (
|
|||||||
SessionInterruptCommand CommandName = "session_interrupt"
|
SessionInterruptCommand CommandName = "session_interrupt"
|
||||||
SessionCompactCommand CommandName = "session_compact"
|
SessionCompactCommand CommandName = "session_compact"
|
||||||
SessionExportCommand CommandName = "session_export"
|
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"
|
MessagesPageUpCommand CommandName = "messages_page_up"
|
||||||
MessagesPageDownCommand CommandName = "messages_page_down"
|
MessagesPageDownCommand CommandName = "messages_page_down"
|
||||||
MessagesHalfPageUpCommand CommandName = "messages_half_page_up"
|
MessagesHalfPageUpCommand CommandName = "messages_half_page_up"
|
||||||
MessagesHalfPageDownCommand CommandName = "messages_half_page_down"
|
MessagesHalfPageDownCommand CommandName = "messages_half_page_down"
|
||||||
|
MessagesFirstCommand CommandName = "messages_first"
|
||||||
MessagesFirstCommand CommandName = "messages_first"
|
MessagesLastCommand CommandName = "messages_last"
|
||||||
MessagesLastCommand CommandName = "messages_last"
|
MessagesCopyCommand CommandName = "messages_copy"
|
||||||
|
MessagesUndoCommand CommandName = "messages_undo"
|
||||||
MessagesCopyCommand CommandName = "messages_copy"
|
MessagesRedoCommand CommandName = "messages_redo"
|
||||||
MessagesUndoCommand CommandName = "messages_undo"
|
ModelListCommand CommandName = "model_list"
|
||||||
MessagesRedoCommand CommandName = "messages_redo"
|
ModelCycleRecentCommand CommandName = "model_cycle_recent"
|
||||||
AppExitCommand CommandName = "app_exit"
|
ModelCycleRecentReverseCommand CommandName = "model_cycle_recent_reverse"
|
||||||
|
AgentListCommand CommandName = "agent_list"
|
||||||
|
AgentCycleCommand CommandName = "agent_cycle"
|
||||||
|
AgentCycleReverseCommand CommandName = "agent_cycle_reverse"
|
||||||
|
InputClearCommand CommandName = "input_clear"
|
||||||
|
InputPasteCommand CommandName = "input_paste"
|
||||||
|
InputSubmitCommand CommandName = "input_submit"
|
||||||
|
InputNewlineCommand CommandName = "input_newline"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (k Command) Matches(msg tea.KeyPressMsg, leader bool) bool {
|
func (k Command) Matches(msg tea.KeyPressMsg, leader bool) bool {
|
||||||
@@ -184,16 +178,6 @@ func LoadFromConfig(config *opencode.Config) CommandRegistry {
|
|||||||
Keybindings: parseBindings("<leader>h"),
|
Keybindings: parseBindings("<leader>h"),
|
||||||
Trigger: []string{"help"},
|
Trigger: []string{"help"},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Name: SwitchAgentCommand,
|
|
||||||
Description: "next agent",
|
|
||||||
Keybindings: parseBindings("tab"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: SwitchAgentReverseCommand,
|
|
||||||
Description: "previous agent",
|
|
||||||
Keybindings: parseBindings("shift+tab"),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Name: EditorOpenCommand,
|
Name: EditorOpenCommand,
|
||||||
Description: "open editor",
|
Description: "open editor",
|
||||||
@@ -258,12 +242,6 @@ func LoadFromConfig(config *opencode.Config) CommandRegistry {
|
|||||||
Keybindings: parseBindings("<leader>m"),
|
Keybindings: parseBindings("<leader>m"),
|
||||||
Trigger: []string{"models"},
|
Trigger: []string{"models"},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Name: AgentListCommand,
|
|
||||||
Description: "list agents",
|
|
||||||
Keybindings: parseBindings("<leader>a"),
|
|
||||||
Trigger: []string{"agents"},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Name: ModelCycleRecentCommand,
|
Name: ModelCycleRecentCommand,
|
||||||
Description: "next recent model",
|
Description: "next recent model",
|
||||||
@@ -274,33 +252,28 @@ func LoadFromConfig(config *opencode.Config) CommandRegistry {
|
|||||||
Description: "previous recent model",
|
Description: "previous recent model",
|
||||||
Keybindings: parseBindings("shift+f2"),
|
Keybindings: parseBindings("shift+f2"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: AgentListCommand,
|
||||||
|
Description: "list agents",
|
||||||
|
Keybindings: parseBindings("<leader>a"),
|
||||||
|
Trigger: []string{"agents"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: AgentCycleCommand,
|
||||||
|
Description: "next agent",
|
||||||
|
Keybindings: parseBindings("tab"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: AgentCycleReverseCommand,
|
||||||
|
Description: "previous agent",
|
||||||
|
Keybindings: parseBindings("shift+tab"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: ThemeListCommand,
|
Name: ThemeListCommand,
|
||||||
Description: "list themes",
|
Description: "list themes",
|
||||||
Keybindings: parseBindings("<leader>t"),
|
Keybindings: parseBindings("<leader>t"),
|
||||||
Trigger: []string{"themes"},
|
Trigger: []string{"themes"},
|
||||||
},
|
},
|
||||||
// {
|
|
||||||
// Name: FileListCommand,
|
|
||||||
// Description: "list files",
|
|
||||||
// Keybindings: parseBindings("<leader>f"),
|
|
||||||
// Trigger: []string{"files"},
|
|
||||||
// },
|
|
||||||
{
|
|
||||||
Name: FileCloseCommand,
|
|
||||||
Description: "close file",
|
|
||||||
Keybindings: parseBindings("esc"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: FileSearchCommand,
|
|
||||||
Description: "search file",
|
|
||||||
Keybindings: parseBindings("<leader>/"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: FileDiffToggleCommand,
|
|
||||||
Description: "split/unified diff",
|
|
||||||
Keybindings: parseBindings("<leader>v"),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Name: ProjectInitCommand,
|
Name: ProjectInitCommand,
|
||||||
Description: "create/update AGENTS.md",
|
Description: "create/update AGENTS.md",
|
||||||
|
|||||||
@@ -1,236 +0,0 @@
|
|||||||
package dialog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log/slog"
|
|
||||||
|
|
||||||
tea "github.com/charmbracelet/bubbletea/v2"
|
|
||||||
"github.com/sst/opencode/internal/completions"
|
|
||||||
"github.com/sst/opencode/internal/components/list"
|
|
||||||
"github.com/sst/opencode/internal/components/modal"
|
|
||||||
"github.com/sst/opencode/internal/layout"
|
|
||||||
"github.com/sst/opencode/internal/styles"
|
|
||||||
"github.com/sst/opencode/internal/theme"
|
|
||||||
"github.com/sst/opencode/internal/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
findDialogWidth = 76
|
|
||||||
)
|
|
||||||
|
|
||||||
type FindSelectedMsg struct {
|
|
||||||
FilePath string
|
|
||||||
}
|
|
||||||
|
|
||||||
type FindDialogCloseMsg struct{}
|
|
||||||
|
|
||||||
type findInitialSuggestionsMsg struct {
|
|
||||||
suggestions []completions.CompletionSuggestion
|
|
||||||
}
|
|
||||||
|
|
||||||
type FindDialog interface {
|
|
||||||
layout.Modal
|
|
||||||
tea.Model
|
|
||||||
tea.ViewModel
|
|
||||||
SetWidth(width int)
|
|
||||||
SetHeight(height int)
|
|
||||||
IsEmpty() bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// findItem is a custom list item for file suggestions
|
|
||||||
type findItem struct {
|
|
||||||
suggestion completions.CompletionSuggestion
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f findItem) Render(
|
|
||||||
selected bool,
|
|
||||||
width int,
|
|
||||||
baseStyle styles.Style,
|
|
||||||
) string {
|
|
||||||
t := theme.CurrentTheme()
|
|
||||||
|
|
||||||
itemStyle := baseStyle.
|
|
||||||
Background(t.BackgroundPanel()).
|
|
||||||
Foreground(t.TextMuted())
|
|
||||||
|
|
||||||
if selected {
|
|
||||||
itemStyle = itemStyle.Foreground(t.Primary())
|
|
||||||
}
|
|
||||||
|
|
||||||
return itemStyle.PaddingLeft(1).Render(f.suggestion.Display(itemStyle))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f findItem) Selectable() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
type findDialogComponent struct {
|
|
||||||
completionProvider completions.CompletionProvider
|
|
||||||
allSuggestions []completions.CompletionSuggestion
|
|
||||||
width, height int
|
|
||||||
modal *modal.Modal
|
|
||||||
searchDialog *SearchDialog
|
|
||||||
dialogWidth int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *findDialogComponent) Init() tea.Cmd {
|
|
||||||
return tea.Batch(
|
|
||||||
f.loadInitialSuggestions(),
|
|
||||||
f.searchDialog.Init(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *findDialogComponent) loadInitialSuggestions() tea.Cmd {
|
|
||||||
return func() tea.Msg {
|
|
||||||
items, err := f.completionProvider.GetChildEntries("")
|
|
||||||
if err != nil {
|
|
||||||
slog.Error("Failed to get initial completion items", "error", err)
|
|
||||||
return findInitialSuggestionsMsg{suggestions: []completions.CompletionSuggestion{}}
|
|
||||||
}
|
|
||||||
return findInitialSuggestionsMsg{suggestions: items}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *findDialogComponent) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
||||||
switch msg := msg.(type) {
|
|
||||||
case findInitialSuggestionsMsg:
|
|
||||||
// Handle initial suggestions setup
|
|
||||||
f.allSuggestions = msg.suggestions
|
|
||||||
|
|
||||||
// Calculate dialog width
|
|
||||||
f.dialogWidth = f.calculateDialogWidth()
|
|
||||||
|
|
||||||
// Initialize search dialog with calculated width
|
|
||||||
f.searchDialog = NewSearchDialog("Search files...", 10)
|
|
||||||
f.searchDialog.SetWidth(f.dialogWidth)
|
|
||||||
|
|
||||||
// Convert to list items
|
|
||||||
items := make([]list.Item, len(f.allSuggestions))
|
|
||||||
for i, suggestion := range f.allSuggestions {
|
|
||||||
items[i] = findItem{suggestion: suggestion}
|
|
||||||
}
|
|
||||||
f.searchDialog.SetItems(items)
|
|
||||||
|
|
||||||
// Update modal with calculated width
|
|
||||||
f.modal = modal.New(
|
|
||||||
modal.WithTitle("Find Files"),
|
|
||||||
modal.WithMaxWidth(f.dialogWidth+4),
|
|
||||||
)
|
|
||||||
|
|
||||||
return f, f.searchDialog.Init()
|
|
||||||
|
|
||||||
case []completions.CompletionSuggestion:
|
|
||||||
// Store suggestions and convert to findItem for the search dialog
|
|
||||||
f.allSuggestions = msg
|
|
||||||
items := make([]list.Item, len(msg))
|
|
||||||
for i, suggestion := range msg {
|
|
||||||
items[i] = findItem{suggestion: suggestion}
|
|
||||||
}
|
|
||||||
f.searchDialog.SetItems(items)
|
|
||||||
return f, nil
|
|
||||||
|
|
||||||
case SearchSelectionMsg:
|
|
||||||
// Handle selection from search dialog - now we can directly access the suggestion
|
|
||||||
if item, ok := msg.Item.(findItem); ok {
|
|
||||||
return f, f.selectFile(item.suggestion)
|
|
||||||
}
|
|
||||||
return f, nil
|
|
||||||
|
|
||||||
case SearchCancelledMsg:
|
|
||||||
return f, f.Close()
|
|
||||||
|
|
||||||
case SearchQueryChangedMsg:
|
|
||||||
// Update completion items based on search query
|
|
||||||
return f, func() tea.Msg {
|
|
||||||
items, err := f.completionProvider.GetChildEntries(msg.Query)
|
|
||||||
if err != nil {
|
|
||||||
slog.Error("Failed to get completion items", "error", err)
|
|
||||||
return []completions.CompletionSuggestion{}
|
|
||||||
}
|
|
||||||
return items
|
|
||||||
}
|
|
||||||
|
|
||||||
case tea.WindowSizeMsg:
|
|
||||||
f.width = msg.Width
|
|
||||||
f.height = msg.Height
|
|
||||||
// Recalculate width based on new viewport size
|
|
||||||
oldWidth := f.dialogWidth
|
|
||||||
f.dialogWidth = f.calculateDialogWidth()
|
|
||||||
if oldWidth != f.dialogWidth {
|
|
||||||
f.searchDialog.SetWidth(f.dialogWidth)
|
|
||||||
// Update modal max width too
|
|
||||||
f.modal = modal.New(
|
|
||||||
modal.WithTitle("Find Files"),
|
|
||||||
modal.WithMaxWidth(f.dialogWidth+4),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
f.searchDialog.SetHeight(msg.Height)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forward all other messages to the search dialog
|
|
||||||
updatedDialog, cmd := f.searchDialog.Update(msg)
|
|
||||||
f.searchDialog = updatedDialog.(*SearchDialog)
|
|
||||||
return f, cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *findDialogComponent) View() string {
|
|
||||||
return f.searchDialog.View()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *findDialogComponent) calculateDialogWidth() int {
|
|
||||||
// Use fixed width unless viewport is smaller
|
|
||||||
if f.width > 0 && f.width < findDialogWidth+10 {
|
|
||||||
return f.width - 10
|
|
||||||
}
|
|
||||||
return findDialogWidth
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *findDialogComponent) SetWidth(width int) {
|
|
||||||
f.width = width
|
|
||||||
f.searchDialog.SetWidth(f.dialogWidth)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *findDialogComponent) SetHeight(height int) {
|
|
||||||
f.height = height
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *findDialogComponent) IsEmpty() bool {
|
|
||||||
return f.searchDialog.GetQuery() == ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *findDialogComponent) selectFile(item completions.CompletionSuggestion) tea.Cmd {
|
|
||||||
return tea.Sequence(
|
|
||||||
f.Close(),
|
|
||||||
util.CmdHandler(FindSelectedMsg{
|
|
||||||
FilePath: item.Value,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *findDialogComponent) Render(background string) string {
|
|
||||||
return f.modal.Render(f.View(), background)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *findDialogComponent) Close() tea.Cmd {
|
|
||||||
f.searchDialog.SetQuery("")
|
|
||||||
f.searchDialog.Blur()
|
|
||||||
return util.CmdHandler(modal.CloseModalMsg{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewFindDialog(completionProvider completions.CompletionProvider) FindDialog {
|
|
||||||
component := &findDialogComponent{
|
|
||||||
completionProvider: completionProvider,
|
|
||||||
dialogWidth: findDialogWidth,
|
|
||||||
allSuggestions: []completions.CompletionSuggestion{},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create search dialog and modal with fixed width
|
|
||||||
component.searchDialog = NewSearchDialog("Search files...", 10)
|
|
||||||
component.searchDialog.SetWidth(findDialogWidth)
|
|
||||||
|
|
||||||
component.modal = modal.New(
|
|
||||||
modal.WithTitle("Find Files"),
|
|
||||||
modal.WithMaxWidth(findDialogWidth+4),
|
|
||||||
)
|
|
||||||
|
|
||||||
return component
|
|
||||||
}
|
|
||||||
@@ -1,184 +0,0 @@
|
|||||||
package dialog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/charmbracelet/bubbles/v2/key"
|
|
||||||
tea "github.com/charmbracelet/bubbletea/v2"
|
|
||||||
"github.com/charmbracelet/lipgloss/v2"
|
|
||||||
|
|
||||||
"github.com/sst/opencode/internal/styles"
|
|
||||||
"github.com/sst/opencode/internal/theme"
|
|
||||||
"github.com/sst/opencode/internal/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
// InitDialogCmp is a component that asks the user if they want to initialize the project.
|
|
||||||
type InitDialogCmp struct {
|
|
||||||
width, height int
|
|
||||||
selected int
|
|
||||||
keys initDialogKeyMap
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInitDialogCmp creates a new InitDialogCmp.
|
|
||||||
func NewInitDialogCmp() InitDialogCmp {
|
|
||||||
return InitDialogCmp{
|
|
||||||
selected: 0,
|
|
||||||
keys: initDialogKeyMap{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type initDialogKeyMap struct {
|
|
||||||
Tab key.Binding
|
|
||||||
Left key.Binding
|
|
||||||
Right key.Binding
|
|
||||||
Enter key.Binding
|
|
||||||
Escape key.Binding
|
|
||||||
Y key.Binding
|
|
||||||
N key.Binding
|
|
||||||
}
|
|
||||||
|
|
||||||
// ShortHelp implements key.Map.
|
|
||||||
func (k initDialogKeyMap) ShortHelp() []key.Binding {
|
|
||||||
return []key.Binding{
|
|
||||||
key.NewBinding(
|
|
||||||
key.WithKeys("tab", "left", "right"),
|
|
||||||
key.WithHelp("tab/←/→", "toggle selection"),
|
|
||||||
),
|
|
||||||
key.NewBinding(
|
|
||||||
key.WithKeys("enter"),
|
|
||||||
key.WithHelp("enter", "confirm"),
|
|
||||||
),
|
|
||||||
key.NewBinding(
|
|
||||||
key.WithKeys("esc", "q"),
|
|
||||||
key.WithHelp("esc/q", "cancel"),
|
|
||||||
),
|
|
||||||
key.NewBinding(
|
|
||||||
key.WithKeys("y", "n"),
|
|
||||||
key.WithHelp("y/n", "yes/no"),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FullHelp implements key.Map.
|
|
||||||
func (k initDialogKeyMap) FullHelp() [][]key.Binding {
|
|
||||||
return [][]key.Binding{k.ShortHelp()}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init implements tea.Model.
|
|
||||||
func (m InitDialogCmp) Init() tea.Cmd {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update implements tea.Model.
|
|
||||||
func (m InitDialogCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
||||||
switch msg := msg.(type) {
|
|
||||||
case tea.KeyMsg:
|
|
||||||
switch {
|
|
||||||
case key.Matches(msg, key.NewBinding(key.WithKeys("esc"))):
|
|
||||||
return m, util.CmdHandler(CloseInitDialogMsg{Initialize: false})
|
|
||||||
case key.Matches(msg, key.NewBinding(key.WithKeys("tab", "left", "right", "h", "l"))):
|
|
||||||
m.selected = (m.selected + 1) % 2
|
|
||||||
return m, nil
|
|
||||||
case key.Matches(msg, key.NewBinding(key.WithKeys("enter"))):
|
|
||||||
return m, util.CmdHandler(CloseInitDialogMsg{Initialize: m.selected == 0})
|
|
||||||
case key.Matches(msg, key.NewBinding(key.WithKeys("y"))):
|
|
||||||
return m, util.CmdHandler(CloseInitDialogMsg{Initialize: true})
|
|
||||||
case key.Matches(msg, key.NewBinding(key.WithKeys("n"))):
|
|
||||||
return m, util.CmdHandler(CloseInitDialogMsg{Initialize: false})
|
|
||||||
}
|
|
||||||
case tea.WindowSizeMsg:
|
|
||||||
m.width = msg.Width
|
|
||||||
m.height = msg.Height
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// View implements tea.Model.
|
|
||||||
func (m InitDialogCmp) View() string {
|
|
||||||
t := theme.CurrentTheme()
|
|
||||||
baseStyle := styles.NewStyle().Foreground(t.Text())
|
|
||||||
|
|
||||||
// Calculate width needed for content
|
|
||||||
maxWidth := 60 // Width for explanation text
|
|
||||||
|
|
||||||
title := baseStyle.
|
|
||||||
Foreground(t.Primary()).
|
|
||||||
Bold(true).
|
|
||||||
Width(maxWidth).
|
|
||||||
Padding(0, 1).
|
|
||||||
Render("Initialize Project")
|
|
||||||
|
|
||||||
explanation := baseStyle.
|
|
||||||
Foreground(t.Text()).
|
|
||||||
Width(maxWidth).
|
|
||||||
Padding(0, 1).
|
|
||||||
Render("Initialization generates a new AGENTS.md file that contains information about your codebase, this file serves as memory for each project, you can freely add to it to help the agents be better at their job.")
|
|
||||||
|
|
||||||
question := baseStyle.
|
|
||||||
Foreground(t.Text()).
|
|
||||||
Width(maxWidth).
|
|
||||||
Padding(1, 1).
|
|
||||||
Render("Would you like to initialize this project?")
|
|
||||||
|
|
||||||
maxWidth = min(maxWidth, m.width-10)
|
|
||||||
yesStyle := baseStyle
|
|
||||||
noStyle := baseStyle
|
|
||||||
|
|
||||||
if m.selected == 0 {
|
|
||||||
yesStyle = yesStyle.
|
|
||||||
Background(t.Primary()).
|
|
||||||
Foreground(t.Background()).
|
|
||||||
Bold(true)
|
|
||||||
noStyle = noStyle.
|
|
||||||
Background(t.Background()).
|
|
||||||
Foreground(t.Primary())
|
|
||||||
} else {
|
|
||||||
noStyle = noStyle.
|
|
||||||
Background(t.Primary()).
|
|
||||||
Foreground(t.Background()).
|
|
||||||
Bold(true)
|
|
||||||
yesStyle = yesStyle.
|
|
||||||
Background(t.Background()).
|
|
||||||
Foreground(t.Primary())
|
|
||||||
}
|
|
||||||
|
|
||||||
yes := yesStyle.Padding(0, 3).Render("Yes")
|
|
||||||
no := noStyle.Padding(0, 3).Render("No")
|
|
||||||
|
|
||||||
buttons := lipgloss.JoinHorizontal(lipgloss.Center, yes, baseStyle.Render(" "), no)
|
|
||||||
buttons = baseStyle.
|
|
||||||
Width(maxWidth).
|
|
||||||
Padding(1, 0).
|
|
||||||
Render(buttons)
|
|
||||||
|
|
||||||
content := lipgloss.JoinVertical(
|
|
||||||
lipgloss.Left,
|
|
||||||
title,
|
|
||||||
baseStyle.Width(maxWidth).Render(""),
|
|
||||||
explanation,
|
|
||||||
question,
|
|
||||||
buttons,
|
|
||||||
baseStyle.Width(maxWidth).Render(""),
|
|
||||||
)
|
|
||||||
|
|
||||||
return baseStyle.Padding(1, 2).
|
|
||||||
Border(lipgloss.RoundedBorder()).
|
|
||||||
BorderBackground(t.Background()).
|
|
||||||
BorderForeground(t.TextMuted()).
|
|
||||||
Width(lipgloss.Width(content) + 4).
|
|
||||||
Render(content)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetSize sets the size of the component.
|
|
||||||
func (m *InitDialogCmp) SetSize(width, height int) {
|
|
||||||
m.width = width
|
|
||||||
m.height = height
|
|
||||||
}
|
|
||||||
|
|
||||||
// CloseInitDialogMsg is a message that is sent when the init dialog is closed.
|
|
||||||
type CloseInitDialogMsg struct {
|
|
||||||
Initialize bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// ShowInitDialogMsg is a message that is sent to show the init dialog.
|
|
||||||
type ShowInitDialogMsg struct {
|
|
||||||
Show bool
|
|
||||||
}
|
|
||||||
@@ -1,278 +0,0 @@
|
|||||||
package fileviewer
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
tea "github.com/charmbracelet/bubbletea/v2"
|
|
||||||
|
|
||||||
"github.com/sst/opencode/internal/app"
|
|
||||||
"github.com/sst/opencode/internal/commands"
|
|
||||||
"github.com/sst/opencode/internal/components/dialog"
|
|
||||||
"github.com/sst/opencode/internal/components/diff"
|
|
||||||
"github.com/sst/opencode/internal/layout"
|
|
||||||
"github.com/sst/opencode/internal/styles"
|
|
||||||
"github.com/sst/opencode/internal/theme"
|
|
||||||
"github.com/sst/opencode/internal/util"
|
|
||||||
"github.com/sst/opencode/internal/viewport"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DiffStyle int
|
|
||||||
|
|
||||||
const (
|
|
||||||
DiffStyleSplit DiffStyle = iota
|
|
||||||
DiffStyleUnified
|
|
||||||
)
|
|
||||||
|
|
||||||
type Model struct {
|
|
||||||
app *app.App
|
|
||||||
width, height int
|
|
||||||
viewport viewport.Model
|
|
||||||
filename *string
|
|
||||||
content *string
|
|
||||||
isDiff *bool
|
|
||||||
diffStyle DiffStyle
|
|
||||||
}
|
|
||||||
|
|
||||||
type fileRenderedMsg struct {
|
|
||||||
content string
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(app *app.App) Model {
|
|
||||||
vp := viewport.New()
|
|
||||||
m := Model{
|
|
||||||
app: app,
|
|
||||||
viewport: vp,
|
|
||||||
diffStyle: DiffStyleUnified,
|
|
||||||
}
|
|
||||||
if app.State.SplitDiff {
|
|
||||||
m.diffStyle = DiffStyleSplit
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m Model) Init() tea.Cmd {
|
|
||||||
return m.viewport.Init()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
|
||||||
var cmds []tea.Cmd
|
|
||||||
|
|
||||||
switch msg := msg.(type) {
|
|
||||||
case fileRenderedMsg:
|
|
||||||
m.viewport.SetContent(msg.content)
|
|
||||||
return m, util.CmdHandler(app.FileRenderedMsg{
|
|
||||||
FilePath: *m.filename,
|
|
||||||
})
|
|
||||||
case dialog.ThemeSelectedMsg:
|
|
||||||
return m, m.render()
|
|
||||||
case tea.KeyMsg:
|
|
||||||
switch msg.String() {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vp, cmd := m.viewport.Update(msg)
|
|
||||||
m.viewport = vp
|
|
||||||
cmds = append(cmds, cmd)
|
|
||||||
|
|
||||||
return m, tea.Batch(cmds...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m Model) View() string {
|
|
||||||
if !m.HasFile() {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
header := *m.filename
|
|
||||||
header = styles.NewStyle().
|
|
||||||
Padding(1, 2).
|
|
||||||
Width(m.width).
|
|
||||||
Background(theme.CurrentTheme().BackgroundElement()).
|
|
||||||
Foreground(theme.CurrentTheme().Text()).
|
|
||||||
Render(header)
|
|
||||||
|
|
||||||
t := theme.CurrentTheme()
|
|
||||||
|
|
||||||
close := m.app.Key(commands.FileCloseCommand)
|
|
||||||
diffToggle := m.app.Key(commands.FileDiffToggleCommand)
|
|
||||||
if m.isDiff == nil || *m.isDiff == false {
|
|
||||||
diffToggle = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
background := t.Background()
|
|
||||||
footer := layout.Render(
|
|
||||||
layout.FlexOptions{
|
|
||||||
Background: &background,
|
|
||||||
Direction: layout.Row,
|
|
||||||
Justify: layout.JustifyCenter,
|
|
||||||
Align: layout.AlignStretch,
|
|
||||||
Width: m.width - 2,
|
|
||||||
Gap: 5,
|
|
||||||
},
|
|
||||||
layout.FlexItem{
|
|
||||||
View: close,
|
|
||||||
},
|
|
||||||
|
|
||||||
layout.FlexItem{
|
|
||||||
View: diffToggle,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
footer = styles.NewStyle().Background(t.Background()).Padding(0, 1).Render(footer)
|
|
||||||
|
|
||||||
return header + "\n" + m.viewport.View() + "\n" + footer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Model) Clear() (Model, tea.Cmd) {
|
|
||||||
m.filename = nil
|
|
||||||
m.content = nil
|
|
||||||
m.isDiff = nil
|
|
||||||
return *m, m.render()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Model) ToggleDiff() (Model, tea.Cmd) {
|
|
||||||
switch m.diffStyle {
|
|
||||||
case DiffStyleSplit:
|
|
||||||
m.diffStyle = DiffStyleUnified
|
|
||||||
default:
|
|
||||||
m.diffStyle = DiffStyleSplit
|
|
||||||
}
|
|
||||||
return *m, m.render()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Model) DiffStyle() DiffStyle {
|
|
||||||
return m.diffStyle
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m Model) HasFile() bool {
|
|
||||||
return m.filename != nil && m.content != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m Model) Filename() string {
|
|
||||||
if m.filename == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return *m.filename
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Model) SetSize(width, height int) (Model, tea.Cmd) {
|
|
||||||
if m.width != width || m.height != height {
|
|
||||||
m.width = width
|
|
||||||
m.height = height
|
|
||||||
m.viewport.SetWidth(width)
|
|
||||||
m.viewport.SetHeight(height - 4)
|
|
||||||
return *m, m.render()
|
|
||||||
}
|
|
||||||
return *m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Model) SetFile(filename string, content string, isDiff bool) (Model, tea.Cmd) {
|
|
||||||
m.filename = &filename
|
|
||||||
m.content = &content
|
|
||||||
m.isDiff = &isDiff
|
|
||||||
return *m, m.render()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Model) render() tea.Cmd {
|
|
||||||
if m.filename == nil || m.content == nil {
|
|
||||||
m.viewport.SetContent("")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return func() tea.Msg {
|
|
||||||
t := theme.CurrentTheme()
|
|
||||||
var rendered string
|
|
||||||
|
|
||||||
if m.isDiff != nil && *m.isDiff {
|
|
||||||
diffResult := ""
|
|
||||||
var err error
|
|
||||||
if m.diffStyle == DiffStyleSplit {
|
|
||||||
diffResult, err = diff.FormatDiff(
|
|
||||||
*m.filename,
|
|
||||||
*m.content,
|
|
||||||
diff.WithWidth(m.width),
|
|
||||||
)
|
|
||||||
} else if m.diffStyle == DiffStyleUnified {
|
|
||||||
diffResult, err = diff.FormatUnifiedDiff(
|
|
||||||
*m.filename,
|
|
||||||
*m.content,
|
|
||||||
diff.WithWidth(m.width),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
rendered = styles.NewStyle().
|
|
||||||
Foreground(t.Error()).
|
|
||||||
Render(fmt.Sprintf("Error rendering diff: %v", err))
|
|
||||||
} else {
|
|
||||||
rendered = strings.TrimRight(diffResult, "\n")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rendered = util.RenderFile(
|
|
||||||
*m.filename,
|
|
||||||
*m.content,
|
|
||||||
m.width,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
rendered = styles.NewStyle().
|
|
||||||
Width(m.width).
|
|
||||||
Background(t.BackgroundPanel()).
|
|
||||||
Render(rendered)
|
|
||||||
|
|
||||||
return fileRenderedMsg{
|
|
||||||
content: rendered,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Model) ScrollTo(line int) {
|
|
||||||
m.viewport.SetYOffset(line)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Model) ScrollToBottom() {
|
|
||||||
m.viewport.GotoBottom()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Model) ScrollToTop() {
|
|
||||||
m.viewport.GotoTop()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Model) PageUp() (Model, tea.Cmd) {
|
|
||||||
m.viewport.ViewUp()
|
|
||||||
return *m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Model) PageDown() (Model, tea.Cmd) {
|
|
||||||
m.viewport.ViewDown()
|
|
||||||
return *m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Model) HalfPageUp() (Model, tea.Cmd) {
|
|
||||||
m.viewport.HalfViewUp()
|
|
||||||
return *m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Model) HalfPageDown() (Model, tea.Cmd) {
|
|
||||||
m.viewport.HalfViewDown()
|
|
||||||
return *m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m Model) AtTop() bool {
|
|
||||||
return m.viewport.AtTop()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m Model) AtBottom() bool {
|
|
||||||
return m.viewport.AtBottom()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m Model) ScrollPercent() float64 {
|
|
||||||
return m.viewport.ScrollPercent()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m Model) TotalLineCount() int {
|
|
||||||
return m.viewport.TotalLineCount()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m Model) VisibleLineCount() int {
|
|
||||||
return m.viewport.VisibleLineCount()
|
|
||||||
}
|
|
||||||
@@ -132,7 +132,7 @@ func (m *statusComponent) View() string {
|
|||||||
modeForeground = t.BackgroundPanel()
|
modeForeground = t.BackgroundPanel()
|
||||||
}
|
}
|
||||||
|
|
||||||
command := m.app.Commands[commands.SwitchAgentCommand]
|
command := m.app.Commands[commands.AgentCycleCommand]
|
||||||
kb := command.Keybindings[0]
|
kb := command.Keybindings[0]
|
||||||
key := kb.Key
|
key := kb.Key
|
||||||
if kb.RequiresLeader {
|
if kb.RequiresLeader {
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import (
|
|||||||
"github.com/sst/opencode/internal/components/chat"
|
"github.com/sst/opencode/internal/components/chat"
|
||||||
cmdcomp "github.com/sst/opencode/internal/components/commands"
|
cmdcomp "github.com/sst/opencode/internal/components/commands"
|
||||||
"github.com/sst/opencode/internal/components/dialog"
|
"github.com/sst/opencode/internal/components/dialog"
|
||||||
"github.com/sst/opencode/internal/components/fileviewer"
|
|
||||||
"github.com/sst/opencode/internal/components/modal"
|
"github.com/sst/opencode/internal/components/modal"
|
||||||
"github.com/sst/opencode/internal/components/status"
|
"github.com/sst/opencode/internal/components/status"
|
||||||
"github.com/sst/opencode/internal/components/toast"
|
"github.com/sst/opencode/internal/components/toast"
|
||||||
@@ -78,7 +77,6 @@ type Model struct {
|
|||||||
interruptKeyState InterruptKeyState
|
interruptKeyState InterruptKeyState
|
||||||
exitKeyState ExitKeyState
|
exitKeyState ExitKeyState
|
||||||
messagesRight bool
|
messagesRight bool
|
||||||
fileViewer fileviewer.Model
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a Model) Init() tea.Cmd {
|
func (a Model) Init() tea.Cmd {
|
||||||
@@ -94,13 +92,6 @@ func (a Model) Init() tea.Cmd {
|
|||||||
cmds = append(cmds, a.status.Init())
|
cmds = append(cmds, a.status.Init())
|
||||||
cmds = append(cmds, a.completions.Init())
|
cmds = append(cmds, a.completions.Init())
|
||||||
cmds = append(cmds, a.toastManager.Init())
|
cmds = append(cmds, a.toastManager.Init())
|
||||||
cmds = append(cmds, a.fileViewer.Init())
|
|
||||||
|
|
||||||
// Check if we should show the init dialog
|
|
||||||
cmds = append(cmds, func() tea.Msg {
|
|
||||||
shouldShow := a.app.Info.Git && a.app.Info.Time.Initialized > 0
|
|
||||||
return dialog.ShowInitDialogMsg{Show: shouldShow}
|
|
||||||
})
|
|
||||||
|
|
||||||
return tea.Batch(cmds...)
|
return tea.Batch(cmds...)
|
||||||
}
|
}
|
||||||
@@ -586,12 +577,6 @@ func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
slog.Error("Server error", "name", err.Name, "message", err.Data.Message)
|
slog.Error("Server error", "name", err.Name, "message", err.Data.Message)
|
||||||
return a, toast.NewErrorToast(err.Data.Message, toast.WithTitle(string(err.Name)))
|
return a, toast.NewErrorToast(err.Data.Message, toast.WithTitle(string(err.Name)))
|
||||||
}
|
}
|
||||||
case opencode.EventListResponseEventFileWatcherUpdated:
|
|
||||||
if a.fileViewer.HasFile() {
|
|
||||||
if a.fileViewer.Filename() == msg.Properties.File {
|
|
||||||
return a.openFile(msg.Properties.File)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case tea.WindowSizeMsg:
|
case tea.WindowSizeMsg:
|
||||||
msg.Height -= 2 // Make space for the status bar
|
msg.Height -= 2 // Make space for the status bar
|
||||||
a.width, a.height = msg.Width, msg.Height
|
a.width, a.height = msg.Width, msg.Height
|
||||||
@@ -653,8 +638,6 @@ func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
// Reset exit key state after timeout
|
// Reset exit key state after timeout
|
||||||
a.exitKeyState = ExitKeyIdle
|
a.exitKeyState = ExitKeyIdle
|
||||||
a.editor.SetExitKeyInDebounce(false)
|
a.editor.SetExitKeyInDebounce(false)
|
||||||
case dialog.FindSelectedMsg:
|
|
||||||
return a.openFile(msg.FilePath)
|
|
||||||
case tea.PasteMsg, tea.ClipboardMsg:
|
case tea.PasteMsg, tea.ClipboardMsg:
|
||||||
// Paste events: prioritize modal if active, otherwise editor
|
// Paste events: prioritize modal if active, otherwise editor
|
||||||
if a.modal != nil {
|
if a.modal != nil {
|
||||||
@@ -753,10 +736,6 @@ func (a Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
cmds = append(cmds, cmd)
|
cmds = append(cmds, cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
fv, cmd := a.fileViewer.Update(msg)
|
|
||||||
a.fileViewer = fv
|
|
||||||
cmds = append(cmds, cmd)
|
|
||||||
|
|
||||||
return a, tea.Batch(cmds...)
|
return a, tea.Batch(cmds...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -806,26 +785,6 @@ func (a Model) Cleanup() {
|
|||||||
a.status.Cleanup()
|
a.status.Cleanup()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a Model) openFile(filepath string) (tea.Model, tea.Cmd) {
|
|
||||||
var cmd tea.Cmd
|
|
||||||
response, err := a.app.Client.File.Read(
|
|
||||||
context.Background(),
|
|
||||||
opencode.FileReadParams{
|
|
||||||
Path: opencode.F(filepath),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
slog.Error("Failed to read file", "error", err)
|
|
||||||
return a, toast.NewErrorToast("Failed to read file")
|
|
||||||
}
|
|
||||||
a.fileViewer, cmd = a.fileViewer.SetFile(
|
|
||||||
filepath,
|
|
||||||
response.Content,
|
|
||||||
response.Type == "patch",
|
|
||||||
)
|
|
||||||
return a, cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a Model) home() (string, int, int) {
|
func (a Model) home() (string, int, int) {
|
||||||
t := theme.CurrentTheme()
|
t := theme.CurrentTheme()
|
||||||
effectiveWidth := a.width - 4
|
effectiveWidth := a.width - 4
|
||||||
@@ -1014,11 +973,11 @@ func (a Model) executeCommand(command commands.Command) (tea.Model, tea.Cmd) {
|
|||||||
case commands.AppHelpCommand:
|
case commands.AppHelpCommand:
|
||||||
helpDialog := dialog.NewHelpDialog(a.app)
|
helpDialog := dialog.NewHelpDialog(a.app)
|
||||||
a.modal = helpDialog
|
a.modal = helpDialog
|
||||||
case commands.SwitchAgentCommand:
|
case commands.AgentCycleCommand:
|
||||||
updated, cmd := a.app.SwitchAgent()
|
updated, cmd := a.app.SwitchAgent()
|
||||||
a.app = updated
|
a.app = updated
|
||||||
cmds = append(cmds, cmd)
|
cmds = append(cmds, cmd)
|
||||||
case commands.SwitchAgentReverseCommand:
|
case commands.AgentCycleReverseCommand:
|
||||||
updated, cmd := a.app.SwitchAgentReverse()
|
updated, cmd := a.app.SwitchAgentReverse()
|
||||||
a.app = updated
|
a.app = updated
|
||||||
cmds = append(cmds, cmd)
|
cmds = append(cmds, cmd)
|
||||||
@@ -1197,21 +1156,6 @@ func (a Model) executeCommand(command commands.Command) (tea.Model, tea.Cmd) {
|
|||||||
case commands.ThemeListCommand:
|
case commands.ThemeListCommand:
|
||||||
themeDialog := dialog.NewThemeDialog()
|
themeDialog := dialog.NewThemeDialog()
|
||||||
a.modal = themeDialog
|
a.modal = themeDialog
|
||||||
// case commands.FileListCommand:
|
|
||||||
// a.editor.Blur()
|
|
||||||
// findDialog := dialog.NewFindDialog(a.fileProvider)
|
|
||||||
// cmds = append(cmds, findDialog.Init())
|
|
||||||
// a.modal = findDialog
|
|
||||||
case commands.FileCloseCommand:
|
|
||||||
a.fileViewer, cmd = a.fileViewer.Clear()
|
|
||||||
cmds = append(cmds, cmd)
|
|
||||||
case commands.FileDiffToggleCommand:
|
|
||||||
a.fileViewer, cmd = a.fileViewer.ToggleDiff()
|
|
||||||
cmds = append(cmds, cmd)
|
|
||||||
a.app.State.SplitDiff = a.fileViewer.DiffStyle() == fileviewer.DiffStyleSplit
|
|
||||||
cmds = append(cmds, a.app.SaveState())
|
|
||||||
case commands.FileSearchCommand:
|
|
||||||
return a, nil
|
|
||||||
case commands.ProjectInitCommand:
|
case commands.ProjectInitCommand:
|
||||||
cmds = append(cmds, a.app.InitializeProject(context.Background()))
|
cmds = append(cmds, a.app.InitializeProject(context.Background()))
|
||||||
case commands.InputClearCommand:
|
case commands.InputClearCommand:
|
||||||
@@ -1242,42 +1186,21 @@ func (a Model) executeCommand(command commands.Command) (tea.Model, tea.Cmd) {
|
|||||||
a.messages = updated.(chat.MessagesComponent)
|
a.messages = updated.(chat.MessagesComponent)
|
||||||
cmds = append(cmds, cmd)
|
cmds = append(cmds, cmd)
|
||||||
case commands.MessagesPageUpCommand:
|
case commands.MessagesPageUpCommand:
|
||||||
if a.fileViewer.HasFile() {
|
updated, cmd := a.messages.PageUp()
|
||||||
a.fileViewer, cmd = a.fileViewer.PageUp()
|
a.messages = updated.(chat.MessagesComponent)
|
||||||
cmds = append(cmds, cmd)
|
cmds = append(cmds, cmd)
|
||||||
} else {
|
|
||||||
updated, cmd := a.messages.PageUp()
|
|
||||||
a.messages = updated.(chat.MessagesComponent)
|
|
||||||
cmds = append(cmds, cmd)
|
|
||||||
}
|
|
||||||
case commands.MessagesPageDownCommand:
|
case commands.MessagesPageDownCommand:
|
||||||
if a.fileViewer.HasFile() {
|
updated, cmd := a.messages.PageDown()
|
||||||
a.fileViewer, cmd = a.fileViewer.PageDown()
|
a.messages = updated.(chat.MessagesComponent)
|
||||||
cmds = append(cmds, cmd)
|
cmds = append(cmds, cmd)
|
||||||
} else {
|
|
||||||
updated, cmd := a.messages.PageDown()
|
|
||||||
a.messages = updated.(chat.MessagesComponent)
|
|
||||||
cmds = append(cmds, cmd)
|
|
||||||
}
|
|
||||||
case commands.MessagesHalfPageUpCommand:
|
case commands.MessagesHalfPageUpCommand:
|
||||||
if a.fileViewer.HasFile() {
|
updated, cmd := a.messages.HalfPageUp()
|
||||||
a.fileViewer, cmd = a.fileViewer.HalfPageUp()
|
a.messages = updated.(chat.MessagesComponent)
|
||||||
cmds = append(cmds, cmd)
|
cmds = append(cmds, cmd)
|
||||||
} else {
|
|
||||||
updated, cmd := a.messages.HalfPageUp()
|
|
||||||
a.messages = updated.(chat.MessagesComponent)
|
|
||||||
cmds = append(cmds, cmd)
|
|
||||||
}
|
|
||||||
case commands.MessagesHalfPageDownCommand:
|
case commands.MessagesHalfPageDownCommand:
|
||||||
if a.fileViewer.HasFile() {
|
updated, cmd := a.messages.HalfPageDown()
|
||||||
a.fileViewer, cmd = a.fileViewer.HalfPageDown()
|
a.messages = updated.(chat.MessagesComponent)
|
||||||
cmds = append(cmds, cmd)
|
cmds = append(cmds, cmd)
|
||||||
} else {
|
|
||||||
updated, cmd := a.messages.HalfPageDown()
|
|
||||||
a.messages = updated.(chat.MessagesComponent)
|
|
||||||
cmds = append(cmds, cmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
case commands.MessagesCopyCommand:
|
case commands.MessagesCopyCommand:
|
||||||
updated, cmd := a.messages.CopyLastMessage()
|
updated, cmd := a.messages.CopyLastMessage()
|
||||||
a.messages = updated.(chat.MessagesComponent)
|
a.messages = updated.(chat.MessagesComponent)
|
||||||
@@ -1327,8 +1250,6 @@ func NewModel(app *app.App) tea.Model {
|
|||||||
toastManager: toast.NewToastManager(),
|
toastManager: toast.NewToastManager(),
|
||||||
interruptKeyState: InterruptKeyIdle,
|
interruptKeyState: InterruptKeyIdle,
|
||||||
exitKeyState: ExitKeyIdle,
|
exitKeyState: ExitKeyIdle,
|
||||||
fileViewer: fileviewer.New(app),
|
|
||||||
messagesRight: app.State.MessagesRight,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return model
|
return model
|
||||||
|
|||||||
@@ -11,33 +11,19 @@ opencode has a list of keybinds that you can customize through the opencode conf
|
|||||||
"keybinds": {
|
"keybinds": {
|
||||||
"leader": "ctrl+x",
|
"leader": "ctrl+x",
|
||||||
"app_help": "<leader>h",
|
"app_help": "<leader>h",
|
||||||
"switch_agent": "tab",
|
"app_exit": "ctrl+c,<leader>q",
|
||||||
"switch_agent_reverse": "shift+tab",
|
|
||||||
|
|
||||||
"editor_open": "<leader>e",
|
"editor_open": "<leader>e",
|
||||||
|
"theme_list": "<leader>t",
|
||||||
|
"project_init": "<leader>i",
|
||||||
|
"tool_details": "<leader>d",
|
||||||
|
"thinking_blocks": "<leader>b",
|
||||||
|
"session_export": "<leader>x",
|
||||||
"session_new": "<leader>n",
|
"session_new": "<leader>n",
|
||||||
"session_list": "<leader>l",
|
"session_list": "<leader>l",
|
||||||
"session_share": "<leader>s",
|
"session_share": "<leader>s",
|
||||||
"session_unshare": "none",
|
"session_unshare": "none",
|
||||||
"session_export": "<leader>x",
|
|
||||||
"session_interrupt": "esc",
|
"session_interrupt": "esc",
|
||||||
"session_compact": "<leader>c",
|
"session_compact": "<leader>c",
|
||||||
|
|
||||||
"tool_details": "<leader>d",
|
|
||||||
"thinking_blocks": "<leader>b",
|
|
||||||
"model_list": "<leader>m",
|
|
||||||
"agent_list": "<leader>a",
|
|
||||||
"model_cycle_recent": "f2",
|
|
||||||
"model_cycle_recent_reverse": "shift+f2",
|
|
||||||
"theme_list": "<leader>t",
|
|
||||||
"project_init": "<leader>i",
|
|
||||||
|
|
||||||
"input_clear": "ctrl+c",
|
|
||||||
"input_paste": "ctrl+v",
|
|
||||||
"input_submit": "enter",
|
|
||||||
"input_newline": "shift+enter,ctrl+j",
|
|
||||||
|
|
||||||
"messages_page_up": "pgup",
|
"messages_page_up": "pgup",
|
||||||
"messages_page_down": "pgdown",
|
"messages_page_down": "pgdown",
|
||||||
"messages_half_page_up": "ctrl+alt+u",
|
"messages_half_page_up": "ctrl+alt+u",
|
||||||
@@ -47,8 +33,16 @@ opencode has a list of keybinds that you can customize through the opencode conf
|
|||||||
"messages_copy": "<leader>y",
|
"messages_copy": "<leader>y",
|
||||||
"messages_undo": "<leader>u",
|
"messages_undo": "<leader>u",
|
||||||
"messages_redo": "<leader>r",
|
"messages_redo": "<leader>r",
|
||||||
|
"model_list": "<leader>m",
|
||||||
"app_exit": "ctrl+c,<leader>q"
|
"model_cycle_recent": "f2",
|
||||||
|
"model_cycle_recent_reverse": "shift+f2",
|
||||||
|
"agent_list": "<leader>a",
|
||||||
|
"agent_cycle": "tab",
|
||||||
|
"agent_cycle_reverse": "shift+tab",
|
||||||
|
"input_clear": "ctrl+c",
|
||||||
|
"input_paste": "ctrl+v",
|
||||||
|
"input_submit": "enter",
|
||||||
|
"input_newline": "shift+enter,ctrl+j"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user