1package app
2
3import (
4 "context"
5 "maps"
6 "time"
7
8 "github.com/charmbracelet/crush/internal/csync"
9 "github.com/charmbracelet/crush/internal/lsp"
10 "github.com/charmbracelet/crush/internal/pubsub"
11)
12
13// LSPEventType represents the type of LSP event
14type LSPEventType string
15
16const (
17 LSPEventStateChanged LSPEventType = "state_changed"
18 LSPEventDiagnosticsChanged LSPEventType = "diagnostics_changed"
19)
20
21func (e LSPEventType) MarshalText() ([]byte, error) {
22 return []byte(e), nil
23}
24
25func (e *LSPEventType) UnmarshalText(data []byte) error {
26 *e = LSPEventType(data)
27 return nil
28}
29
30// LSPEvent represents an event in the LSP system
31type LSPEvent struct {
32 Type LSPEventType `json:"type"`
33 Name string `json:"name"`
34 State lsp.ServerState `json:"state"`
35 Error error `json:"error,omitempty"`
36 DiagnosticCount int `json:"diagnostic_count,omitempty"`
37}
38
39// LSPClientInfo holds information about an LSP client's state
40type LSPClientInfo struct {
41 Name string
42 State lsp.ServerState
43 Error error
44 Client *lsp.Client
45 DiagnosticCount int
46 ConnectedAt time.Time
47}
48
49var (
50 lspStates = csync.NewMap[string, LSPClientInfo]()
51 lspBroker = pubsub.NewBroker[LSPEvent]()
52)
53
54// SubscribeLSPEvents returns a channel for LSP events
55func SubscribeLSPEvents(ctx context.Context) <-chan pubsub.Event[LSPEvent] {
56 return lspBroker.Subscribe(ctx)
57}
58
59// GetLSPStates returns the current state of all LSP clients
60func GetLSPStates() map[string]LSPClientInfo {
61 return maps.Collect(lspStates.Seq2())
62}
63
64// GetLSPState returns the state of a specific LSP client
65func GetLSPState(name string) (LSPClientInfo, bool) {
66 return lspStates.Get(name)
67}
68
69// updateLSPState updates the state of an LSP client and publishes an event
70func updateLSPState(name string, state lsp.ServerState, err error, client *lsp.Client, diagnosticCount int) {
71 info := LSPClientInfo{
72 Name: name,
73 State: state,
74 Error: err,
75 Client: client,
76 DiagnosticCount: diagnosticCount,
77 }
78 if state == lsp.StateReady {
79 info.ConnectedAt = time.Now()
80 }
81 lspStates.Set(name, info)
82
83 // Publish state change event
84 lspBroker.Publish(pubsub.UpdatedEvent, LSPEvent{
85 Type: LSPEventStateChanged,
86 Name: name,
87 State: state,
88 Error: err,
89 DiagnosticCount: diagnosticCount,
90 })
91}
92
93// updateLSPDiagnostics updates the diagnostic count for an LSP client and publishes an event
94func updateLSPDiagnostics(name string, diagnosticCount int) {
95 if info, exists := lspStates.Get(name); exists {
96 info.DiagnosticCount = diagnosticCount
97 lspStates.Set(name, info)
98
99 // Publish diagnostics change event
100 lspBroker.Publish(pubsub.UpdatedEvent, LSPEvent{
101 Type: LSPEventDiagnosticsChanged,
102 Name: name,
103 State: info.State,
104 Error: info.Error,
105 DiagnosticCount: diagnosticCount,
106 })
107 }
108}