Skip to content

Pass through package names, use it for godoc in emacs-company #463

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Merged
merged 5 commits into from
Aug 25, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 33 additions & 17 deletions autocompletecontext.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ import (

// fields must be exported for RPC
type candidate struct {
Name string
Type string
Class decl_class
Name string
Type string
Class decl_class
Package string
}

type out_buffers struct {
Expand All @@ -43,7 +44,7 @@ func new_out_buffers(ctx *auto_complete_context) *out_buffers {
b.ctx = ctx
b.canonical_aliases = make(map[string]string)
for _, imp := range b.ctx.current.packages {
b.canonical_aliases[imp.path] = imp.alias
b.canonical_aliases[imp.abspath] = imp.alias
}
return b
}
Expand All @@ -65,7 +66,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)
Expand All @@ -78,14 +79,15 @@ func (b *out_buffers) append_decl(p, name string, decl *decl, class decl_class)

decl.pretty_print_type(b.tmpbuf, b.canonical_aliases)
b.candidates = append(b.candidates, candidate{
Name: name,
Type: b.tmpbuf.String(),
Class: decl.class,
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
}
Expand Down Expand Up @@ -119,10 +121,10 @@ func (b *out_buffers) append_embedded(p string, decl *decl, class decl_class) {
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 {
Expand Down Expand Up @@ -208,7 +210,11 @@ 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)
}
}

Expand All @@ -229,6 +235,16 @@ func (c *auto_complete_context) get_candidates_from_decl_alias(cc cursor_context
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)
Expand All @@ -246,19 +262,19 @@ 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) {
Expand Down Expand Up @@ -482,7 +498,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
}
Expand All @@ -500,7 +516,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
}
Expand Down
2 changes: 1 addition & 1 deletion cursorcontext.go
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ func resolveKnownPackageIdent(ident string, filename string, context *package_lo
return nil
}

p := new_package_file_cache(path)
p := new_package_file_cache(path, path)
p.update_cache()
return p.main
}
Expand Down
9 changes: 5 additions & 4 deletions declcache.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ import (
//-------------------------------------------------------------------------

type package_import struct {
alias string
path string
alias string
abspath string
path string
}

// Parses import declarations until the first non-import declaration and fills
Expand All @@ -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 {
Expand Down
33 changes: 32 additions & 1 deletion emacs-company/company-go.el
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ symbol is preceded by a \".\", ignoring `company-minimum-prefix-length'."
:group 'company-go
:type '(repeat string))

(defcustom company-go-godoc-command "go doc"
"The command to invoke `go doc' with."
:group 'company-go
:type 'string)

(defcustom company-go-godoc-args "-u"
"Arguments to pass to `go doc'."
:group 'company-go
:type 'string)

(defun company-go--invoke-autocomplete ()
(let ((code-buffer (current-buffer))
(gocode-args (append company-go-gocode-args
Expand Down Expand Up @@ -90,7 +100,10 @@ symbol is preceded by a \".\", ignoring `company-minimum-prefix-length'."
(defun company-go--get-candidates (strings)
(mapcar (lambda (str)
(let ((candidate (split-string str ",,")))
(propertize (nth 1 candidate) 'meta (company-go--format-meta candidate)))) strings))
(propertize (nth 1 candidate)
'meta (company-go--format-meta candidate)
'package (nth 3 candidate))))
strings))

(defun company-go--candidates ()
(let ((candidates (company-go--get-candidates (split-string (company-go--invoke-autocomplete) "\n" t))))
Expand Down Expand Up @@ -207,6 +220,22 @@ triggers a completion immediately."
(buffer-string))
str))

(defun company-go--godoc-as-buffer (arg)
"Return Go documentation for QUERY as a buffer."
(unless (string= arg "")
(let* ((package (get-text-property 0 'package arg))
(query (if (string= package "")
arg
(format "%s.%s" package arg)))
(buf (godoc--get-buffer query))
(exit-code (call-process-shell-command
(concat company-go-godoc-command " " company-go-godoc-args " " query)
nil buf nil)))
(if (zerop exit-code)
buf
(kill-buffer buf)
nil))))

;;;###autoload
(defun company-go (command &optional arg &rest ignored)
(interactive (list 'interactive))
Expand All @@ -223,6 +252,8 @@ triggers a completion immediately."
(when company-go-show-annotation
(company-go--extract-annotation (get-text-property 0 'meta arg))))
(location (company-go--location arg))
(doc-buffer
(company-go--godoc-as-buffer arg))
(sorted t)
(post-completion
(when (and company-go-insert-arguments
Expand Down
6 changes: 3 additions & 3 deletions formatters.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ type csv_formatter struct{}

func (*csv_formatter) write_candidates(candidates []candidate, num int) {
for _, c := range candidates {
fmt.Printf("%s,,%s,,%s\n", c.Class, c.Name, c.Type)
fmt.Printf("%s,,%s,,%s,,%s\n", c.Class, c.Name, c.Type, c.Package)
}
}

Expand All @@ -145,8 +145,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("]]")
}
Expand Down
26 changes: 14 additions & 12 deletions package.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,20 @@ type package_parser interface {
//-------------------------------------------------------------------------

type package_file_cache struct {
name string // file name
mtime int64
defalias string
name string // file name
import_name string
mtime int64
defalias string

scope *scope
main *decl // package declaration
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
Expand Down Expand Up @@ -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', '$', '$'})
Expand Down Expand Up @@ -219,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
}
}
}
Expand Down
11 changes: 11 additions & 0 deletions scope.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down