summaryrefslogtreecommitdiffhomepage
path: root/packages/tui/internal
diff options
context:
space:
mode:
authorFrank <[email protected]>2025-07-21 19:10:51 -0400
committerFrank <[email protected]>2025-07-21 19:10:57 -0400
commit5611ef8b28216aa9dd2ceb6ed17d5779a29154f6 (patch)
treea58c6dceb5f0e6243a6cbe3e4dc87a259119fd10 /packages/tui/internal
parentbec796e3c3c097bfc7bb9090729ec23573151d79 (diff)
downloadopencode-5611ef8b28216aa9dd2ceb6ed17d5779a29154f6.tar.gz
opencode-5611ef8b28216aa9dd2ceb6ed17d5779a29154f6.zip
wip: vscode extension
Diffstat (limited to 'packages/tui/internal')
-rw-r--r--packages/tui/internal/commands/command.go22
-rw-r--r--packages/tui/internal/components/ide/ide.go112
-rw-r--r--packages/tui/internal/tui/tui.go32
3 files changed, 164 insertions, 2 deletions
diff --git a/packages/tui/internal/commands/command.go b/packages/tui/internal/commands/command.go
index dde49e824..6015ab85b 100644
--- a/packages/tui/internal/commands/command.go
+++ b/packages/tui/internal/commands/command.go
@@ -63,17 +63,37 @@ func (r CommandRegistry) Sorted() []Command {
commands = append(commands, command)
}
slices.SortFunc(commands, func(a, b Command) int {
+ // Priority order: session_new, session_share, model_list, app_help first, app_exit last
+ priorityOrder := map[CommandName]int{
+ SessionNewCommand: 0,
+ AppHelpCommand: 1,
+ SessionShareCommand: 2,
+ ModelListCommand: 3,
+ }
+
+ aPriority, aHasPriority := priorityOrder[a.Name]
+ bPriority, bHasPriority := priorityOrder[b.Name]
+
+ if aHasPriority && bHasPriority {
+ return aPriority - bPriority
+ }
+ if aHasPriority {
+ return -1
+ }
+ if bHasPriority {
+ return 1
+ }
if a.Name == AppExitCommand {
return 1
}
if b.Name == AppExitCommand {
return -1
}
+
return strings.Compare(string(a.Name), string(b.Name))
})
return commands
}
-
func (r CommandRegistry) Matches(msg tea.KeyPressMsg, leader bool) []Command {
var matched []Command
for _, command := range r.Sorted() {
diff --git a/packages/tui/internal/components/ide/ide.go b/packages/tui/internal/components/ide/ide.go
new file mode 100644
index 000000000..cb10f0fc9
--- /dev/null
+++ b/packages/tui/internal/components/ide/ide.go
@@ -0,0 +1,112 @@
+package ide
+
+import (
+ "fmt"
+ "strings"
+
+ tea "github.com/charmbracelet/bubbletea/v2"
+ "github.com/charmbracelet/lipgloss/v2"
+ "github.com/charmbracelet/lipgloss/v2/compat"
+ "github.com/sst/opencode/internal/styles"
+ "github.com/sst/opencode/internal/theme"
+)
+
+type IdeComponent interface {
+ tea.ViewModel
+ SetSize(width, height int) tea.Cmd
+ SetBackgroundColor(color compat.AdaptiveColor)
+}
+
+type ideComponent struct {
+ width, height int
+ background *compat.AdaptiveColor
+}
+
+func (c *ideComponent) SetSize(width, height int) tea.Cmd {
+ c.width = width
+ c.height = height
+ return nil
+}
+
+func (c *ideComponent) SetBackgroundColor(color compat.AdaptiveColor) {
+ c.background = &color
+}
+
+func (c *ideComponent) View() string {
+ t := theme.CurrentTheme()
+
+ triggerStyle := styles.NewStyle().Foreground(t.Primary()).Bold(true)
+ descriptionStyle := styles.NewStyle().Foreground(t.Text())
+
+ if c.background != nil {
+ triggerStyle = triggerStyle.Background(*c.background)
+ descriptionStyle = descriptionStyle.Background(*c.background)
+ }
+
+ // VSCode shortcuts data
+ shortcuts := []struct {
+ shortcut string
+ description string
+ }{
+ {"Cmd+Esc", "open opencode in VS Code"},
+ {"Cmd+Opt+K", "insert file from VS Code"},
+ }
+
+ // Calculate column widths
+ maxShortcutWidth := 0
+ maxDescriptionWidth := 0
+
+ for _, shortcut := range shortcuts {
+ if len(shortcut.shortcut) > maxShortcutWidth {
+ maxShortcutWidth = len(shortcut.shortcut)
+ }
+ if len(shortcut.description) > maxDescriptionWidth {
+ maxDescriptionWidth = len(shortcut.description)
+ }
+ }
+
+ // Add padding between columns
+ columnPadding := 3
+
+ // Build the output
+ var output strings.Builder
+
+ maxWidth := 0
+ for _, shortcut := range shortcuts {
+ // Pad each column to align properly
+ shortcutText := fmt.Sprintf("%-*s", maxShortcutWidth, shortcut.shortcut)
+ description := fmt.Sprintf("%-*s", maxDescriptionWidth, shortcut.description)
+
+ // Apply styles and combine
+ line := triggerStyle.Render(shortcutText) +
+ triggerStyle.Render(strings.Repeat(" ", columnPadding)) +
+ descriptionStyle.Render(description)
+
+ output.WriteString(line + "\n")
+ maxWidth = max(maxWidth, lipgloss.Width(line))
+ }
+
+ // Remove trailing newline
+ result := strings.TrimSuffix(output.String(), "\n")
+ if c.background != nil {
+ result = styles.NewStyle().Background(*c.background).Width(maxWidth).Render(result)
+ }
+
+ return result
+}
+
+type Option func(*ideComponent)
+
+func WithBackground(background compat.AdaptiveColor) Option {
+ return func(c *ideComponent) {
+ c.background = &background
+ }
+}
+
+func New(opts ...Option) IdeComponent {
+ c := &ideComponent{}
+ for _, opt := range opts {
+ opt(c)
+ }
+ return c
+}
diff --git a/packages/tui/internal/tui/tui.go b/packages/tui/internal/tui/tui.go
index 6ff8f9282..bd0eaeada 100644
--- a/packages/tui/internal/tui/tui.go
+++ b/packages/tui/internal/tui/tui.go
@@ -22,6 +22,7 @@ import (
cmdcomp "github.com/sst/opencode/internal/components/commands"
"github.com/sst/opencode/internal/components/dialog"
"github.com/sst/opencode/internal/components/fileviewer"
+ "github.com/sst/opencode/internal/components/ide"
"github.com/sst/opencode/internal/components/modal"
"github.com/sst/opencode/internal/components/status"
"github.com/sst/opencode/internal/components/toast"
@@ -347,6 +348,11 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
"opencode updated to "+msg.Properties.Version+", restart to apply.",
toast.WithTitle("New version installed"),
)
+ case opencode.EventListResponseEventIdeInstalled:
+ return a, toast.NewSuccessToast(
+ "Installed the opencode extension in "+msg.Properties.Ide,
+ toast.WithTitle(msg.Properties.Ide+" extension installed"),
+ )
case opencode.EventListResponseEventSessionDeleted:
if a.app.Session != nil && msg.Properties.Info.ID == a.app.Session.ID {
a.app.Session = &opencode.Session{}
@@ -623,10 +629,17 @@ func (a appModel) home() string {
logoAndVersion,
styles.WhitespaceStyle(t.Background()),
)
+
+ // Use limit of 4 for vscode, 6 for others
+ limit := 6
+ if os.Getenv("OPENCODE_CALLER") == "vscode" {
+ limit = 4
+ }
+
commandsView := cmdcomp.New(
a.app,
cmdcomp.WithBackground(t.Background()),
- cmdcomp.WithLimit(6),
+ cmdcomp.WithLimit(limit),
)
cmds := lipgloss.PlaceHorizontal(
effectiveWidth,
@@ -635,6 +648,19 @@ func (a appModel) home() string {
styles.WhitespaceStyle(t.Background()),
)
+ // Add VSCode shortcuts if in VSCode environment
+ var ideShortcuts string
+ if os.Getenv("OPENCODE_CALLER") == "vscode" {
+ ideView := ide.New()
+ ideView.SetBackgroundColor(t.Background())
+ ideShortcuts = lipgloss.PlaceHorizontal(
+ effectiveWidth,
+ lipgloss.Center,
+ ideView.View(),
+ styles.WhitespaceStyle(t.Background()),
+ )
+ }
+
lines := []string{}
lines = append(lines, "")
lines = append(lines, "")
@@ -642,6 +668,10 @@ func (a appModel) home() string {
lines = append(lines, "")
lines = append(lines, "")
lines = append(lines, cmds)
+ if os.Getenv("OPENCODE_CALLER") == "vscode" {
+ lines = append(lines, "")
+ lines = append(lines, ideShortcuts)
+ }
lines = append(lines, "")
lines = append(lines, "")