github.com/nevalang/neva@v0.23.1-0.20240507185603-7696a9bb8dda/cmd/lsp/server/server.go (about) 1 package server 2 3 import ( 4 "context" 5 "fmt" 6 "sync" 7 "time" 8 9 "github.com/tliron/commonlog" 10 "github.com/tliron/glsp" 11 protocol "github.com/tliron/glsp/protocol_3_16" 12 13 "github.com/nevalang/neva/cmd/lsp/indexer" 14 "github.com/nevalang/neva/internal/compiler" 15 src "github.com/nevalang/neva/internal/compiler/sourcecode" 16 ) 17 18 type Server struct { 19 workspacePath string 20 name, version string 21 22 handler *Handler 23 logger commonlog.Logger 24 indexer indexer.Indexer 25 26 mu *sync.Mutex 27 index *src.Build 28 } 29 30 // setState allows to update state in a thread-safe manner. 31 func (s *Server) saveIndex(build src.Build) { 32 s.mu.Lock() 33 s.index = &build 34 s.mu.Unlock() 35 } 36 37 func (s *Server) indexAndNotifyProblems(notify glsp.NotifyFunc) error { 38 build, analyzerErr, err := s.indexer.FullIndex(context.Background(), s.workspacePath) 39 if err != nil { 40 return fmt.Errorf("%w: index", err) 41 } 42 s.saveIndex(build) 43 44 if analyzerErr == nil { 45 notify( 46 protocol.ServerTextDocumentPublishDiagnostics, 47 protocol.PublishDiagnosticsParams{}, // clear problems 48 ) 49 s.logger.Info("full index without problems, sent empty diagnostics") 50 return nil 51 } 52 53 notify( 54 protocol.ServerTextDocumentPublishDiagnostics, 55 s.createDiagnostics(*analyzerErr), 56 ) 57 58 s.logger.Info("diagnostic sent: " + analyzerErr.Error()) 59 60 return nil 61 } 62 63 func (s *Server) createDiagnostics(analyzerErr compiler.Error) protocol.PublishDiagnosticsParams { 64 source := "neva" 65 severity := protocol.DiagnosticSeverityError 66 67 var uri string 68 if analyzerErr.Location != nil { 69 uri = fmt.Sprintf( 70 "%s/%s/%s", 71 s.workspacePath, 72 analyzerErr.Location.PkgName, 73 analyzerErr.Location.FileName+".neva", 74 ) 75 } 76 77 var protocolRange protocol.Range 78 if analyzerErr.Meta != nil { 79 protocolRange = protocol.Range{ 80 Start: protocol.Position{ 81 Line: uint32(analyzerErr.Meta.Start.Line), 82 Character: uint32(analyzerErr.Meta.Start.Column), 83 }, 84 End: protocol.Position{ 85 Line: uint32(analyzerErr.Meta.Stop.Line), 86 Character: uint32(analyzerErr.Meta.Stop.Column), 87 }, 88 } 89 } 90 91 return protocol.PublishDiagnosticsParams{ 92 URI: uri, 93 Diagnostics: []protocol.Diagnostic{ 94 { 95 Range: protocolRange, 96 Severity: &severity, 97 Source: &source, 98 Message: analyzerErr.Error(), 99 Data: time.Now(), 100 // Unused: 101 Tags: []protocol.DiagnosticTag{}, 102 Code: &protocol.IntegerOrString{Value: nil}, 103 CodeDescription: &protocol.CodeDescription{HRef: ""}, 104 RelatedInformation: []protocol.DiagnosticRelatedInformation{}, 105 }, 106 }, 107 } 108 }