Skip to content

Commit

Permalink
✨ Add auto complete comments with current value, template, and line num
Browse files Browse the repository at this point in the history
  • Loading branch information
gabe565 committed Jul 18, 2022
1 parent 326fb9c commit defcaca
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 44 deletions.
88 changes: 67 additions & 21 deletions internal/visitor/find_args.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package visitor

import (
"fmt"
"github.com/clevyr/go-yampl/internal/config"
"github.com/clevyr/go-yampl/internal/node"
template2 "github.com/clevyr/go-yampl/internal/template"
"github.com/goccy/go-yaml/ast"
"github.com/goccy/go-yaml/token"
"regexp"
"strconv"
"strings"
"text/template"
"text/template/parse"
)
Expand All @@ -14,39 +18,81 @@ var fieldRe = regexp.MustCompile(`\.([A-Za-z_.]+)`)

func NewFindArgs(conf config.Config) FindArgs {
return FindArgs{
conf: conf,
valMap: make(map[string]struct{}),
conf: conf,
matchMap: make(map[string]MatchSlice),
}
}

type Match struct {
Value any
Template string
Position *token.Position
}

func (m Match) String() string {
val := fmt.Sprintf("%v", m.Value)
maxLen := 33
if len(val) > maxLen {
val = val[:maxLen-3] + "..."
}
var result string
if m.Position != nil {
result += "line " + strconv.Itoa(m.Position.Line) + ": "
}
result += fmt.Sprintf("%s %#v", val, m.Template)
result = strings.ReplaceAll(result, "\n", " ")
return result
}

type MatchSlice []Match

func (v MatchSlice) String() string {
var s []string
for _, match := range v {
s = append(s, match.String())
}
return strings.Join(s, "; ")
}

type FindArgs struct {
conf config.Config
valMap map[string]struct{}
err error
conf config.Config
matchMap map[string]MatchSlice
err error
}

