➕ Update gocode in vendor
This commit is contained in:
parent
bfd836c6fc
commit
0a51a03f35
|
@ -1,20 +1,13 @@
|
|||
FROM golang:latest
|
||||
MAINTAINER Liang Ding <d@b3log.org>
|
||||
|
||||
ENV GOROOT /usr/local/go
|
||||
|
||||
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/
|
||||
ADD . /go/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 useradd wide && useradd runner
|
||||
|
||||
ENV GOPATH /wide/gogogo
|
||||
|
||||
WORKDIR /wide/gogogo/src/github.com/b3log/wide
|
||||
WORKDIR /go/src/github.com/b3log/wide
|
||||
RUN go build -v
|
||||
|
||||
EXPOSE 7070
|
||||
|
|
|
@ -8,7 +8,7 @@ set -e
|
|||
echo "mode: count" > profile.cov
|
||||
|
||||
# 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
|
||||
if ls $dir/*.go &> /dev/null; then
|
||||
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*
|
||||
|
||||
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*
|
||||
|
||||
|
@ -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).
|
||||
|
||||
- *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
|
||||
|
||||
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/parser"
|
||||
"go/token"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
@ -25,11 +26,13 @@ type candidate struct {
|
|||
Name string
|
||||
Type string
|
||||
Class decl_class
|
||||
Package string
|
||||
}
|
||||
|
||||
type out_buffers struct {
|
||||
tmpbuf *bytes.Buffer
|
||||
candidates []candidate
|
||||
canonical_aliases map[string]string
|
||||
ctx *auto_complete_context
|
||||
tmpns map[string]bool
|
||||
ignorecase bool
|
||||
|
@ -40,6 +43,10 @@ func new_out_buffers(ctx *auto_complete_context) *out_buffers {
|
|||
b.tmpbuf = bytes.NewBuffer(make([]byte, 0, 1024))
|
||||
b.candidates = make([]candidate, 0, 64)
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -60,7 +67,7 @@ func (b *out_buffers) Swap(i, j int) {
|
|||
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"
|
||||
c2 := class != decl_invalid && decl.class != class
|
||||
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
|
||||
}
|
||||
|
||||
decl.pretty_print_type(b.tmpbuf)
|
||||
decl.pretty_print_type(b.tmpbuf, b.canonical_aliases)
|
||||
b.candidates = append(b.candidates, candidate{
|
||||
Name: name,
|
||||
Type: b.tmpbuf.String(),
|
||||
Class: decl.class,
|
||||
Package: pkg,
|
||||
})
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
@ -103,21 +111,26 @@ func (b *out_buffers) append_embedded(p string, decl *decl, class decl_class) {
|
|||
continue
|
||||
}
|
||||
|
||||
// could be type alias
|
||||
if typedecl.is_alias() {
|
||||
typedecl = typedecl.type_dealias()
|
||||
}
|
||||
|
||||
// prevent infinite recursion here
|
||||
if typedecl.flags&decl_visited != 0 {
|
||||
if typedecl.is_visited() {
|
||||
continue
|
||||
}
|
||||
typedecl.flags |= decl_visited
|
||||
typedecl.set_visited()
|
||||
defer typedecl.clear_visited()
|
||||
|
||||
for _, c := range typedecl.children {
|
||||
if _, has := b.tmpns[c.name]; has {
|
||||
continue
|
||||
}
|
||||
b.append_decl(p, c.name, c, class)
|
||||
b.append_decl(p, c.name, pkg, c, class)
|
||||
b.tmpns[c.name] = true
|
||||
}
|
||||
b.append_embedded(p, typedecl, class)
|
||||
b.append_embedded(p, typedecl, pkg, class)
|
||||
}
|
||||
|
||||
if first_level {
|
||||
|
@ -183,6 +196,12 @@ func (c *auto_complete_context) merge_decls() {
|
|||
merge_decls(f.filescope, c.pkg, f.decls)
|
||||
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 {
|
||||
|
@ -197,11 +216,47 @@ func (c *auto_complete_context) get_candidates_from_set(set map[string]*decl, pa
|
|||
continue
|
||||
}
|
||||
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) {
|
||||
if cc.decl.is_alias() {
|
||||
c.get_candidates_from_decl_alias(cc, class, b)
|
||||
return
|
||||
}
|
||||
|
||||
// propose all children of a subject declaration and
|
||||
for _, decl := range cc.decl.children {
|
||||
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
|
||||
}
|
||||
}
|
||||
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
|
||||
adecl := advance_to_struct_or_interface(cc.decl)
|
||||
if adecl != nil && adecl != cc.decl {
|
||||
for _, decl := range adecl.children {
|
||||
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
|
||||
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) {
|
||||
pkgdirs := g_daemon.context.pkg_dirs()
|
||||
currentPackagePath, pkgdirs := g_daemon.context.pkg_dirs()
|
||||
resultSet := map[string]struct{}{}
|
||||
for _, pkgdir := range pkgdirs {
|
||||
// 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 {
|
||||
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 match bool
|
||||
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) {
|
||||
continue
|
||||
} 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 {
|
||||
ext := filepath.Ext(name)
|
||||
if ext != ".a" {
|
||||
|
@ -267,7 +322,9 @@ func get_import_candidates_dir(root, partial string, ignorecase bool, r map[stri
|
|||
} else {
|
||||
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. ;)
|
||||
|
||||
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)
|
||||
partial := len(cc.partial)
|
||||
if !g_config.Partials {
|
||||
if *g_debug {
|
||||
log.Printf("not performing partial prefix matching")
|
||||
}
|
||||
cc.partial = ""
|
||||
}
|
||||
if !ok {
|
||||
var d *decl
|
||||
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 {
|
||||
return nil, 0
|
||||
|
@ -320,6 +393,7 @@ func (c *auto_complete_context) apropos(file []byte, filename string, cursor int
|
|||
}
|
||||
|
||||
class := decl_invalid
|
||||
if g_config.ClassFiltering {
|
||||
switch cc.partial {
|
||||
case "const":
|
||||
class = decl_const
|
||||
|
@ -332,6 +406,7 @@ func (c *auto_complete_context) apropos(file []byte, filename string, cursor int
|
|||
case "package":
|
||||
class = decl_package
|
||||
}
|
||||
}
|
||||
|
||||
if cc.decl_import {
|
||||
c.get_import_candidates(cc.partial, b)
|
||||
|
@ -357,7 +432,6 @@ func (c *auto_complete_context) apropos(file []byte, filename string, cursor int
|
|||
c.get_candidates_from_decl(cc, class, b)
|
||||
}
|
||||
}
|
||||
partial = len(cc.partial)
|
||||
|
||||
if len(b.candidates) == 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) {
|
||||
for _, d := range decls {
|
||||
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) {
|
||||
for _, p := range pkgs {
|
||||
path, alias := p.path, p.alias
|
||||
path, alias := p.abspath, p.alias
|
||||
if alias != "." {
|
||||
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) {
|
||||
for _, p := range pkgs {
|
||||
path, alias := p.path, p.alias
|
||||
path, alias := p.abspath, p.alias
|
||||
if alias == "" {
|
||||
alias = pcache[path].defalias
|
||||
}
|
||||
|
@ -555,7 +675,6 @@ func check_type_expr(e ast.Expr) bool {
|
|||
default:
|
||||
return true
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
|
|
@ -141,7 +141,7 @@ func (f *auto_complete_file) process_decl(decl ast.Decl) {
|
|||
for i, name := range data.names {
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
@ -243,9 +243,11 @@ 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 {
|
||||
vname := astmt.Lhs[0].(*ast.Ident).Name
|
||||
v := new_decl_var(vname, nil, astmt.Rhs[0], -1, prevscope)
|
||||
if v != nil {
|
||||
f.scope.add_named_decl(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, s := range last_cursor_after.Body {
|
||||
f.process_stmt(s)
|
||||
}
|
||||
|
|
|
@ -50,6 +50,8 @@ func do_client() int {
|
|||
cmd_drop_cache(client)
|
||||
case "set":
|
||||
cmd_set(client)
|
||||
case "options":
|
||||
cmd_options(client)
|
||||
default:
|
||||
fmt.Printf("unknown argument: %q, try running \"gocode -h\"\n", flag.Arg(0))
|
||||
return 1
|
||||
|
@ -180,3 +182,7 @@ func cmd_set(c *rpc.Client) {
|
|||
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"
|
||||
"os"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
|
@ -28,9 +29,27 @@ type config struct {
|
|||
PackageLookupMode string `json:"package-lookup-mode"`
|
||||
CloseTimeout int `json:"close-timeout"`
|
||||
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,
|
||||
LibPath: "",
|
||||
CustomPkgPrefix: "",
|
||||
|
@ -39,7 +58,11 @@ var g_config = config{
|
|||
PackageLookupMode: "go",
|
||||
CloseTimeout: 1800,
|
||||
UnimportedPackages: false,
|
||||
Partials: true,
|
||||
IgnoreCase: false,
|
||||
ClassFiltering: true,
|
||||
}
|
||||
var g_config = g_default_config
|
||||
|
||||
var g_string_to_bool = map[string]bool{
|
||||
"t": true,
|
||||
|
@ -175,3 +198,43 @@ func (this *config) read() error {
|
|||
|
||||
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 {
|
||||
if i.tok.IsLiteral() {
|
||||
return i.lit
|
||||
} else {
|
||||
return i.tok.String()
|
||||
}
|
||||
return ""
|
||||
return i.tok.String()
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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.
|
||||
// Examples (# - the cursor):
|
||||
// &lib.Struct{Whatever: 1, Hel#} // returns "lib.Struct"
|
||||
|
@ -130,23 +150,21 @@ func (ti *token_iterator) extract_struct_type() string {
|
|||
if !ti.go_back() {
|
||||
return ""
|
||||
}
|
||||
if ti.token().tok != token.IDENT {
|
||||
if ti.token().tok == token.LBRACE { // Foo{#{}}
|
||||
if !ti.go_back() {
|
||||
return ""
|
||||
}
|
||||
b := ti.token().literal()
|
||||
if !ti.go_back() {
|
||||
return b
|
||||
} else if ti.token().tok == token.COMMA { // Foo{abc,#{}}
|
||||
return ti.extract_struct_type()
|
||||
}
|
||||
if ti.token().tok != token.PERIOD {
|
||||
return b
|
||||
typ := ti.extract_type_alike()
|
||||
if typ == "" {
|
||||
return ""
|
||||
}
|
||||
if !ti.go_back() {
|
||||
return b
|
||||
if ti.token().tok == token.RPAREN || ti.token().tok == token.MUL {
|
||||
return ""
|
||||
}
|
||||
if ti.token().tok != token.IDENT {
|
||||
return b
|
||||
}
|
||||
return ti.token().literal() + "." + b
|
||||
return typ
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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 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
|
||||
// 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?
|
||||
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]
|
||||
if !ok {
|
||||
return nil
|
||||
|
@ -406,9 +431,9 @@ func resolveKnownPackageIdent(ident string, filename string, context *package_lo
|
|||
return nil
|
||||
}
|
||||
|
||||
p := new_package_file_cache(path)
|
||||
p := new_package_file_cache(path, importPath)
|
||||
p.update_cache()
|
||||
return p.main
|
||||
return p
|
||||
}
|
||||
|
||||
var knownPackageIdents = map[string]string{
|
||||
|
|
|
@ -56,12 +56,15 @@ func (this decl_class) String() string {
|
|||
type decl_flags int16
|
||||
|
||||
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
|
||||
// its type is inferred in a special way
|
||||
decl_rangevar
|
||||
|
||||
// decl of decl_type class is a type alias
|
||||
decl_alias
|
||||
|
||||
// for preventing infinite recursions and loops in type inference code
|
||||
decl_visited
|
||||
)
|
||||
|
@ -115,7 +118,19 @@ func ast_decl_type(d ast.Decl) ast.Expr {
|
|||
return t.Type
|
||||
}
|
||||
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 {
|
||||
|
@ -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 {
|
||||
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) {
|
||||
case *ast.StarExpr:
|
||||
if se, ok := t.X.(*ast.SelectorExpr); ok {
|
||||
|
@ -348,6 +363,7 @@ func (other *decl) deep_copy() *decl {
|
|||
d := new(decl)
|
||||
d.name = other.name
|
||||
d.class = other.class
|
||||
d.flags = other.flags
|
||||
d.typ = other.typ
|
||||
d.value = other.value
|
||||
d.value_index = other.value_index
|
||||
|
@ -363,20 +379,36 @@ func (other *decl) deep_copy() *decl {
|
|||
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() {
|
||||
d.flags &^= decl_visited
|
||||
}
|
||||
|
||||
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 {
|
||||
d = other
|
||||
return
|
||||
}
|
||||
|
||||
if d.class == decl_methods_stub {
|
||||
d.typ = other.typ
|
||||
d.class = other.class
|
||||
d.flags = other.flags
|
||||
}
|
||||
|
||||
if other.children != nil {
|
||||
|
@ -398,7 +430,7 @@ func (d *decl) matches() bool {
|
|||
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 {
|
||||
case decl_type:
|
||||
switch d.typ.(type) {
|
||||
|
@ -410,15 +442,15 @@ func (d *decl) pretty_print_type(out io.Writer) {
|
|||
fmt.Fprintf(out, "interface")
|
||||
default:
|
||||
if d.typ != nil {
|
||||
pretty_print_type_expr(out, d.typ)
|
||||
pretty_print_type_expr(out, d.typ, canonical_aliases)
|
||||
}
|
||||
}
|
||||
case decl_var:
|
||||
if d.typ != nil {
|
||||
pretty_print_type_expr(out, d.typ)
|
||||
pretty_print_type_expr(out, d.typ, canonical_aliases)
|
||||
}
|
||||
case decl_func:
|
||||
pretty_print_type_expr(out, d.typ)
|
||||
pretty_print_type_expr(out, d.typ, canonical_aliases)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -481,18 +513,15 @@ func func_return_type(f *ast.FuncType, index int) ast.Expr {
|
|||
i := 0
|
||||
var field *ast.Field
|
||||
for _, field = range f.Results.List {
|
||||
if i >= index {
|
||||
return field.Type
|
||||
}
|
||||
n := 1
|
||||
if field.Names != nil {
|
||||
i += len(field.Names)
|
||||
} else {
|
||||
i++
|
||||
n = len(field.Names)
|
||||
}
|
||||
}
|
||||
if i >= index {
|
||||
if i <= index && index < i+n {
|
||||
return field.Type
|
||||
}
|
||||
i += n
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -599,20 +628,20 @@ func advance_to_type(pred type_predicate, v ast.Expr, scope *scope) (ast.Expr, *
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
if decl.flags&decl_visited != 0 {
|
||||
if decl.is_visited() {
|
||||
return nil, nil
|
||||
}
|
||||
decl.flags |= decl_visited
|
||||
decl.set_visited()
|
||||
defer decl.clear_visited()
|
||||
|
||||
return advance_to_type(pred, decl.typ, decl.scope)
|
||||
}
|
||||
|
||||
func advance_to_struct_or_interface(decl *decl) *decl {
|
||||
if decl.flags&decl_visited != 0 {
|
||||
if decl.is_visited() {
|
||||
return nil
|
||||
}
|
||||
decl.flags |= decl_visited
|
||||
decl.set_visited()
|
||||
defer decl.clear_visited()
|
||||
|
||||
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.
|
||||
func (d *decl) infer_type() (ast.Expr, *scope) {
|
||||
// special case for range vars
|
||||
if d.flags&decl_rangevar != 0 {
|
||||
if d.is_rangevar() {
|
||||
var scope *scope
|
||||
d.typ, scope = infer_range_type(d.value, d.scope, d.value_index)
|
||||
return d.typ, scope
|
||||
|
@ -937,10 +966,10 @@ func (d *decl) infer_type() (ast.Expr, *scope) {
|
|||
}
|
||||
|
||||
// prevent loops
|
||||
if d.flags&decl_visited != 0 {
|
||||
if d.is_visited() {
|
||||
return nil, nil
|
||||
}
|
||||
d.flags |= decl_visited
|
||||
d.set_visited()
|
||||
defer d.clear_visited()
|
||||
|
||||
var scope *scope
|
||||
|
@ -948,13 +977,34 @@ func (d *decl) infer_type() (ast.Expr, *scope) {
|
|||
return d.typ, scope
|
||||
}
|
||||
|
||||
func (d *decl) find_child(name string) *decl {
|
||||
if d.flags&decl_visited != 0 {
|
||||
func (d *decl) type_dealias() *decl {
|
||||
if d.is_visited() {
|
||||
return nil
|
||||
}
|
||||
d.flags |= decl_visited
|
||||
d.set_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 c, ok := d.children[name]; ok {
|
||||
return c
|
||||
|
@ -963,6 +1013,12 @@ func (d *decl) find_child(name string) *decl {
|
|||
|
||||
decl := advance_to_struct_or_interface(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 nil
|
||||
|
@ -1053,11 +1109,11 @@ func get_array_len(e ast.Expr) string {
|
|||
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) {
|
||||
case *ast.StarExpr:
|
||||
fmt.Fprintf(out, "*")
|
||||
pretty_print_type_expr(out, t.X)
|
||||
pretty_print_type_expr(out, t.X, canonical_aliases)
|
||||
case *ast.Ident:
|
||||
if strings.HasPrefix(t.Name, "$") {
|
||||
// beautify anonymous types
|
||||
|
@ -1070,15 +1126,19 @@ func pretty_print_type_expr(out io.Writer, e ast.Expr) {
|
|||
// it's always true
|
||||
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, "!") {
|
||||
// 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
|
||||
// another ugly hack, if people are punished in hell for ugly hacks
|
||||
// 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 {
|
||||
fmt.Fprintf(out, t.Name)
|
||||
}
|
||||
|
@ -1092,17 +1152,17 @@ func pretty_print_type_expr(out io.Writer, e ast.Expr) {
|
|||
} else {
|
||||
fmt.Fprintf(out, "[]")
|
||||
}
|
||||
pretty_print_type_expr(out, t.Elt)
|
||||
pretty_print_type_expr(out, t.Elt, canonical_aliases)
|
||||
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)
|
||||
case *ast.FuncType:
|
||||
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, ")")
|
||||
|
||||
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 {
|
||||
results := buf.String()
|
||||
if strings.IndexAny(results, ", ") != -1 {
|
||||
|
@ -1112,14 +1172,14 @@ func pretty_print_type_expr(out io.Writer, e ast.Expr) {
|
|||
}
|
||||
case *ast.MapType:
|
||||
fmt.Fprintf(out, "map[")
|
||||
pretty_print_type_expr(out, t.Key)
|
||||
pretty_print_type_expr(out, t.Key, canonical_aliases)
|
||||
fmt.Fprintf(out, "]")
|
||||
pretty_print_type_expr(out, t.Value)
|
||||
pretty_print_type_expr(out, t.Value, canonical_aliases)
|
||||
case *ast.InterfaceType:
|
||||
fmt.Fprintf(out, "interface{}")
|
||||
case *ast.Ellipsis:
|
||||
fmt.Fprintf(out, "...")
|
||||
pretty_print_type_expr(out, t.Elt)
|
||||
pretty_print_type_expr(out, t.Elt, canonical_aliases)
|
||||
case *ast.StructType:
|
||||
fmt.Fprintf(out, "struct")
|
||||
case *ast.ChanType:
|
||||
|
@ -1131,10 +1191,10 @@ func pretty_print_type_expr(out io.Writer, e ast.Expr) {
|
|||
case ast.SEND | ast.RECV:
|
||||
fmt.Fprintf(out, "chan ")
|
||||
}
|
||||
pretty_print_type_expr(out, t.Value)
|
||||
pretty_print_type_expr(out, t.Value, canonical_aliases)
|
||||
case *ast.ParenExpr:
|
||||
fmt.Fprintf(out, "(")
|
||||
pretty_print_type_expr(out, t.X)
|
||||
pretty_print_type_expr(out, t.X, canonical_aliases)
|
||||
fmt.Fprintf(out, ")")
|
||||
case *ast.BadExpr:
|
||||
// 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
|
||||
if f == nil {
|
||||
return count
|
||||
|
@ -1172,7 +1232,7 @@ func pretty_print_func_field_list(out io.Writer, f *ast.FieldList) int {
|
|||
}
|
||||
|
||||
// type
|
||||
pretty_print_type_expr(out, field.Type)
|
||||
pretty_print_type_expr(out, field.Type, canonical_aliases)
|
||||
|
||||
// ,
|
||||
if i != len(f.List)-1 {
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
|
||||
type package_import struct {
|
||||
alias string
|
||||
abspath string
|
||||
path string
|
||||
}
|
||||
|
||||
|
@ -32,9 +33,9 @@ func collect_package_imports(filename string, decls []ast.Decl, context *package
|
|||
for _, spec := range gd.Specs {
|
||||
imp := spec.(*ast.ImportSpec)
|
||||
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 != "_" {
|
||||
pi = append(pi, package_import{alias, path})
|
||||
pi = append(pi, package_import{alias, abspath, path})
|
||||
}
|
||||
}
|
||||
} 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 {
|
||||
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 {
|
||||
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
|
||||
if g_config.PackageLookupMode == "gb" && 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) {
|
||||
log_found_package_maybe(imp, pkg_path)
|
||||
return pkg_path, true
|
||||
|
@ -453,9 +458,10 @@ func (ctxt *package_lookup_context) gopath() []string {
|
|||
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)
|
||||
|
||||
var currentPackagePath string
|
||||
var all []string
|
||||
if ctxt.GOROOT != "" {
|
||||
dir := filepath.Join(ctxt.GOROOT, "pkg", pkgdir)
|
||||
|
@ -466,15 +472,23 @@ func (ctxt *package_lookup_context) pkg_dirs() []string {
|
|||
|
||||
switch g_config.PackageLookupMode {
|
||||
case "go":
|
||||
currentPackagePath = ctxt.CurrentPackagePath
|
||||
for _, p := range ctxt.gopath() {
|
||||
dir := filepath.Join(p, "pkg", pkgdir)
|
||||
if is_dir(dir) {
|
||||
all = append(all, dir)
|
||||
}
|
||||
dir = filepath.Join(dir, currentPackagePath, "vendor")
|
||||
if is_dir(dir) {
|
||||
all = append(all, dir)
|
||||
}
|
||||
}
|
||||
case "gb":
|
||||
if ctxt.GBProjectRoot != "" {
|
||||
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)
|
||||
if is_dir(dir) {
|
||||
all = append(all, dir)
|
||||
|
@ -483,7 +497,7 @@ func (ctxt *package_lookup_context) pkg_dirs() []string {
|
|||
case "bzl":
|
||||
// TODO: Support bazel mode
|
||||
}
|
||||
return all
|
||||
return currentPackagePath, all
|
||||
}
|
||||
|
||||
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
|
||||
//-------------------------------------------------------------------------
|
||||
|
@ -145,8 +157,8 @@ func (*json_formatter) write_candidates(candidates []candidate, num int) {
|
|||
if i != 0 {
|
||||
fmt.Printf(", ")
|
||||
}
|
||||
fmt.Printf(`{"class": "%s", "name": "%s", "type": "%s"}`,
|
||||
c.Class, c.Name, c.Type)
|
||||
fmt.Printf(`{"class": "%s", "name": "%s", "type": "%s", "package": "%s"}`,
|
||||
c.Class, c.Name, c.Type, c.Package)
|
||||
}
|
||||
fmt.Print("]]")
|
||||
}
|
||||
|
@ -163,6 +175,8 @@ func get_formatter(name string) formatter {
|
|||
return new(nice_formatter)
|
||||
case "csv":
|
||||
return new(csv_formatter)
|
||||
case "csv-with-package":
|
||||
return new(csv_with_package_formatter)
|
||||
case "json":
|
||||
return new(json_formatter)
|
||||
case "godit":
|
||||
|
|
|
@ -12,7 +12,7 @@ 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_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_sock = create_sock_flag("sock", "socket type (unix | tcp)")
|
||||
g_addr = flag.String("addr", "127.0.0.1:37373", "address for tcp socket")
|
||||
|
@ -40,9 +40,11 @@ func show_usage() {
|
|||
"\nCommands:\n"+
|
||||
" autocomplete [<path>] <offset> main autocompletion command\n"+
|
||||
" close close the gocode daemon\n"+
|
||||
" status gocode daemon status report\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() {
|
||||
|
|
|
@ -21,6 +21,7 @@ type package_parser interface {
|
|||
|
||||
type package_file_cache struct {
|
||||
name string // file name
|
||||
import_name string
|
||||
mtime int64
|
||||
defalias string
|
||||
|
||||
|
@ -29,9 +30,10 @@ type package_file_cache struct {
|
|||
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.name = name
|
||||
m.name = absname
|
||||
m.import_name = name
|
||||
m.mtime = 0
|
||||
m.defalias = ""
|
||||
return m
|
||||
|
@ -92,7 +94,7 @@ func (m *package_file_cache) update_cache() {
|
|||
}
|
||||
|
||||
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
|
||||
i := bytes.Index(data, []byte{'\n', '$', '$'})
|
||||
|
@ -126,9 +128,10 @@ func (m *package_file_cache) process_package_data(data []byte) {
|
|||
pp = &p
|
||||
}
|
||||
|
||||
prefix := "!" + m.name + "!"
|
||||
pp.parse_export(func(pkg string, decl ast.Decl) {
|
||||
anonymify_ast(decl, decl_foreign, m.scope)
|
||||
if pkg == "" || strings.HasPrefix(pkg, "#") {
|
||||
if pkg == "" || strings.HasPrefix(pkg, prefix) {
|
||||
// main package
|
||||
add_ast_decl_to_package(m.main, decl, m.scope)
|
||||
} else {
|
||||
|
@ -141,12 +144,12 @@ func (m *package_file_cache) process_package_data(data []byte) {
|
|||
})
|
||||
|
||||
// hack, add ourselves to the package scope
|
||||
mainName := "#" + m.defalias
|
||||
mainName := "!" + m.name + "!" + m.defalias
|
||||
m.add_package_to_scope(mainName, m.name)
|
||||
|
||||
// replace dummy package decls in package scope to actual packages
|
||||
for key := range m.scope.entities {
|
||||
if !strings.HasPrefix(key, "#") && !strings.HasPrefix(key, "!") {
|
||||
if !strings.HasPrefix(key, "!") {
|
||||
continue
|
||||
}
|
||||
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 {
|
||||
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 {
|
||||
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.
|
||||
func (c package_cache) append_packages(ps map[string]*package_file_cache, pkgs []package_import) {
|
||||
for _, m := range pkgs {
|
||||
if _, ok := ps[m.path]; ok {
|
||||
if _, ok := ps[m.abspath]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if mod, ok := c[m.path]; ok {
|
||||
ps[m.path] = mod
|
||||
if mod, ok := c[m.abspath]; ok {
|
||||
ps[m.abspath] = mod
|
||||
} else {
|
||||
mod = new_package_file_cache(m.path)
|
||||
ps[m.path] = mod
|
||||
c[m.path] = mod
|
||||
mod = new_package_file_cache(m.abspath, m.path)
|
||||
ps[m.abspath] = mod
|
||||
c[m.abspath] = mod
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -240,11 +243,6 @@ package unsafe
|
|||
func @"".Offsetof (? any) uintptr
|
||||
func @"".Sizeof (? 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 {
|
||||
data []byte
|
||||
buf []byte // for reading strings
|
||||
version int
|
||||
version int // export format version
|
||||
|
||||
// object lists
|
||||
strList []string // in order of appearance
|
||||
pathList []string // in order of appearance
|
||||
pkgList []string // in order of appearance
|
||||
typList []ast.Expr // in order of appearance
|
||||
callback func(pkg string, decl ast.Decl)
|
||||
|
@ -74,6 +75,7 @@ func (p *gc_bin_parser) init(data []byte, pfc *package_file_cache) {
|
|||
p.data = data
|
||||
p.version = -1 // unknown version
|
||||
p.strList = []string{""} // empty string is mapped to 0
|
||||
p.pathList = []string{""} // empty string is mapped to 0
|
||||
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
|
||||
switch p.version {
|
||||
// case 4:
|
||||
// case 6:
|
||||
// ...
|
||||
// fallthrough
|
||||
case 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.
|
||||
case 5, 4, 3, 2, 1:
|
||||
p.debugFormat = p.rawStringln(p.rawByte()) == "debug"
|
||||
p.trackAllTypes = 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...)
|
||||
|
||||
// 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)
|
||||
objcount := 0
|
||||
|
@ -165,12 +161,17 @@ func (p *gc_bin_parser) pkg() string {
|
|||
|
||||
// otherwise, i is the package tag (< 0)
|
||||
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
|
||||
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
|
||||
if name == "" {
|
||||
|
@ -188,7 +189,7 @@ func (p *gc_bin_parser) pkg() string {
|
|||
fullName = "!" + path + "!" + name
|
||||
p.pfc.add_package_to_scope(fullName, path)
|
||||
} else {
|
||||
fullName = "#" + name
|
||||
fullName = "!" + p.pfc.name + "!" + name
|
||||
}
|
||||
|
||||
// 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:
|
||||
_ = p.typ("")
|
||||
|
||||
|
@ -229,6 +241,7 @@ func (p *gc_bin_parser) obj(tag int) {
|
|||
},
|
||||
},
|
||||
})
|
||||
|
||||
case funcTag:
|
||||
p.pos()
|
||||
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() {
|
||||
if !p.posInfoFormat {
|
||||
return
|
||||
|
@ -251,15 +266,26 @@ func (p *gc_bin_parser) pos() {
|
|||
|
||||
file := p.prevFile
|
||||
line := p.prevLine
|
||||
if delta := p.int(); delta != 0 {
|
||||
// line changed
|
||||
delta := p.int()
|
||||
line += delta
|
||||
} else if n := p.int(); n >= 0 {
|
||||
if p.version >= 5 {
|
||||
if delta == deltaNewFile {
|
||||
if n := p.int(); n >= 0 {
|
||||
// file changed
|
||||
file = p.path()
|
||||
line = n
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if delta == 0 {
|
||||
if n := p.int(); n >= 0 {
|
||||
// file changed
|
||||
file = p.prevFile[:n] + p.string()
|
||||
p.prevFile = file
|
||||
line = p.int()
|
||||
}
|
||||
}
|
||||
}
|
||||
p.prevFile = file
|
||||
p.prevLine = line
|
||||
|
||||
// TODO(gri) register new position
|
||||
|
@ -391,10 +417,17 @@ func (p *gc_bin_parser) typ(parent string) ast.Expr {
|
|||
|
||||
case interfaceTag:
|
||||
i := p.reserveMaybe()
|
||||
if p.int() != 0 {
|
||||
panic("unexpected embedded interface")
|
||||
var embeddeds []*ast.SelectorExpr
|
||||
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)
|
||||
for _, field := range embeddeds {
|
||||
methods = append(methods, &ast.Field{Type: field})
|
||||
}
|
||||
return p.recordMaybe(i, &ast.InterfaceType{Methods: &ast.FieldList{List: methods}})
|
||||
|
||||
case mapTag:
|
||||
|
@ -429,17 +462,17 @@ func (p *gc_bin_parser) structType(parent string) *ast.StructType {
|
|||
if n := p.int(); n > 0 {
|
||||
fields = make([]*ast.Field, n)
|
||||
for i := range fields {
|
||||
fields[i] = p.field(parent)
|
||||
p.string() // tag, not interested in tags
|
||||
fields[i], _ = p.field(parent) // (*ast.Field, tag), not interested in tags
|
||||
}
|
||||
}
|
||||
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()
|
||||
_, name := p.fieldName(parent)
|
||||
_, name, _ := p.fieldName(parent)
|
||||
typ := p.typ(parent)
|
||||
tag := p.string()
|
||||
|
||||
var names []*ast.Ident
|
||||
if name != "" {
|
||||
|
@ -448,7 +481,7 @@ func (p *gc_bin_parser) field(parent string) *ast.Field {
|
|||
return &ast.Field{
|
||||
Names: names,
|
||||
Type: typ,
|
||||
}
|
||||
}, tag
|
||||
}
|
||||
|
||||
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 {
|
||||
p.pos()
|
||||
_, name := p.fieldName(parent)
|
||||
_, name, _ := p.fieldName(parent)
|
||||
params := p.paramList()
|
||||
results := p.paramList()
|
||||
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()
|
||||
pkg := parent
|
||||
if p.version == 0 && name == "_" {
|
||||
// versions < 1 don't export a package for _ fields
|
||||
// TODO: remove once versions are not supported anymore
|
||||
return pkg, name
|
||||
// version 0 didn't export a package for _ fields
|
||||
return pkg, name, false
|
||||
}
|
||||
if name != "" && !exported(name) {
|
||||
// explicitly qualified field
|
||||
if name == "?" {
|
||||
var alias bool
|
||||
switch name {
|
||||
case "":
|
||||
// 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()
|
||||
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 {
|
||||
|
@ -594,6 +637,26 @@ func (p *gc_bin_parser) int64() int64 {
|
|||
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 {
|
||||
if p.debugFormat {
|
||||
p.marker('s')
|
||||
|
@ -710,7 +773,11 @@ const (
|
|||
fractionTag // not used by gc
|
||||
complexTag
|
||||
stringTag
|
||||
nilTag // only used by gc (appears in exported inlined function bodies)
|
||||
unknownTag // not used by gc (only appears in packages with errors)
|
||||
|
||||
// Type aliases
|
||||
aliasTag
|
||||
)
|
||||
|
||||
var predeclared = []ast.Expr{
|
||||
|
@ -733,7 +800,7 @@ var predeclared = []ast.Expr{
|
|||
ast.NewIdent("complex128"),
|
||||
ast.NewIdent("string"),
|
||||
|
||||
// aliases
|
||||
// basic type aliases
|
||||
ast.NewIdent("byte"),
|
||||
ast.NewIdent("rune"),
|
||||
|
||||
|
|
|
@ -172,7 +172,7 @@ func (p *gc_parser) parse_exported_name() *ast.SelectorExpr {
|
|||
p.expect('@')
|
||||
pkg := p.parse_package()
|
||||
if pkg.Name == "" {
|
||||
pkg.Name = "#" + p.pfc.defalias
|
||||
pkg.Name = "!" + p.pfc.name + "!" + p.pfc.defalias
|
||||
} else {
|
||||
pkg.Name = p.path_to_name[pkg.Name]
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build !go1.7
|
||||
// +build !go1.7,!go1.8
|
||||
|
||||
package main
|
||||
|
||||
|
|
|
@ -136,3 +136,27 @@ func client_set(cli *rpc.Client, Arg0, Arg1 string) string {
|
|||
}
|
||||
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 {
|
||||
// the package name that this scope resides in
|
||||
pkgname string
|
||||
parent *scope // nil for universe scope
|
||||
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 {
|
||||
s := new(scope)
|
||||
if outer != nil {
|
||||
s.pkgname = outer.pkgname
|
||||
}
|
||||
s.parent = outer
|
||||
s.entities = make(map[string]*decl)
|
||||
return s
|
||||
|
|
|
@ -137,7 +137,7 @@ func server_auto_complete(file []byte, filename string, cursor int, context_pack
|
|||
if err := recover(); err != nil {
|
||||
print_backtrace(err)
|
||||
c = []candidate{
|
||||
{"PANIC", "PANIC", decl_invalid},
|
||||
{"PANIC", "PANIC", decl_invalid, "panic"},
|
||||
}
|
||||
|
||||
// drop cache
|
||||
|
@ -186,6 +186,11 @@ func server_auto_complete(file []byte, filename string, cursor int, context_pack
|
|||
var buf bytes.Buffer
|
||||
log.Printf("Got autocompletion request for '%s'\n", filename)
|
||||
log.Printf("Cursor at: %d\n", cursor)
|
||||
if cursor > len(file) || cursor < 0 {
|
||||
log.Println("ERROR! Cursor is outside of the boundaries of the buffer, " +
|
||||
"this is most likely a text editor plugin bug. Text editor is responsible " +
|
||||
"for passing the correct cursor position to gocode.")
|
||||
} else {
|
||||
buf.WriteString("-------------------------------------------------------\n")
|
||||
buf.Write(file[:cursor])
|
||||
buf.WriteString("#")
|
||||
|
@ -193,6 +198,7 @@ func server_auto_complete(file []byte, filename string, cursor int, context_pack
|
|||
log.Print(buf.String())
|
||||
log.Println("-------------------------------------------------------")
|
||||
}
|
||||
}
|
||||
candidates, d := g_daemon.autocomplete.apropos(file, filename, cursor)
|
||||
if *g_debug {
|
||||
log.Printf("Offset: %d\n", d)
|
||||
|
@ -235,3 +241,7 @@ func server_set(key, value string) string {
|
|||
g_daemon.drop_cache()
|
||||
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.
|
||||
// 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.
|
||||
if i := strings.LastIndex(ipath, "/vendor/"); i >= 0 {
|
||||
return ipath[i+len("/vendor/"):]
|
||||
return ipath[i+len("/vendor/"):], true
|
||||
}
|
||||
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",
|
||||
"package": [
|
||||
{
|
||||
"checksumSHA1": "7NpGLW+EOhRLs5cDvi1S+LqUNQ8=",
|
||||
"checksumSHA1": "ZesPb1w0u5/uv/fdVc+G6wOee30=",
|
||||
"path": "github.com/b3log/wide",
|
||||
"revision": "f96c8befdf3484ad4d3abdf7a11c7a3d6182d018",
|
||||
"revisionTime": "2018-03-13T04:09:30Z"
|
||||
"revision": "bfd836c6fc8fbc007ce437db1406455493cd532f",
|
||||
"revisionTime": "2018-03-13T04:57:02Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "83iEp3SqOoIkZUYyR7BOVP4vaGE=",
|
||||
|
@ -45,10 +45,10 @@
|
|||
"revisionTime": "2015-05-30T03:03:52Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "5i+5zScV0FNuG3cmRzRPn6PFsfo=",
|
||||
"checksumSHA1": "gKm38IQHqLfYHwS7B6JDTJzXYYI=",
|
||||
"path": "github.com/nsf/gocode",
|
||||
"revision": "5070dacabf2a80deeaf4ddb0be3761d06fce7be5",
|
||||
"revisionTime": "2016-11-22T21:38:51Z"
|
||||
"revision": "416643789f088aa5077f667cecde7f966131f6be",
|
||||
"revisionTime": "2018-01-07T08:36:41Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "4fp/TH5nX7seO5p4qJfIj/BokbI=",
|
||||
|
|
Loading…
Reference in New Issue