From 2ef462a75f9e49b58a7dd64713743ec43d9d47bd Mon Sep 17 00:00:00 2001 From: Paul Jolly Date: Wed, 16 Nov 2016 16:54:43 +0000 Subject: [PATCH 1/4] Use import name if set else package name when qualifying types --- suggest/candidate.go | 22 +++++++++++++++++++++ suggest/suggest.go | 9 +++++---- suggest/testdata/test.0065/out.expected | 26 +++++++++++++++++++++++++ suggest/testdata/test.0065/test.go.in | 8 ++++++++ 4 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 suggest/testdata/test.0065/out.expected create mode 100644 suggest/testdata/test.0065/test.go.in diff --git a/suggest/candidate.go b/suggest/candidate.go index 48328c42..d884e79e 100644 --- a/suggest/candidate.go +++ b/suggest/candidate.go @@ -2,6 +2,7 @@ package suggest import ( "fmt" + "go/ast" "go/types" "sort" "strings" @@ -78,6 +79,7 @@ type candidateCollector struct { candidates []Candidate exact []types.Object badcase []types.Object + imports []*ast.ImportSpec localpkg *types.Package partial string filter objectFilter @@ -157,6 +159,26 @@ func (b *candidateCollector) qualify(pkg *types.Package) string { if pkg == b.localpkg { return "" } + + // the *types.Package we are asked to qualify might _not_ be imported + // by the file in which we are asking for candidates. Hence... we retain + // the default of pkg.Name() as the qualifier + + for _, i := range b.imports { + // given the import spec has been correctly parsed (by virtue of + // its existence) we can safely byte-index the path value knowing + // that len("\"") == 1 + iPath := i.Path.Value[1 : len(i.Path.Value)-1] + + if iPath == pkg.Path() { + if i.Name != nil && i.Name.Name != "." { + return i.Name.Name + } else { + return pkg.Name() + } + } + } + return pkg.Name() } diff --git a/suggest/suggest.go b/suggest/suggest.go index 7d9ddf73..4bf8e586 100644 --- a/suggest/suggest.go +++ b/suggest/suggest.go @@ -26,7 +26,7 @@ func (c *Config) Suggest(filename string, data []byte, cursor int) ([]Candidate, return nil, 0 } - fset, pos, pkg := c.analyzePackage(filename, data, cursor) + fset, pos, pkg, imports := c.analyzePackage(filename, data, cursor) if pkg == nil { return nil, 0 } @@ -35,6 +35,7 @@ func (c *Config) Suggest(filename string, data []byte, cursor int) ([]Candidate, ctx, expr, partial := deduceCursorContext(data, cursor) b := candidateCollector{ localpkg: pkg, + imports: imports, partial: partial, filter: objectFilters[partial], } @@ -75,7 +76,7 @@ func (c *Config) Suggest(filename string, data []byte, cursor int) ([]Candidate, return res, len(partial) } -func (c *Config) analyzePackage(filename string, data []byte, cursor int) (*token.FileSet, token.Pos, *types.Package) { +func (c *Config) analyzePackage(filename string, data []byte, cursor int) (*token.FileSet, token.Pos, *types.Package, []*ast.ImportSpec) { // If we're in trailing white space at the end of a scope, // sometimes go/types doesn't recognize that variables should // still be in scope there. @@ -88,7 +89,7 @@ func (c *Config) analyzePackage(filename string, data []byte, cursor int) (*toke } astPos := fileAST.Pos() if astPos == 0 { - return nil, token.NoPos, nil + return nil, token.NoPos, nil, nil } pos := fset.File(astPos).Pos(cursor) @@ -118,7 +119,7 @@ func (c *Config) analyzePackage(filename string, data []byte, cursor int) (*toke } pkg, _ := cfg.Check("", fset, files, nil) - return fset, pos, pkg + return fset, pos, pkg, fileAST.Imports } func (c *Config) fieldNameCandidates(typ types.Type, b *candidateCollector) { diff --git a/suggest/testdata/test.0065/out.expected b/suggest/testdata/test.0065/out.expected new file mode 100644 index 00000000..040ba3c3 --- /dev/null +++ b/suggest/testdata/test.0065/out.expected @@ -0,0 +1,26 @@ +Found 25 candidates: + func Errorf(format string, a ...interface{}) error + func Fprint(w banana.Writer, a ...interface{}) (n int, err error) + func Fprintf(w banana.Writer, format string, a ...interface{}) (n int, err error) + func Fprintln(w banana.Writer, a ...interface{}) (n int, err error) + func Fscan(r banana.Reader, a ...interface{}) (n int, err error) + func Fscanf(r banana.Reader, format string, a ...interface{}) (n int, err error) + func Fscanln(r banana.Reader, a ...interface{}) (n int, err error) + func Print(a ...interface{}) (n int, err error) + func Printf(format string, a ...interface{}) (n int, err error) + func Println(a ...interface{}) (n int, err error) + func Scan(a ...interface{}) (n int, err error) + func Scanf(format string, a ...interface{}) (n int, err error) + func Scanln(a ...interface{}) (n int, err error) + func Sprint(a ...interface{}) string + func Sprintf(format string, a ...interface{}) string + func Sprintln(a ...interface{}) string + func Sscan(str string, a ...interface{}) (n int, err error) + func Sscanf(str string, format string, a ...interface{}) (n int, err error) + func Sscanln(str string, a ...interface{}) (n int, err error) + type Formatter interface + type GoStringer interface + type ScanState interface + type Scanner interface + type State interface + type Stringer interface diff --git a/suggest/testdata/test.0065/test.go.in b/suggest/testdata/test.0065/test.go.in new file mode 100644 index 00000000..2120ae51 --- /dev/null +++ b/suggest/testdata/test.0065/test.go.in @@ -0,0 +1,8 @@ +package p + +import ( + "fmt" + banana "io" +) + +var _ = fmt.@ From 4f8a253d3a56ec2ad2fb00ca3e7f2e5ce3e0b2b2 Mon Sep 17 00:00:00 2001 From: DisposaBoy Date: Tue, 31 Jul 2018 13:46:15 +0100 Subject: [PATCH 2/4] add support for case-insensitive completion --- client.go | 1 + gocode.go | 17 +++++++++-------- internal/suggest/candidate.go | 4 ++-- internal/suggest/suggest.go | 16 +++++++++------- .../suggest/testdata/test.0066/config.json | 1 + .../suggest/testdata/test.0066/out.expected | 2 ++ internal/suggest/testdata/test.0066/test.go.in | 8 ++++++++ .../suggest/testdata/test.0067/config.json | 1 + .../suggest/testdata/test.0067/out.expected | 2 ++ internal/suggest/testdata/test.0067/test.go.in | 8 ++++++++ .../suggest/testdata/test.0068/config.json | 1 + .../suggest/testdata/test.0068/out.expected | 3 +++ internal/suggest/testdata/test.0068/test.go.in | 8 ++++++++ server.go | 18 ++++++++++-------- 14 files changed, 65 insertions(+), 25 deletions(-) create mode 100644 internal/suggest/testdata/test.0066/config.json create mode 100644 internal/suggest/testdata/test.0066/out.expected create mode 100644 internal/suggest/testdata/test.0066/test.go.in create mode 100644 internal/suggest/testdata/test.0067/config.json create mode 100644 internal/suggest/testdata/test.0067/out.expected create mode 100644 internal/suggest/testdata/test.0067/test.go.in create mode 100644 internal/suggest/testdata/test.0068/config.json create mode 100644 internal/suggest/testdata/test.0068/out.expected create mode 100644 internal/suggest/testdata/test.0068/test.go.in diff --git a/client.go b/client.go index 8d59eb66..a3ee74e2 100644 --- a/client.go +++ b/client.go @@ -129,6 +129,7 @@ func cmdAutoComplete(c *rpc.Client) { req.Context = gbimporter.PackContext(&build.Default) req.Source = *g_source req.Builtin = *g_builtin + req.IgnoreCase = *g_ignore_case var res AutoCompleteReply var err error diff --git a/gocode.go b/gocode.go index 7e2a4725..6e914186 100644 --- a/gocode.go +++ b/gocode.go @@ -8,14 +8,15 @@ import ( ) var ( - g_is_server = flag.Bool("s", false, "run a server instead of a client") - g_format = flag.String("f", "nice", "output format (vim | emacs | nice | csv | json)") - g_input = flag.String("in", "", "use this file instead of stdin input") - g_sock = flag.String("sock", defaultSocketType, "socket type (unix | tcp | none)") - g_addr = flag.String("addr", "127.0.0.1:37373", "address for tcp socket") - g_debug = flag.Bool("debug", false, "enable server-side debug mode") - g_source = flag.Bool("source", false, "use source importer") - g_builtin = flag.Bool("builtin", false, "propose builtin objects") + g_is_server = flag.Bool("s", false, "run a server instead of a client") + g_format = flag.String("f", "nice", "output format (vim | emacs | nice | csv | json)") + g_input = flag.String("in", "", "use this file instead of stdin input") + g_sock = flag.String("sock", defaultSocketType, "socket type (unix | tcp | none)") + g_addr = flag.String("addr", "127.0.0.1:37373", "address for tcp socket") + g_debug = flag.Bool("debug", false, "enable server-side debug mode") + g_source = flag.Bool("source", false, "use source importer") + g_builtin = flag.Bool("builtin", false, "propose builtin objects") + g_ignore_case = flag.Bool("ignore-case", false, "do case-insensitive matching") ) func getSocketPath() string { diff --git a/internal/suggest/candidate.go b/internal/suggest/candidate.go index d83bda90..d9a71c13 100644 --- a/internal/suggest/candidate.go +++ b/internal/suggest/candidate.go @@ -81,6 +81,7 @@ type candidateCollector struct { partial string filter objectFilter builtin bool + ignoreCase bool } func (b *candidateCollector) getCandidates() []Candidate { @@ -180,8 +181,7 @@ func (b *candidateCollector) appendObject(obj types.Object) { if b.filter != nil && !b.filter(obj) { return } - - if b.filter != nil || strings.HasPrefix(obj.Name(), b.partial) { + if !b.ignoreCase && (b.filter != nil || strings.HasPrefix(obj.Name(), b.partial)) { b.exact = append(b.exact, obj) } else if strings.HasPrefix(strings.ToLower(obj.Name()), strings.ToLower(b.partial)) { b.badcase = append(b.badcase, obj) diff --git a/internal/suggest/suggest.go b/internal/suggest/suggest.go index e9c02208..224f0f8f 100644 --- a/internal/suggest/suggest.go +++ b/internal/suggest/suggest.go @@ -15,9 +15,10 @@ import ( ) type Config struct { - Importer types.Importer - Logf func(fmt string, args ...interface{}) - Builtin bool + Importer types.Importer + Logf func(fmt string, args ...interface{}) + Builtin bool + IgnoreCase bool } // Suggest returns a list of suggestion candidates and the length of @@ -35,10 +36,11 @@ func (c *Config) Suggest(filename string, data []byte, cursor int) ([]Candidate, ctx, expr, partial := deduceCursorContext(data, cursor) b := candidateCollector{ - localpkg: pkg, - partial: partial, - filter: objectFilters[partial], - builtin: ctx != selectContext && c.Builtin, + localpkg: pkg, + partial: partial, + filter: objectFilters[partial], + builtin: ctx != selectContext && c.Builtin, + ignoreCase: c.IgnoreCase, } switch ctx { diff --git a/internal/suggest/testdata/test.0066/config.json b/internal/suggest/testdata/test.0066/config.json new file mode 100644 index 00000000..e30fee59 --- /dev/null +++ b/internal/suggest/testdata/test.0066/config.json @@ -0,0 +1 @@ +{"IgnoreCase": false} diff --git a/internal/suggest/testdata/test.0066/out.expected b/internal/suggest/testdata/test.0066/out.expected new file mode 100644 index 00000000..4dbcfa95 --- /dev/null +++ b/internal/suggest/testdata/test.0066/out.expected @@ -0,0 +1,2 @@ +Found 1 candidates: + func FuncX() diff --git a/internal/suggest/testdata/test.0066/test.go.in b/internal/suggest/testdata/test.0066/test.go.in new file mode 100644 index 00000000..d4f2f733 --- /dev/null +++ b/internal/suggest/testdata/test.0066/test.go.in @@ -0,0 +1,8 @@ +package p + +func FuncX() {} +func funcY() {} + +func f() { + Fun@ +} diff --git a/internal/suggest/testdata/test.0067/config.json b/internal/suggest/testdata/test.0067/config.json new file mode 100644 index 00000000..e30fee59 --- /dev/null +++ b/internal/suggest/testdata/test.0067/config.json @@ -0,0 +1 @@ +{"IgnoreCase": false} diff --git a/internal/suggest/testdata/test.0067/out.expected b/internal/suggest/testdata/test.0067/out.expected new file mode 100644 index 00000000..eb986f88 --- /dev/null +++ b/internal/suggest/testdata/test.0067/out.expected @@ -0,0 +1,2 @@ +Found 1 candidates: + func funcY() diff --git a/internal/suggest/testdata/test.0067/test.go.in b/internal/suggest/testdata/test.0067/test.go.in new file mode 100644 index 00000000..0efabfee --- /dev/null +++ b/internal/suggest/testdata/test.0067/test.go.in @@ -0,0 +1,8 @@ +package p + +func FuncX() {} +func funcY() {} + +func f() { + fun@ +} diff --git a/internal/suggest/testdata/test.0068/config.json b/internal/suggest/testdata/test.0068/config.json new file mode 100644 index 00000000..30d49ee2 --- /dev/null +++ b/internal/suggest/testdata/test.0068/config.json @@ -0,0 +1 @@ +{"IgnoreCase": true} diff --git a/internal/suggest/testdata/test.0068/out.expected b/internal/suggest/testdata/test.0068/out.expected new file mode 100644 index 00000000..1b60778a --- /dev/null +++ b/internal/suggest/testdata/test.0068/out.expected @@ -0,0 +1,3 @@ +Found 2 candidates: + func FuncX() + func funcY() diff --git a/internal/suggest/testdata/test.0068/test.go.in b/internal/suggest/testdata/test.0068/test.go.in new file mode 100644 index 00000000..0efabfee --- /dev/null +++ b/internal/suggest/testdata/test.0068/test.go.in @@ -0,0 +1,8 @@ +package p + +func FuncX() {} +func funcY() {} + +func f() { + fun@ +} diff --git a/server.go b/server.go index 6b759593..1fd3dc78 100644 --- a/server.go +++ b/server.go @@ -52,12 +52,13 @@ type Server struct { } type AutoCompleteRequest struct { - Filename string - Data []byte - Cursor int - Context gbimporter.PackedContext - Source bool - Builtin bool + Filename string + Data []byte + Cursor int + Context gbimporter.PackedContext + Source bool + Builtin bool + IgnoreCase bool } type AutoCompleteReply struct { @@ -95,8 +96,9 @@ func (s *Server) AutoComplete(req *AutoCompleteRequest, res *AutoCompleteReply) underlying = importer.Default().(types.ImporterFrom) } cfg := suggest.Config{ - Importer: gbimporter.New(&req.Context, req.Filename, underlying), - Builtin: req.Builtin, + Importer: gbimporter.New(&req.Context, req.Filename, underlying), + Builtin: req.Builtin, + IgnoreCase: req.IgnoreCase, } if *g_debug { cfg.Logf = log.Printf From 212101e697adddb6b6e39ff7d88887108277bad2 Mon Sep 17 00:00:00 2001 From: Rebecca Stambler Date: Thu, 11 Oct 2018 19:21:13 -0400 Subject: [PATCH 3/4] fix broken test for Go 1.11, skip for lower versions --- .travis.yml | 1 + internal/suggest/suggest_test.go | 14 ++++++++++++++ internal/suggest/testdata/test.0011/out.expected | 3 ++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 011789e1..87f786e1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,4 +3,5 @@ language: go go: - 1.9.x - 1.10.x + - 1.11.x - master diff --git a/internal/suggest/suggest_test.go b/internal/suggest/suggest_test.go index cfcbbe9c..13d8dff7 100644 --- a/internal/suggest/suggest_test.go +++ b/internal/suggest/suggest_test.go @@ -3,6 +3,7 @@ package suggest_test import ( "bytes" "encoding/json" + "go/build" "go/importer" "io/ioutil" "os" @@ -20,6 +21,10 @@ func TestRegress(t *testing.T) { } for _, testDir := range testDirs { + // Skip test test.0011 for Go < 1.11 because a method was added to reflect.Value. + if !contains(build.Default.ReleaseTags, "go1.11") && strings.HasSuffix(testDir, "test.0011") { + continue + } testDir := testDir // capture name := strings.TrimPrefix(testDir, "testdata/") t.Run(name, func(t *testing.T) { @@ -76,3 +81,12 @@ func testRegress(t *testing.T, testDir string) { return } } + +func contains(haystack []string, needle string) bool { + for _, x := range haystack { + if needle == x { + return true + } + } + return false +} \ No newline at end of file diff --git a/internal/suggest/testdata/test.0011/out.expected b/internal/suggest/testdata/test.0011/out.expected index 7de665e1..c02ffaf0 100644 --- a/internal/suggest/testdata/test.0011/out.expected +++ b/internal/suggest/testdata/test.0011/out.expected @@ -1,4 +1,4 @@ -Found 59 candidates: +Found 60 candidates: func Addr() reflect.Value func Bool() bool func Bytes() []byte @@ -27,6 +27,7 @@ Found 59 candidates: func Len() int func MapIndex(key reflect.Value) reflect.Value func MapKeys() []reflect.Value + func MapRange() *reflect.MapIter func Method(i int) reflect.Value func MethodByName(name string) reflect.Value func NumField() int From 32181df22c3e74ff09d4e12f1276ab3beea37659 Mon Sep 17 00:00:00 2001 From: Rebecca Stambler Date: Thu, 11 Oct 2018 19:55:26 -0400 Subject: [PATCH 4/4] fix test for Go 1.11 --- internal/suggest/suggest_test.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/internal/suggest/suggest_test.go b/internal/suggest/suggest_test.go index 13d8dff7..b59faead 100644 --- a/internal/suggest/suggest_test.go +++ b/internal/suggest/suggest_test.go @@ -3,11 +3,11 @@ package suggest_test import ( "bytes" "encoding/json" - "go/build" "go/importer" "io/ioutil" "os" "path/filepath" + "runtime" "strings" "testing" @@ -21,9 +21,10 @@ func TestRegress(t *testing.T) { } for _, testDir := range testDirs { - // Skip test test.0011 for Go < 1.11 because a method was added to reflect.Value. - if !contains(build.Default.ReleaseTags, "go1.11") && strings.HasSuffix(testDir, "test.0011") { - continue + // Skip test.0011 for Go <= 1.11 because a method was added to reflect.Value. + // TODO(rstambler): Change this when Go 1.12 comes out. + if !strings.HasPrefix(runtime.Version(), "devel") && strings.HasSuffix(testDir, "test.0011") { + continue } testDir := testDir // capture name := strings.TrimPrefix(testDir, "testdata/")