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  }