diff --git a/server/internal/lang/parser.go b/server/internal/lang/parser.go index 98561c0..0e02300 100644 --- a/server/internal/lang/parser.go +++ b/server/internal/lang/parser.go @@ -148,17 +148,26 @@ type CaseNode struct { Statement AlwaysStatement } type Parser struct { - skipTokens []string + skipTokens []string + FarthestErrorPosition int + FarthestError *error } func NewParser() *Parser { return &Parser{ - skipTokens: []string{"whitespace", "comment", "newline"}, + skipTokens: []string{"whitespace", "comment", "newline"}, + FarthestErrorPosition: -1, + FarthestError: nil, } } -func newErrorFrom(from string, expected []string, pos int, tokens []Token) error { - return fmt.Errorf("parsing %s, expected %v, got: %v at position %d", from, expected, tokens[pos], pos) +func (p *Parser) newErrorFrom(from string, expected []string, pos int, tokens []Token) error { + err := fmt.Errorf("parsing %s, expected %v, got: %v at position %d", from, expected, tokens[pos], pos) + if pos > p.FarthestErrorPosition { + p.FarthestErrorPosition = pos + p.FarthestError = &err + } + return err } func (p *Parser) skip(tokens []Token, skippables []string, pos int) int { i := pos @@ -183,7 +192,7 @@ func (p *Parser) checkToken(from string, expected []string, pos int, tokens []To pos = p.skip(tokens, p.skipTokens, pos) if pos >= len(tokens) { - return -1, newErrorFrom(from, expected, len(tokens), append(tokens, Token{Type: "EOF"})) + return -1, p.newErrorFrom(from, expected, len(tokens), append(tokens, Token{Type: "EOF"})) } for _, tp := range expected { @@ -191,7 +200,7 @@ func (p *Parser) checkToken(from string, expected []string, pos int, tokens []To return pos, nil } } - return -1, newErrorFrom(from, expected, pos, tokens) + return -1, p.newErrorFrom(from, expected, pos, tokens) } func (p *Parser) isEOF(tokens []Token, pos int) bool { @@ -1775,7 +1784,7 @@ func (p *Parser) ParseFile(tokens []Token) (result FileNode, err error) { // try module module, newPos, e := p.parseModule(tokens, pos) if e != nil { - err = e + err = *p.FarthestError return } result.Statements = append(result.Statements, TopLevelStatement{ diff --git a/server/internal/vlsp/symbols.go b/server/internal/vlsp/symbols.go index ba8c000..4b66514 100644 --- a/server/internal/vlsp/symbols.go +++ b/server/internal/vlsp/symbols.go @@ -43,12 +43,31 @@ func (h Handler) GetSymbolsForFile(fname string, firstTime bool) { h.state.defines[fname] = []lang.DefineNode{} h.state.modules[fname] = []lang.ModuleNode{} - // publish no diagnostics since stuff failed - obj := protocol.PublishDiagnosticsParams{ - URI: protocol.DocumentURI(PathToURI(fname)), - Diagnostics: []protocol.Diagnostic{}, + // publish the error as a diagnostic + if parser.FarthestErrorPosition >= 0 && parser.FarthestErrorPosition < len(tokens) { + tok := tokens[parser.FarthestErrorPosition] + diag := protocol.Diagnostic{ + Range: protocol.Range{ + Start: protocol.Position{Line: uint32(tok.Line()), Character: uint32(tok.StartCharacter())}, + End: protocol.Position{Line: uint32(tok.Line()), Character: uint32(tok.EndCharacter())}, + }, + Severity: protocol.DiagnosticSeverityError, + Message: err.Error(), + } + obj := protocol.PublishDiagnosticsParams{ + URI: protocol.DocumentURI(PathToURI(fname)), + Diagnostics: []protocol.Diagnostic{diag}, + } + h.state.client.PublishDiagnostics(context.Background(), &obj) + } else { + // somehow we got an error out of bounds + // might happen if someone puts an emoji in the file + obj := protocol.PublishDiagnosticsParams{ + URI: protocol.DocumentURI(PathToURI(fname)), + Diagnostics: []protocol.Diagnostic{}, + } + h.state.client.PublishDiagnostics(context.Background(), &obj) } - h.state.client.PublishDiagnostics(context.Background(), &obj) } else { for _, statement := range results.Statements { if statement.Module != nil { diff --git a/server/internal/vlsp/sync.go b/server/internal/vlsp/sync.go index c49f185..a46fc20 100644 --- a/server/internal/vlsp/sync.go +++ b/server/internal/vlsp/sync.go @@ -21,9 +21,7 @@ func (h Handler) DidChange(ctx context.Context, params *protocol.DidChangeTextDo fnode.SetContents(params.ContentChanges[len(params.ContentChanges)-1].Text) // update symbols - h.state.log.Sugar().Info("getting symbols") h.GetSymbolsForFile(file, false) - h.state.log.Sugar().Info("done getting them") } return }