11" sample config:
22"
3- " - Ctrl+F - trigger FIM completion
3+ " - Ctrl+F - trigger FIM completion manually
44"
55" run this once to initialise the plugin:
66"
@@ -31,46 +31,30 @@ function! llama#init()
3131
3232 let s: line_cur = ' '
3333
34+ let s: line_cur_prefix = ' '
35+ let s: line_cur_suffix = ' '
36+
3437 let s: pos_dx = 0
3538 let s: content = []
3639 let s: can_accept = v: false
3740
3841 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
4046
4147 augroup llama
4248 autocmd !
4349 autocmd InsertEnter * inoremap <buffer> <silent> <C-F> <C-O> :call llama#fim(v:false)<CR>
50+ autocmd InsertLeave * call llama#fim_cancel ()
4451 augroup END
4552
4653 silent ! call llama#fim_cancel ()
4754endfunction
4855
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-
7256function ! llama#fim (is_auto) abort
73- let l: t_start = reltime ()
57+ let s: t_fim_start = reltime ()
7458
7559 let s: content = []
7660 let s: can_accept = v: false
@@ -86,16 +70,16 @@ function! llama#fim(is_auto) abort
8670
8771 let s: pos_x0 = s: pos_x == len (s: line_cur ) ? s: pos_x : s: pos_x - 1
8872
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 )
9175
9276 let l: prefix = " "
9377 \ . join (l: lines_prefix , " \n " )
9478 \ . " \n "
95- \ . l : line_cur_prefix
79+ \ . s : line_cur_prefix
9680
9781 let l: suffix = " "
98- \ . l : line_cur_suffix
82+ \ . s : line_cur_suffix
9983 \ . " \n "
10084 \ . join (l: lines_suffix , " \n " )
10185 \ . " \n "
@@ -116,12 +100,80 @@ function! llama#fim(is_auto) abort
116100 \ ' samplers' : [" top_k" , " infill" ]
117101 \ })
118102
119- " request completion from the server
120103 let l: curl_command = printf (
121104 \ " curl --silent --no-buffer --request POST --url %s --header \" Content-Type: application/json\" --data %s" ,
122105 \ g: llama_config .endpoint, shellescape (l: request )
123106 \ )
124107
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+
125177 let s: can_accept = v: true
126178 let l: has_info = v: false
127179
@@ -133,17 +185,15 @@ function! llama#fim(is_auto) abort
133185 let l: t_gen_ms = 1.0
134186 let l: s_gen = 0
135187
136- " TODO: async this
137- let l: raw = system (l: curl_command )
138188 if s: can_accept && v: shell_error
139- if ! a: is_auto
189+ if ! self . is_auto
140190 call add (s: content , " <| curl error: is the server on? |>" )
141191 endif
142192 let s: can_accept = v: false
143193 endif
144194
145195 if s: can_accept && l: raw == " "
146- if ! a: is_auto
196+ if ! self . is_auto
147197 call add (s: content , " <| empty response: is the server on? |>" )
148198 endif
149199 let s: can_accept = v: false
@@ -178,7 +228,7 @@ function! llama#fim(is_auto) abort
178228 endif
179229
180230 if len (s: content ) == 0
181- if ! a: is_auto
231+ if ! self . is_auto
182232 call add (s: content , " <| nothing to suggest |>" )
183233 endif
184234 let s: can_accept = v: false
@@ -189,7 +239,7 @@ function! llama#fim(is_auto) abort
189239 endif
190240
191241 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
193243
194244 call llama#fim_cancel ()
195245
@@ -202,13 +252,13 @@ function! llama#fim(is_auto) abort
202252 " construct the info message:
203253 if l: has_info
204254 " 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 )
206256
207257 let l: info = printf (" %s | prompt: %d (%.2f ms, %.2f t/s) | predict: %d (%.2f ms, %.2f t/s) | total: %f.2 ms" ,
208258 \ l: prefix ,
209259 \ l: n_prompt , l: t_prompt_ms , l: s_prompt ,
210260 \ 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 ))
212262 \ )
213263
214264 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
227277 \ ' virt_text_win_col' : virtcol (' .' )
228278 \ })
229279
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>
261283
262284 augroup llama_insert
263285 autocmd !
264- if g: llama_config .auto_fim
265- autocmd CursorMovedI * call llama#fim_auto ()
266- endif
286+ autocmd CursorMovedI * call llama#fim_cancel ()
267287 augroup END
268288endfunction
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