Skip to content

Commit

Permalink
Merge pull request #736 from nevalang/lsp-improvements
Browse files Browse the repository at this point in the history
Lsp improvements
  • Loading branch information
emil14 authored Oct 24, 2024
2 parents 821999f + baf81e3 commit 3c9aab5
Show file tree
Hide file tree
Showing 94 changed files with 505 additions and 515 deletions.
10 changes: 9 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,24 @@ web/src/sdk
plugins
.antlr
cmd/tmp
/neva
/examples/output
/examples/output.wasm
/neva
/neva-darwin-amd64
/neva-darwin-arm64
/neva-linux-amd64
/neva-linux-arm64
/neva-linux-loong64
/neva-windows-amd64.exe
/neva-windows-arm64.exe
/neva-lsp
/neva-lsp-darwin-amd64
/neva-lsp-darwin-arm64
/neva-lsp-linux-amd64
/neva-lsp-linux-arm64
/neva-lsp-linux-loong64
/neva-lsp-windows-amd64.exe
/neva-lsp-windows-arm64.exe
dist
trace.log
output
Expand Down
15 changes: 0 additions & 15 deletions assets/header/big_4.svg

This file was deleted.

45 changes: 0 additions & 45 deletions assets/header/small.svg

This file was deleted.

38 changes: 0 additions & 38 deletions assets/logo/square_gradient.svg

This file was deleted.

13 changes: 3 additions & 10 deletions cmd/lsp/indexer/indexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package indexer

