]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.1.1825: completion: flicker when LSP server is slow v9.1.1825
authorGirish Palya <girishji@gmail.com>
Sat, 4 Oct 2025 10:55:40 +0000 (10:55 +0000)
committerChristian Brabandt <cb@256bit.org>
Sat, 4 Oct 2025 10:55:40 +0000 (10:55 +0000)
Problem:  completion: flicker when LSP server is slow
Solution: reinsert leader text before invoking user function
          (Girish Palya)

Reference:
https://github.com/girishji/vimcomplete/issues/101#issuecomment-3343063245

In insert-mode completion, the leader text is temporarily removed while
searching for candidates. When the LSP server responds slowly, the
client may call `:sleep` to wait, which triggers `out_flush()`. This
causes the deleted text to disappear briefly before being redrawn,
resulting in visible flicker.

This commit reinserts the leader text before invoking the user function,
and removes it again afterward to eliminate flicker.

closes: #18468

Signed-off-by: Girish Palya <girishji@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
src/insexpand.c
src/testdir/test_ins_complete.vim
src/version.c

index c231aa41b8dc459b3ded5721fb15ef0d29f5581d..38b2095632a488562d67c739b4948cee7b7cff47 100644 (file)
@@ -7690,17 +7690,26 @@ remove_old_matches(void)
     static void
 get_cpt_func_completion_matches(callback_T *cb UNUSED)
 {
-    int        startcol = cpt_sources_array[cpt_sources_index].cs_startcol;
+    cpt_source_T    *cpt_src = &cpt_sources_array[cpt_sources_index];
+    int                    startcol = cpt_src->cs_startcol;
 
     if (startcol == -2 || startcol == -3)
        return;
 
     if (set_compl_globals(startcol, curwin->w_cursor.col, TRUE) == OK)
     {
+       // Insert the leader string (previously removed) before expansion.
+       // This prevents flicker when `func` (e.g. an LSP client) is slow and
+       // calls 'sleep', which triggers out_flush().
+       if (!cpt_src->cs_refresh_always)
+           ins_compl_insert_bytes(ins_compl_leader(), -1);
+
        expand_by_function(0, cpt_compl_pattern.string, cb);
 
-       cpt_sources_array[cpt_sources_index].cs_refresh_always =
-           compl_opt_refresh_always;
+       if (!cpt_src->cs_refresh_always)
+           ins_compl_delete();
+
+       cpt_src->cs_refresh_always = compl_opt_refresh_always;
        compl_opt_refresh_always = FALSE;
     }
 }
index b10e07433a18d47a61fe4dce8fa352f66b6b85f6..c2465030dd49089ba6364a367130a8292a41d3de 100644 (file)
@@ -586,15 +586,19 @@ func Test_completefunc_info()
   set completefunc&
 endfunc
 
-func Test_cpt_func_cursorcol()
+" For ^N completion, `completefunc` receives the same leader string in both the
+" 'info' and 'expansion' phases (the leader is not removed before expansion).
+" This avoids flicker when `completefunc` (e.g. an LSP client) is slow and calls
+" 'sleep', which triggers out_flush().
+func Test_completefunc_leader()
   func CptColTest(findstart, query)
     if a:findstart
-      call assert_equal(b:info_compl_line, getline(1))
-      call assert_equal(b:info_cursor_col, col('.'))
+      call assert_equal(b:compl_line, getline(1))
+      call assert_equal(b:cursor_col, col('.'))
       return col('.')
     endif
-    call assert_equal(b:expn_compl_line, getline(1))
-    call assert_equal(b:expn_cursor_col, col('.'))
+    call assert_equal(b:compl_line, getline(1))
+    call assert_equal(b:cursor_col, col('.'))
     return v:none
   endfunc
 
@@ -602,17 +606,13 @@ func Test_cpt_func_cursorcol()
   new
 
   " Replace mode
-  let b:info_compl_line = "foo barxyz"
-  let b:expn_compl_line = "foo barbaz"
-  let b:info_cursor_col = 10
-  let b:expn_cursor_col = 5
+  let b:compl_line = "foo barxyz"
+  let b:cursor_col = 10
   call feedkeys("ifoo barbaz\<Esc>2hRxy\<C-N>", "tx")
 
   " Insert mode
-  let b:info_compl_line = "foo bar"
-  let b:expn_compl_line = "foo "
-  let b:info_cursor_col = 8
-  let b:expn_cursor_col = 5
+  let b:compl_line = "foo bar"
+  let b:cursor_col = 8
   call feedkeys("Sfoo bar\<C-N>", "tx")
 
   set completeopt=longest
@@ -4128,7 +4128,6 @@ func Test_autocomplete_completeopt_preinsert()
   endfunc
   set omnifunc=Omni_test complete+=o
   set completeopt=preinsert autocomplete
-  " set completeopt=preinsert,menuone autocomplete
   func GetLine()
     let g:line = getline('.')
     let g:col = col('.')
index 48241d3ddc1d9513c78be14926188d87eab3b759..01a0dd08a52d7018d9582ede06ca98e9ac3b5e04 100644 (file)
@@ -729,6 +729,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1825,
 /**/
     1824,
 /**/