forked from DisposaBoy/GoSublime
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgscomplete.py
122 lines (109 loc) · 4.79 KB
/
gscomplete.py
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
import sublime, sublime_plugin
import json, os
import gscommon as gs
from os.path import basename
class GoSublime(sublime_plugin.EventListener):
gocode_set = False
def on_query_completions(self, view, prefix, locations):
pos = locations[0]
scopes = view.scope_name(pos).split()
if 'source.go' not in scopes or not gs.setting('gscomplete_enabled', False):
return []
# if we complete inside e.g. a map's key we're going to cause subtle bugs so bail
if 'string.quoted.double.go' in scopes or 'string.quoted.single.go' in scopes or 'string.quoted.raw.go' in scopes:
# afaik we must return something in order to disable st2's word completion
return [(' ', '$0')]
if not self.gocode_set:
self.gocode_set = True
# autostart the daemon
gs.runcmd([gs.setting('gocode_cmd', 'gocode')])
# gocode is case-sesitive so push the location back to the 'dot' so it gives
# gives us everything then st2 can pick the matches for us
offset = pos - len(prefix)
src = view.substr(sublime.Region(0, view.size()))
fn = view.file_name()
if not src or not fn:
return []
cl = self.complete(fn, offset, src, view.substr(sublime.Region(pos, pos+1)) == '(')
pc = view.substr(sublime.Region(pos-1, pos))
if gs.setting('autocomplete_snippets', True) and (pc.isspace() or pc.isalpha()):
if scopes[-1] == 'source.go':
cl.extend(gs.GLOBAL_SNIPPETS)
elif scopes[-1] == 'meta.block.go' and ('meta.function.plain.go' in scopes or 'meta.function.receiver.go' in scopes):
cl.extend(gs.LOCAL_SNIPPETS)
return cl
def complete(self, fn, offset, src, func_name_only):
comps = []
cmd = gs.setting('gocode_cmd', 'gocode')
offset = 'c%s' % offset
args = [cmd, "-f=json", "autocomplete", fn, offset]
js, err = gs.runcmd(args, src)
if err:
gs.notice('GsComplete', err)
else:
try:
js = json.loads(js)
if js and js[1]:
for ent in js[1]:
tn = ent['type']
cn = ent['class']
nm = ent['name']
sfx = self.typeclass_prefix(cn, tn)
if cn == 'func':
if nm in ('main', 'init'):
continue
act = gs.setting('autocomplete_tests', False)
if not act and nm.startswith(('Test', 'Benchmark', 'Example')):
continue
params, ret = declex(tn)
ret = ret.strip('() ')
if func_name_only:
a = nm
else:
a = []
for i, p in enumerate(params):
n, t = p
if t.startswith('...'):
n = '...'
a.append('${%d:%s}' % (i+1, n))
a = '%s(%s)' % (nm, ', '.join(a))
comps.append(('%s\t%s %s' % (nm, ret, sfx), a))
elif cn != 'PANIC':
comps.append(('%s\t%s %s' % (nm, tn, sfx), nm))
except KeyError as e:
gs.notice('GsComplete', 'Error while running gocode, possibly malformed data returned: %s' % e)
except ValueError as e:
gs.notice('GsComplete', "Error while decoding gocode output: %s" % e)
return comps
def typeclass_prefix(self, typeclass, typename):
return gs.NAME_PREFIXES.get(typename, gs.CLASS_PREFIXES.get(typeclass, ' '))
def declex(s):
params = []
ret = ''
if s.startswith('func('):
lp = len(s)
sp = 5
ep = sp
dc = 1
names = []
while ep < lp and dc > 0:
c = s[ep]
if dc == 1 and c in (',', ')'):
if sp < ep:
n, _, t = s[sp:ep].strip().partition(' ')
t = t.strip()
if t:
for name in names:
params.append((name, t))
names = []
params.append((n, t))
else:
names.append(n)
sp = ep + 1
if c == '(':
dc += 1
elif c == ')':
dc -= 1
ep += 1
ret = s[ep:].strip() if ep < lp else ''
return (params, ret)