forked from x-motemen/gore
-
Notifications
You must be signed in to change notification settings - Fork 0
/
gocode.go
126 lines (104 loc) · 2.59 KB
/
gocode.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// Package gocode is an interface to github.com/nsf/gocode.
package gocode
import (
"encoding/json"
"fmt"
"io"
"os/exec"
)
// DefaultCompleter is a default Completer with gocode's path set to "gocode".
var DefaultCompleter = Completer{
GocodePath: "gocode",
}
// Completer is the interface to gocode that this package provides.
type Completer struct {
// The path to gocode
GocodePath string
unavailable bool
}
// Result represents a completion result of Query().
type Result struct {
// Cursor position within Candidates
Cursor int
// The list of Candidates
Candidates []Candidate
}
// Candidate is resulting entries from gocode.
type Candidate struct {
// One of "package", "func", "type", "var", "const".
Class string `json:"class"`
// The name of the candidate.
Name string `json:"name"`
// The type (in Go) of the candidate.
Type string `json:"type"`
}
// Query asks gocode for completion of Go code source for a cursor position cursor.
func Query(source []byte, cursor int) (*Result, error) {
return DefaultCompleter.Query(source, cursor)
}
// Available checks if gocode executable is available or not.
func Available() bool {
return DefaultCompleter.Available()
}
// Query asks gocode for completion of Go code source for a cursor position cursor.
func (c *Completer) Query(source []byte, cursor int) (*Result, error) {
cmd := exec.Command(c.GocodePath, "-f=json", "autocomplete", fmt.Sprintf("%d", cursor))
in, err := cmd.StdinPipe()
if err != nil {
return nil, err
}
err = writeClose(in, source)
if err != nil {
return nil, err
}
out, err := cmd.Output()
if err != nil {
if _, ok := err.(*exec.Error); ok {
// cannot invoke gocode
c.unavailable = true
}
return nil, err
}
var result Result
err = json.Unmarshal(out, &result)
if err != nil {
return nil, err
}
return &result, nil
}
// Available checks if gocode executable is available or not.
func (c *Completer) Available() bool {
if c.unavailable {
return false
}
_, err := exec.LookPath(c.GocodePath)
if err != nil {
c.unavailable = true
return false
}
return true
}
func writeClose(w io.WriteCloser, buf []byte) error {
_, err := w.Write(buf)
if err != nil {
return err
}
return w.Close()
}
// UnmarshalJSON decodes JSON bytes text to Result.
func (r *Result) UnmarshalJSON(text []byte) error {
result := []json.RawMessage{}
err := json.Unmarshal(text, &result)
if err != nil {
return err
}
if len(result) < 2 {
return nil
}
err = json.Unmarshal(result[0], &r.Cursor)
if err != nil {
return err
}
r.Candidates = make([]Candidate, 0)
return json.Unmarshal(result[1], &r.Candidates)
}