1
1
" sample config:
2
2
"
3
- " - Ctrl+F - trigger FIM completion
3
+ " - Ctrl+F - trigger FIM completion manually
4
4
"
5
5
" run this once to initialise the plugin:
6
6
"
@@ -31,46 +31,30 @@ function! llama#init()
31
31
32
32
let s: line_cur = ' '
33
33
34
+ let s: line_cur_prefix = ' '
35
+ let s: line_cur_suffix = ' '
36
+
34
37
let s: pos_dx = 0
35
38
let s: content = []
36
39
let s: can_accept = v: false
37
40
38
41
let s: timer_fim = -1
39
- let s: t_fim_last = reltime ()
42
+ let s: t_fim_last = reltime ()
43
+ let s: t_fim_start = reltime ()
44
+
45
+ let s: current_job = v: null
40
46
41
47
augroup llama
42
48
autocmd !
43
49
autocmd InsertEnter * inoremap <buffer> <silent> <C-F> <C-O> :call llama#fim(v:false)<CR>
50
+ autocmd InsertLeave * call llama#fim_cancel ()
44
51
augroup END
45
52
46
53
silent ! call llama#fim_cancel ()
47
54
endfunction
48
55
49
- " setup accept/cancel events
50
- function ! llama#on_hint (id_timer)
51
- inoremap <buffer> <Tab> <C-O> :call llama#fim_accept()<CR>
52
- inoremap <buffer> <Esc> <C-O> :call llama#fim_cancel()<CR><Esc>
53
-
54
- augroup llama_insert
55
- autocmd !
56
- autocmd CursorMovedI * call llama#fim_cancel ()
57
- augroup END
58
- endfunction
59
-
60
- function ! llama#fim_auto ()
61
- if reltimefloat (reltime (s: t_fim_last )) < 0.50
62
- if s: timer_fim != -1
63
- call timer_stop (s: timer_fim )
64
- let s: timer_fim = -1
65
- endif
66
- endif
67
-
68
- let s: t_fim_last = reltime ()
69
- let s: timer_fim = timer_start (500 , {- > llama#fim (v: true )})
70
- endfunction
71
-
72
56
function ! llama#fim (is_auto) abort
73
- let l: t_start = reltime ()
57
+ let s: t_fim_start = reltime ()
74
58
75
59
let s: content = []
76
60
let s: can_accept = v: false
@@ -86,16 +70,16 @@ function! llama#fim(is_auto) abort
86
70
87
71
let s: pos_x0 = s: pos_x == len (s: line_cur ) ? s: pos_x : s: pos_x - 1
88
72
89
- let l : line_cur_prefix = strpart (s: line_cur , 0 , s: pos_x0 )
90
- let l : line_cur_suffix = strpart (s: line_cur , s: pos_x0 )
73
+ let s : line_cur_prefix = strpart (s: line_cur , 0 , s: pos_x0 )
74
+ let s : line_cur_suffix = strpart (s: line_cur , s: pos_x0 )
91
75
92
76
let l: prefix = " "
93
77
\ . join (l: lines_prefix , " \n " )
94
78
\ . " \n "
95
- \ . l : line_cur_prefix
79
+ \ . s : line_cur_prefix
96
80
97
81
let l: suffix = " "
98
- \ . l : line_cur_suffix
82
+ \ . s : line_cur_suffix
99
83
\ . " \n "
100
84
\ . join (l: lines_suffix , " \n " )
101
85
\ . " \n "
@@ -116,12 +100,80 @@ function! llama#fim(is_auto) abort
116
100
\ ' samplers' : [" top_k" , " infill" ]
117
101
\ })
118
102
119
- " request completion from the server
120
103
let l: curl_command = printf (
121
104
\ " curl --silent --no-buffer --request POST --url %s --header \" Content-Type: application/json\" --data %s" ,
122
105
\ g: llama_config .endpoint, shellescape (l: request )
123
106
\ )
124
107
108
+ " send the request asynchronously
109
+ let s: current_job = jobstart (l: curl_command , {
110
+ \ ' on_stdout' : function (' s:fim_on_stdout' ),
111
+ \ ' on_exit' : function (' s:fim_on_exit' ),
112
+ \ ' stdout_buffered' : v: true ,
113
+ \ ' is_auto' : a: is_auto
114
+ \ })
115
+ endfunction
116
+
117
+ function ! llama#fim_accept ()
118
+ " insert the suggestion at the cursor location
119
+ if s: can_accept && len (s: content ) > 0
120
+ call setline (s: pos_y , s: line_cur [:(s: pos_x0 - 1 )] . s: content [0 ])
121
+ if len (s: content ) > 1
122
+ call append (s: pos_y , s: content [1 :-1 ])
123
+ endif
124
+
125
+ " move the cursor to the end of the accepted text
126
+ call cursor (s: pos_y + len (s: content ) - 1 , s: pos_x + s: pos_dx )
127
+ endif
128
+
129
+ call llama#fim_cancel ()
130
+ endfunction
131
+
132
+ function ! llama#fim_cancel ()
133
+ if s: current_job != v: null
134
+ call jobstop (s: current_job )
135
+ endif
136
+
137
+ " clear the virtual text
138
+ let l: bufnr = bufnr (' %' )
139
+
140
+ let l: id_vt_fim = nvim_create_namespace (' vt_fim' )
141
+ let l: id_vt_info = nvim_create_namespace (' vt_info' )
142
+
143
+ call nvim_buf_clear_namespace (l: bufnr , l: id_vt_fim , 0 , -1 )
144
+ call nvim_buf_clear_namespace (l: bufnr , l: id_vt_info , 0 , -1 )
145
+
146
+ silent ! iunmap <buffer> <Tab>
147
+ silent ! iunmap <buffer> <Esc>
148
+
149
+ augroup llama_insert
150
+ autocmd !
151
+ if g: llama_config .auto_fim
152
+ autocmd CursorMovedI * call s: fim_auto ()
153
+ endif
154
+ augroup END
155
+ endfunction
156
+
157
+ function ! s: fim_auto ()
158
+ if s: current_job != v: null
159
+ call jobstop (s: current_job )
160
+ endif
161
+
162
+ if reltimefloat (reltime (s: t_fim_last )) < 0.001 * 250
163
+ if s: timer_fim != -1
164
+ call timer_stop (s: timer_fim )
165
+ let s: timer_fim = -1
166
+ endif
167
+ endif
168
+
169
+ let s: t_fim_last = reltime ()
170
+ let s: timer_fim = timer_start (250 , {- > llama#fim (v: true )})
171
+ endfunction
172
+
173
+
174
+ function ! s: fim_on_stdout (job_id, data, event ) dict
175
+ let l: raw = join (a: data , " \n " )
176
+
125
177
let s: can_accept = v: true
126
178
let l: has_info = v: false
127
179
@@ -133,17 +185,15 @@ function! llama#fim(is_auto) abort
133
185
let l: t_gen_ms = 1.0
134
186
let l: s_gen = 0
135
187
136
- " TODO: async this
137
- let l: raw = system (l: curl_command )
138
188
if s: can_accept && v: shell_error
139
- if ! a: is_auto
189
+ if ! self . is_auto
140
190
call add (s: content , " <| curl error: is the server on? |>" )
141
191
endif
142
192
let s: can_accept = v: false
143
193
endif
144
194
145
195
if s: can_accept && l: raw == " "
146
- if ! a: is_auto
196
+ if ! self . is_auto
147
197
call add (s: content , " <| empty response: is the server on? |>" )
148
198
endif
149
199
let s: can_accept = v: false
@@ -178,7 +228,7 @@ function! llama#fim(is_auto) abort
178
228
endif
179
229
180
230
if len (s: content ) == 0
181
- if ! a: is_auto
231
+ if ! self . is_auto
182
232
call add (s: content , " <| nothing to suggest |>" )
183
233
endif
184
234
let s: can_accept = v: false
@@ -189,7 +239,7 @@ function! llama#fim(is_auto) abort
189
239
endif
190
240
191
241
let s: pos_dx = len (s: content [-1 ])
192
- let s: content [-1 ] .= l : line_cur_suffix
242
+ let s: content [-1 ] .= s : line_cur_suffix
193
243
194
244
call llama#fim_cancel ()
195
245
@@ -202,13 +252,13 @@ function! llama#fim(is_auto) abort
202
252
" construct the info message:
203
253
if l: has_info
204
254
" prefix the info string with whitespace in order to offset it to the right of the fim overlay
205
- let l: prefix = repeat (' ' , len (s: content [0 ]) - len (l : line_cur_suffix ) + 3 )
255
+ let l: prefix = repeat (' ' , len (s: content [0 ]) - len (s : line_cur_suffix ) + 3 )
206
256
207
257
let l: info = printf (" %s | prompt: %d (%.2f ms, %.2f t/s) | predict: %d (%.2f ms, %.2f t/s) | total: %f.2 ms" ,
208
258
\ l: prefix ,
209
259
\ l: n_prompt , l: t_prompt_ms , l: s_prompt ,
210
260
\ l: n_gen , l: t_gen_ms , l: s_gen ,
211
- \ 1000.0 * reltimefloat (reltime (l: t_start ))
261
+ \ 1000.0 * reltimefloat (reltime (s: t_fim_start ))
212
262
\ )
213
263
214
264
call nvim_buf_set_extmark (l: bufnr , l: id_vt_info , s: pos_y - 1 , s: pos_x - 1 , {
@@ -227,42 +277,20 @@ function! llama#fim(is_auto) abort
227
277
\ ' virt_text_win_col' : virtcol (' .' )
228
278
\ })
229
279
230
- " need to async this call because the <C-O> in insert mode causes the cursor to move when at the end of the line
231
- call timer_start (0 , ' llama#on_hint' )
232
- endfunction
233
-
234
- function ! llama#fim_accept ()
235
- " insert the suggestion at the cursor location
236
- if s: can_accept && len (s: content ) > 0
237
- call setline (s: pos_y , s: line_cur [:(s: pos_x0 - 1 )] . s: content [0 ])
238
- if len (s: content ) > 1
239
- call append (s: pos_y , s: content [1 :-1 ])
240
- endif
241
-
242
- " move the cursor to the end of the accepted text
243
- call cursor (s: pos_y + len (s: content ) - 1 , s: pos_x + s: pos_dx )
244
- endif
245
-
246
- call llama#fim_cancel ()
247
- endfunction
248
-
249
- function ! llama#fim_cancel ()
250
- " clear the virtual text
251
- let l: bufnr = bufnr (' %' )
252
-
253
- let l: id_vt_fim = nvim_create_namespace (' vt_fim' )
254
- let l: id_vt_info = nvim_create_namespace (' vt_info' )
255
-
256
- call nvim_buf_clear_namespace (l: bufnr , l: id_vt_fim , 0 , -1 )
257
- call nvim_buf_clear_namespace (l: bufnr , l: id_vt_info , 0 , -1 )
258
-
259
- silent ! iunmap <buffer> <Tab>
260
- silent ! iunmap <buffer> <Esc>
280
+ " setup accept/cancel events
281
+ inoremap <buffer> <Tab> <C-O> :call llama#fim_accept()<CR>
282
+ inoremap <buffer> <Esc> <C-O> :call llama#fim_cancel()<CR><Esc>
261
283
262
284
augroup llama_insert
263
285
autocmd !
264
- if g: llama_config .auto_fim
265
- autocmd CursorMovedI * call llama#fim_auto ()
266
- endif
286
+ autocmd CursorMovedI * call llama#fim_cancel ()
267
287
augroup END
268
288
endfunction
289
+
290
+ function ! s: fim_on_exit (job_id, exit_code, event ) dict
291
+ if a: exit_code != 0
292
+ echom " Job failed with exit code: " . a: exit_code
293
+ endif
294
+
295
+ let s: current_job = v: null
296
+ endfunction
0 commit comments