Skip to content

Commit

Permalink
feat: tree-sitter powered fragments
Browse files Browse the repository at this point in the history
  • Loading branch information
jdkato committed May 18, 2024
1 parent 4a5ca7f commit a484bbe
Show file tree
Hide file tree
Showing 12 changed files with 113 additions and 62 deletions.
6 changes: 4 additions & 2 deletions internal/lint/code/comments.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ import (
// Comment represents an in-code comment (line or block).
type Comment struct {
Text string
Source string
Line int
Offset int
Scope string
}

func getComments(source []byte, lang *Language) ([]Comment, error) {
// GetComments returns all comments in the given source code.
func GetComments(source []byte, lang *Language) ([]Comment, error) {
var comments []Comment

parser := sitter.NewParser()
Expand All @@ -25,7 +27,7 @@ func getComments(source []byte, lang *Language) ([]Comment, error) {
if err != nil {
return comments, err
}
engine := NewQueryEngine(tree, lang.Delims)
engine := NewQueryEngine(tree, lang)

for _, query := range lang.Queries {
q, qErr := sitter.NewQuery([]byte(query), lang.Parser)
Expand Down
4 changes: 2 additions & 2 deletions internal/lint/code/comments_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ func TestComments(t *testing.T) {
t.Error(err1)
}

lang, err2 := getLanguageFromExt(filepath.Ext(f.Name()))
lang, err2 := GetLanguageFromExt(filepath.Ext(f.Name()))
if err2 != nil {
t.Error(err2)
}

comments, err3 := getComments(b, lang)
comments, err3 := GetComments(b, lang)
if err3 != nil {
t.Error(err3)
}
Expand Down
3 changes: 2 additions & 1 deletion internal/lint/code/go.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import (

func Go() *Language {
return &Language{
Delims: regexp.MustCompile(`//\s?|/\*\s?|\s?\*/`),
Delims: regexp.MustCompile(`// ?|/\* ?| ?\*/`),
Parser: golang.GetLanguage(),
Queries: []string{`(comment)+ @comment`},
Padding: cStyle,
}
}
6 changes: 5 additions & 1 deletion internal/lint/code/lang.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,20 @@ import (
sitter "github.com/smacker/go-tree-sitter"
)

type padding func(string) int

// Language represents a supported programming language.
//
// NOTE: What about haskell, less, perl, php, powershell, r, sass, swift?
type Language struct {
Delims *regexp.Regexp
Parser *sitter.Language
Queries []string
Padding padding
}

func getLanguageFromExt(ext string) (*Language, error) {
// GetLanguageFromExt returns a Language based on the given file extension.
func GetLanguageFromExt(ext string) (*Language, error) {
switch ext {
case ".go":
return Go(), nil
Expand Down
18 changes: 9 additions & 9 deletions internal/lint/code/query.go
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
package code

import (
"regexp"
"strings"

sitter "github.com/smacker/go-tree-sitter"
)

type QueryEngine struct {
tree *sitter.Tree
// NOTE: Should we strip the delimiters using `#strip!`?
delims *regexp.Regexp
lang *Language
}

func NewQueryEngine(tree *sitter.Tree, delims *regexp.Regexp) *QueryEngine {
func NewQueryEngine(tree *sitter.Tree, lang *Language) *QueryEngine {
return &QueryEngine{
tree: tree,
delims: delims,
tree: tree,
lang: lang,
}
}

Expand All @@ -34,18 +32,20 @@ func (qe *QueryEngine) run(q *sitter.Query, source []byte) []Comment {

m = qc.FilterPredicates(m, source)
for _, c := range m.Captures {
text := qe.delims.ReplaceAllString(c.Node.Content(source), "")
rText := c.Node.Content(source)
cText := qe.lang.Delims.ReplaceAllString(rText, "")

scope := "text.comment.line"
if strings.Count(text, "\n") > 1 {
if strings.Count(cText, "\n") > 1 {
scope = "text.comment.block"
}

comments = append(comments, Comment{
Line: int(c.Node.StartPoint().Row) + 1,
Offset: int(c.Node.StartPoint().Column),
Scope: scope,
Text: text,
Text: cText,
Source: rText,
})
}
}
Expand Down
26 changes: 25 additions & 1 deletion internal/lint/code/util.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,32 @@
package code

import "encoding/json"
import (
"encoding/json"
"strings"
)

func toJSON(comments []Comment) string {
j, _ := json.MarshalIndent(comments, "", " ")
return string(j)
}

func cStyle(s string) int {
padding := 0

if strings.HasPrefix(s, "//") || strings.HasPrefix(s, "/*") {
padding = 2
for i, r := range s {
if i < 2 {
continue
}

if r == ' ' {
padding++
} else {
break
}
}
}

return padding
}
38 changes: 30 additions & 8 deletions internal/lint/fragment.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,53 @@ package lint

import (
"fmt"
"strings"

"github.com/errata-ai/vale/v3/internal/core"
"github.com/errata-ai/vale/v3/internal/lint/code"
)

func adjustAlerts(last int, ctx code.Comment, alerts []core.Alert) []core.Alert {
func findLine(s string, line int) string {
lines := strings.Split(s, "\n")
if line > len(lines) {
return ""
}
return lines[line-1]
}

func adjustAlerts(alerts []core.Alert, last int, comment code.Comment, lang *code.Language) []core.Alert {
for i := range alerts {
if i >= last {
alerts[i].Line += ctx.Line - 1
alerts[i].Span = []int{alerts[i].Span[0] + ctx.Offset, alerts[i].Span[1] + ctx.Offset}
line := findLine(comment.Source, alerts[i].Line)
padding := lang.Padding(line)

alerts[i].Line += comment.Line - 1
alerts[i].Span = []int{
alerts[i].Span[0] + comment.Offset + padding,
alerts[i].Span[1] + comment.Offset + padding,
}
}
}
return alerts
}

func (l *Linter) lintFragments(f *core.File) error {
var err error

// We want to set up our processing servers as if we were dealing with
// a directory since we likely have many fragments to convert.
l.HasDir = true

lang, err := code.GetLanguageFromExt(f.RealExt)
if err != nil {
return err
}

comments, err := code.GetComments([]byte(f.Content), lang)
if err != nil {
return err
}

last := 0
// coalesce(getComments(f.Content, f.RealExt))
for _, comment := range []code.Comment{} {
for _, comment := range comments {
f.SetText(comment.Text)

switch f.NormedExt {
Expand All @@ -44,7 +66,7 @@ func (l *Linter) lintFragments(f *core.File) error {

size := len(f.Alerts)
if size != last {
f.Alerts = adjustAlerts(last, comment, f.Alerts)
f.Alerts = adjustAlerts(f.Alerts, last, comment, lang)
}
last = size
}
Expand Down
10 changes: 9 additions & 1 deletion testdata/comments/out/0.json
Original file line number Diff line number Diff line change
@@ -1,48 +1,56 @@
[
{
"Text": "Package lint implments Vale's syntax-aware linting functionality.\n\nThe package is split into core linting logic (this file), source code\n(code.go), and markup (markup.go).",
"Text": "\nPackage lint implments Vale's syntax-aware linting functionality.\n\nThe package is split into core linting logic (this file), source code\n(code.go), and markup (markup.go).\n",
"Source": "/*\nPackage lint implments Vale's syntax-aware linting functionality.\n\nThe package is split into core linting logic (this file), source code\n(code.go), and markup (markup.go).\n*/",
"Line": 1,
"Offset": 0,
"Scope": "text.comment.block"
},
{
"Text": "Println formats using the default formats for its oprands and writes to",
"Source": "// Println formats using the default formats for its oprands and writes to",
"Line": 11,
"Offset": 0,
"Scope": "text.comment.line"
},
{
"Text": "standard output.",
"Source": "// standard output.",
"Line": 12,
"Offset": 0,
"Scope": "text.comment.line"
},
{
"Text": "",
"Source": "//",
"Line": 13,
"Offset": 0,
"Scope": "text.comment.line"
},
{
"Text": "Spaces are always added between operands and a newline is appended.",
"Source": "// Spaces are always added between operands and a newline is appended.",
"Line": 14,
"Offset": 0,
"Scope": "text.comment.line"
},
{
"Text": "",
"Source": "//",
"Line": 15,
"Offset": 0,
"Scope": "text.comment.line"
},
{
"Text": "It returns the number of bytes written and any write error encountered.",
"Source": "// It returns the number of bytes written and any write error encountered.",
"Line": 16,
"Offset": 0,
"Scope": "text.comment.line"
},
{
"Text": "foo bar",
"Source": "// foo bar",
"Line": 21,
"Offset": 14,
"Scope": "text.comment.line"
Expand Down
Loading

0 comments on commit a484bbe

Please sign in to comment.