handlers.go

  1package lsp
  2
  3import (
  4	"context"
  5	"encoding/json"
  6	"log/slog"
  7
  8	"github.com/charmbracelet/crush/internal/lsp/util"
  9	powernap "github.com/charmbracelet/x/powernap/pkg/lsp"
 10	"github.com/charmbracelet/x/powernap/pkg/lsp/protocol"
 11)
 12
 13// HandleWorkspaceConfiguration handles workspace configuration requests
 14func HandleWorkspaceConfiguration(_ context.Context, _ string, params json.RawMessage) (any, error) {
 15	return []map[string]any{{}}, nil
 16}
 17
 18// HandleRegisterCapability handles capability registration requests
 19func HandleRegisterCapability(_ context.Context, _ string, params json.RawMessage) (any, error) {
 20	var registerParams protocol.RegistrationParams
 21	if err := json.Unmarshal(params, &registerParams); 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			var options protocol.DidChangeWatchedFilesRegistrationOptions
 36			if err := json.Unmarshal(optionsJSON, &options); err != nil {
 37				slog.Error("Error unmarshaling registration options", "error", err)
 38				continue
 39			}
 40			// Store the file watchers registrations
 41			notifyFileWatchRegistration(reg.ID, options.Watchers)
 42		}
 43	}
 44	return nil, nil
 45}
 46
 47// HandleApplyEdit handles workspace edit requests
 48func HandleApplyEdit(encoding powernap.OffsetEncoding) func(_ context.Context, _ string, params json.RawMessage) (any, error) {
 49	return func(_ context.Context, _ string, params json.RawMessage) (any, error) {
 50		var edit protocol.ApplyWorkspaceEditParams
 51		if err := json.Unmarshal(params, &edit); err != nil {
 52			return nil, err
 53		}
 54
 55		err := util.ApplyWorkspaceEdit(edit.Edit, encoding)
 56		if err != nil {
 57			slog.Error("Error applying workspace edit", "error", err)
 58			return protocol.ApplyWorkspaceEditResult{Applied: false, FailureReason: err.Error()}, nil
 59		}
 60
 61		return protocol.ApplyWorkspaceEditResult{Applied: true}, nil
 62	}
 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// HandleServerMessage handles server messages
 84func HandleServerMessage(_ context.Context, method string, params json.RawMessage) {
 85	var msg protocol.ShowMessageParams
 86	if err := json.Unmarshal(params, &msg); err != nil {
 87		slog.Debug("Error unmarshal server message", "error", err)
 88		return
 89	}
 90
 91	switch msg.Type {
 92	case protocol.Error:
 93		slog.Error("LSP Server", "message", msg.Message)
 94	case protocol.Warning:
 95		slog.Warn("LSP Server", "message", msg.Message)
 96	case protocol.Info:
 97		slog.Info("LSP Server", "message", msg.Message)
 98	case protocol.Log:
 99		slog.Debug("LSP Server", "message", msg.Message)
100	}
101}
102
103// HandleDiagnostics handles diagnostic notifications from the LSP server
104func HandleDiagnostics(client *Client, params json.RawMessage) {
105	var diagParams protocol.PublishDiagnosticsParams
106	if err := json.Unmarshal(params, &diagParams); err != nil {
107		slog.Error("Error unmarshaling diagnostics params", "error", err)
108		return
109	}
110
111	client.diagnostics.Set(diagParams.URI, diagParams.Diagnostics)
112
113	// Calculate total diagnostic count
114	totalCount := 0
115	for _, diagnostics := range client.diagnostics.Seq2() {
116		totalCount += len(diagnostics)
117	}
118
119	// Trigger callback if set
120	if client.onDiagnosticsChanged != nil {
121		client.onDiagnosticsChanged(client.name, totalCount)
122	}
123}