func (v *FindArgs) Visit(n ast.Node) ast.Visitor {
if comment := node.GetCommentTmpl(v.conf.Prefix, n); comment != "" {
func (visitor *FindArgs) Visit(n ast.Node) ast.Visitor {
if comment := node.GetCommentTmpl(visitor.conf.Prefix, n); comment != "" {
tmpl, err := template.New("").
Funcs(template2.FuncMap()).
Delims(v.conf.LeftDelim, v.conf.RightDelim).
Delims(visitor.conf.LeftDelim, visitor.conf.RightDelim).
Option("missingkey=zero").
Parse(comment)
if err != nil {
v.err = err
visitor.err = err
return nil
}

for _, field := range listTemplFields(tmpl) {
matches := fieldRe.FindStringSubmatch(field)
if matches != nil {
for _, match := range matches[1:] {
v.valMap[match] = struct{}{}
if tokens := fieldRe.FindStringSubmatch(field); tokens != nil {
for _, tok := range tokens[1:] {
match := Match{
Template: comment,
Position: n.GetToken().Position,
}
switch n := n.(type) {
case *ast.LiteralNode:
match.Value = n.Value.String()
default:
if scalar, ok := n.(ast.ScalarNode); ok {
match.Value = scalar.GetValue()
}
}
visitor.matchMap[tok] = append(visitor.matchMap[tok], match)
}
}
}
}
return v
return visitor
}

func listTemplFields(t *template.Template) []string {
Expand All @@ -66,11 +112,11 @@ func listNodeFields(node parse.Node, res []string) []string {
return res
}

func (v FindArgs) Values() []string {
result := make([]string, 0, len(v.valMap))
func (visitor FindArgs) Values() []string {
result := make([]string, 0, len(visitor.matchMap))
outer:
for k := range v.valMap {
for kconf := range v.conf.Values {
for k, v := range visitor.matchMap {
for kconf := range visitor.conf.Values {
if k == kconf {
continue outer
}
Expand All @@ -80,11 +126,11 @@ outer:
continue outer
}
}
result = append(result, k+"=")
result = append(result, fmt.Sprintf("%s=\t%v", k, v))
}
return result
}

func (v FindArgs) Error() error {
return v.err
func (visitor FindArgs) Error() error {
return visitor.err
}
46 changes: 23 additions & 23 deletions internal/visitor/find_args_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import (

func TestFindArgs_Error(t *testing.T) {
type fields struct {
conf config.Config
valMap map[string]struct{}
err error
conf config.Config
matchMap map[string]MatchSlice
err error
}
tests := []struct {
name string
Expand All @@ -26,9 +26,9 @@ func TestFindArgs_Error(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
v := FindArgs{
conf: tt.fields.conf,
valMap: tt.fields.valMap,
err: tt.fields.err,
conf: tt.fields.conf,
matchMap: tt.fields.matchMap,
err: tt.fields.err,
}
if err := v.Error(); (err != nil) != tt.wantErr {
t.Errorf("Error() error = %v, wantErr %v", err, tt.wantErr)
Expand All @@ -39,26 +39,26 @@ func TestFindArgs_Error(t *testing.T) {

func TestFindArgs_Values(t *testing.T) {
type fields struct {
conf config.Config
valMap map[string]struct{}
err error
conf config.Config
matchMap map[string]MatchSlice
err error
}
tests := []struct {
name string
fields fields
want []string
}{
{"simple", fields{valMap: map[string]struct{}{"a": {}}}, []string{"a="}},
{"nested", fields{valMap: map[string]struct{}{"a.b": {}}}, []string{"a.b="}},
{"duplicate", fields{conf: config.Config{Values: map[string]any{"b": "b"}}, valMap: map[string]struct{}{"b": {}}}, []string{}},
{"reserved", fields{valMap: map[string]struct{}{"Value": {}}}, []string{}},
{name: "simple", fields: fields{matchMap: map[string]MatchSlice{"a": []Match{}}}, want: []string{"a=\t"}},
{"nested", fields{matchMap: map[string]MatchSlice{"a.b": []Match{}}}, []string{"a.b=\t"}},
{"duplicate", fields{conf: config.Config{Values: map[string]any{"b": "b"}}, matchMap: map[string]MatchSlice{"b": []Match{{}}}}, []string{}},
{"reserved", fields{matchMap: map[string]MatchSlice{"Value": []Match{}}}, []string{}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
v := FindArgs{
conf: tt.fields.conf,
valMap: tt.fields.valMap,
err: tt.fields.err,
conf: tt.fields.conf,
matchMap: tt.fields.matchMap,
err: tt.fields.err,
}
if got := v.Values(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Values() = %v, want %v", got, tt.want)
Expand All @@ -75,11 +75,11 @@ func TestFindArgs_Visit(t *testing.T) {
name string
v map[string]struct{}
source string
want map[string]struct{}
wantLen int
wantErr bool
}{
{"simple", make(map[string]struct{}), "a #yampl {{ .a }}", map[string]struct{}{"a": {}}, false},
{"invalid template", make(map[string]struct{}), "a #yampl {{", map[string]struct{}{}, true},
{"simple", make(map[string]struct{}), "a #yampl {{ .a }}", 1, false},
{"invalid template", make(map[string]struct{}), "a #yampl {{", 0, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand All @@ -91,9 +91,9 @@ func TestFindArgs_Visit(t *testing.T) {
return
}

got := v.valMap
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Visitor() = %v, want %v", got, tt.want)
got := v.matchMap
if len(got) != tt.wantLen {
t.Errorf("Visitor() len = %v, want len %v", len(got), tt.wantLen)
}
})
}
Expand All @@ -108,7 +108,7 @@ func TestNewFindArgs(t *testing.T) {
args args
want FindArgs
}{
{"default", args{conf: config.Config{}}, FindArgs{conf: config.Config{}, valMap: make(map[string]struct{})}},
{"default", args{conf: config.Config{}}, FindArgs{conf: config.Config{}, matchMap: make(map[string]MatchSlice)}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down

0 comments on commit defcaca

Please sign in to comment.