Skip to content

Commit d13d932

Browse files
authored
cache : keep cached suggestions (#18)
* check nearby cached completions * coding style * coding style * Disable cache when gen new suggestion with CTRL+F * removed echom
1 parent 3a08e7d commit d13d932

File tree

1 file changed

+56
-26
lines changed

1 file changed

+56
-26
lines changed

autoload/llama.vim

Lines changed: 56 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -124,15 +124,15 @@ function! llama#init()
124124

125125
augroup llama
126126
autocmd!
127-
autocmd InsertEnter * inoremap <expr> <silent> <C-F> llama#fim_inline(v:false)
127+
autocmd InsertEnter * inoremap <expr> <silent> <C-F> llama#fim_inline(v:false, v:false)
128128
autocmd InsertLeavePre * call llama#fim_cancel()
129129

130130
autocmd CursorMoved * call s:on_move()
131131
autocmd CursorMovedI * call s:on_move()
132132
autocmd CompleteChanged * call llama#fim_cancel()
133133

134134
if g:llama_config.auto_fim
135-
autocmd CursorMovedI * call llama#fim(v:true)
135+
autocmd CursorMovedI * call llama#fim(v:true, v:true)
136136
endif
137137

138138
" gather chunks upon yanking
@@ -332,14 +332,14 @@ function! s:ring_update()
332332
endfunction
333333

334334
" necessary for 'inoremap <expr>'
335-
function! llama#fim_inline(is_auto) abort
336-
call llama#fim(a:is_auto)
335+
function! llama#fim_inline(is_auto, cache) abort
336+
call llama#fim(a:is_auto, a:cache)
337337
return ''
338338
endfunction
339339

340340
" the main FIM call
341341
" takes local context around the cursor and sends it together with the extra context to the server for completion
342-
function! llama#fim(is_auto) abort
342+
function! llama#fim(is_auto, cache) abort
343343
" we already have a suggestion for the current cursor position
344344
if s:hint_shown && !a:is_auto
345345
call llama#fim_cancel()
@@ -356,7 +356,7 @@ function! llama#fim(is_auto) abort
356356
endif
357357

358358
let s:t_fim_start = reltime()
359-
let s:timer_fim = timer_start(600, {-> llama#fim(v:true)})
359+
let s:timer_fim = timer_start(600, {-> llama#fim(v:true, a:cache)})
360360
return
361361
endif
362362

@@ -445,26 +445,53 @@ function! llama#fim(is_auto) abort
445445
endif
446446
let s:job_error = 0
447447

448-
" Construct hash from prefix, suffix, and prompt
449-
let l:request_context = l:prefix . "|" . l:suffix . "|" . l:prompt
450-
let l:hash = sha256(l:request_context)
451-
452-
" Check if the completion is cached
453-
let l:cached_completion = get(g:result_cache, l:hash , v:null)
448+
" Construct hash from prefix, prompt, and suffix
449+
let l:request_context = l:prefix . l:prompt . l:suffix
450+
let l:hash = sha256(l:request_context)
451+
452+
if a:cache
453+
" Check if the completion is cached
454+
let l:cached_completion = get(g:result_cache, l:hash , v:null)
455+
456+
" ... or if there is a cached completion nearby (10 characters behind)
457+
" Looks at the previous 10 characters to see if a completion is cached. If one is found at (x,y)
458+
" then it checks that the characters typed after (x,y) match up with the cached completion result.
459+
if l:cached_completion == v:null
460+
let l:past_text = l:prefix . l:prompt
461+
for i in range(10)
462+
let l:hash_txt = l:past_text[:-(2+i)] . l:suffix
463+
let l:temp_hash = sha256(l:hash_txt)
464+
if has_key(g:result_cache, l:temp_hash)
465+
let l:temp_cached_completion = get(g:result_cache, l:temp_hash)
466+
if l:temp_cached_completion == ""
467+
break
468+
endif
469+
let l:response = json_decode(l:temp_cached_completion)
470+
if l:response['content'][0:len(l:past_text[-(1+i):])-1] !=# l:past_text[-(1+i):]
471+
break
472+
endif
473+
let l:response['content'] = l:response['content'][i+1:]
474+
let g:result_cache[l:hash] = json_encode(l:response)
475+
let l:cached_completion = g:result_cache[l:hash]
476+
break
477+
endif
478+
endfor
479+
endif
480+
endif
454481

455-
if l:cached_completion != v:null
456-
call s:fim_on_stdout(l:hash, s:pos_x, s:pos_y, a:is_auto, 0, l:cached_completion)
482+
if a:cache && l:cached_completion != v:null
483+
call s:fim_on_stdout(l:hash, a:cache, s:pos_x, s:pos_y, a:is_auto, 0, l:cached_completion)
457484
else
458485
" send the request asynchronously
459486
if s:ghost_text_nvim
460487
let s:current_job = jobstart(l:curl_command, {
461-
\ 'on_stdout': function('s:fim_on_stdout', [l:hash, s:pos_x, s:pos_y, a:is_auto]),
488+
\ 'on_stdout': function('s:fim_on_stdout', [l:hash, a:cache, s:pos_x, s:pos_y, a:is_auto]),
462489
\ 'on_exit': function('s:fim_on_exit'),
463490
\ 'stdout_buffered': v:true
464491
\ })
465492
elseif s:ghost_text_vim
466493
let s:current_job = job_start(l:curl_command, {
467-
\ 'out_cb': function('s:fim_on_stdout', [l:hash, s:pos_x, s:pos_y, a:is_auto]),
494+
\ 'out_cb': function('s:fim_on_stdout', [l:hash, a:cache, s:pos_x, s:pos_y, a:is_auto]),
468495
\ 'exit_cb': function('s:fim_on_exit')
469496
\ })
470497
endif
@@ -552,25 +579,28 @@ function! s:on_move()
552579
call llama#fim_cancel()
553580
endfunction
554581

582+
" TODO: Currently the cache uses a random eviction policy. A more clever policy could be implemented (eg. LRU).
583+
function! s:insert_cache(key, value)
584+
if len(keys(g:result_cache)) > (g:llama_config.max_cache_keys - 1)
585+
let l:keys = keys(g:result_cache)
586+
let l:hash = l:keys[rand() % len(l:keys)]
587+
call remove(g:result_cache, l:hash)
588+
endif
589+
let g:result_cache[a:key] = a:value
590+
endfunction
591+
555592
" callback that processes the FIM result from the server and displays the suggestion
556-
function! s:fim_on_stdout(hash, pos_x, pos_y, is_auto, job_id, data, event = v:null)
593+
function! s:fim_on_stdout(hash, cache, pos_x, pos_y, is_auto, job_id, data, event = v:null)
557594
" Retrieve the FIM result from cache
558-
" TODO: Currently the cache uses a random eviction policy. A more clever policy could be implemented (eg. LRU).
559-
if has_key(g:result_cache, a:hash)
595+
if a:cache && has_key(g:result_cache, a:hash)
560596
let l:raw = get(g:result_cache, a:hash)
561597
else
562598
if s:ghost_text_nvim
563599
let l:raw = join(a:data, "\n")
564600
elseif s:ghost_text_vim
565601
let l:raw = a:data
566602
endif
567-
568-
if len(keys(g:result_cache)) > (g:llama_config.max_cache_keys - 1)
569-
let l:keys = keys(g:result_cache)
570-
let l:hash = l:keys[rand() % len(l:keys)]
571-
call remove(g:result_cache, l:hash)
572-
endif
573-
let g:result_cache[a:hash] = l:raw
603+
call s:insert_cache(a:hash, l:raw)
574604
endif
575605

576606
if a:pos_x != col('.') - 1 || a:pos_y != line('.')

0 commit comments

Comments
 (0)