1package lsp
  2
  3import (
  4	"encoding/json"
  5	"log/slog"
  6
  7	"github.com/charmbracelet/crush/internal/config"
  8
  9	"github.com/charmbracelet/crush/internal/lsp/protocol"
 10	"github.com/charmbracelet/crush/internal/lsp/util"
 11)
 12
 13// Requests
 14
 15func HandleWorkspaceConfiguration(params json.RawMessage) (any, error) {
 16	return []map[string]any{{}}, nil
 17}
 18
 19func HandleRegisterCapability(params json.RawMessage) (any, error) {
 20	var registerParams protocol.RegistrationParams
 21	if err := json.Unmarshal(params, ®isterParams); err != nil {
 22		slog.Error("Error unmarshaling registration params", "error", err)
 23		return nil, err
 24	}
 25
 26	for _, reg := range registerParams.Registrations {
 27		switch reg.Method {
 28		case "workspace/didChangeWatchedFiles":
 29			// Parse the registration options
 30			optionsJSON, err := json.Marshal(reg.RegisterOptions)
 31			if err != nil {
 32				slog.Error("Error marshaling registration options", "error", err)
 33				continue
 34			}
 35
 36			var options protocol.DidChangeWatchedFilesRegistrationOptions
 37			if err := json.Unmarshal(optionsJSON, &options); err != nil {
 38				slog.Error("Error unmarshaling registration options", "error", err)
 39				continue
 40			}
 41
 42			// Store the file watchers registrations
 43			notifyFileWatchRegistration(reg.ID, options.Watchers)
 44		}
 45	}
 46
 47	return nil, nil
 48}
 49
 50func HandleApplyEdit(params json.RawMessage) (any, error) {
 51	var edit protocol.ApplyWorkspaceEditParams
 52	if err := json.Unmarshal(params, &edit); err != nil {
 53		return nil, err
 54	}
 55
 56	err := util.ApplyWorkspaceEdit(edit.Edit)
 57	if err != nil {
 58		slog.Error("Error applying workspace edit", "error", err)
 59		return protocol.ApplyWorkspaceEditResult{Applied: false, FailureReason: err.Error()}, nil
 60	}
 61
 62	return protocol.ApplyWorkspaceEditResult{Applied: true}, nil
 63}
 64
 65// FileWatchRegistrationHandler is a function that will be called when file watch registrations are received
 66type FileWatchRegistrationHandler func(id string, watchers []protocol.FileSystemWatcher)
 67
 68// fileWatchHandler holds the current handler for file watch registrations
 69var fileWatchHandler FileWatchRegistrationHandler
 70
 71// RegisterFileWatchHandler sets the handler for file watch registrations
 72func RegisterFileWatchHandler(handler FileWatchRegistrationHandler) {
 73	fileWatchHandler = handler
 74}
 75
 76// notifyFileWatchRegistration notifies the handler about new file watch registrations
 77func notifyFileWatchRegistration(id string, watchers []protocol.FileSystemWatcher) {
 78	if fileWatchHandler != nil {
 79		fileWatchHandler(id, watchers)
 80	}
 81}
 82
 83// Notifications
 84
 85func HandleServerMessage(params json.RawMessage) {
 86	cfg := config.Get()
 87	var msg struct {
 88		Type    int    `json:"type"`
 89		Message string `json:"message"`
 90	}
 91	if err := json.Unmarshal(params, &msg); err == nil {
 92		if cfg.Options.DebugLSP {
 93			slog.Debug("Server message", "type", msg.Type, "message", msg.Message)
 94		}
 95	}
 96}
 97
 98func HandleDiagnostics(client *Client, params json.RawMessage) {
 99	var diagParams protocol.PublishDiagnosticsParams
100	if err := json.Unmarshal(params, &diagParams); err != nil {
101		slog.Error("Error unmarshaling diagnostics params", "error", err)
102		return
103	}
104
105	client.diagnosticsMu.Lock()
106	client.diagnostics[diagParams.URI] = diagParams.Diagnostics
107
108	// Calculate total diagnostic count
109	totalCount := 0
110	for _, diagnostics := range client.diagnostics {
111		totalCount += len(diagnostics)
112	}
113	client.diagnosticsMu.Unlock()
114
115	// Trigger callback if set
116	if client.onDiagnosticsChanged != nil {
117		client.onDiagnosticsChanged(client.name, totalCount)
118	}
119}