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
21// LSPEvent represents an event in the LSP system
22type LSPEvent struct {
23	Type            LSPEventType
24	Name            string
25	State           lsp.ServerState
26	Error           error
27	DiagnosticCount int
28}
29
30// LSPClientInfo holds information about an LSP client's state
31type LSPClientInfo struct {
32	Name            string
33	State           lsp.ServerState
34	Error           error
35	Client          *lsp.Client
36	DiagnosticCount int
37	ConnectedAt     time.Time
38}
39
40var (
41	lspStates = csync.NewMap[string, LSPClientInfo]()
42	lspBroker = pubsub.NewBroker[LSPEvent]()
43)
44
45// SubscribeLSPEvents returns a channel for LSP events
46func SubscribeLSPEvents(ctx context.Context) <-chan pubsub.Event[LSPEvent] {
47	return lspBroker.Subscribe(ctx)
48}
49
50// GetLSPStates returns the current state of all LSP clients
51func GetLSPStates() map[string]LSPClientInfo {
52	return maps.Collect(lspStates.Seq2())
53}
54
55// GetLSPState returns the state of a specific LSP client
56func GetLSPState(name string) (LSPClientInfo, bool) {
57	return lspStates.Get(name)
58}
59
60// updateLSPState updates the state of an LSP client and publishes an event
61func updateLSPState(name string, state lsp.ServerState, err error, client *lsp.Client, diagnosticCount int) {
62	info := LSPClientInfo{
63		Name:            name,
64		State:           state,
65		Error:           err,
66		Client:          client,
67		DiagnosticCount: diagnosticCount,
68	}
69	if state == lsp.StateReady {
70		info.ConnectedAt = time.Now()
71	}
72	lspStates.Set(name, info)
73
74	// Publish state change event
75	lspBroker.Publish(pubsub.UpdatedEvent, LSPEvent{
76		Type:            LSPEventStateChanged,
77		Name:            name,
78		State:           state,
79		Error:           err,
80		DiagnosticCount: diagnosticCount,
81	})
82}
83
84// updateLSPDiagnostics updates the diagnostic count for an LSP client and publishes an event
85func updateLSPDiagnostics(name string, diagnosticCount int) {
86	if info, exists := lspStates.Get(name); exists {
87		info.DiagnosticCount = diagnosticCount
88		lspStates.Set(name, info)
89
90		// Publish diagnostics change event
91		lspBroker.Publish(pubsub.UpdatedEvent, LSPEvent{
92			Type:            LSPEventDiagnosticsChanged,
93			Name:            name,
94			State:           info.State,
95			Error:           info.Error,
96			DiagnosticCount: diagnosticCount,
97		})
98	}
99}