gitstack

grindlemire/go-tui code browser

2.8 KB Go 89 lines 2026-06-03 · d15bb9f raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package lsp

import (
	"github.com/grindlemire/go-tui/internal/lsp/log"
	"github.com/grindlemire/go-tui/internal/lsp/provider"
)

// Diagnostic and DiagnosticSeverity are type aliases for the canonical definitions
// in the provider package, eliminating duplicate type definitions.
type (
	Diagnostic         = provider.Diagnostic
	DiagnosticSeverity = provider.DiagnosticSeverity
)

// Re-export severity constants so existing lsp package code compiles unchanged.
const (
	DiagnosticSeverityError       = provider.DiagnosticSeverityError
	DiagnosticSeverityWarning     = provider.DiagnosticSeverityWarning
	DiagnosticSeverityInformation = provider.DiagnosticSeverityInformation
	DiagnosticSeverityHint        = provider.DiagnosticSeverityHint
)

// PublishDiagnosticsParams represents the parameters for publishDiagnostics.
type PublishDiagnosticsParams struct {
	URI         string       `json:"uri"`
	Version     *int         `json:"version,omitempty"`
	Diagnostics []Diagnostic `json:"diagnostics"`
}

// publishDiagnostics sends diagnostics for a document.
// If a DiagnosticsProvider is registered, it delegates to the provider;
// otherwise it falls back to inline conversion.
// Gopls diagnostics are merged with parse diagnostics.
func (s *Server) publishDiagnostics(doc *Document) {
	if doc == nil {
		return
	}

	var diagnostics []Diagnostic

	if s.router != nil && s.router.registry != nil && s.router.registry.Diagnostics != nil {
		diags, err := s.router.registry.Diagnostics.Diagnose(doc)
		if err != nil {
			log.Server("Diagnostics provider error: %v", err)
			diagnostics = []Diagnostic{}
		} else {
			diagnostics = diags
		}
	} else {
		// No provider registered — fall back to inline conversion of parse errors
		for _, e := range doc.Errors {
			diagnostics = append(diagnostics, Diagnostic{
				Range: Range{
					Start: Position{Line: e.Pos.Line - 1, Character: e.Pos.Column - 1},
					End:   Position{Line: e.Pos.Line - 1, Character: e.Pos.Column - 1 + 10},
				},
				Severity: DiagnosticSeverityError,
				Source:   "gsx",
				Message:  e.Message,
			})
		}
	}

	// Add gopls diagnostics (type errors, undefined identifiers, etc.)
	s.goplsDiagnosticsMu.RLock()
	goplsDiags := s.goplsDiagnostics[doc.URI]
	s.goplsDiagnosticsMu.RUnlock()

	for _, gd := range goplsDiags {
		diagnostics = append(diagnostics, Diagnostic{
			Range: Range{
				Start: Position{Line: gd.Range.Start.Line, Character: gd.Range.Start.Character},
				End:   Position{Line: gd.Range.End.Line, Character: gd.Range.End.Character},
			},
			Severity: DiagnosticSeverity(gd.Severity),
			Source:   gd.Source,
			Message:  gd.Message,
		})
	}

	params := PublishDiagnosticsParams{
		URI:         doc.URI,
		Diagnostics: diagnostics,
	}

	if err := s.sendNotification("textDocument/publishDiagnostics", params); err != nil {
		log.Server("Error publishing diagnostics: %v", err)
	}
}