1
1
let s: sock_type = (has (' win32' ) || has (' win64' )) ? ' tcp' : ' unix'
2
2
3
- function ! s: gocodeCurrentBuffer () abort
4
- let file = tempname ()
5
- call writefile (go#util#GetLines (), file )
6
- return file
7
- endfunction
8
-
9
- function ! s: gocodeCommand (cmd, preargs, args ) abort
10
- for i in range (0 , len (a: args ) - 1 )
11
- let a: args [i ] = go#util#Shellescape (a: args [i ])
12
- endfor
13
- for i in range (0 , len (a: preargs ) - 1 )
14
- let a: preargs [i ] = go#util#Shellescape (a: preargs [i ])
15
- endfor
16
-
3
+ function ! s: gocodeCommand (cmd, args ) abort
17
4
let bin_path = go#path#CheckBinPath (" gocode" )
18
5
if empty (bin_path)
19
- return
6
+ return []
20
7
endif
21
8
9
+ let socket_type = get (g: , ' go_gocode_socket_type' , s: sock_type )
10
+
11
+ let cmd = [bin_path]
12
+ let cmd = extend (cmd, [' -sock' , socket_type])
13
+ let cmd = extend (cmd, [' -f' , ' vim' ])
14
+ let cmd = extend (cmd, [a: cmd ])
15
+ let cmd = extend (cmd, a: args )
16
+
17
+ return cmd
18
+ endfunction
19
+
20
+ function ! s: sync_gocode (cmd, args , input ) abort
22
21
" We might hit cache problems, as gocode doesn't handle different GOPATHs
23
22
" well. See: https://github.com/nsf/gocode/issues/239
24
23
let old_goroot = $GOROOT
25
24
let $GOROOT = go#util#env (" goroot" )
26
25
27
26
try
28
- let socket_type = get (g: , ' go_gocode_socket_type' , s: sock_type )
29
- let cmd = printf (' %s -sock %s %s %s %s' ,
30
- \ go#util#Shellescape (bin_path),
31
- \ socket_type,
32
- \ join (a: preargs ),
33
- \ go#util#Shellescape (a: cmd ),
34
- \ join (a: args )
35
- \ )
36
-
27
+ let cmd = s: gocodeCommand (a: cmd , a: args )
37
28
" gocode can sometimes be slow, so redraw now to avoid waiting for gocode
38
29
" to return before redrawing automatically.
39
30
redraw
40
31
41
- let result = go#util#System (cmd)
32
+ let [ l: result, l: err ] = go#util#Exec (cmd, a: input )
42
33
finally
43
34
let $GOROOT = old_goroot
44
35
endtry
45
36
46
- if go#util#ShellError () != 0
47
- return " [\" 0\" , []]"
48
- else
49
- if &encoding != ' utf-8'
50
- let result = iconv (result, ' utf-8' , &encoding )
51
- endif
52
- return result
37
+ if l: err != 0
38
+ return " [0, []]"
39
+ endif
40
+
41
+ if &encoding != ' utf-8'
42
+ let l: result = iconv (l: result , ' utf-8' , &encoding )
53
43
endif
54
- endfunction
55
44
56
- function ! s: gocodeCurrentBufferOpt (filename) abort
57
- return ' -in=' . a: filename
45
+ return l: result
58
46
endfunction
59
47
48
+ " TODO(bc): reset when gocode isn't running
60
49
let s: optionsEnabled = 0
61
50
function ! s: gocodeEnableOptions () abort
62
51
if s: optionsEnabled
@@ -82,62 +71,161 @@ endfunction
82
71
function ! s: gocodeAutocomplete () abort
83
72
call s: gocodeEnableOptions ()
84
73
85
- let filename = s: gocodeCurrentBuffer ()
86
- let result = s: gocodeCommand (' autocomplete' ,
87
- \ [s: gocodeCurrentBufferOpt (filename), ' -f=vim' ],
88
- \ [expand (' %:p' ), go#util#OffsetCursor ()])
89
- call delete (filename)
90
- return result
74
+ " use the offset as is, because the cursor position is the position for
75
+ " which autocomplete candidates are needed.
76
+ return s: sync_gocode (' autocomplete' ,
77
+ \ [expand (' %:p' ), go#util#OffsetCursor ()],
78
+ \ go#util#GetLines ())
91
79
endfunction
92
80
81
+ " go#complete#GoInfo returns the description of the identifier under the
82
+ " cursor.
93
83
function ! go#complete#GetInfo () abort
84
+ return s: sync_info (0 )
85
+ endfunction
86
+
87
+ function ! go#complete#Info (auto) abort
88
+ if go#util#has_job ()
89
+ return s: async_info (a: auto )
90
+ else
91
+ return s: sync_info (a: auto )
92
+ endif
93
+ endfunction
94
+
95
+ function ! s: async_info (auto)
96
+ if exists (" s:async_info_job" )
97
+ call job_stop (s: async_info_job )
98
+ unlet s: async_info_job
99
+ endif
100
+
101
+ let state = {
102
+ \ ' exited' : 0 ,
103
+ \ ' exit_status' : 0 ,
104
+ \ ' closed' : 0 ,
105
+ \ ' messages' : [],
106
+ \ ' auto' : a: auto
107
+ \ }
108
+
109
+ function ! s: callback (chan, msg) dict
110
+ let l: msg = a: msg
111
+ if &encoding != ' utf-8'
112
+ let l: msg = iconv (l: msg , ' utf-8' , &encoding )
113
+ endif
114
+ call add (self .messages , l: msg )
115
+ endfunction
116
+
117
+ function ! s: exit_cb (job, exitval) dict
118
+ let self .exit_status = a: exitval
119
+ let self .exited = 1
120
+
121
+ if self .closed
122
+ call self .complete ()
123
+ endif
124
+ endfunction
125
+
126
+ function ! s: close_cb (ch ) dict
127
+ let self .closed = 1
128
+ if self .exited
129
+ call self .complete ()
130
+ endif
131
+ endfunction
132
+
133
+ function state .complete () dict
134
+ if self .exit_status != 0
135
+ return
136
+ endif
137
+
138
+ let result = s: info_filter (self .auto, join (self .messages , " \n " ))
139
+ call s: info_complete (self .auto, result)
140
+ endfunction
141
+
142
+ " add 1 to the offset, so that the position at the cursor will be included
143
+ " in gocode's search
94
144
let offset = go#util#OffsetCursor ()+ 1
95
- let filename = s: gocodeCurrentBuffer ()
96
- let result = s: gocodeCommand (' autocomplete' ,
97
- \ [s: gocodeCurrentBufferOpt (filename), ' -f=godit' ],
145
+
146
+ " We might hit cache problems, as gocode doesn't handle different GOPATHs
147
+ " well. See: https://github.com/nsf/gocode/issues/239
148
+ let env = {
149
+ \ " GOROOT" : go#util#env (" goroot" )
150
+ \ }
151
+
152
+ let cmd = s: gocodeCommand (' autocomplete' ,
98
153
\ [expand (' %:p' ), offset])
99
- call delete (filename)
100
154
101
- " first line is: Charcount,,NumberOfCandidates, i.e: 8,,1
102
- " following lines are candiates, i.e: func foo(name string),,foo(
103
- let out = split (result, ' \n' )
155
+ " TODO(bc): Don't write the buffer to a file; pass the buffer directrly to
156
+ " gocode's stdin. It shouldn't be necessary to use {in_io: 'file', in_name:
157
+ " s:gocodeFile()}, but unfortunately {in_io: 'buffer', in_buf: bufnr('%')}
158
+ " should work.
159
+ let options = {
160
+ \ ' env' : env,
161
+ \ ' in_io' : ' file' ,
162
+ \ ' in_name' : s: gocodeFile (),
163
+ \ ' callback' : funcref (" s:callback" , [], state ),
164
+ \ ' exit_cb' : funcref (" s:exit_cb" , [], state ),
165
+ \ ' close_cb' : funcref (" s:close_cb" , [], state )
166
+ \ }
104
167
105
- " no candidates are found
106
- if len (out) == 1
168
+ let s: async_info_job = job_start (cmd, options )
169
+ endfunction
170
+
171
+ function ! s: gocodeFile ()
172
+ let file = tempname ()
173
+ call writefile (go#util#GetLines (), file )
174
+ return file
175
+ endfunction
176
+
177
+ function ! s: sync_info (auto)
178
+ " auto is true if we were called by g:go_auto_type_info's autocmd
179
+
180
+ " add 1 to the offset, so that the position at the cursor will be included
181
+ " in gocode's search
182
+ let offset = go#util#OffsetCursor ()+ 1
183
+
184
+ let result = s: sync_gocode (' autocomplete' ,
185
+ \ [expand (' %:p' ), offset],
186
+ \ go#util#GetLines ())
187
+
188
+ let result = s: info_filter (a: auto , result)
189
+ call s: info_complete (a: auto , result)
190
+ endfunction
191
+
192
+ function ! s: info_filter (auto, result) abort
193
+ if empty (a: result )
107
194
return " "
108
195
endif
109
196
110
- " only one candidate is found
111
- if len (out) = = 2
112
- return split (out[ 1 ], ' ,, ' )[ 0 ]
197
+ let l: result = eval ( a: result )
198
+ if len (l: result ) ! = 2
199
+ return " "
113
200
endif
114
201
115
- " to many candidates are available, pick one that maches the word under the
116
- " cursor
117
- let infos = []
118
- for info in out[1 :]
119
- call add (infos, split (info, ' ,,' )[0 ])
120
- endfor
202
+ let l: candidates = l: result [1 ]
203
+ if len (l: candidates ) == 1
204
+ " When gocode panics in vim mode, it returns
205
+ " [0, [{'word': 'PANIC', 'abbr': 'PANIC PANIC PANIC', 'info': 'PANIC PANIC PANIC'}]]
206
+ if a: auto && l: candidates [0 ].info == # " PANIC PANIC PANIC"
207
+ return " "
208
+ endif
209
+
210
+ return l: candidates [0 ].info
211
+ endif
121
212
213
+ let filtered = []
122
214
let wordMatch = ' \<' . expand (" <cword>" ) . ' \>'
123
215
" escape single quotes in wordMatch before passing it to filter
124
216
let wordMatch = substitute (wordMatch, " '" , " ''" , " g" )
125
- let filtered = filter (infos , " v:val =~ '" .wordMatch." '" )
217
+ let filtered = filter (l: candidates , " v:val.info =~ '" .wordMatch." '" )
126
218
127
- if len (filtered) = = 1
128
- return filtered[ 0 ]
219
+ if len (l: filtered ) ! = 1
220
+ return " "
129
221
endif
130
222
131
- return " "
223
+ return l: filtered [ 0 ].info
132
224
endfunction
133
225
134
- function ! go#complete#Info (auto) abort
135
- " auto is true if we were called by g:go_auto_type_info's autocmd
136
- let result = go#complete#GetInfo ()
137
- if ! empty (result)
138
- " if auto, and the result is a PANIC by gocode, hide it
139
- if a: auto && result == # ' PANIC PANIC PANIC' | return | endif
140
- echo " vim-go: " | echohl Function | echon result | echohl None
226
+ function ! s: info_complete (auto, result) abort
227
+ if ! empty (a: result )
228
+ echo " vim-go: " | echohl Function | echon a: result | echohl None
141
229
endif
142
230
endfunction
143
231
@@ -146,20 +234,22 @@ function! s:trim_bracket(val) abort
146
234
return a: val
147
235
endfunction
148
236
237
+ let s: completions = " "
149
238
function ! go#complete#Complete (findstart, base) abort
150
239
" findstart = 1 when we need to get the text length
151
240
if a: findstart == 1
152
- execute " silent let g:gocomplete_completions = " . s: gocodeAutocomplete ()
153
- return col (' .' ) - g: gocomplete_completions [0 ] - 1
241
+ execute " silent let s:completions = " . s: gocodeAutocomplete ()
242
+ return col (' .' ) - s: completions [0 ] - 1
154
243
" findstart = 0 when we need to return the list of completions
155
244
else
156
245
let s = getline (" ." )[col (' .' ) - 1 ]
157
246
if s = ~ ' [(){}\{\}]'
158
- return map (copy (g: gocomplete_completions [1 ]), ' s:trim_bracket(v:val)' )
247
+ return map (copy (s: completions [1 ]), ' s:trim_bracket(v:val)' )
159
248
endif
160
- return g: gocomplete_completions [1 ]
249
+
250
+ return s: completions [1 ]
161
251
endif
162
- endf
252
+ endfunction
163
253
164
254
function ! go#complete#ToggleAutoTypeInfo () abort
165
255
if get (g: , " go_auto_type_info" , 0 )
@@ -172,5 +262,4 @@ function! go#complete#ToggleAutoTypeInfo() abort
172
262
call go#util#EchoProgress (" auto type info enabled" )
173
263
endfunction
174
264
175
-
176
265
" vim: sw = 2 ts = 2 et
0 commit comments