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