handlers.go

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