import (
"context"
"fmt"

"github.com/nevalang/neva/internal/builder"
"github.com/nevalang/neva/internal/compiler"
Expand All @@ -16,18 +15,12 @@ type Indexer struct {
analyzer analyzer.Analyzer
}

func (i Indexer) FullIndex(ctx context.Context, path string) (src.Build, *compiler.Error, error) {
func (i Indexer) FullIndex(ctx context.Context, path string) (src.Build, *compiler.Error) {
feResult, err := i.fe.Process(ctx, path)
if err != nil {
return src.Build{}, nil, fmt.Errorf("frontend: %w", err)
return src.Build{}, err
}

analyzedBuild, err := i.analyzer.AnalyzeBuild(feResult.ParsedBuild)
if err != nil {
return src.Build{}, err, nil
}

return analyzedBuild, nil, nil
return i.analyzer.AnalyzeBuild(feResult.ParsedBuild)
}

func New(
Expand Down
19 changes: 10 additions & 9 deletions cmd/lsp/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,10 @@ func main() {
isDebug := flag.Bool("debug", false, "-debug")
flag.Parse()

verbosity := 1
if *isDebug {
verbosity = 2
}

commonlog.Configure(verbosity, nil)
commonlog.Configure(1, nil)
logger := commonlog.GetLoggerf("%s.server", serverName)

p := parser.New(*isDebug)
p := parser.New()

terminator := typesystem.Terminator{}
checker := typesystem.MustNewSubtypeChecker(terminator)
Expand All @@ -46,7 +41,13 @@ func main() {
*isDebug,
)

if err := srv.RunStdio(); err != nil {
panic(err)
if *isDebug {
if err := srv.RunTCP("localhost:6007"); err != nil {
panic(err)
}
} else {
if err := srv.RunStdio(); err != nil {
panic(err)
}
}
}
24 changes: 13 additions & 11 deletions cmd/lsp/server/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,17 @@ func BuildHandler(logger commonlog.Logger, serverName string, indexer indexer.In
}

s := Server{
handler: h,
logger: logger,
name: serverName,
version: pkg.Version,
indexer: indexer,
mu: &sync.Mutex{},
index: nil,
handler: h,
logger: logger,
name: serverName,
version: pkg.Version,
indexer: indexer,
indexMutex: &sync.Mutex{},
index: nil,
problemsMutex: &sync.Mutex{},
problemFiles: make(map[string]struct{}),
activeFile: "",
activeFileMutex: &sync.Mutex{},
}

// Basic
Expand Down Expand Up @@ -129,14 +133,12 @@ func BuildHandler(logger commonlog.Logger, serverName string, indexer indexer.In
h.TextDocumentWillSaveWaitUntil = func(context *glsp.Context, params *protocol.WillSaveTextDocumentParams) ([]protocol.TextEdit, error) {
return nil, nil
}
h.TextDocumentDidSave = func(context *glsp.Context, params *protocol.DidSaveTextDocumentParams) error {
return nil
}
h.TextDocumentDidSave = s.TextDocumentDidSave
h.TextDocumentDidClose = func(context *glsp.Context, params *protocol.DidCloseTextDocumentParams) error {
return nil
}

h.TextDocumentCompletion = nil
h.TextDocumentCompletion = s.TextDocumentCompletion
h.CompletionItemResolve = nil
h.TextDocumentHover = nil
h.TextDocumentSignatureHelp = nil
Expand Down
25 changes: 25 additions & 0 deletions cmd/lsp/server/language_features.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package server

import (
"github.com/tliron/glsp"
protocol "github.com/tliron/glsp/protocol_3_16"
)

func (s *Server) TextDocumentCompletion(
glspCtx *glsp.Context,
params *protocol.CompletionParams,
) (any, error) {
s.logger.Info("TextDocumentCompletion")
return []protocol.CompletionItem{}, nil
// return []protocol.CompletionItem{
// {
// Label: "Simple Test",
// Kind: compiler.Pointer(protocol.CompletionItemKindVariable),
// Data: core.EntityRef{
// Pkg: "test_pkg",
// Name: "TestName",
// },
// Detail: compiler.Pointer("Simple test completion"),
// },
// }, nil
}
105 changes: 56 additions & 49 deletions cmd/lsp/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package server

import (
"context"
"fmt"
"path/filepath"
"sync"
"time"

Expand All @@ -23,85 +23,92 @@ type Server struct {
logger commonlog.Logger
indexer indexer.Indexer

mu *sync.Mutex
index *src.Build
}
indexMutex *sync.Mutex
index *src.Build

// setState allows to update state in a thread-safe manner.
func (s *Server) saveIndex(build src.Build) {
s.mu.Lock()
s.index = &build
s.mu.Unlock()
problemsMutex *sync.Mutex
problemFiles map[string]struct{}

activeFile string
activeFileMutex *sync.Mutex
}

func (s *Server) indexAndNotifyProblems(notify glsp.NotifyFunc) error {
build, analyzerErr, err := s.indexer.FullIndex(context.Background(), s.workspacePath)
if err != nil {
return fmt.Errorf("%w: index", err)
}
s.saveIndex(build)
build, err := s.indexer.FullIndex(context.Background(), s.workspacePath)

if analyzerErr == nil {
notify(
protocol.ServerTextDocumentPublishDiagnostics,
protocol.PublishDiagnosticsParams{}, // clear problems
)
s.indexMutex.Lock()
s.index = &build
s.indexMutex.Unlock()

if err == nil {
// clear problems
s.problemsMutex.Lock()
for uri := range s.problemFiles {
notify(
protocol.ServerTextDocumentPublishDiagnostics,
protocol.PublishDiagnosticsParams{
URI: uri,
Diagnostics: []protocol.Diagnostic{},
},
)
}
s.problemFiles = make(map[string]struct{})
s.logger.Info("full index without problems, sent empty diagnostics")
s.problemsMutex.Unlock()
return nil
}

// remember problem and send diagnostic
s.problemsMutex.Lock()
uri := filepath.Join(s.workspacePath, err.Location.String())
s.problemFiles[uri] = struct{}{}
notify(
protocol.ServerTextDocumentPublishDiagnostics,
s.createDiagnostics(*analyzerErr),
s.createDiagnostics(*err, uri),
)

s.logger.Info("diagnostic sent: " + analyzerErr.Error())
s.logger.Info("diagnostic sent:", "err", err)
s.problemsMutex.Unlock()

return nil
}

func (s *Server) createDiagnostics(analyzerErr compiler.Error) protocol.PublishDiagnosticsParams {
source := "neva"
severity := protocol.DiagnosticSeverityError

var uri string
if analyzerErr.Location != nil {
uri = fmt.Sprintf(
"%s/%s/%s",
s.workspacePath,
analyzerErr.Location.PkgName,
analyzerErr.Location.FileName+".neva",
)
}
func (s *Server) createDiagnostics(compilerErr compiler.Error, uri string) protocol.PublishDiagnosticsParams {
var startStopRange protocol.Range
if compilerErr.Meta != nil {
// If stop is 0 0, set it to the same as start but with character incremented by 1
if compilerErr.Meta.Stop.Line == 0 && compilerErr.Meta.Stop.Column == 0 {
compilerErr.Meta.Stop = compilerErr.Meta.Start
compilerErr.Meta.Stop.Column++
}

var protocolRange protocol.Range
if analyzerErr.Meta != nil {
protocolRange = protocol.Range{
startStopRange = protocol.Range{
Start: protocol.Position{
Line: uint32(analyzerErr.Meta.Start.Line),
Character: uint32(analyzerErr.Meta.Start.Column),
Line: uint32(compilerErr.Meta.Start.Line),
Character: uint32(compilerErr.Meta.Start.Column),
},
End: protocol.Position{
Line: uint32(analyzerErr.Meta.Stop.Line),
Character: uint32(analyzerErr.Meta.Stop.Column),
Line: uint32(compilerErr.Meta.Stop.Line),
Character: uint32(compilerErr.Meta.Stop.Column),
},
}

// Adjust for 0-based indexing
startStopRange.Start.Line--
startStopRange.End.Line--
}

source := "neva"
severity := protocol.DiagnosticSeverityError

return protocol.PublishDiagnosticsParams{
URI: uri,
Diagnostics: []protocol.Diagnostic{
{
Range: protocolRange,
Range: startStopRange,
Severity: &severity,
Source: &source,
Message: analyzerErr.Error(),
Message: compilerErr.Error(),
Data: time.Now(),
// Unused:
Tags: []protocol.DiagnosticTag{},
Code: &protocol.IntegerOrString{Value: nil},
CodeDescription: &protocol.CodeDescription{HRef: ""},
RelatedInformation: []protocol.DiagnosticRelatedInformation{},
},
},
}
Expand Down
27 changes: 25 additions & 2 deletions cmd/lsp/server/text_document_synchronization.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,30 @@ import (
protocol "github.com/tliron/glsp/protocol_3_16"
)

func (s *Server) TextDocumentDidChange(glspCtx *glsp.Context, params *protocol.DidChangeTextDocumentParams) error {
s.logger.Info("TextDocumentDidChange")
func (s *Server) TextDocumentDidOpen(
glspCtx *glsp.Context,
params *protocol.DidOpenTextDocumentParams,
) error {
s.activeFileMutex.Lock()
s.activeFile = params.TextDocument.URI
s.activeFileMutex.Unlock()
return nil
}

func (s *Server) TextDocumentDidChange(
glspCtx *glsp.Context,
params *protocol.DidChangeTextDocumentParams,
) error {
s.activeFileMutex.Lock()
s.activeFile = params.TextDocument.URI
s.activeFileMutex.Unlock()
return nil
}

func (s *Server) TextDocumentDidSave(
glspCtx *glsp.Context,
params *protocol.DidSaveTextDocumentParams,
) error {
s.logger.Info("TextDocumentDidSave")
return s.indexAndNotifyProblems(glspCtx.Notify)
}
Loading

0 comments on commit 3c9aab5

Please sign in to comment.