summaryrefslogtreecommitdiffhomepage
path: root/internal/tui
diff options
context:
space:
mode:
authorKujtim Hoxha <[email protected]>2025-04-03 15:20:15 +0200
committerKujtim Hoxha <[email protected]>2025-04-03 17:23:41 +0200
commitcfdd687216799cb5b47f099f1e7cd5dd16b3bdd0 (patch)
treea822bfde1463a7080c0ea06dd17796d7a1617d3d /internal/tui
parentafd9ad0560d76c2a6d161dad52553b10ff428905 (diff)
downloadopencode-cfdd687216799cb5b47f099f1e7cd5dd16b3bdd0.tar.gz
opencode-cfdd687216799cb5b47f099f1e7cd5dd16b3bdd0.zip
add initial lsp support
Diffstat (limited to 'internal/tui')
-rw-r--r--internal/tui/components/repl/messages.go85
-rw-r--r--internal/tui/components/repl/sessions.go1
-rw-r--r--internal/tui/styles/icons.go9
3 files changed, 76 insertions, 19 deletions
diff --git a/internal/tui/components/repl/messages.go b/internal/tui/components/repl/messages.go
index 7956867ce..2b5e599aa 100644
--- a/internal/tui/components/repl/messages.go
+++ b/internal/tui/components/repl/messages.go
@@ -5,6 +5,7 @@ import (
"fmt"
"sort"
"strings"
+ "time"
"github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/bubbles/viewport"
@@ -13,6 +14,7 @@ import (
"github.com/charmbracelet/lipgloss"
"github.com/kujtimiihoxha/termai/internal/app"
"github.com/kujtimiihoxha/termai/internal/llm/agent"
+ "github.com/kujtimiihoxha/termai/internal/lsp/protocol"
"github.com/kujtimiihoxha/termai/internal/message"
"github.com/kujtimiihoxha/termai/internal/pubsub"
"github.com/kujtimiihoxha/termai/internal/session"
@@ -39,6 +41,7 @@ type messagesCmp struct {
height int
focused bool
cachedView string
+ timeLoaded time.Time
}
func (m *messagesCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
@@ -51,7 +54,8 @@ func (m *messagesCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.viewport.GotoBottom()
}
for _, v := range m.messages {
- for _, c := range v.ToolCalls {
+ for _, c := range v.ToolCalls() {
+ // the message is being added to the session of a tool called
if c.ID == msg.Payload.SessionID {
m.renderView()
m.viewport.GotoBottom()
@@ -130,12 +134,11 @@ func hasUnfinishedMessages(messages []message.Message) bool {
return false
}
for _, msg := range messages {
- if !msg.Finished {
+ if !msg.IsFinished() {
return true
}
}
- lastMessage := messages[len(messages)-1]
- return lastMessage.Role != message.Assistant
+ return false
}
func (m *messagesCmp) renderMessageWithToolCall(content string, tools []message.ToolCall, futureMessages []message.Message) string {
@@ -205,7 +208,7 @@ func (m *messagesCmp) renderMessageWithToolCall(content string, tools []message.
findToolResult := func(toolCallID string, messages []message.Message) *message.ToolResult {
for _, msg := range messages {
if msg.Role == message.Tool {
- for _, result := range msg.ToolResults {
+ for _, result := range msg.ToolResults() {
if result.ToolCallID == toolCallID {
return &result
}
@@ -257,7 +260,7 @@ func (m *messagesCmp) renderMessageWithToolCall(content string, tools []message.
taskSessionMessages, _ := m.app.Messages.List(toolCall.ID)
for _, msg := range taskSessionMessages {
if msg.Role == message.Assistant {
- for _, toolCall := range msg.ToolCalls {
+ for _, toolCall := range msg.ToolCalls() {
toolHeader := lipgloss.NewStyle().
Bold(true).
Foreground(styles.Blue).
@@ -304,11 +307,11 @@ func (m *messagesCmp) renderMessageWithToolCall(content string, tools []message.
}
for _, msg := range futureMessages {
- if msg.Content != "" {
+ if msg.Content().String() != "" {
break
}
- for _, toolCall := range msg.ToolCalls {
+ for _, toolCall := range msg.ToolCalls() {
toolOutput := renderTool(toolCall)
allParts = append(allParts, " "+strings.ReplaceAll(toolOutput, "\n", "\n "))
@@ -339,10 +342,10 @@ func (m *messagesCmp) renderView() {
prevMessageWasUser := false
for inx, msg := range m.messages {
- content := msg.Content
+ content := msg.Content().String()
if content != "" || prevMessageWasUser {
- if msg.Thinking != "" && content == "" {
- content = msg.Thinking
+ if msg.ReasoningContent().String() != "" && content == "" {
+ content = msg.ReasoningContent().String()
} else if content == "" {
content = "..."
}
@@ -367,14 +370,14 @@ func (m *messagesCmp) renderView() {
EmbeddedText: borderText(msg.Role, currentMessage),
},
)
- if len(msg.ToolCalls) > 0 {
- content = m.renderMessageWithToolCall(content, msg.ToolCalls, m.messages[inx+1:])
+ if len(msg.ToolCalls()) > 0 {
+ content = m.renderMessageWithToolCall(content, msg.ToolCalls(), m.messages[inx+1:])
}
stringMessages = append(stringMessages, content)
currentMessage++
displayedMsgCount++
}
- if msg.Role == message.User && msg.Content != "" {
+ if msg.Role == message.User && msg.Content().String() != "" {
prevMessageWasUser = true
} else {
prevMessageWasUser = false
@@ -398,6 +401,57 @@ func (m *messagesCmp) Blur() tea.Cmd {
return nil
}
+func (m *messagesCmp) projectDiagnostics() string {
+ errorDiagnostics := []protocol.Diagnostic{}
+ warnDiagnostics := []protocol.Diagnostic{}
+ hintDiagnostics := []protocol.Diagnostic{}
+ infoDiagnostics := []protocol.Diagnostic{}
+ for _, client := range m.app.LSPClients {
+ for _, d := range client.GetDiagnostics() {
+ for _, diag := range d {
+ switch diag.Severity {
+ case protocol.SeverityError:
+ errorDiagnostics = append(errorDiagnostics, diag)
+ case protocol.SeverityWarning:
+ warnDiagnostics = append(warnDiagnostics, diag)
+ case protocol.SeverityHint:
+ hintDiagnostics = append(hintDiagnostics, diag)
+ case protocol.SeverityInformation:
+ infoDiagnostics = append(infoDiagnostics, diag)
+ }
+ }
+ }
+ }
+
+ if len(errorDiagnostics) == 0 && len(warnDiagnostics) == 0 && len(hintDiagnostics) == 0 && len(infoDiagnostics) == 0 {
+ if time.Since(m.timeLoaded) < time.Second*10 {
+ return "Loading diagnostics..."
+ }
+ return "No diagnostics"
+ }
+
+ diagnostics := []string{}
+
+ if len(errorDiagnostics) > 0 {
+ errStr := lipgloss.NewStyle().Foreground(styles.Error).Render(fmt.Sprintf("%s %d", styles.ErrorIcon, len(errorDiagnostics)))
+ diagnostics = append(diagnostics, errStr)
+ }
+ if len(warnDiagnostics) > 0 {
+ warnStr := lipgloss.NewStyle().Foreground(styles.Warning).Render(fmt.Sprintf("%s %d", styles.WarningIcon, len(warnDiagnostics)))
+ diagnostics = append(diagnostics, warnStr)
+ }
+ if len(hintDiagnostics) > 0 {
+ hintStr := lipgloss.NewStyle().Foreground(styles.Text).Render(fmt.Sprintf("%s %d", styles.HintIcon, len(hintDiagnostics)))
+ diagnostics = append(diagnostics, hintStr)
+ }
+ if len(infoDiagnostics) > 0 {
+ infoStr := lipgloss.NewStyle().Foreground(styles.Peach).Render(fmt.Sprintf("%s %d", styles.InfoIcon, len(infoDiagnostics)))
+ diagnostics = append(diagnostics, infoStr)
+ }
+
+ return strings.Join(diagnostics, " ")
+}
+
func (m *messagesCmp) BorderText() map[layout.BorderPosition]string {
title := m.session.Title
titleWidth := m.width / 2
@@ -409,7 +463,7 @@ func (m *messagesCmp) BorderText() map[layout.BorderPosition]string {
}
borderTest := map[layout.BorderPosition]string{
layout.TopLeftBorder: title,
- layout.BottomRightBorder: formatTokensAndCost(m.session.CompletionTokens+m.session.PromptTokens, m.session.Cost),
+ layout.BottomRightBorder: m.projectDiagnostics(),
}
if hasUnfinishedMessages(m.messages) {
borderTest[layout.BottomLeftBorder] = lipgloss.NewStyle().Foreground(styles.Peach).Render("Thinking...")
@@ -442,6 +496,7 @@ func (m *messagesCmp) SetSize(width int, height int) {
}
func (m *messagesCmp) Init() tea.Cmd {
+ m.timeLoaded = time.Now()
return nil
}
diff --git a/internal/tui/components/repl/sessions.go b/internal/tui/components/repl/sessions.go
index a1302baae..093337b18 100644
--- a/internal/tui/components/repl/sessions.go
+++ b/internal/tui/components/repl/sessions.go
@@ -245,4 +245,3 @@ func NewSessionsCmp(app *app.App) SessionsCmp {
focused: false,
}
}
-
diff --git a/internal/tui/styles/icons.go b/internal/tui/styles/icons.go
index d3dcc0c56..f641984e7 100644
--- a/internal/tui/styles/icons.go
+++ b/internal/tui/styles/icons.go
@@ -9,8 +9,11 @@ const (
UserIcon string = ""
CheckIcon string = "✓"
- ErrorIcon string = "✗"
+ ErrorIcon string = ""
+ WarningIcon string = ""
+ InfoIcon string = ""
+ HintIcon string = ""
SpinnerIcon string = "..."
-
- SleepIcon string = "󰒲"
+ BugIcon string = ""
+ SleepIcon string = "󰒲"
)