Skip to content

Commit 31bbd58

Browse files
committed
Generate syntax from Go source analysis
A small utility, gensyntax.go, is introduced to generate a vim syntax by analyzing the Go source files of Ginkgo and related packages.
1 parent 004b741 commit 31bbd58

File tree

3 files changed

+168
-26
lines changed

3 files changed

+168
-26
lines changed

gensyntax.go

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
//go:generate go run gensyntax.go
2+
3+
// Command gensyntax generates a vim syntax for Ginkgo and related packages by
4+
// parsing and searching their exported matchers and assertions.
5+
package main
6+
7+
import (
8+
"flag"
9+
"fmt"
10+
"go/importer"
11+
"go/types"
12+
"html/template"
13+
"log"
14+
"os"
15+
"sort"
16+
"time"
17+
)
18+
19+
const warning = `" This file was generated by gensyntax.go on %s
20+
" DO NOT modify this file by hand!
21+
" Instead, edit ginkgo.vim.tpl and/or run: go generate`
22+
23+
var (
24+
packages = []string{
25+
"github.com/onsi/gomega",
26+
"github.com/onsi/gomega/gbytes",
27+
"github.com/onsi/gomega/gexec",
28+
"github.com/onsi/gomega/ghttp",
29+
"github.com/onsi/gomega/gstruct",
30+
"github.com/sclevine/agouti/matchers",
31+
}
32+
33+
srcImporter = importer.For("source", nil)
34+
)
35+
36+
func init() {
37+
flag.Parse()
38+
}
39+
40+
func main() {
41+
tpl, err := template.ParseFiles("syntax/ginkgo.vim.tpl")
42+
if err != nil {
43+
log.Fatal(err)
44+
}
45+
46+
keywords := &Keywords{
47+
Assertions: make([]string, 0),
48+
Matchers: make([]string, 0),
49+
}
50+
if err := keywords.Search(packages); err != nil {
51+
log.Fatal(err)
52+
}
53+
log.Printf("Found %d assertions and %d matchers",
54+
len(keywords.Assertions), len(keywords.Matchers))
55+
56+
f, err := os.OpenFile("syntax/ginkgo.vim",
57+
os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
58+
if err != nil {
59+
log.Fatal(err)
60+
}
61+
defer f.Close()
62+
63+
_, err = f.Write([]byte(fmt.Sprintf(warning,
64+
time.Now().UTC().Format(time.RFC1123Z))))
65+
if err != nil {
66+
log.Fatal(err)
67+
}
68+
69+
tpl.Execute(f, keywords)
70+
}
71+
72+
type Keywords struct {
73+
Assertions []string
74+
Matchers []string
75+
}
76+
77+
func (k *Keywords) Search(pkgs []string) (first error) {
78+
for _, path := range pkgs {
79+
log.Printf("Searching %s...", path)
80+
pkg, err := srcImporter.Import(path)
81+
if err != nil {
82+
first = err
83+
return
84+
}
85+
86+
for _, fn := range filterExports(pkg) {
87+
sig := fn.Type().(*types.Signature)
88+
res := sig.Results()
89+
if res != nil && res.Len() == 1 {
90+
if named, ok := res.At(0).Type().(*types.Named); ok {
91+
switch named.Obj().Name() {
92+
case "GomegaAssertion", "GomegaAsyncAssertion":
93+
k.Assertions = append(k.Assertions, fn.Name())
94+
case "GomegaMatcher":
95+
k.Matchers = append(k.Matchers, fn.Name())
96+
}
97+
}
98+
}
99+
}
100+
}
101+
sort.Strings(k.Assertions)
102+
sort.Strings(k.Matchers)
103+
return
104+
}
105+
106+
func filterExports(pkg *types.Package) (funcs []*types.Func) {
107+
for _, name := range pkg.Scope().Names() {
108+
obj := pkg.Scope().Lookup(name)
109+
if obj != nil && obj.Exported() {
110+
if fn, ok := obj.(*types.Func); ok {
111+
funcs = append(funcs, fn)
112+
}
113+
}
114+
}
115+
return
116+
}

syntax/ginkgo.vim

+12-26
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
" This file was generated by gensyntax.go on Sun, 03 Dec 2017 01:11:23 +0000
2+
" DO NOT modify this file by hand!
3+
" Instead, edit ginkgo.vim.tpl and/or run: go generate
4+
15
if exists('b:current_syntax')
26
finish
37
endif
@@ -22,32 +26,14 @@ highlight link ginkgoPendingGroups Todo
2226
syntax keyword ginkgoDisabledGroups XContext XDescribe XIt XMeasure XSpecify
2327
highlight link ginkgoDisabledGroups Comment
2428

25-
" Gomega keywords
26-
27-
syntax keyword ginkgoAssertions Expect Ω Consistently Eventually Should ShouldNot To ToNot NotTo
28-
highlight link ginkgoAssertions Constant
29-
30-
syntax keyword ginkgoMatchers BeAssignableToTypeOf BeClosed BeEmpty BeEquivalentTo BeFalse BeNil BeNumerically BeSent BeTemporarily BeTrue BeZero ConsistOf ContainElement ContainSubstring Equal HaveKey HaveKeyWithValue HaveLen HaveOccurred HavePrefix HaveSuffix MatchError MatchJSON MatchRegexp Panic Receive Succeed
31-
highlight link ginkgoMatchers Function
32-
33-
" Agouti keywords
34-
35-
syntax keyword ginkgoAgoutiCallbacks Background
36-
highlight link ginkgoAgoutiCallbacks Identifier
29+
" Gomega assertions
30+
syntax keyword gomegaAssertions Consistently ConsistentlyWithOffset Eventually EventuallyWithOffset Expect ExpectWithOffset Ω
31+
highlight link gomegaAssertions Constant
3732

38-
syntax keyword ginkgoAgoutiGroups Feature Scenario Step
39-
highlight link ginkgoAgoutiGroups Statement
40-
41-
syntax keyword ginkgoAgoutiFocusedGroups FFeature FScenario
42-
highlight link ginkgoAgoutiFocusedGroups Underlined
43-
44-
syntax keyword ginkgoAgoutiPendingGroups PFeature PScenario XFeature XScenario
45-
highlight link ginkgoAgoutiPendingGroups Comment
46-
47-
syntax keyword ginkgoAgoutiShortcuts Back CancelPopup Check ClearCookies Click CloseWindow ConfirmPopup CreatePage CustomPage DeleteCookie Destroy DoubleClick EnterPopupText Fill Forward Navigate NextWindow Refresh RunScript Screenshot Select SetCookie Size StartChromeDriver StartPhantomJS StartSelenium StopWebDriver Submit SwitchToFrame SwitchToRootFrame SwitchToWindow Uncheck
48-
highlight link ginkgoAgoutiShortcuts Function
49-
50-
syntax keyword ginkgoAgoutiMatchers BeActive BeEnabled BeFound BeSelected BeVisible EqualElement HaveAttribute HaveCSS HaveLoggedError HaveLoggedInfo HavePopupText HaveText HaveTitle HaveURL MatchText
51-
highlight link ginkgoAgoutiMatchers Function
33+
" Gomega matchers
34+
syntax keyword gomegaMatchers And BeADirectory BeARegularFile BeActive BeAnExistingFile BeAssignableToTypeOf BeClosed BeEmpty BeEnabled BeEquivalentTo BeFalse BeFound BeIdenticalTo BeNil BeNumerically BeSelected BeSent BeTemporally BeTrue BeVisible BeZero ConsistOf ContainElement ContainSubstring Equal EqualElement HaveAttribute HaveCSS HaveCap HaveCount HaveKey HaveKeyWithValue HaveLen HaveLoggedError HaveLoggedInfo HaveOccurred HavePopupText HavePrefix HaveSuffix HaveText HaveTitle HaveURL HaveWindowCount Ignore MatchAllElements MatchAllFields MatchElements MatchError MatchFields MatchJSON MatchRegexp MatchText MatchXML MatchYAML Not Or Panic PointTo Receive Reject SatisfyAll SatisfyAny Succeed WithTransform
35+
highlight link gomegaMatchers Constant
5236

5337
let b:current_syntax = 'ginkgo'
38+
39+
" vi: set ft=vim :

syntax/ginkgo.vim.tpl

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{{/*
2+
This template is used by gensyntax.go to generate a vim syntax supporting
3+
Ginkgo and related assertion/matcher packages.
4+
*/}}
5+
6+
if exists('b:current_syntax')
7+
finish
8+
endif
9+
10+
runtime! syntax/go.vim
11+
unlet! b:current_syntax
12+
13+
" Ginkgo keywords
14+
15+
syntax keyword ginkgoCallbacks AfterEach AfterSuite BeforeEach BeforeSuite JustBeforeEach SynchronizedAfterSuite SynchronizedBeforeSuite
16+
highlight link ginkgoCallbacks Identifier
17+
18+
syntax keyword ginkgoGroups By Context Describe It Specify
19+
highlight link ginkgoGroups Statement
20+
21+
syntax keyword ginkgoFocusedGroups FContext FDescribe FIt FMeasure FSpecify
22+
highlight link ginkgoFocusedGroups Underlined
23+
24+
syntax keyword ginkgoPendingGroups PContext PDescribe PIt PMeasure PSpecify
25+
highlight link ginkgoPendingGroups Todo
26+
27+
syntax keyword ginkgoDisabledGroups XContext XDescribe XIt XMeasure XSpecify
28+
highlight link ginkgoDisabledGroups Comment
29+
30+
" Gomega assertions
31+
syntax keyword gomegaAssertions {{range $i, $word := .Assertions}}{{if $i}} {{end}}{{$word}}{{end}}
32+
highlight link gomegaAssertions Constant
33+
34+
" Gomega matchers
35+
syntax keyword gomegaMatchers {{range $i, $word := .Matchers}}{{if $i}} {{end}}{{$word}}{{end}}
36+
highlight link gomegaMatchers Constant
37+
38+
let b:current_syntax = 'ginkgo'
39+
40+
" vi: set ft=vim :

0 commit comments

Comments
 (0)