2
2
"
3
3
" - Ctrl+F - trigger FIM completion
4
4
"
5
- " copy paste this in your .vimrc :
5
+ " run this once to initialise the plugin :
6
6
"
7
- " augroup llama_cpp
8
- " autocmd!
9
- " autocmd InsertEnter * inoremap <buffer> <silent> <C-F> <Esc>:call llama#fim()<CR>a
10
- " augroup END
7
+ " :call llama#init()
11
8
"
12
9
13
10
" color of the suggested text
@@ -21,24 +18,76 @@ let s:default_config = {
21
18
\ ' n_predict' : 64 ,
22
19
\ ' n_probs' : 3 ,
23
20
\ ' temperature' : 0.1 ,
21
+ \ ' auto_fim' : v: true ,
24
22
\ ' stop' : [" \n " ]
25
23
\ }
26
24
27
25
let g: llama_config = get (g: , ' llama_config' , s: default_config )
28
26
29
- function ! llama#fim () abort
27
+ function ! llama#init ()
28
+ let s: pos_x = 0
29
+ let s: pos_y = 0
30
+ let s: pos_x0 = 0 " pos_x corrected for end-of-line edge case
31
+
32
+ let s: line_cur = ' '
33
+
34
+ let s: pos_dx = 0
35
+ let s: content = []
36
+ let s: can_accept = v: false
37
+
38
+ let s: timer_fim = -1
39
+ let s: t_fim_last = reltime ()
40
+
41
+ augroup llama
42
+ autocmd !
43
+ autocmd InsertEnter * inoremap <buffer> <silent> <C-F> <C-O> :call llama#fim(v:false)<CR>
44
+ augroup END
45
+
46
+ silent ! call llama#fim_cancel ()
47
+ endfunction
48
+
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
+ function ! llama#fim (is_auto) abort
30
73
let l: t_start = reltime ()
31
74
32
- let l: pos_x = col (' .' )
33
- let l: pos_y = line (' .' )
75
+ let s: content = []
76
+ let s: can_accept = v: false
77
+
78
+ let s: pos_x = col (' .' )
79
+ let s: pos_y = line (' .' )
34
80
let l: max_y = line (' $' )
35
81
36
- let l: lines_prefix = getline (max ([1 , l: pos_y - g: llama_config .n_prefix]), l: pos_y - 1 )
37
- let l: lines_suffix = getline (l: pos_y + 1 , min ([l: max_y , l: pos_y + g: llama_config .n_suffix]))
82
+ let l: lines_prefix = getline (max ([1 , s: pos_y - g: llama_config .n_prefix]), s: pos_y - 1 )
83
+ let l: lines_suffix = getline (s: pos_y + 1 , min ([l: max_y , s: pos_y + g: llama_config .n_suffix]))
84
+
85
+ let s: line_cur = getline (' .' )
86
+
87
+ let s: pos_x0 = s: pos_x == len (s: line_cur ) ? s: pos_x : s: pos_x - 1
38
88
39
- let l: line_cur = getline (' .' )
40
- let l: line_cur_prefix = strpart (l: line_cur , 0 , l: pos_x )
41
- let l: line_cur_suffix = strpart (l: line_cur , l: pos_x )
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 )
42
91
43
92
let l: prefix = " "
44
93
\ . join (l: lines_prefix , " \n " )
@@ -73,7 +122,7 @@ function! llama#fim() abort
73
122
\ g: llama_config .endpoint, shellescape (l: request )
74
123
\ )
75
124
76
- let l : can_accept = v: true
125
+ let s : can_accept = v: true
77
126
let l: has_info = v: false
78
127
79
128
let l: n_prompt = 0
@@ -84,21 +133,24 @@ function! llama#fim() abort
84
133
let l: t_gen_ms = 1.0
85
134
let l: s_gen = 0
86
135
87
- let s: content = []
88
-
136
+ " TODO: async this
89
137
let l: raw = system (l: curl_command )
90
- if l: can_accept && v: shell_error
91
- call add (s: content , " <| curl error: is the server on? |>" )
92
- let l: can_accept = v: false
138
+ if s: can_accept && v: shell_error
139
+ if ! a: is_auto
140
+ call add (s: content , " <| curl error: is the server on? |>" )
141
+ endif
142
+ let s: can_accept = v: false
93
143
endif
94
144
95
- if l: can_accept && l: raw == " "
96
- call add (s: content , " <| empty response: is the server on? |>" )
97
- let l: can_accept = v: false
145
+ if s: can_accept && l: raw == " "
146
+ if ! a: is_auto
147
+ call add (s: content , " <| empty response: is the server on? |>" )
148
+ endif
149
+ let s: can_accept = v: false
98
150
endif
99
151
100
152
" get the generated suggestion
101
- if l : can_accept
153
+ if s : can_accept
102
154
let l: response = json_decode (l: raw )
103
155
104
156
for l: part in split (get (l: response , ' content' , ' ' ), " \n " , 1 )
@@ -126,14 +178,20 @@ function! llama#fim() abort
126
178
endif
127
179
128
180
if len (s: content ) == 0
129
- call add (s: content , " <| nothing to suggest |>" )
130
- let l: can_accept = v: false
181
+ if ! a: is_auto
182
+ call add (s: content , " <| nothing to suggest |>" )
183
+ endif
184
+ let s: can_accept = v: false
185
+ endif
186
+
187
+ if len (s: content ) == 0
188
+ return
131
189
endif
132
190
133
191
let s: pos_dx = len (s: content [-1 ])
134
192
let s: content [-1 ] .= l: line_cur_suffix
135
193
136
- call llama#cancel_vt_fim ()
194
+ call llama#fim_cancel ()
137
195
138
196
" display virtual text with the suggestion
139
197
let l: bufnr = bufnr (' %' )
@@ -153,74 +211,42 @@ function! llama#fim() abort
153
211
\ 1000.0 * reltimefloat (reltime (l: t_start ))
154
212
\ )
155
213
156
- call nvim_buf_set_extmark (l: bufnr , l: id_vt_info , l : pos_y - 1 , l : pos_x - 1 , {
214
+ call nvim_buf_set_extmark (l: bufnr , l: id_vt_info , s : pos_y - 1 , s : pos_x - 1 , {
157
215
\ ' virt_text' : [[l: info , ' llama_hl_info' ]],
158
216
\ ' virt_text_pos' : ' eol' ,
159
217
\ })
160
218
endif
161
219
162
- call nvim_buf_set_extmark (l: bufnr , l: id_vt_fim , l : pos_y - 1 , l : pos_x - 1 , {
220
+ call nvim_buf_set_extmark (l: bufnr , l: id_vt_fim , s : pos_y - 1 , s : pos_x - 1 , {
163
221
\ ' virt_text' : [[s: content [0 ], ' llama_hl_hint' ]],
164
- \ ' virt_text_win_col' : l : pos_x == 1 ? 0 : virtcol (' .' )
222
+ \ ' virt_text_win_col' : s : pos_x == len ( s: line_cur ) ? virtcol ( ' . ' ) : virtcol (' .' ) - 1
165
223
\ })
166
224
167
- call nvim_buf_set_extmark (l: bufnr , l: id_vt_fim , l : pos_y - 1 , 0 , {
225
+ call nvim_buf_set_extmark (l: bufnr , l: id_vt_fim , s : pos_y - 1 , 0 , {
168
226
\ ' virt_lines' : map (s: content [1 :], {idx, val - > [[val, ' llama_hl_hint' ]]}),
169
227
\ ' virt_text_win_col' : virtcol (' .' )
170
228
\ })
171
229
172
- " accept suggestion with Tab and reject it with any other key
173
- let s: mapping_on = v: true
174
-
175
- if l: can_accept
176
- inoremap <buffer> <Tab> <C-O> :call llama#accept_vt_fim()<CR>
177
- else
178
- inoremap <buffer> <Tab> <C-O> :call llama#cancel_vt_fim()<CR>
179
- endif
180
-
181
- for l: key in range (32 , 127 ) + [8 , 27 ]
182
- if l: key != 0x7C
183
- if l: key == 8
184
- execute ' inoremap <buffer> <Bs> <C-O>:call llama#cancel_vt_fim()<CR><Bs>'
185
- elseif l: key == 27
186
- execute ' inoremap <buffer> <Esc> <C-O>:call llama#cancel_vt_fim()<CR><Esc>'
187
- elseif l: key == 32
188
- execute ' inoremap <buffer> <Space> <C-O>:call llama#cancel_vt_fim()<CR><Space>'
189
- elseif l: key == 127
190
- execute ' inoremap <buffer> <Del> <C-O>:call llama#cancel_vt_fim()<CR><Del>'
191
- else
192
- execute ' inoremap <buffer> ' . nr2char (l: key ) . ' <C-O>:call llama#cancel_vt_fim()<CR>' . nr2char (l: key )
193
- endif
194
- endif
195
- endfor
196
-
197
- inoremap <buffer> <Up> <C-O> :call llama#cancel_vt_fim()<CR><Up>
198
- inoremap <buffer> <Down> <C-O> :call llama#cancel_vt_fim()<CR><Down>
199
- inoremap <buffer> <Left> <C-O> :call llama#cancel_vt_fim()<CR><Left>
200
- inoremap <buffer> <Right> <C-O> :call llama#cancel_vt_fim()<CR><Right>
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' )
201
232
endfunction
202
233
203
- function ! llama#accept_vt_fim ()
204
- let l: pos_x = col (' .' )
205
- let l: pos_y = line (' .' )
206
-
207
- let l: line_cur = getline (' .' )
208
-
209
- let l: pos0 = l: pos_x == len (l: line_cur ) ? l: pos_x - 1 : l: pos_x - 2
210
-
234
+ function ! llama#fim_accept ()
211
235
" insert the suggestion at the cursor location
212
- call setline (l: pos_y , l: line_cur [:l: pos0 ] . s: content [0 ])
213
- if len (s: content ) > 1
214
- call append (l: pos_y , s: content [1 :-1 ])
215
- endif
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
216
241
217
- " move the cursor to the end of the accepted text
218
- call cursor (l: pos_y + len (s: content ) - 1 , l: pos_x + s: pos_dx )
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
219
245
220
- call llama#cancel_vt_fim ()
246
+ call llama#fim_cancel ()
221
247
endfunction
222
248
223
- function ! llama#cancel_vt_fim ()
249
+ function ! llama#fim_cancel ()
224
250
" clear the virtual text
225
251
let l: bufnr = bufnr (' %' )
226
252
@@ -230,31 +256,13 @@ function! llama#cancel_vt_fim()
230
256
call nvim_buf_clear_namespace (l: bufnr , l: id_vt_fim , 0 , -1 )
231
257
call nvim_buf_clear_namespace (l: bufnr , l: id_vt_info , 0 , -1 )
232
258
233
- " remove the key mappings
234
- if exists (' s:mapping_on' ) && s: mapping_on
235
- iunmap <buffer> <Tab>
236
-
237
- for l: key in range (32 , 127 ) + [8 , 27 ]
238
- if l: key != 0x7C
239
- if l: key == 8
240
- execute ' iunmap <buffer> <Bs>'
241
- elseif l: key == 27
242
- execute ' iunmap <buffer> <Esc>'
243
- elseif l: key == 32
244
- execute ' iunmap <buffer> <Space>'
245
- elseif l: key == 127
246
- execute ' iunmap <buffer> <Del>'
247
- else
248
- execute ' iunmap <buffer> ' . nr2char (l: key )
249
- endif
250
- endif
251
- endfor
252
-
253
- iunmap <buffer> <Up>
254
- iunmap <buffer> <Down>
255
- iunmap <buffer> <Left>
256
- iunmap <buffer> <Right>
259
+ silent ! iunmap <buffer> <Tab>
260
+ silent ! iunmap <buffer> <Esc>
257
261
258
- let s: mapping_on = v: false
259
- endif
262
+ augroup llama_insert
263
+ autocmd !
264
+ if g: llama_config .auto_fim
265
+ autocmd CursorMovedI * call llama#fim_auto ()
266
+ endif
267
+ augroup END
260
268
endfunction
0 commit comments