➕ Update gocode in vendor
This commit is contained in:
parent
bfd836c6fc
commit
0a51a03f35
|
@ -1,20 +1,13 @@
|
||||||
FROM golang:latest
|
FROM golang:latest
|
||||||
MAINTAINER Liang Ding <d@b3log.org>
|
MAINTAINER Liang Ding <d@b3log.org>
|
||||||
|
|
||||||
ENV GOROOT /usr/local/go
|
ADD . /go/src/github.com/b3log/wide
|
||||||
|
ADD vendor/ /go/src/
|
||||||
RUN apt-get update && apt-get install bzip2 zip unzip && cp -r /usr/local/go /usr/local/gobt
|
|
||||||
ENV GOROOT_BOOTSTRAP=/usr/local/gobt
|
|
||||||
|
|
||||||
ADD . /wide/gogogo/src/github.com/b3log/wide
|
|
||||||
ADD vendor/* /go/src/
|
|
||||||
RUN go install github.com/visualfc/gotools github.com/nsf/gocode github.com/bradfitz/goimports
|
RUN go install github.com/visualfc/gotools github.com/nsf/gocode github.com/bradfitz/goimports
|
||||||
|
|
||||||
RUN useradd wide && useradd runner
|
RUN useradd wide && useradd runner
|
||||||
|
|
||||||
ENV GOPATH /wide/gogogo
|
WORKDIR /go/src/github.com/b3log/wide
|
||||||
|
|
||||||
WORKDIR /wide/gogogo/src/github.com/b3log/wide
|
|
||||||
RUN go build -v
|
RUN go build -v
|
||||||
|
|
||||||
EXPOSE 7070
|
EXPOSE 7070
|
||||||
|
|
|
@ -8,7 +8,7 @@ set -e
|
||||||
echo "mode: count" > profile.cov
|
echo "mode: count" > profile.cov
|
||||||
|
|
||||||
# Standard go tooling behavior is to ignore dirs with leading underscors
|
# Standard go tooling behavior is to ignore dirs with leading underscors
|
||||||
for dir in $(find . -maxdepth 10 -not -path './.git*' -not -path '*/_*' -type d);
|
for dir in $(find . -maxdepth 10 -not -path './.git*' -not -path '*/_*' -not -path './vendor*' -type d);
|
||||||
do
|
do
|
||||||
if ls $dir/*.go &> /dev/null; then
|
if ls $dir/*.go &> /dev/null; then
|
||||||
go test -covermode=count -coverprofile=$dir/profile.tmp $dir
|
go test -covermode=count -coverprofile=$dir/profile.tmp $dir
|
||||||
|
|
|
@ -151,7 +151,7 @@ You can change all available options using `gocode set` command. The config file
|
||||||
|
|
||||||
- *propose-builtins*
|
- *propose-builtins*
|
||||||
|
|
||||||
A boolean option. If **true**, gocode will add built-in types, functions and constants to an autocompletion proposals. Default: **false**.
|
A boolean option. If **true**, gocode will add built-in types, functions and constants to autocompletion proposals. Default: **false**.
|
||||||
|
|
||||||
- *lib-path*
|
- *lib-path*
|
||||||
|
|
||||||
|
@ -173,6 +173,22 @@ You can change all available options using `gocode set` command. The config file
|
||||||
|
|
||||||
An integer option. If there have been no completion requests after this number of seconds, the gocode process will terminate. Defaults to 1800 (30 minutes).
|
An integer option. If there have been no completion requests after this number of seconds, the gocode process will terminate. Defaults to 1800 (30 minutes).
|
||||||
|
|
||||||
|
- *unimported-packages*
|
||||||
|
|
||||||
|
A boolean option. If set to true, gocode will try to import certain known packages automatically for identifiers which cannot be resolved otherwise. Currently only a limited set of standard library packages are supported. Default: **false**.
|
||||||
|
|
||||||
|
- *partials*
|
||||||
|
|
||||||
|
A boolean option. If set to false, gocode will not filter autocompletion results based on entered prefix before the cursor. Instead it will return all available autocompletion results viable for a given context. Whether this option is set to true or false, gocode will return a valid prefix length for output formats which support it. Setting this option to a non-default value may result in editor misbehaviour. Default: **true**.
|
||||||
|
|
||||||
|
- *ignore-case*
|
||||||
|
|
||||||
|
A boolean option. If set to true, gocode will perform case-insensitive matching when doing prefix-based filtering. Default: **false**.
|
||||||
|
|
||||||
|
- *class-filtering*
|
||||||
|
|
||||||
|
A boolean option. Enables or disables gocode's feature where it performs class-based filtering if partial input matches corresponding class keyword: const, var, type, func, package. Default: **true**.
|
||||||
|
|
||||||
### Debugging
|
### Debugging
|
||||||
|
|
||||||
If something went wrong, the first thing you may want to do is manually start the gocode daemon with a debug mode enabled and in a separate terminal window. It will show you all the stack traces, panics if any and additional info about autocompletion requests. Shutdown the daemon if it was already started and run a new one explicitly with a debug mode enabled:
|
If something went wrong, the first thing you may want to do is manually start the gocode daemon with a debug mode enabled and in a separate terminal window. It will show you all the stack traces, panics if any and additional info about autocompletion requests. Shutdown the daemon if it was already started and run a new one explicitly with a debug mode enabled:
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/parser"
|
"go/parser"
|
||||||
"go/token"
|
"go/token"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -22,17 +23,19 @@ import (
|
||||||
|
|
||||||
// fields must be exported for RPC
|
// fields must be exported for RPC
|
||||||
type candidate struct {
|
type candidate struct {
|
||||||
Name string
|
Name string
|
||||||
Type string
|
Type string
|
||||||
Class decl_class
|
Class decl_class
|
||||||
|
Package string
|
||||||
}
|
}
|
||||||
|
|
||||||
type out_buffers struct {
|
type out_buffers struct {
|
||||||
tmpbuf *bytes.Buffer
|
tmpbuf *bytes.Buffer
|
||||||
candidates []candidate
|
candidates []candidate
|
||||||
ctx *auto_complete_context
|
canonical_aliases map[string]string
|
||||||
tmpns map[string]bool
|
ctx *auto_complete_context
|
||||||
ignorecase bool
|
tmpns map[string]bool
|
||||||
|
ignorecase bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func new_out_buffers(ctx *auto_complete_context) *out_buffers {
|
func new_out_buffers(ctx *auto_complete_context) *out_buffers {
|
||||||
|
@ -40,6 +43,10 @@ func new_out_buffers(ctx *auto_complete_context) *out_buffers {
|
||||||
b.tmpbuf = bytes.NewBuffer(make([]byte, 0, 1024))
|
b.tmpbuf = bytes.NewBuffer(make([]byte, 0, 1024))
|
||||||
b.candidates = make([]candidate, 0, 64)
|
b.candidates = make([]candidate, 0, 64)
|
||||||
b.ctx = ctx
|
b.ctx = ctx
|
||||||
|
b.canonical_aliases = make(map[string]string)
|
||||||
|
for _, imp := range b.ctx.current.packages {
|
||||||
|
b.canonical_aliases[imp.abspath] = imp.alias
|
||||||
|
}
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +67,7 @@ func (b *out_buffers) Swap(i, j int) {
|
||||||
b.candidates[i], b.candidates[j] = b.candidates[j], b.candidates[i]
|
b.candidates[i], b.candidates[j] = b.candidates[j], b.candidates[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *out_buffers) append_decl(p, name string, decl *decl, class decl_class) {
|
func (b *out_buffers) append_decl(p, name, pkg string, decl *decl, class decl_class) {
|
||||||
c1 := !g_config.ProposeBuiltins && decl.scope == g_universe_scope && decl.name != "Error"
|
c1 := !g_config.ProposeBuiltins && decl.scope == g_universe_scope && decl.name != "Error"
|
||||||
c2 := class != decl_invalid && decl.class != class
|
c2 := class != decl_invalid && decl.class != class
|
||||||
c3 := class == decl_invalid && !has_prefix(name, p, b.ignorecase)
|
c3 := class == decl_invalid && !has_prefix(name, p, b.ignorecase)
|
||||||
|
@ -71,16 +78,17 @@ func (b *out_buffers) append_decl(p, name string, decl *decl, class decl_class)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
decl.pretty_print_type(b.tmpbuf)
|
decl.pretty_print_type(b.tmpbuf, b.canonical_aliases)
|
||||||
b.candidates = append(b.candidates, candidate{
|
b.candidates = append(b.candidates, candidate{
|
||||||
Name: name,
|
Name: name,
|
||||||
Type: b.tmpbuf.String(),
|
Type: b.tmpbuf.String(),
|
||||||
Class: decl.class,
|
Class: decl.class,
|
||||||
|
Package: pkg,
|
||||||
})
|
})
|
||||||
b.tmpbuf.Reset()
|
b.tmpbuf.Reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *out_buffers) append_embedded(p string, decl *decl, class decl_class) {
|
func (b *out_buffers) append_embedded(p string, decl *decl, pkg string, class decl_class) {
|
||||||
if decl.embedded == nil {
|
if decl.embedded == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -103,21 +111,26 @@ func (b *out_buffers) append_embedded(p string, decl *decl, class decl_class) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// could be type alias
|
||||||
|
if typedecl.is_alias() {
|
||||||
|
typedecl = typedecl.type_dealias()
|
||||||
|
}
|
||||||
|
|
||||||
// prevent infinite recursion here
|
// prevent infinite recursion here
|
||||||
if typedecl.flags&decl_visited != 0 {
|
if typedecl.is_visited() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
typedecl.flags |= decl_visited
|
typedecl.set_visited()
|
||||||
defer typedecl.clear_visited()
|
defer typedecl.clear_visited()
|
||||||
|
|
||||||
for _, c := range typedecl.children {
|
for _, c := range typedecl.children {
|
||||||
if _, has := b.tmpns[c.name]; has {
|
if _, has := b.tmpns[c.name]; has {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
b.append_decl(p, c.name, c, class)
|
b.append_decl(p, c.name, pkg, c, class)
|
||||||
b.tmpns[c.name] = true
|
b.tmpns[c.name] = true
|
||||||
}
|
}
|
||||||
b.append_embedded(p, typedecl, class)
|
b.append_embedded(p, typedecl, pkg, class)
|
||||||
}
|
}
|
||||||
|
|
||||||
if first_level {
|
if first_level {
|
||||||
|
@ -183,6 +196,12 @@ func (c *auto_complete_context) merge_decls() {
|
||||||
merge_decls(f.filescope, c.pkg, f.decls)
|
merge_decls(f.filescope, c.pkg, f.decls)
|
||||||
merge_decls_from_packages(c.pkg, f.packages, c.pcache)
|
merge_decls_from_packages(c.pkg, f.packages, c.pcache)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// special pass for type aliases which also have methods, while this is
|
||||||
|
// valid code, it shouldn't happen a lot in practice, so, whatever
|
||||||
|
// let's move all type alias methods to their first non-alias type down in
|
||||||
|
// the chain
|
||||||
|
propagate_type_alias_methods(c.pkg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *auto_complete_context) make_decl_set(scope *scope) map[string]*decl {
|
func (c *auto_complete_context) make_decl_set(scope *scope) map[string]*decl {
|
||||||
|
@ -197,11 +216,47 @@ func (c *auto_complete_context) get_candidates_from_set(set map[string]*decl, pa
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
value.infer_type()
|
value.infer_type()
|
||||||
b.append_decl(partial, key, value, class)
|
pkgname := ""
|
||||||
|
if pkg, ok := c.pcache[value.name]; ok {
|
||||||
|
pkgname = pkg.import_name
|
||||||
|
}
|
||||||
|
b.append_decl(partial, key, pkgname, value, class)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *auto_complete_context) get_candidates_from_decl_alias(cc cursor_context, class decl_class, b *out_buffers) {
|
||||||
|
if cc.decl.is_visited() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cc.decl = cc.decl.type_dealias()
|
||||||
|
if cc.decl == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cc.decl.set_visited()
|
||||||
|
defer cc.decl.clear_visited()
|
||||||
|
|
||||||
|
c.get_candidates_from_decl(cc, class, b)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *auto_complete_context) decl_package_import_path(decl *decl) string {
|
||||||
|
if decl == nil || decl.scope == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if pkg, ok := c.pcache[decl.scope.pkgname]; ok {
|
||||||
|
return pkg.import_name
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func (c *auto_complete_context) get_candidates_from_decl(cc cursor_context, class decl_class, b *out_buffers) {
|
func (c *auto_complete_context) get_candidates_from_decl(cc cursor_context, class decl_class, b *out_buffers) {
|
||||||
|
if cc.decl.is_alias() {
|
||||||
|
c.get_candidates_from_decl_alias(cc, class, b)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// propose all children of a subject declaration and
|
// propose all children of a subject declaration and
|
||||||
for _, decl := range cc.decl.children {
|
for _, decl := range cc.decl.children {
|
||||||
if cc.decl.class == decl_package && !ast.IsExported(decl.name) {
|
if cc.decl.class == decl_package && !ast.IsExported(decl.name) {
|
||||||
|
@ -213,34 +268,34 @@ func (c *auto_complete_context) get_candidates_from_decl(cc cursor_context, clas
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
b.append_decl(cc.partial, decl.name, decl, class)
|
b.append_decl(cc.partial, decl.name, c.decl_package_import_path(decl), decl, class)
|
||||||
}
|
}
|
||||||
// propose all children of an underlying struct/interface type
|
// propose all children of an underlying struct/interface type
|
||||||
adecl := advance_to_struct_or_interface(cc.decl)
|
adecl := advance_to_struct_or_interface(cc.decl)
|
||||||
if adecl != nil && adecl != cc.decl {
|
if adecl != nil && adecl != cc.decl {
|
||||||
for _, decl := range adecl.children {
|
for _, decl := range adecl.children {
|
||||||
if decl.class == decl_var {
|
if decl.class == decl_var {
|
||||||
b.append_decl(cc.partial, decl.name, decl, class)
|
b.append_decl(cc.partial, decl.name, c.decl_package_import_path(decl), decl, class)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// propose all children of its embedded types
|
// propose all children of its embedded types
|
||||||
b.append_embedded(cc.partial, cc.decl, class)
|
b.append_embedded(cc.partial, cc.decl, c.decl_package_import_path(cc.decl), class)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *auto_complete_context) get_import_candidates(partial string, b *out_buffers) {
|
func (c *auto_complete_context) get_import_candidates(partial string, b *out_buffers) {
|
||||||
pkgdirs := g_daemon.context.pkg_dirs()
|
currentPackagePath, pkgdirs := g_daemon.context.pkg_dirs()
|
||||||
resultSet := map[string]struct{}{}
|
resultSet := map[string]struct{}{}
|
||||||
for _, pkgdir := range pkgdirs {
|
for _, pkgdir := range pkgdirs {
|
||||||
// convert srcpath to pkgpath and get candidates
|
// convert srcpath to pkgpath and get candidates
|
||||||
get_import_candidates_dir(pkgdir, filepath.FromSlash(partial), b.ignorecase, resultSet)
|
get_import_candidates_dir(pkgdir, filepath.FromSlash(partial), b.ignorecase, currentPackagePath, resultSet)
|
||||||
}
|
}
|
||||||
for k := range resultSet {
|
for k := range resultSet {
|
||||||
b.candidates = append(b.candidates, candidate{Name: k, Class: decl_import})
|
b.candidates = append(b.candidates, candidate{Name: k, Class: decl_import})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func get_import_candidates_dir(root, partial string, ignorecase bool, r map[string]struct{}) {
|
func get_import_candidates_dir(root, partial string, ignorecase bool, currentPackagePath string, r map[string]struct{}) {
|
||||||
var fpath string
|
var fpath string
|
||||||
var match bool
|
var match bool
|
||||||
if strings.HasSuffix(partial, "/") {
|
if strings.HasSuffix(partial, "/") {
|
||||||
|
@ -259,7 +314,7 @@ func get_import_candidates_dir(root, partial string, ignorecase bool, r map[stri
|
||||||
if match && !has_prefix(rel, partial, ignorecase) {
|
if match && !has_prefix(rel, partial, ignorecase) {
|
||||||
continue
|
continue
|
||||||
} else if fi[i].IsDir() {
|
} else if fi[i].IsDir() {
|
||||||
get_import_candidates_dir(root, rel+string(filepath.Separator), ignorecase, r)
|
get_import_candidates_dir(root, rel+string(filepath.Separator), ignorecase, currentPackagePath, r)
|
||||||
} else {
|
} else {
|
||||||
ext := filepath.Ext(name)
|
ext := filepath.Ext(name)
|
||||||
if ext != ".a" {
|
if ext != ".a" {
|
||||||
|
@ -267,7 +322,9 @@ func get_import_candidates_dir(root, partial string, ignorecase bool, r map[stri
|
||||||
} else {
|
} else {
|
||||||
rel = rel[0 : len(rel)-2]
|
rel = rel[0 : len(rel)-2]
|
||||||
}
|
}
|
||||||
r[vendorlessImportPath(filepath.ToSlash(rel))] = struct{}{}
|
if ipath, ok := vendorlessImportPath(filepath.ToSlash(rel), currentPackagePath); ok {
|
||||||
|
r[ipath] = struct{}{}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -305,13 +362,29 @@ func (c *auto_complete_context) apropos(file []byte, filename string, cursor int
|
||||||
// And we're ready to Go. ;)
|
// And we're ready to Go. ;)
|
||||||
|
|
||||||
b := new_out_buffers(c)
|
b := new_out_buffers(c)
|
||||||
|
if g_config.IgnoreCase {
|
||||||
|
if *g_debug {
|
||||||
|
log.Printf("ignoring case sensitivity")
|
||||||
|
}
|
||||||
|
b.ignorecase = true
|
||||||
|
}
|
||||||
|
|
||||||
partial := 0
|
|
||||||
cc, ok := c.deduce_cursor_context(file, cursor)
|
cc, ok := c.deduce_cursor_context(file, cursor)
|
||||||
|
partial := len(cc.partial)
|
||||||
|
if !g_config.Partials {
|
||||||
|
if *g_debug {
|
||||||
|
log.Printf("not performing partial prefix matching")
|
||||||
|
}
|
||||||
|
cc.partial = ""
|
||||||
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
var d *decl
|
var d *decl
|
||||||
if ident, ok := cc.expr.(*ast.Ident); ok && g_config.UnimportedPackages {
|
if ident, ok := cc.expr.(*ast.Ident); ok && g_config.UnimportedPackages {
|
||||||
d = resolveKnownPackageIdent(ident.Name, c.current.name, c.current.context)
|
p := resolveKnownPackageIdent(ident.Name, c.current.name, c.current.context)
|
||||||
|
if p != nil {
|
||||||
|
c.pcache[p.name] = p
|
||||||
|
d = p.main
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if d == nil {
|
if d == nil {
|
||||||
return nil, 0
|
return nil, 0
|
||||||
|
@ -320,17 +393,19 @@ func (c *auto_complete_context) apropos(file []byte, filename string, cursor int
|
||||||
}
|
}
|
||||||
|
|
||||||
class := decl_invalid
|
class := decl_invalid
|
||||||
switch cc.partial {
|
if g_config.ClassFiltering {
|
||||||
case "const":
|
switch cc.partial {
|
||||||
class = decl_const
|
case "const":
|
||||||
case "var":
|
class = decl_const
|
||||||
class = decl_var
|
case "var":
|
||||||
case "type":
|
class = decl_var
|
||||||
class = decl_type
|
case "type":
|
||||||
case "func":
|
class = decl_type
|
||||||
class = decl_func
|
case "func":
|
||||||
case "package":
|
class = decl_func
|
||||||
class = decl_package
|
case "package":
|
||||||
|
class = decl_package
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cc.decl_import {
|
if cc.decl_import {
|
||||||
|
@ -357,7 +432,6 @@ func (c *auto_complete_context) apropos(file []byte, filename string, cursor int
|
||||||
c.get_candidates_from_decl(cc, class, b)
|
c.get_candidates_from_decl(cc, class, b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
partial = len(cc.partial)
|
|
||||||
|
|
||||||
if len(b.candidates) == 0 {
|
if len(b.candidates) == 0 {
|
||||||
return nil, 0
|
return nil, 0
|
||||||
|
@ -391,6 +465,52 @@ func update_packages(ps map[string]*package_file_cache) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func collect_type_alias_methods(d *decl) map[string]*decl {
|
||||||
|
if d == nil || d.is_visited() || !d.is_alias() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
d.set_visited()
|
||||||
|
defer d.clear_visited()
|
||||||
|
|
||||||
|
// add own methods
|
||||||
|
m := map[string]*decl{}
|
||||||
|
for k, v := range d.children {
|
||||||
|
m[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
// recurse into more aliases
|
||||||
|
dd := type_to_decl(d.typ, d.scope)
|
||||||
|
for k, v := range collect_type_alias_methods(dd) {
|
||||||
|
m[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func propagate_type_alias_methods(s *scope) {
|
||||||
|
for _, e := range s.entities {
|
||||||
|
if !e.is_alias() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
methods := collect_type_alias_methods(e)
|
||||||
|
if len(methods) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
dd := e.type_dealias()
|
||||||
|
if dd == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
decl := dd.deep_copy()
|
||||||
|
for _, v := range methods {
|
||||||
|
decl.add_child(v)
|
||||||
|
}
|
||||||
|
s.entities[decl.name] = decl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func merge_decls(filescope *scope, pkg *scope, decls map[string]*decl) {
|
func merge_decls(filescope *scope, pkg *scope, decls map[string]*decl) {
|
||||||
for _, d := range decls {
|
for _, d := range decls {
|
||||||
pkg.merge_decl(d)
|
pkg.merge_decl(d)
|
||||||
|
@ -400,7 +520,7 @@ func merge_decls(filescope *scope, pkg *scope, decls map[string]*decl) {
|
||||||
|
|
||||||
func merge_decls_from_packages(pkgscope *scope, pkgs []package_import, pcache package_cache) {
|
func merge_decls_from_packages(pkgscope *scope, pkgs []package_import, pcache package_cache) {
|
||||||
for _, p := range pkgs {
|
for _, p := range pkgs {
|
||||||
path, alias := p.path, p.alias
|
path, alias := p.abspath, p.alias
|
||||||
if alias != "." {
|
if alias != "." {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -418,7 +538,7 @@ func merge_decls_from_packages(pkgscope *scope, pkgs []package_import, pcache pa
|
||||||
|
|
||||||
func fixup_packages(filescope *scope, pkgs []package_import, pcache package_cache) {
|
func fixup_packages(filescope *scope, pkgs []package_import, pcache package_cache) {
|
||||||
for _, p := range pkgs {
|
for _, p := range pkgs {
|
||||||
path, alias := p.path, p.alias
|
path, alias := p.abspath, p.alias
|
||||||
if alias == "" {
|
if alias == "" {
|
||||||
alias = pcache[path].defalias
|
alias = pcache[path].defalias
|
||||||
}
|
}
|
||||||
|
@ -555,7 +675,6 @@ func check_type_expr(e ast.Expr) bool {
|
||||||
default:
|
default:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
|
|
@ -141,7 +141,7 @@ func (f *auto_complete_file) process_decl(decl ast.Decl) {
|
||||||
for i, name := range data.names {
|
for i, name := range data.names {
|
||||||
typ, v, vi := data.type_value_index(i)
|
typ, v, vi := data.type_value_index(i)
|
||||||
|
|
||||||
d := new_decl_full(name.Name, class, 0, typ, v, vi, prevscope)
|
d := new_decl_full(name.Name, class, ast_decl_flags(data.decl), typ, v, vi, prevscope)
|
||||||
if d == nil {
|
if d == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -243,7 +243,9 @@ func (f *auto_complete_file) process_select_stmt(a *ast.SelectStmt) {
|
||||||
if astmt, ok := last_cursor_after.Comm.(*ast.AssignStmt); ok && astmt.Tok == token.DEFINE {
|
if astmt, ok := last_cursor_after.Comm.(*ast.AssignStmt); ok && astmt.Tok == token.DEFINE {
|
||||||
vname := astmt.Lhs[0].(*ast.Ident).Name
|
vname := astmt.Lhs[0].(*ast.Ident).Name
|
||||||
v := new_decl_var(vname, nil, astmt.Rhs[0], -1, prevscope)
|
v := new_decl_var(vname, nil, astmt.Rhs[0], -1, prevscope)
|
||||||
f.scope.add_named_decl(v)
|
if v != nil {
|
||||||
|
f.scope.add_named_decl(v)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, s := range last_cursor_after.Body {
|
for _, s := range last_cursor_after.Body {
|
||||||
|
|
|
@ -50,6 +50,8 @@ func do_client() int {
|
||||||
cmd_drop_cache(client)
|
cmd_drop_cache(client)
|
||||||
case "set":
|
case "set":
|
||||||
cmd_set(client)
|
cmd_set(client)
|
||||||
|
case "options":
|
||||||
|
cmd_options(client)
|
||||||
default:
|
default:
|
||||||
fmt.Printf("unknown argument: %q, try running \"gocode -h\"\n", flag.Arg(0))
|
fmt.Printf("unknown argument: %q, try running \"gocode -h\"\n", flag.Arg(0))
|
||||||
return 1
|
return 1
|
||||||
|
@ -180,3 +182,7 @@ func cmd_set(c *rpc.Client) {
|
||||||
fmt.Print(client_set(c, flag.Arg(1), flag.Arg(2)))
|
fmt.Print(client_set(c, flag.Arg(1), flag.Arg(2)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cmd_options(c *rpc.Client) {
|
||||||
|
fmt.Print(client_options(c, 0))
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -28,9 +29,27 @@ type config struct {
|
||||||
PackageLookupMode string `json:"package-lookup-mode"`
|
PackageLookupMode string `json:"package-lookup-mode"`
|
||||||
CloseTimeout int `json:"close-timeout"`
|
CloseTimeout int `json:"close-timeout"`
|
||||||
UnimportedPackages bool `json:"unimported-packages"`
|
UnimportedPackages bool `json:"unimported-packages"`
|
||||||
|
Partials bool `json:"partials"`
|
||||||
|
IgnoreCase bool `json:"ignore-case"`
|
||||||
|
ClassFiltering bool `json:"class-filtering"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var g_config = config{
|
var g_config_desc = map[string]string{
|
||||||
|
"propose-builtins": "If set to {true}, gocode will add built-in types, functions and constants to autocompletion proposals.",
|
||||||
|
"lib-path": "A string option. Allows you to add search paths for packages. By default, gocode only searches {$GOPATH/pkg/$GOOS_$GOARCH} and {$GOROOT/pkg/$GOOS_$GOARCH} in terms of previously existed environment variables. Also you can specify multiple paths using ':' (colon) as a separator (on Windows use semicolon ';'). The paths specified by {lib-path} are prepended to the default ones.",
|
||||||
|
"custom-pkg-prefix": "",
|
||||||
|
"custom-vendor-dir": "",
|
||||||
|
"autobuild": "If set to {true}, gocode will try to automatically build out-of-date packages when their source files are modified, in order to obtain the freshest autocomplete results for them. This feature is experimental.",
|
||||||
|
"force-debug-output": "If is not empty, gocode will forcefully redirect the logging into that file. Also forces enabling of the debug mode on the server side.",
|
||||||
|
"package-lookup-mode": "If set to {go}, use standard Go package lookup rules. If set to {gb}, use gb-specific lookup rules. See {https://github.com/constabulary/gb} for details.",
|
||||||
|
"close-timeout": "If there have been no completion requests after this number of seconds, the gocode process will terminate. Default is 30 minutes.",
|
||||||
|
"unimported-packages": "If set to {true}, gocode will try to import certain known packages automatically for identifiers which cannot be resolved otherwise. Currently only a limited set of standard library packages is supported.",
|
||||||
|
"partials": "If set to {false}, gocode will not filter autocompletion results based on entered prefix before the cursor. Instead it will return all available autocompletion results viable for a given context. Whether this option is set to {true} or {false}, gocode will return a valid prefix length for output formats which support it. Setting this option to a non-default value may result in editor misbehaviour.",
|
||||||
|
"ignore-case": "If set to {true}, gocode will perform case-insensitive matching when doing prefix-based filtering.",
|
||||||
|
"class-filtering": "Enables or disables gocode's feature where it performs class-based filtering if partial input matches corresponding class keyword: const, var, type, func, package.",
|
||||||
|
}
|
||||||
|
|
||||||
|
var g_default_config = config{
|
||||||
ProposeBuiltins: false,
|
ProposeBuiltins: false,
|
||||||
LibPath: "",
|
LibPath: "",
|
||||||
CustomPkgPrefix: "",
|
CustomPkgPrefix: "",
|
||||||
|
@ -39,7 +58,11 @@ var g_config = config{
|
||||||
PackageLookupMode: "go",
|
PackageLookupMode: "go",
|
||||||
CloseTimeout: 1800,
|
CloseTimeout: 1800,
|
||||||
UnimportedPackages: false,
|
UnimportedPackages: false,
|
||||||
|
Partials: true,
|
||||||
|
IgnoreCase: false,
|
||||||
|
ClassFiltering: true,
|
||||||
}
|
}
|
||||||
|
var g_config = g_default_config
|
||||||
|
|
||||||
var g_string_to_bool = map[string]bool{
|
var g_string_to_bool = map[string]bool{
|
||||||
"t": true,
|
"t": true,
|
||||||
|
@ -175,3 +198,43 @@ func (this *config) read() error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func quoted(v interface{}) string {
|
||||||
|
switch v.(type) {
|
||||||
|
case string:
|
||||||
|
return fmt.Sprintf("%q", v)
|
||||||
|
case int:
|
||||||
|
return fmt.Sprint(v)
|
||||||
|
case bool:
|
||||||
|
return fmt.Sprint(v)
|
||||||
|
default:
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var descRE = regexp.MustCompile(`{[^}]+}`)
|
||||||
|
|
||||||
|
func preprocess_desc(v string) string {
|
||||||
|
return descRE.ReplaceAllStringFunc(v, func(v string) string {
|
||||||
|
return color_cyan + v[1:len(v)-1] + color_none
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *config) options() string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
fmt.Fprintf(&buf, "%sConfig file location%s: %s\n", color_white_bold, color_none, config_file())
|
||||||
|
dv := reflect.ValueOf(g_default_config)
|
||||||
|
v, t := this.value_and_type()
|
||||||
|
for i, n := 0, t.NumField(); i < n; i++ {
|
||||||
|
f := t.Field(i)
|
||||||
|
index := f.Index
|
||||||
|
tag := f.Tag.Get("json")
|
||||||
|
fmt.Fprintf(&buf, "\n%s%s%s\n", color_yellow_bold, tag, color_none)
|
||||||
|
fmt.Fprintf(&buf, "%stype%s: %s\n", color_yellow, color_none, f.Type)
|
||||||
|
fmt.Fprintf(&buf, "%svalue%s: %s\n", color_yellow, color_none, quoted(v.FieldByIndex(index).Interface()))
|
||||||
|
fmt.Fprintf(&buf, "%sdefault%s: %s\n", color_yellow, color_none, quoted(dv.FieldByIndex(index).Interface()))
|
||||||
|
fmt.Fprintf(&buf, "%sdescription%s: %s\n", color_yellow, color_none, preprocess_desc(g_config_desc[tag]))
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
|
@ -35,10 +35,8 @@ type token_item struct {
|
||||||
func (i token_item) literal() string {
|
func (i token_item) literal() string {
|
||||||
if i.tok.IsLiteral() {
|
if i.tok.IsLiteral() {
|
||||||
return i.lit
|
return i.lit
|
||||||
} else {
|
|
||||||
return i.tok.String()
|
|
||||||
}
|
}
|
||||||
return ""
|
return i.tok.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func new_token_iterator(src []byte, cursor int) token_iterator {
|
func new_token_iterator(src []byte, cursor int) token_iterator {
|
||||||
|
@ -116,6 +114,28 @@ func (this *token_iterator) skip_to_left_curly() bool {
|
||||||
return this.skip_to_left(token.LBRACE, token.RBRACE)
|
return this.skip_to_left(token.LBRACE, token.RBRACE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ti *token_iterator) extract_type_alike() string {
|
||||||
|
if ti.token().tok != token.IDENT { // not Foo, return nothing
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
b := ti.token().literal()
|
||||||
|
if !ti.go_back() { // just Foo
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
if ti.token().tok != token.PERIOD { // not .Foo, return Foo
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
if !ti.go_back() { // just .Foo, return Foo (best choice recovery)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
if ti.token().tok != token.IDENT { // not lib.Foo, return Foo
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
out := ti.token().literal() + "." + b // lib.Foo
|
||||||
|
ti.go_back()
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// Extract the type expression right before the enclosing curly bracket block.
|
// Extract the type expression right before the enclosing curly bracket block.
|
||||||
// Examples (# - the cursor):
|
// Examples (# - the cursor):
|
||||||
// &lib.Struct{Whatever: 1, Hel#} // returns "lib.Struct"
|
// &lib.Struct{Whatever: 1, Hel#} // returns "lib.Struct"
|
||||||
|
@ -130,23 +150,21 @@ func (ti *token_iterator) extract_struct_type() string {
|
||||||
if !ti.go_back() {
|
if !ti.go_back() {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
if ti.token().tok != token.IDENT {
|
if ti.token().tok == token.LBRACE { // Foo{#{}}
|
||||||
|
if !ti.go_back() {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
} else if ti.token().tok == token.COMMA { // Foo{abc,#{}}
|
||||||
|
return ti.extract_struct_type()
|
||||||
|
}
|
||||||
|
typ := ti.extract_type_alike()
|
||||||
|
if typ == "" {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
b := ti.token().literal()
|
if ti.token().tok == token.RPAREN || ti.token().tok == token.MUL {
|
||||||
if !ti.go_back() {
|
return ""
|
||||||
return b
|
|
||||||
}
|
}
|
||||||
if ti.token().tok != token.PERIOD {
|
return typ
|
||||||
return b
|
|
||||||
}
|
|
||||||
if !ti.go_back() {
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
if ti.token().tok != token.IDENT {
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
return ti.token().literal() + "." + b
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Starting from the token under the cursor move back and extract something
|
// Starting from the token under the cursor move back and extract something
|
||||||
|
@ -266,7 +284,14 @@ func (c *auto_complete_context) deduce_struct_type_decl(iter *token_iterator) *d
|
||||||
if decl == nil {
|
if decl == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if _, ok := decl.typ.(*ast.StructType); !ok {
|
|
||||||
|
// we allow only struct types here, but also support type aliases
|
||||||
|
if decl.is_alias() {
|
||||||
|
dd := decl.type_dealias()
|
||||||
|
if _, ok := dd.typ.(*ast.StructType); !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
} else if _, ok := decl.typ.(*ast.StructType); !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return decl
|
return decl
|
||||||
|
@ -395,7 +420,7 @@ func (c *auto_complete_context) deduce_cursor_context(file []byte, cursor int) (
|
||||||
// package name has nothing to do with package file name, that's why we need to
|
// package name has nothing to do with package file name, that's why we need to
|
||||||
// scan the packages. And many of them will have conflicts. Can we make a smart
|
// scan the packages. And many of them will have conflicts. Can we make a smart
|
||||||
// prediction algorithm which will prefer certain packages over another ones?
|
// prediction algorithm which will prefer certain packages over another ones?
|
||||||
func resolveKnownPackageIdent(ident string, filename string, context *package_lookup_context) *decl {
|
func resolveKnownPackageIdent(ident string, filename string, context *package_lookup_context) *package_file_cache {
|
||||||
importPath, ok := knownPackageIdents[ident]
|
importPath, ok := knownPackageIdents[ident]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
|
@ -406,9 +431,9 @@ func resolveKnownPackageIdent(ident string, filename string, context *package_lo
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
p := new_package_file_cache(path)
|
p := new_package_file_cache(path, importPath)
|
||||||
p.update_cache()
|
p.update_cache()
|
||||||
return p.main
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
var knownPackageIdents = map[string]string{
|
var knownPackageIdents = map[string]string{
|
||||||
|
|
|
@ -56,12 +56,15 @@ func (this decl_class) String() string {
|
||||||
type decl_flags int16
|
type decl_flags int16
|
||||||
|
|
||||||
const (
|
const (
|
||||||
decl_foreign = decl_flags(1 << iota) // imported from another package
|
decl_foreign decl_flags = 1 << iota // imported from another package
|
||||||
|
|
||||||
// means that the decl is a part of the range statement
|
// means that the decl is a part of the range statement
|
||||||
// its type is inferred in a special way
|
// its type is inferred in a special way
|
||||||
decl_rangevar
|
decl_rangevar
|
||||||
|
|
||||||
|
// decl of decl_type class is a type alias
|
||||||
|
decl_alias
|
||||||
|
|
||||||
// for preventing infinite recursions and loops in type inference code
|
// for preventing infinite recursions and loops in type inference code
|
||||||
decl_visited
|
decl_visited
|
||||||
)
|
)
|
||||||
|
@ -115,7 +118,19 @@ func ast_decl_type(d ast.Decl) ast.Expr {
|
||||||
return t.Type
|
return t.Type
|
||||||
}
|
}
|
||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
return nil
|
}
|
||||||
|
|
||||||
|
func ast_decl_flags(d ast.Decl) decl_flags {
|
||||||
|
switch t := d.(type) {
|
||||||
|
case *ast.GenDecl:
|
||||||
|
switch t.Tok {
|
||||||
|
case token.TYPE:
|
||||||
|
if isAliasTypeSpec(t.Specs[0].(*ast.TypeSpec)) {
|
||||||
|
return decl_alias
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func ast_decl_class(d ast.Decl) decl_class {
|
func ast_decl_class(d ast.Decl) decl_class {
|
||||||
|
@ -324,7 +339,7 @@ func new_decl_var(name string, typ ast.Expr, value ast.Expr, vindex int, scope *
|
||||||
|
|
||||||
func method_of(d ast.Decl) string {
|
func method_of(d ast.Decl) string {
|
||||||
if t, ok := d.(*ast.FuncDecl); ok {
|
if t, ok := d.(*ast.FuncDecl); ok {
|
||||||
if t.Recv != nil {
|
if t.Recv != nil && len(t.Recv.List) != 0 {
|
||||||
switch t := t.Recv.List[0].Type.(type) {
|
switch t := t.Recv.List[0].Type.(type) {
|
||||||
case *ast.StarExpr:
|
case *ast.StarExpr:
|
||||||
if se, ok := t.X.(*ast.SelectorExpr); ok {
|
if se, ok := t.X.(*ast.SelectorExpr); ok {
|
||||||
|
@ -348,6 +363,7 @@ func (other *decl) deep_copy() *decl {
|
||||||
d := new(decl)
|
d := new(decl)
|
||||||
d.name = other.name
|
d.name = other.name
|
||||||
d.class = other.class
|
d.class = other.class
|
||||||
|
d.flags = other.flags
|
||||||
d.typ = other.typ
|
d.typ = other.typ
|
||||||
d.value = other.value
|
d.value = other.value
|
||||||
d.value_index = other.value_index
|
d.value_index = other.value_index
|
||||||
|
@ -363,20 +379,36 @@ func (other *decl) deep_copy() *decl {
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *decl) is_rangevar() bool {
|
||||||
|
return d.flags&decl_rangevar != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decl) is_alias() bool {
|
||||||
|
return d.flags&decl_alias != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decl) is_visited() bool {
|
||||||
|
return d.flags&decl_visited != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decl) set_visited() {
|
||||||
|
d.flags |= decl_visited
|
||||||
|
}
|
||||||
|
|
||||||
func (d *decl) clear_visited() {
|
func (d *decl) clear_visited() {
|
||||||
d.flags &^= decl_visited
|
d.flags &^= decl_visited
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *decl) expand_or_replace(other *decl) {
|
func (d *decl) expand_or_replace(other *decl) {
|
||||||
// expand only if it's a methods stub, otherwise simply copy
|
// expand only if it's a methods stub, otherwise simply keep it as is
|
||||||
if d.class != decl_methods_stub && other.class != decl_methods_stub {
|
if d.class != decl_methods_stub && other.class != decl_methods_stub {
|
||||||
d = other
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.class == decl_methods_stub {
|
if d.class == decl_methods_stub {
|
||||||
d.typ = other.typ
|
d.typ = other.typ
|
||||||
d.class = other.class
|
d.class = other.class
|
||||||
|
d.flags = other.flags
|
||||||
}
|
}
|
||||||
|
|
||||||
if other.children != nil {
|
if other.children != nil {
|
||||||
|
@ -398,7 +430,7 @@ func (d *decl) matches() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *decl) pretty_print_type(out io.Writer) {
|
func (d *decl) pretty_print_type(out io.Writer, canonical_aliases map[string]string) {
|
||||||
switch d.class {
|
switch d.class {
|
||||||
case decl_type:
|
case decl_type:
|
||||||
switch d.typ.(type) {
|
switch d.typ.(type) {
|
||||||
|
@ -410,15 +442,15 @@ func (d *decl) pretty_print_type(out io.Writer) {
|
||||||
fmt.Fprintf(out, "interface")
|
fmt.Fprintf(out, "interface")
|
||||||
default:
|
default:
|
||||||
if d.typ != nil {
|
if d.typ != nil {
|
||||||
pretty_print_type_expr(out, d.typ)
|
pretty_print_type_expr(out, d.typ, canonical_aliases)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case decl_var:
|
case decl_var:
|
||||||
if d.typ != nil {
|
if d.typ != nil {
|
||||||
pretty_print_type_expr(out, d.typ)
|
pretty_print_type_expr(out, d.typ, canonical_aliases)
|
||||||
}
|
}
|
||||||
case decl_func:
|
case decl_func:
|
||||||
pretty_print_type_expr(out, d.typ)
|
pretty_print_type_expr(out, d.typ, canonical_aliases)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,17 +513,14 @@ func func_return_type(f *ast.FuncType, index int) ast.Expr {
|
||||||
i := 0
|
i := 0
|
||||||
var field *ast.Field
|
var field *ast.Field
|
||||||
for _, field = range f.Results.List {
|
for _, field = range f.Results.List {
|
||||||
if i >= index {
|
n := 1
|
||||||
|
if field.Names != nil {
|
||||||
|
n = len(field.Names)
|
||||||
|
}
|
||||||
|
if i <= index && index < i+n {
|
||||||
return field.Type
|
return field.Type
|
||||||
}
|
}
|
||||||
if field.Names != nil {
|
i += n
|
||||||
i += len(field.Names)
|
|
||||||
} else {
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if i >= index {
|
|
||||||
return field.Type
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -599,20 +628,20 @@ func advance_to_type(pred type_predicate, v ast.Expr, scope *scope) (ast.Expr, *
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if decl.flags&decl_visited != 0 {
|
if decl.is_visited() {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
decl.flags |= decl_visited
|
decl.set_visited()
|
||||||
defer decl.clear_visited()
|
defer decl.clear_visited()
|
||||||
|
|
||||||
return advance_to_type(pred, decl.typ, decl.scope)
|
return advance_to_type(pred, decl.typ, decl.scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
func advance_to_struct_or_interface(decl *decl) *decl {
|
func advance_to_struct_or_interface(decl *decl) *decl {
|
||||||
if decl.flags&decl_visited != 0 {
|
if decl.is_visited() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
decl.flags |= decl_visited
|
decl.set_visited()
|
||||||
defer decl.clear_visited()
|
defer decl.clear_visited()
|
||||||
|
|
||||||
if struct_interface_predicate(decl.typ) {
|
if struct_interface_predicate(decl.typ) {
|
||||||
|
@ -917,7 +946,7 @@ func infer_type(v ast.Expr, scope *scope, index int) (ast.Expr, *scope, bool) {
|
||||||
// makes sense.
|
// makes sense.
|
||||||
func (d *decl) infer_type() (ast.Expr, *scope) {
|
func (d *decl) infer_type() (ast.Expr, *scope) {
|
||||||
// special case for range vars
|
// special case for range vars
|
||||||
if d.flags&decl_rangevar != 0 {
|
if d.is_rangevar() {
|
||||||
var scope *scope
|
var scope *scope
|
||||||
d.typ, scope = infer_range_type(d.value, d.scope, d.value_index)
|
d.typ, scope = infer_range_type(d.value, d.scope, d.value_index)
|
||||||
return d.typ, scope
|
return d.typ, scope
|
||||||
|
@ -937,10 +966,10 @@ func (d *decl) infer_type() (ast.Expr, *scope) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// prevent loops
|
// prevent loops
|
||||||
if d.flags&decl_visited != 0 {
|
if d.is_visited() {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
d.flags |= decl_visited
|
d.set_visited()
|
||||||
defer d.clear_visited()
|
defer d.clear_visited()
|
||||||
|
|
||||||
var scope *scope
|
var scope *scope
|
||||||
|
@ -948,13 +977,34 @@ func (d *decl) infer_type() (ast.Expr, *scope) {
|
||||||
return d.typ, scope
|
return d.typ, scope
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *decl) find_child(name string) *decl {
|
func (d *decl) type_dealias() *decl {
|
||||||
if d.flags&decl_visited != 0 {
|
if d.is_visited() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
d.flags |= decl_visited
|
d.set_visited()
|
||||||
defer d.clear_visited()
|
defer d.clear_visited()
|
||||||
|
|
||||||
|
dd := type_to_decl(d.typ, d.scope)
|
||||||
|
if dd != nil && dd.is_alias() {
|
||||||
|
return dd.type_dealias()
|
||||||
|
}
|
||||||
|
return dd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decl) find_child(name string) *decl {
|
||||||
|
// type aliases don't really have any children on their own, but they
|
||||||
|
// point to a different type, let's try to find one
|
||||||
|
if d.is_alias() {
|
||||||
|
dd := d.type_dealias()
|
||||||
|
if dd != nil {
|
||||||
|
return dd.find_child(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// note that type alias can also point to a type literal, something like
|
||||||
|
// type A = struct { A int }
|
||||||
|
// in this case we rely on "advance_to_struct_or_interface" below
|
||||||
|
}
|
||||||
|
|
||||||
if d.children != nil {
|
if d.children != nil {
|
||||||
if c, ok := d.children[name]; ok {
|
if c, ok := d.children[name]; ok {
|
||||||
return c
|
return c
|
||||||
|
@ -963,6 +1013,12 @@ func (d *decl) find_child(name string) *decl {
|
||||||
|
|
||||||
decl := advance_to_struct_or_interface(d)
|
decl := advance_to_struct_or_interface(d)
|
||||||
if decl != nil && decl != d {
|
if decl != nil && decl != d {
|
||||||
|
if d.is_visited() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
d.set_visited()
|
||||||
|
defer d.clear_visited()
|
||||||
|
|
||||||
return decl.find_child(name)
|
return decl.find_child(name)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -1053,11 +1109,11 @@ func get_array_len(e ast.Expr) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func pretty_print_type_expr(out io.Writer, e ast.Expr) {
|
func pretty_print_type_expr(out io.Writer, e ast.Expr, canonical_aliases map[string]string) {
|
||||||
switch t := e.(type) {
|
switch t := e.(type) {
|
||||||
case *ast.StarExpr:
|
case *ast.StarExpr:
|
||||||
fmt.Fprintf(out, "*")
|
fmt.Fprintf(out, "*")
|
||||||
pretty_print_type_expr(out, t.X)
|
pretty_print_type_expr(out, t.X, canonical_aliases)
|
||||||
case *ast.Ident:
|
case *ast.Ident:
|
||||||
if strings.HasPrefix(t.Name, "$") {
|
if strings.HasPrefix(t.Name, "$") {
|
||||||
// beautify anonymous types
|
// beautify anonymous types
|
||||||
|
@ -1070,15 +1126,19 @@ func pretty_print_type_expr(out io.Writer, e ast.Expr) {
|
||||||
// it's always true
|
// it's always true
|
||||||
fmt.Fprintf(out, "interface{}")
|
fmt.Fprintf(out, "interface{}")
|
||||||
}
|
}
|
||||||
} else if !*g_debug && strings.HasPrefix(t.Name, "#") {
|
|
||||||
fmt.Fprintf(out, t.Name[1:])
|
|
||||||
} else if !*g_debug && strings.HasPrefix(t.Name, "!") {
|
} else if !*g_debug && strings.HasPrefix(t.Name, "!") {
|
||||||
// these are full package names for disambiguating and pretty
|
// these are full package names for disambiguating and pretty
|
||||||
// printing packages withing packages, e.g.
|
// printing packages within packages, e.g.
|
||||||
// !go/ast!ast vs. !github.com/nsf/my/ast!ast
|
// !go/ast!ast vs. !github.com/nsf/my/ast!ast
|
||||||
// another ugly hack, if people are punished in hell for ugly hacks
|
// another ugly hack, if people are punished in hell for ugly hacks
|
||||||
// I'm screwed...
|
// I'm screwed...
|
||||||
fmt.Fprintf(out, t.Name[strings.LastIndex(t.Name, "!")+1:])
|
emarkIdx := strings.LastIndex(t.Name, "!")
|
||||||
|
path := t.Name[1:emarkIdx]
|
||||||
|
alias := canonical_aliases[path]
|
||||||
|
if alias == "" {
|
||||||
|
alias = t.Name[emarkIdx+1:]
|
||||||
|
}
|
||||||
|
fmt.Fprintf(out, alias)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(out, t.Name)
|
fmt.Fprintf(out, t.Name)
|
||||||
}
|
}
|
||||||
|
@ -1092,17 +1152,17 @@ func pretty_print_type_expr(out io.Writer, e ast.Expr) {
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(out, "[]")
|
fmt.Fprintf(out, "[]")
|
||||||
}
|
}
|
||||||
pretty_print_type_expr(out, t.Elt)
|
pretty_print_type_expr(out, t.Elt, canonical_aliases)
|
||||||
case *ast.SelectorExpr:
|
case *ast.SelectorExpr:
|
||||||
pretty_print_type_expr(out, t.X)
|
pretty_print_type_expr(out, t.X, canonical_aliases)
|
||||||
fmt.Fprintf(out, ".%s", t.Sel.Name)
|
fmt.Fprintf(out, ".%s", t.Sel.Name)
|
||||||
case *ast.FuncType:
|
case *ast.FuncType:
|
||||||
fmt.Fprintf(out, "func(")
|
fmt.Fprintf(out, "func(")
|
||||||
pretty_print_func_field_list(out, t.Params)
|
pretty_print_func_field_list(out, t.Params, canonical_aliases)
|
||||||
fmt.Fprintf(out, ")")
|
fmt.Fprintf(out, ")")
|
||||||
|
|
||||||
buf := bytes.NewBuffer(make([]byte, 0, 256))
|
buf := bytes.NewBuffer(make([]byte, 0, 256))
|
||||||
nresults := pretty_print_func_field_list(buf, t.Results)
|
nresults := pretty_print_func_field_list(buf, t.Results, canonical_aliases)
|
||||||
if nresults > 0 {
|
if nresults > 0 {
|
||||||
results := buf.String()
|
results := buf.String()
|
||||||
if strings.IndexAny(results, ", ") != -1 {
|
if strings.IndexAny(results, ", ") != -1 {
|
||||||
|
@ -1112,14 +1172,14 @@ func pretty_print_type_expr(out io.Writer, e ast.Expr) {
|
||||||
}
|
}
|
||||||
case *ast.MapType:
|
case *ast.MapType:
|
||||||
fmt.Fprintf(out, "map[")
|
fmt.Fprintf(out, "map[")
|
||||||
pretty_print_type_expr(out, t.Key)
|
pretty_print_type_expr(out, t.Key, canonical_aliases)
|
||||||
fmt.Fprintf(out, "]")
|
fmt.Fprintf(out, "]")
|
||||||
pretty_print_type_expr(out, t.Value)
|
pretty_print_type_expr(out, t.Value, canonical_aliases)
|
||||||
case *ast.InterfaceType:
|
case *ast.InterfaceType:
|
||||||
fmt.Fprintf(out, "interface{}")
|
fmt.Fprintf(out, "interface{}")
|
||||||
case *ast.Ellipsis:
|
case *ast.Ellipsis:
|
||||||
fmt.Fprintf(out, "...")
|
fmt.Fprintf(out, "...")
|
||||||
pretty_print_type_expr(out, t.Elt)
|
pretty_print_type_expr(out, t.Elt, canonical_aliases)
|
||||||
case *ast.StructType:
|
case *ast.StructType:
|
||||||
fmt.Fprintf(out, "struct")
|
fmt.Fprintf(out, "struct")
|
||||||
case *ast.ChanType:
|
case *ast.ChanType:
|
||||||
|
@ -1131,10 +1191,10 @@ func pretty_print_type_expr(out io.Writer, e ast.Expr) {
|
||||||
case ast.SEND | ast.RECV:
|
case ast.SEND | ast.RECV:
|
||||||
fmt.Fprintf(out, "chan ")
|
fmt.Fprintf(out, "chan ")
|
||||||
}
|
}
|
||||||
pretty_print_type_expr(out, t.Value)
|
pretty_print_type_expr(out, t.Value, canonical_aliases)
|
||||||
case *ast.ParenExpr:
|
case *ast.ParenExpr:
|
||||||
fmt.Fprintf(out, "(")
|
fmt.Fprintf(out, "(")
|
||||||
pretty_print_type_expr(out, t.X)
|
pretty_print_type_expr(out, t.X, canonical_aliases)
|
||||||
fmt.Fprintf(out, ")")
|
fmt.Fprintf(out, ")")
|
||||||
case *ast.BadExpr:
|
case *ast.BadExpr:
|
||||||
// TODO: probably I should check that in a separate function
|
// TODO: probably I should check that in a separate function
|
||||||
|
@ -1145,7 +1205,7 @@ func pretty_print_type_expr(out io.Writer, e ast.Expr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func pretty_print_func_field_list(out io.Writer, f *ast.FieldList) int {
|
func pretty_print_func_field_list(out io.Writer, f *ast.FieldList, canonical_aliases map[string]string) int {
|
||||||
count := 0
|
count := 0
|
||||||
if f == nil {
|
if f == nil {
|
||||||
return count
|
return count
|
||||||
|
@ -1172,7 +1232,7 @@ func pretty_print_func_field_list(out io.Writer, f *ast.FieldList) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// type
|
// type
|
||||||
pretty_print_type_expr(out, field.Type)
|
pretty_print_type_expr(out, field.Type, canonical_aliases)
|
||||||
|
|
||||||
// ,
|
// ,
|
||||||
if i != len(f.List)-1 {
|
if i != len(f.List)-1 {
|
||||||
|
|
|
@ -19,8 +19,9 @@ import (
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
type package_import struct {
|
type package_import struct {
|
||||||
alias string
|
alias string
|
||||||
path string
|
abspath string
|
||||||
|
path string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parses import declarations until the first non-import declaration and fills
|
// Parses import declarations until the first non-import declaration and fills
|
||||||
|
@ -32,9 +33,9 @@ func collect_package_imports(filename string, decls []ast.Decl, context *package
|
||||||
for _, spec := range gd.Specs {
|
for _, spec := range gd.Specs {
|
||||||
imp := spec.(*ast.ImportSpec)
|
imp := spec.(*ast.ImportSpec)
|
||||||
path, alias := path_and_alias(imp)
|
path, alias := path_and_alias(imp)
|
||||||
path, ok := abs_path_for_package(filename, path, context)
|
abspath, ok := abs_path_for_package(filename, path, context)
|
||||||
if ok && alias != "_" {
|
if ok && alias != "_" {
|
||||||
pi = append(pi, package_import{alias, path})
|
pi = append(pi, package_import{alias, abspath, path})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -121,7 +122,7 @@ func append_to_top_decls(decls map[string]*decl, decl ast.Decl, scope *scope) {
|
||||||
for i, name := range data.names {
|
for i, name := range data.names {
|
||||||
typ, v, vi := data.type_value_index(i)
|
typ, v, vi := data.type_value_index(i)
|
||||||
|
|
||||||
d := new_decl_full(name.Name, class, 0, typ, v, vi, scope)
|
d := new_decl_full(name.Name, class, ast_decl_flags(data.decl), typ, v, vi, scope)
|
||||||
if d == nil {
|
if d == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -314,7 +315,11 @@ func find_global_file(imp string, context *package_lookup_context) (string, bool
|
||||||
// gb-specific lookup mode, only if the root dir was found
|
// gb-specific lookup mode, only if the root dir was found
|
||||||
if g_config.PackageLookupMode == "gb" && context.GBProjectRoot != "" {
|
if g_config.PackageLookupMode == "gb" && context.GBProjectRoot != "" {
|
||||||
root := context.GBProjectRoot
|
root := context.GBProjectRoot
|
||||||
pkg_path := filepath.Join(root, "pkg", context.GOOS+"-"+context.GOARCH, pkgfile)
|
pkgdir := filepath.Join(root, "pkg", context.GOOS+"-"+context.GOARCH)
|
||||||
|
if !is_dir(pkgdir) {
|
||||||
|
pkgdir = filepath.Join(root, "pkg", context.GOOS+"-"+context.GOARCH+"-race")
|
||||||
|
}
|
||||||
|
pkg_path := filepath.Join(pkgdir, pkgfile)
|
||||||
if file_exists(pkg_path) {
|
if file_exists(pkg_path) {
|
||||||
log_found_package_maybe(imp, pkg_path)
|
log_found_package_maybe(imp, pkg_path)
|
||||||
return pkg_path, true
|
return pkg_path, true
|
||||||
|
@ -453,9 +458,10 @@ func (ctxt *package_lookup_context) gopath() []string {
|
||||||
return all
|
return all
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctxt *package_lookup_context) pkg_dirs() []string {
|
func (ctxt *package_lookup_context) pkg_dirs() (string, []string) {
|
||||||
pkgdir := fmt.Sprintf("%s_%s", ctxt.GOOS, ctxt.GOARCH)
|
pkgdir := fmt.Sprintf("%s_%s", ctxt.GOOS, ctxt.GOARCH)
|
||||||
|
|
||||||
|
var currentPackagePath string
|
||||||
var all []string
|
var all []string
|
||||||
if ctxt.GOROOT != "" {
|
if ctxt.GOROOT != "" {
|
||||||
dir := filepath.Join(ctxt.GOROOT, "pkg", pkgdir)
|
dir := filepath.Join(ctxt.GOROOT, "pkg", pkgdir)
|
||||||
|
@ -466,15 +472,23 @@ func (ctxt *package_lookup_context) pkg_dirs() []string {
|
||||||
|
|
||||||
switch g_config.PackageLookupMode {
|
switch g_config.PackageLookupMode {
|
||||||
case "go":
|
case "go":
|
||||||
|
currentPackagePath = ctxt.CurrentPackagePath
|
||||||
for _, p := range ctxt.gopath() {
|
for _, p := range ctxt.gopath() {
|
||||||
dir := filepath.Join(p, "pkg", pkgdir)
|
dir := filepath.Join(p, "pkg", pkgdir)
|
||||||
if is_dir(dir) {
|
if is_dir(dir) {
|
||||||
all = append(all, dir)
|
all = append(all, dir)
|
||||||
}
|
}
|
||||||
|
dir = filepath.Join(dir, currentPackagePath, "vendor")
|
||||||
|
if is_dir(dir) {
|
||||||
|
all = append(all, dir)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case "gb":
|
case "gb":
|
||||||
if ctxt.GBProjectRoot != "" {
|
if ctxt.GBProjectRoot != "" {
|
||||||
pkgdir := fmt.Sprintf("%s-%s", ctxt.GOOS, ctxt.GOARCH)
|
pkgdir := fmt.Sprintf("%s-%s", ctxt.GOOS, ctxt.GOARCH)
|
||||||
|
if !is_dir(pkgdir) {
|
||||||
|
pkgdir = fmt.Sprintf("%s-%s-race", ctxt.GOOS, ctxt.GOARCH)
|
||||||
|
}
|
||||||
dir := filepath.Join(ctxt.GBProjectRoot, "pkg", pkgdir)
|
dir := filepath.Join(ctxt.GBProjectRoot, "pkg", pkgdir)
|
||||||
if is_dir(dir) {
|
if is_dir(dir) {
|
||||||
all = append(all, dir)
|
all = append(all, dir)
|
||||||
|
@ -483,7 +497,7 @@ func (ctxt *package_lookup_context) pkg_dirs() []string {
|
||||||
case "bzl":
|
case "bzl":
|
||||||
// TODO: Support bazel mode
|
// TODO: Support bazel mode
|
||||||
}
|
}
|
||||||
return all
|
return currentPackagePath, all
|
||||||
}
|
}
|
||||||
|
|
||||||
type decl_cache struct {
|
type decl_cache struct {
|
||||||
|
|
|
@ -128,6 +128,18 @@ func (*csv_formatter) write_candidates(candidates []candidate, num int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
// csv_with_package_formatter
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type csv_with_package_formatter struct{}
|
||||||
|
|
||||||
|
func (*csv_with_package_formatter) write_candidates(candidates []candidate, num int) {
|
||||||
|
for _, c := range candidates {
|
||||||
|
fmt.Printf("%s,,%s,,%s,,%s\n", c.Class, c.Name, c.Type, c.Package)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
// json_formatter
|
// json_formatter
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
@ -145,8 +157,8 @@ func (*json_formatter) write_candidates(candidates []candidate, num int) {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
fmt.Printf(", ")
|
fmt.Printf(", ")
|
||||||
}
|
}
|
||||||
fmt.Printf(`{"class": "%s", "name": "%s", "type": "%s"}`,
|
fmt.Printf(`{"class": "%s", "name": "%s", "type": "%s", "package": "%s"}`,
|
||||||
c.Class, c.Name, c.Type)
|
c.Class, c.Name, c.Type, c.Package)
|
||||||
}
|
}
|
||||||
fmt.Print("]]")
|
fmt.Print("]]")
|
||||||
}
|
}
|
||||||
|
@ -163,6 +175,8 @@ func get_formatter(name string) formatter {
|
||||||
return new(nice_formatter)
|
return new(nice_formatter)
|
||||||
case "csv":
|
case "csv":
|
||||||
return new(csv_formatter)
|
return new(csv_formatter)
|
||||||
|
case "csv-with-package":
|
||||||
|
return new(csv_with_package_formatter)
|
||||||
case "json":
|
case "json":
|
||||||
return new(json_formatter)
|
return new(json_formatter)
|
||||||
case "godit":
|
case "godit":
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
g_is_server = flag.Bool("s", false, "run a server instead of a client")
|
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_format = flag.String("f", "nice", "output format (vim | emacs | nice | csv | csv-with-package | json)")
|
||||||
g_input = flag.String("in", "", "use this file instead of stdin input")
|
g_input = flag.String("in", "", "use this file instead of stdin input")
|
||||||
g_sock = create_sock_flag("sock", "socket type (unix | tcp)")
|
g_sock = create_sock_flag("sock", "socket type (unix | tcp)")
|
||||||
g_addr = flag.String("addr", "127.0.0.1:37373", "address for tcp socket")
|
g_addr = flag.String("addr", "127.0.0.1:37373", "address for tcp socket")
|
||||||
|
@ -40,9 +40,11 @@ func show_usage() {
|
||||||
"\nCommands:\n"+
|
"\nCommands:\n"+
|
||||||
" autocomplete [<path>] <offset> main autocompletion command\n"+
|
" autocomplete [<path>] <offset> main autocompletion command\n"+
|
||||||
" close close the gocode daemon\n"+
|
" close close the gocode daemon\n"+
|
||||||
" status gocode daemon status report\n"+
|
|
||||||
" drop-cache drop gocode daemon's cache\n"+
|
" drop-cache drop gocode daemon's cache\n"+
|
||||||
" set [<name> [<value>]] list or set config options\n")
|
" options list config options (extended)\n"+
|
||||||
|
" set [<name> [<value>]] list or set config options\n"+
|
||||||
|
" status gocode daemon status report\n"+
|
||||||
|
"")
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
@ -20,18 +20,20 @@ type package_parser interface {
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
type package_file_cache struct {
|
type package_file_cache struct {
|
||||||
name string // file name
|
name string // file name
|
||||||
mtime int64
|
import_name string
|
||||||
defalias string
|
mtime int64
|
||||||
|
defalias string
|
||||||
|
|
||||||
scope *scope
|
scope *scope
|
||||||
main *decl // package declaration
|
main *decl // package declaration
|
||||||
others map[string]*decl
|
others map[string]*decl
|
||||||
}
|
}
|
||||||
|
|
||||||
func new_package_file_cache(name string) *package_file_cache {
|
func new_package_file_cache(absname, name string) *package_file_cache {
|
||||||
m := new(package_file_cache)
|
m := new(package_file_cache)
|
||||||
m.name = name
|
m.name = absname
|
||||||
|
m.import_name = name
|
||||||
m.mtime = 0
|
m.mtime = 0
|
||||||
m.defalias = ""
|
m.defalias = ""
|
||||||
return m
|
return m
|
||||||
|
@ -92,7 +94,7 @@ func (m *package_file_cache) update_cache() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *package_file_cache) process_package_data(data []byte) {
|
func (m *package_file_cache) process_package_data(data []byte) {
|
||||||
m.scope = new_scope(g_universe_scope)
|
m.scope = new_named_scope(g_universe_scope, m.name)
|
||||||
|
|
||||||
// find import section
|
// find import section
|
||||||
i := bytes.Index(data, []byte{'\n', '$', '$'})
|
i := bytes.Index(data, []byte{'\n', '$', '$'})
|
||||||
|
@ -126,9 +128,10 @@ func (m *package_file_cache) process_package_data(data []byte) {
|
||||||
pp = &p
|
pp = &p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prefix := "!" + m.name + "!"
|
||||||
pp.parse_export(func(pkg string, decl ast.Decl) {
|
pp.parse_export(func(pkg string, decl ast.Decl) {
|
||||||
anonymify_ast(decl, decl_foreign, m.scope)
|
anonymify_ast(decl, decl_foreign, m.scope)
|
||||||
if pkg == "" || strings.HasPrefix(pkg, "#") {
|
if pkg == "" || strings.HasPrefix(pkg, prefix) {
|
||||||
// main package
|
// main package
|
||||||
add_ast_decl_to_package(m.main, decl, m.scope)
|
add_ast_decl_to_package(m.main, decl, m.scope)
|
||||||
} else {
|
} else {
|
||||||
|
@ -141,12 +144,12 @@ func (m *package_file_cache) process_package_data(data []byte) {
|
||||||
})
|
})
|
||||||
|
|
||||||
// hack, add ourselves to the package scope
|
// hack, add ourselves to the package scope
|
||||||
mainName := "#" + m.defalias
|
mainName := "!" + m.name + "!" + m.defalias
|
||||||
m.add_package_to_scope(mainName, m.name)
|
m.add_package_to_scope(mainName, m.name)
|
||||||
|
|
||||||
// replace dummy package decls in package scope to actual packages
|
// replace dummy package decls in package scope to actual packages
|
||||||
for key := range m.scope.entities {
|
for key := range m.scope.entities {
|
||||||
if !strings.HasPrefix(key, "#") && !strings.HasPrefix(key, "!") {
|
if !strings.HasPrefix(key, "!") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
pkg, ok := m.others[key]
|
pkg, ok := m.others[key]
|
||||||
|
@ -168,7 +171,7 @@ func add_ast_decl_to_package(pkg *decl, decl ast.Decl, scope *scope) {
|
||||||
for i, name := range data.names {
|
for i, name := range data.names {
|
||||||
typ, v, vi := data.type_value_index(i)
|
typ, v, vi := data.type_value_index(i)
|
||||||
|
|
||||||
d := new_decl_full(name.Name, class, decl_foreign, typ, v, vi, scope)
|
d := new_decl_full(name.Name, class, decl_foreign|ast_decl_flags(data.decl), typ, v, vi, scope)
|
||||||
if d == nil {
|
if d == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -218,16 +221,16 @@ func new_package_cache() package_cache {
|
||||||
// In case if package is not in the cache, it creates one and adds one to the cache.
|
// In case if package is not in the cache, it creates one and adds one to the cache.
|
||||||
func (c package_cache) append_packages(ps map[string]*package_file_cache, pkgs []package_import) {
|
func (c package_cache) append_packages(ps map[string]*package_file_cache, pkgs []package_import) {
|
||||||
for _, m := range pkgs {
|
for _, m := range pkgs {
|
||||||
if _, ok := ps[m.path]; ok {
|
if _, ok := ps[m.abspath]; ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if mod, ok := c[m.path]; ok {
|
if mod, ok := c[m.abspath]; ok {
|
||||||
ps[m.path] = mod
|
ps[m.abspath] = mod
|
||||||
} else {
|
} else {
|
||||||
mod = new_package_file_cache(m.path)
|
mod = new_package_file_cache(m.abspath, m.path)
|
||||||
ps[m.path] = mod
|
ps[m.abspath] = mod
|
||||||
c[m.path] = mod
|
c[m.abspath] = mod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -240,11 +243,6 @@ package unsafe
|
||||||
func @"".Offsetof (? any) uintptr
|
func @"".Offsetof (? any) uintptr
|
||||||
func @"".Sizeof (? any) uintptr
|
func @"".Sizeof (? any) uintptr
|
||||||
func @"".Alignof (? any) uintptr
|
func @"".Alignof (? any) uintptr
|
||||||
func @"".Typeof (i interface { }) interface { }
|
|
||||||
func @"".Reflect (i interface { }) (typ interface { }, addr @"".Pointer)
|
|
||||||
func @"".Unreflect (typ interface { }, addr @"".Pointer) interface { }
|
|
||||||
func @"".New (typ interface { }) @"".Pointer
|
|
||||||
func @"".NewArray (typ interface { }, n int) @"".Pointer
|
|
||||||
|
|
||||||
$$
|
$$
|
||||||
`)
|
`)
|
||||||
|
|
|
@ -49,10 +49,11 @@ import (
|
||||||
type gc_bin_parser struct {
|
type gc_bin_parser struct {
|
||||||
data []byte
|
data []byte
|
||||||
buf []byte // for reading strings
|
buf []byte // for reading strings
|
||||||
version int
|
version int // export format version
|
||||||
|
|
||||||
// object lists
|
// object lists
|
||||||
strList []string // in order of appearance
|
strList []string // in order of appearance
|
||||||
|
pathList []string // in order of appearance
|
||||||
pkgList []string // in order of appearance
|
pkgList []string // in order of appearance
|
||||||
typList []ast.Expr // in order of appearance
|
typList []ast.Expr // in order of appearance
|
||||||
callback func(pkg string, decl ast.Decl)
|
callback func(pkg string, decl ast.Decl)
|
||||||
|
@ -72,8 +73,9 @@ type gc_bin_parser struct {
|
||||||
|
|
||||||
func (p *gc_bin_parser) init(data []byte, pfc *package_file_cache) {
|
func (p *gc_bin_parser) init(data []byte, pfc *package_file_cache) {
|
||||||
p.data = data
|
p.data = data
|
||||||
p.version = -1 // unknown version
|
p.version = -1 // unknown version
|
||||||
p.strList = []string{""} // empty string is mapped to 0
|
p.strList = []string{""} // empty string is mapped to 0
|
||||||
|
p.pathList = []string{""} // empty string is mapped to 0
|
||||||
p.pfc = pfc
|
p.pfc = pfc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,17 +113,10 @@ func (p *gc_bin_parser) parse_export(callback func(string, ast.Decl)) {
|
||||||
|
|
||||||
// read version specific flags - extend as necessary
|
// read version specific flags - extend as necessary
|
||||||
switch p.version {
|
switch p.version {
|
||||||
// case 4:
|
// case 6:
|
||||||
// ...
|
// ...
|
||||||
// fallthrough
|
// fallthrough
|
||||||
case 3, 2, 1:
|
case 5, 4, 3, 2, 1:
|
||||||
// Support for Go 1.8 type aliases will be added very
|
|
||||||
// soon (Oct 2016). In the meantime, we make a
|
|
||||||
// best-effort attempt to read v3 export data, failing
|
|
||||||
// if we encounter a type alias. This allows the
|
|
||||||
// automated builders to make progress since
|
|
||||||
// type aliases are not yet used in practice.
|
|
||||||
// TODO(gri): add support for type aliases.
|
|
||||||
p.debugFormat = p.rawStringln(p.rawByte()) == "debug"
|
p.debugFormat = p.rawStringln(p.rawByte()) == "debug"
|
||||||
p.trackAllTypes = p.int() != 0
|
p.trackAllTypes = p.int() != 0
|
||||||
p.posInfoFormat = p.int() != 0
|
p.posInfoFormat = p.int() != 0
|
||||||
|
@ -137,7 +132,8 @@ func (p *gc_bin_parser) parse_export(callback func(string, ast.Decl)) {
|
||||||
p.typList = append(p.typList, predeclared...)
|
p.typList = append(p.typList, predeclared...)
|
||||||
|
|
||||||
// read package data
|
// read package data
|
||||||
p.pfc.defalias = p.pkg()[1:]
|
pkgName := p.pkg()
|
||||||
|
p.pfc.defalias = pkgName[strings.LastIndex(pkgName, "!")+1:]
|
||||||
|
|
||||||
// read objects of phase 1 only (see cmd/compiler/internal/gc/bexport.go)
|
// read objects of phase 1 only (see cmd/compiler/internal/gc/bexport.go)
|
||||||
objcount := 0
|
objcount := 0
|
||||||
|
@ -165,12 +161,17 @@ func (p *gc_bin_parser) pkg() string {
|
||||||
|
|
||||||
// otherwise, i is the package tag (< 0)
|
// otherwise, i is the package tag (< 0)
|
||||||
if i != packageTag {
|
if i != packageTag {
|
||||||
panic(fmt.Sprintf("unexpected package tag %d", i))
|
panic(fmt.Sprintf("unexpected package tag %d version %d", i, p.version))
|
||||||
}
|
}
|
||||||
|
|
||||||
// read package data
|
// read package data
|
||||||
name := p.string()
|
name := p.string()
|
||||||
path := p.string()
|
var path string
|
||||||
|
if p.version >= 5 {
|
||||||
|
path = p.path()
|
||||||
|
} else {
|
||||||
|
path = p.string()
|
||||||
|
}
|
||||||
|
|
||||||
// we should never see an empty package name
|
// we should never see an empty package name
|
||||||
if name == "" {
|
if name == "" {
|
||||||
|
@ -188,7 +189,7 @@ func (p *gc_bin_parser) pkg() string {
|
||||||
fullName = "!" + path + "!" + name
|
fullName = "!" + path + "!" + name
|
||||||
p.pfc.add_package_to_scope(fullName, path)
|
p.pfc.add_package_to_scope(fullName, path)
|
||||||
} else {
|
} else {
|
||||||
fullName = "#" + name
|
fullName = "!" + p.pfc.name + "!" + name
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the package was imported before, use that one; otherwise create a new one
|
// if the package was imported before, use that one; otherwise create a new one
|
||||||
|
@ -213,6 +214,17 @@ func (p *gc_bin_parser) obj(tag int) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
case aliasTag:
|
||||||
|
// TODO(gri) verify type alias hookup is correct
|
||||||
|
p.pos()
|
||||||
|
pkg, name := p.qualifiedName()
|
||||||
|
typ := p.typ("")
|
||||||
|
p.callback(pkg, &ast.GenDecl{
|
||||||
|
Tok: token.TYPE,
|
||||||
|
Specs: []ast.Spec{typeAliasSpec(name, typ)},
|
||||||
|
})
|
||||||
|
|
||||||
case typeTag:
|
case typeTag:
|
||||||
_ = p.typ("")
|
_ = p.typ("")
|
||||||
|
|
||||||
|
@ -229,6 +241,7 @@ func (p *gc_bin_parser) obj(tag int) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
case funcTag:
|
case funcTag:
|
||||||
p.pos()
|
p.pos()
|
||||||
pkg, name := p.qualifiedName()
|
pkg, name := p.qualifiedName()
|
||||||
|
@ -244,6 +257,8 @@ func (p *gc_bin_parser) obj(tag int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const deltaNewFile = -64 // see cmd/compile/internal/gc/bexport.go
|
||||||
|
|
||||||
func (p *gc_bin_parser) pos() {
|
func (p *gc_bin_parser) pos() {
|
||||||
if !p.posInfoFormat {
|
if !p.posInfoFormat {
|
||||||
return
|
return
|
||||||
|
@ -251,15 +266,26 @@ func (p *gc_bin_parser) pos() {
|
||||||
|
|
||||||
file := p.prevFile
|
file := p.prevFile
|
||||||
line := p.prevLine
|
line := p.prevLine
|
||||||
if delta := p.int(); delta != 0 {
|
delta := p.int()
|
||||||
// line changed
|
line += delta
|
||||||
line += delta
|
if p.version >= 5 {
|
||||||
} else if n := p.int(); n >= 0 {
|
if delta == deltaNewFile {
|
||||||
// file changed
|
if n := p.int(); n >= 0 {
|
||||||
file = p.prevFile[:n] + p.string()
|
// file changed
|
||||||
p.prevFile = file
|
file = p.path()
|
||||||
line = p.int()
|
line = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if delta == 0 {
|
||||||
|
if n := p.int(); n >= 0 {
|
||||||
|
// file changed
|
||||||
|
file = p.prevFile[:n] + p.string()
|
||||||
|
line = p.int()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
p.prevFile = file
|
||||||
p.prevLine = line
|
p.prevLine = line
|
||||||
|
|
||||||
// TODO(gri) register new position
|
// TODO(gri) register new position
|
||||||
|
@ -391,10 +417,17 @@ func (p *gc_bin_parser) typ(parent string) ast.Expr {
|
||||||
|
|
||||||
case interfaceTag:
|
case interfaceTag:
|
||||||
i := p.reserveMaybe()
|
i := p.reserveMaybe()
|
||||||
if p.int() != 0 {
|
var embeddeds []*ast.SelectorExpr
|
||||||
panic("unexpected embedded interface")
|
for n := p.int(); n > 0; n-- {
|
||||||
|
p.pos()
|
||||||
|
if named, ok := p.typ(parent).(*ast.SelectorExpr); ok {
|
||||||
|
embeddeds = append(embeddeds, named)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
methods := p.methodList(parent)
|
methods := p.methodList(parent)
|
||||||
|
for _, field := range embeddeds {
|
||||||
|
methods = append(methods, &ast.Field{Type: field})
|
||||||
|
}
|
||||||
return p.recordMaybe(i, &ast.InterfaceType{Methods: &ast.FieldList{List: methods}})
|
return p.recordMaybe(i, &ast.InterfaceType{Methods: &ast.FieldList{List: methods}})
|
||||||
|
|
||||||
case mapTag:
|
case mapTag:
|
||||||
|
@ -429,17 +462,17 @@ func (p *gc_bin_parser) structType(parent string) *ast.StructType {
|
||||||
if n := p.int(); n > 0 {
|
if n := p.int(); n > 0 {
|
||||||
fields = make([]*ast.Field, n)
|
fields = make([]*ast.Field, n)
|
||||||
for i := range fields {
|
for i := range fields {
|
||||||
fields[i] = p.field(parent)
|
fields[i], _ = p.field(parent) // (*ast.Field, tag), not interested in tags
|
||||||
p.string() // tag, not interested in tags
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &ast.StructType{Fields: &ast.FieldList{List: fields}}
|
return &ast.StructType{Fields: &ast.FieldList{List: fields}}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *gc_bin_parser) field(parent string) *ast.Field {
|
func (p *gc_bin_parser) field(parent string) (*ast.Field, string) {
|
||||||
p.pos()
|
p.pos()
|
||||||
_, name := p.fieldName(parent)
|
_, name, _ := p.fieldName(parent)
|
||||||
typ := p.typ(parent)
|
typ := p.typ(parent)
|
||||||
|
tag := p.string()
|
||||||
|
|
||||||
var names []*ast.Ident
|
var names []*ast.Ident
|
||||||
if name != "" {
|
if name != "" {
|
||||||
|
@ -448,7 +481,7 @@ func (p *gc_bin_parser) field(parent string) *ast.Field {
|
||||||
return &ast.Field{
|
return &ast.Field{
|
||||||
Names: names,
|
Names: names,
|
||||||
Type: typ,
|
Type: typ,
|
||||||
}
|
}, tag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *gc_bin_parser) methodList(parent string) (methods []*ast.Field) {
|
func (p *gc_bin_parser) methodList(parent string) (methods []*ast.Field) {
|
||||||
|
@ -463,7 +496,7 @@ func (p *gc_bin_parser) methodList(parent string) (methods []*ast.Field) {
|
||||||
|
|
||||||
func (p *gc_bin_parser) method(parent string) *ast.Field {
|
func (p *gc_bin_parser) method(parent string) *ast.Field {
|
||||||
p.pos()
|
p.pos()
|
||||||
_, name := p.fieldName(parent)
|
_, name, _ := p.fieldName(parent)
|
||||||
params := p.paramList()
|
params := p.paramList()
|
||||||
results := p.paramList()
|
results := p.paramList()
|
||||||
return &ast.Field{
|
return &ast.Field{
|
||||||
|
@ -472,22 +505,32 @@ func (p *gc_bin_parser) method(parent string) *ast.Field {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *gc_bin_parser) fieldName(parent string) (string, string) {
|
func (p *gc_bin_parser) fieldName(parent string) (string, string, bool) {
|
||||||
name := p.string()
|
name := p.string()
|
||||||
pkg := parent
|
pkg := parent
|
||||||
if p.version == 0 && name == "_" {
|
if p.version == 0 && name == "_" {
|
||||||
// versions < 1 don't export a package for _ fields
|
// version 0 didn't export a package for _ fields
|
||||||
// TODO: remove once versions are not supported anymore
|
return pkg, name, false
|
||||||
return pkg, name
|
|
||||||
}
|
}
|
||||||
if name != "" && !exported(name) {
|
var alias bool
|
||||||
// explicitly qualified field
|
switch name {
|
||||||
if name == "?" {
|
case "":
|
||||||
name = ""
|
// 1) field name matches base type name and is exported: nothing to do
|
||||||
}
|
case "?":
|
||||||
|
// 2) field name matches base type name and is not exported: need package
|
||||||
|
name = ""
|
||||||
pkg = p.pkg()
|
pkg = p.pkg()
|
||||||
|
case "@":
|
||||||
|
// 3) field name doesn't match type name (alias)
|
||||||
|
name = p.string()
|
||||||
|
alias = true
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
if !exported(name) {
|
||||||
|
pkg = p.pkg()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return pkg, name
|
return pkg, name, alias
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *gc_bin_parser) paramList() *ast.FieldList {
|
func (p *gc_bin_parser) paramList() *ast.FieldList {
|
||||||
|
@ -594,6 +637,26 @@ func (p *gc_bin_parser) int64() int64 {
|
||||||
return p.rawInt64()
|
return p.rawInt64()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *gc_bin_parser) path() string {
|
||||||
|
if p.debugFormat {
|
||||||
|
p.marker('p')
|
||||||
|
}
|
||||||
|
// if the path was seen before, i is its index (>= 0)
|
||||||
|
// (the empty string is at index 0)
|
||||||
|
i := p.rawInt64()
|
||||||
|
if i >= 0 {
|
||||||
|
return p.pathList[i]
|
||||||
|
}
|
||||||
|
// otherwise, i is the negative path length (< 0)
|
||||||
|
a := make([]string, -i)
|
||||||
|
for n := range a {
|
||||||
|
a[n] = p.string()
|
||||||
|
}
|
||||||
|
s := strings.Join(a, "/")
|
||||||
|
p.pathList = append(p.pathList, s)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
func (p *gc_bin_parser) string() string {
|
func (p *gc_bin_parser) string() string {
|
||||||
if p.debugFormat {
|
if p.debugFormat {
|
||||||
p.marker('s')
|
p.marker('s')
|
||||||
|
@ -710,7 +773,11 @@ const (
|
||||||
fractionTag // not used by gc
|
fractionTag // not used by gc
|
||||||
complexTag
|
complexTag
|
||||||
stringTag
|
stringTag
|
||||||
|
nilTag // only used by gc (appears in exported inlined function bodies)
|
||||||
unknownTag // not used by gc (only appears in packages with errors)
|
unknownTag // not used by gc (only appears in packages with errors)
|
||||||
|
|
||||||
|
// Type aliases
|
||||||
|
aliasTag
|
||||||
)
|
)
|
||||||
|
|
||||||
var predeclared = []ast.Expr{
|
var predeclared = []ast.Expr{
|
||||||
|
@ -733,7 +800,7 @@ var predeclared = []ast.Expr{
|
||||||
ast.NewIdent("complex128"),
|
ast.NewIdent("complex128"),
|
||||||
ast.NewIdent("string"),
|
ast.NewIdent("string"),
|
||||||
|
|
||||||
// aliases
|
// basic type aliases
|
||||||
ast.NewIdent("byte"),
|
ast.NewIdent("byte"),
|
||||||
ast.NewIdent("rune"),
|
ast.NewIdent("rune"),
|
||||||
|
|
||||||
|
|
|
@ -172,7 +172,7 @@ func (p *gc_parser) parse_exported_name() *ast.SelectorExpr {
|
||||||
p.expect('@')
|
p.expect('@')
|
||||||
pkg := p.parse_package()
|
pkg := p.parse_package()
|
||||||
if pkg.Name == "" {
|
if pkg.Name == "" {
|
||||||
pkg.Name = "#" + p.pfc.defalias
|
pkg.Name = "!" + p.pfc.name + "!" + p.pfc.defalias
|
||||||
} else {
|
} else {
|
||||||
pkg.Name = p.path_to_name[pkg.Name]
|
pkg.Name = p.path_to_name[pkg.Name]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// +build !go1.7
|
// +build !go1.7,!go1.8
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
|
|
@ -136,3 +136,27 @@ func client_set(cli *rpc.Client, Arg0, Arg1 string) string {
|
||||||
}
|
}
|
||||||
return reply.Arg0
|
return reply.Arg0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wrapper for: server_options
|
||||||
|
|
||||||
|
type Args_options struct {
|
||||||
|
Arg0 int
|
||||||
|
}
|
||||||
|
type Reply_options struct {
|
||||||
|
Arg0 string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RPC) RPC_options(args *Args_options, reply *Reply_options) error {
|
||||||
|
reply.Arg0 = server_options(args.Arg0)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func client_options(cli *rpc.Client, Arg0 int) string {
|
||||||
|
var args Args_options
|
||||||
|
var reply Reply_options
|
||||||
|
args.Arg0 = Arg0
|
||||||
|
err := cli.Call("RPC.RPC_options", &args, &reply)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return reply.Arg0
|
||||||
|
}
|
||||||
|
|
|
@ -5,12 +5,23 @@ package main
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
type scope struct {
|
type scope struct {
|
||||||
|
// the package name that this scope resides in
|
||||||
|
pkgname string
|
||||||
parent *scope // nil for universe scope
|
parent *scope // nil for universe scope
|
||||||
entities map[string]*decl
|
entities map[string]*decl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func new_named_scope(outer *scope, name string) *scope {
|
||||||
|
s := new_scope(outer)
|
||||||
|
s.pkgname = name
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
func new_scope(outer *scope) *scope {
|
func new_scope(outer *scope) *scope {
|
||||||
s := new(scope)
|
s := new(scope)
|
||||||
|
if outer != nil {
|
||||||
|
s.pkgname = outer.pkgname
|
||||||
|
}
|
||||||
s.parent = outer
|
s.parent = outer
|
||||||
s.entities = make(map[string]*decl)
|
s.entities = make(map[string]*decl)
|
||||||
return s
|
return s
|
||||||
|
|
|
@ -137,7 +137,7 @@ func server_auto_complete(file []byte, filename string, cursor int, context_pack
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
print_backtrace(err)
|
print_backtrace(err)
|
||||||
c = []candidate{
|
c = []candidate{
|
||||||
{"PANIC", "PANIC", decl_invalid},
|
{"PANIC", "PANIC", decl_invalid, "panic"},
|
||||||
}
|
}
|
||||||
|
|
||||||
// drop cache
|
// drop cache
|
||||||
|
@ -186,12 +186,18 @@ func server_auto_complete(file []byte, filename string, cursor int, context_pack
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
log.Printf("Got autocompletion request for '%s'\n", filename)
|
log.Printf("Got autocompletion request for '%s'\n", filename)
|
||||||
log.Printf("Cursor at: %d\n", cursor)
|
log.Printf("Cursor at: %d\n", cursor)
|
||||||
buf.WriteString("-------------------------------------------------------\n")
|
if cursor > len(file) || cursor < 0 {
|
||||||
buf.Write(file[:cursor])
|
log.Println("ERROR! Cursor is outside of the boundaries of the buffer, " +
|
||||||
buf.WriteString("#")
|
"this is most likely a text editor plugin bug. Text editor is responsible " +
|
||||||
buf.Write(file[cursor:])
|
"for passing the correct cursor position to gocode.")
|
||||||
log.Print(buf.String())
|
} else {
|
||||||
log.Println("-------------------------------------------------------")
|
buf.WriteString("-------------------------------------------------------\n")
|
||||||
|
buf.Write(file[:cursor])
|
||||||
|
buf.WriteString("#")
|
||||||
|
buf.Write(file[cursor:])
|
||||||
|
log.Print(buf.String())
|
||||||
|
log.Println("-------------------------------------------------------")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
candidates, d := g_daemon.autocomplete.apropos(file, filename, cursor)
|
candidates, d := g_daemon.autocomplete.apropos(file, filename, cursor)
|
||||||
if *g_debug {
|
if *g_debug {
|
||||||
|
@ -235,3 +241,7 @@ func server_set(key, value string) string {
|
||||||
g_daemon.drop_cache()
|
g_daemon.drop_cache()
|
||||||
return g_config.set_option(key, value)
|
return g_config.set_option(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func server_options(notused int) string {
|
||||||
|
return g_config.options()
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
// +build !go1.9,!go1.8.typealias
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go/ast"
|
||||||
|
)
|
||||||
|
|
||||||
|
func typeAliasSpec(name string, typ ast.Expr) *ast.TypeSpec {
|
||||||
|
return &ast.TypeSpec{
|
||||||
|
Name: ast.NewIdent(name),
|
||||||
|
Type: typ,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isAliasTypeSpec(t *ast.TypeSpec) bool {
|
||||||
|
return false
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
// +build go1.9 go1.8.typealias
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go/ast"
|
||||||
|
)
|
||||||
|
|
||||||
|
func typeAliasSpec(name string, typ ast.Expr) *ast.TypeSpec {
|
||||||
|
return &ast.TypeSpec{
|
||||||
|
Name: ast.NewIdent(name),
|
||||||
|
Assign: 1,
|
||||||
|
Type: typ,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isAliasTypeSpec(t *ast.TypeSpec) bool {
|
||||||
|
return t.Assign != 0
|
||||||
|
}
|
|
@ -153,15 +153,24 @@ func find_gb_project_root(path string) (string, error) {
|
||||||
|
|
||||||
// vendorlessImportPath returns the devendorized version of the provided import path.
|
// vendorlessImportPath returns the devendorized version of the provided import path.
|
||||||
// e.g. "foo/bar/vendor/a/b" => "a/b"
|
// e.g. "foo/bar/vendor/a/b" => "a/b"
|
||||||
func vendorlessImportPath(ipath string) string {
|
func vendorlessImportPath(ipath string, currentPackagePath string) (string, bool) {
|
||||||
|
split := strings.Split(ipath, "vendor/")
|
||||||
|
// no vendor in path
|
||||||
|
if len(split) == 1 {
|
||||||
|
return ipath, true
|
||||||
|
}
|
||||||
|
// this import path does not belong to the current package
|
||||||
|
if currentPackagePath != "" && !strings.Contains(currentPackagePath, split[0]) {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
// Devendorize for use in import statement.
|
// Devendorize for use in import statement.
|
||||||
if i := strings.LastIndex(ipath, "/vendor/"); i >= 0 {
|
if i := strings.LastIndex(ipath, "/vendor/"); i >= 0 {
|
||||||
return ipath[i+len("/vendor/"):]
|
return ipath[i+len("/vendor/"):], true
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(ipath, "vendor/") {
|
if strings.HasPrefix(ipath, "vendor/") {
|
||||||
return ipath[len("vendor/"):]
|
return ipath[len("vendor/"):], true
|
||||||
}
|
}
|
||||||
return ipath
|
return ipath, true
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
|
|
@ -3,10 +3,10 @@
|
||||||
"ignore": "test",
|
"ignore": "test",
|
||||||
"package": [
|
"package": [
|
||||||
{
|
{
|
||||||
"checksumSHA1": "7NpGLW+EOhRLs5cDvi1S+LqUNQ8=",
|
"checksumSHA1": "ZesPb1w0u5/uv/fdVc+G6wOee30=",
|
||||||
"path": "github.com/b3log/wide",
|
"path": "github.com/b3log/wide",
|
||||||
"revision": "f96c8befdf3484ad4d3abdf7a11c7a3d6182d018",
|
"revision": "bfd836c6fc8fbc007ce437db1406455493cd532f",
|
||||||
"revisionTime": "2018-03-13T04:09:30Z"
|
"revisionTime": "2018-03-13T04:57:02Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "83iEp3SqOoIkZUYyR7BOVP4vaGE=",
|
"checksumSHA1": "83iEp3SqOoIkZUYyR7BOVP4vaGE=",
|
||||||
|
@ -45,10 +45,10 @@
|
||||||
"revisionTime": "2015-05-30T03:03:52Z"
|
"revisionTime": "2015-05-30T03:03:52Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "5i+5zScV0FNuG3cmRzRPn6PFsfo=",
|
"checksumSHA1": "gKm38IQHqLfYHwS7B6JDTJzXYYI=",
|
||||||
"path": "github.com/nsf/gocode",
|
"path": "github.com/nsf/gocode",
|
||||||
"revision": "5070dacabf2a80deeaf4ddb0be3761d06fce7be5",
|
"revision": "416643789f088aa5077f667cecde7f966131f6be",
|
||||||
"revisionTime": "2016-11-22T21:38:51Z"
|
"revisionTime": "2018-01-07T08:36:41Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "4fp/TH5nX7seO5p4qJfIj/BokbI=",
|
"checksumSHA1": "4fp/TH5nX7seO5p4qJfIj/BokbI=",
|
||||||
|
|
Loading…
Reference in New Issue