]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.2.0485: clipboard provider callback can be called recursively v9.2.0485
authorFoxe Chen <chen.foxe@gmail.com>
Fri, 15 May 2026 16:00:04 +0000 (16:00 +0000)
committerChristian Brabandt <cb@256bit.org>
Fri, 15 May 2026 16:00:04 +0000 (16:00 +0000)
Problem:  clipboard provider callback can be called recursively, leading
          to E132: Function call depth is higher than 'maxfuncdepth'
Solution: Prevent recursive calls of
          clip_provider_copy()/clip_provider_paste() (Foxe Chen).

closes: #20213

Signed-off-by: Foxe Chen <chen.foxe@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
runtime/doc/eval.txt
src/clipboard.c
src/testdir/test_eval_stuff.vim
src/version.c

index 71585da898cf878351de1922674d6c418bf87acc..2bcad93a39175d93eac3377c7ba5870fbd85a44b 100644 (file)
@@ -5346,6 +5346,9 @@ a |lambda| expression.
 With the exception of the "available" callback if a callback is not provided,
 Vim will not invoke anything, and this is not an error.
 
+If the "paste" or "copy" callbacks are triggered recursively, then they will
+not be called.
+
                                                *clipboard-providers-textlock*
 In both the "paste" and "copy" callbacks, it is not allowed to change the
 buffer text, see |textlock|.
index e47c9a5adf29fe4d3916ec7bdd7ec051abb5e334..745a8c47a23c51caa535f40336945485a5353245 100644 (file)
@@ -3428,6 +3428,7 @@ clip_provider_get_callback(
     static void
 clip_provider_copy(char_u *reg, char_u *provider)
 {
+    static bool        recursive = false;
     callback_T callback;
     typval_T   rettv;
     typval_T   argvars[4];
@@ -3435,6 +3436,9 @@ clip_provider_copy(char_u *reg, char_u *provider)
     char_u     type[2 + NUMBUFLEN] = {0};
     list_T     *list = NULL;
 
+    if (recursive)
+       return;
+
     if (clip_provider_get_callback(
                reg,
                provider,
@@ -3497,7 +3501,9 @@ clip_provider_copy(char_u *reg, char_u *provider)
     argvars[3].v_type = VAR_UNKNOWN;
 
     textlock++;
+    recursive = true;
     call_callback(&callback, -1, &rettv, 3, argvars);
+    recursive = false;
     clear_tv(&rettv);
     textlock--;
 
@@ -3508,6 +3514,7 @@ clip_provider_copy(char_u *reg, char_u *provider)
     static void
 clip_provider_paste(char_u *reg, char_u *provider)
 {
+    static bool        recursive = false;
     callback_T callback;
     typval_T   argvars[2];
     typval_T   rettv;
@@ -3515,6 +3522,9 @@ clip_provider_paste(char_u *reg, char_u *provider)
     char_u     *reg_type;
     list_T     *lines;
 
+    if (recursive)
+       return;
+
     if (clip_provider_get_callback(
                reg,
                provider,
@@ -3528,7 +3538,9 @@ clip_provider_paste(char_u *reg, char_u *provider)
     argvars[1].v_type = VAR_UNKNOWN;
 
     textlock++;
+    recursive = true;
     ret = call_callback(&callback, -1, &rettv, 1, argvars);
+    recursive = false;
     textlock--;
 
     if (ret == FAIL)
index c3d98b96e3811ac7c4cf623b16468989a9e9508a..e1afbfbe2c509e78d71e31b6ea43090ede80fd51 100644 (file)
@@ -765,7 +765,10 @@ func s:Paste(reg)
     else
       return ("c", [])
     endif
+  endif
 
+  if exists("g:vim_paste_recursive")
+    call getreg(a:reg)
   endif
 endfunc
 
@@ -773,6 +776,9 @@ func s:Copy(reg, type, lines)
   if exists("g:vim_copy_count")
     let g:vim_copy_count[a:reg] += 1
   endif
+  if exists("g:vim_copy_recursive")
+    call setreg(a:reg, a:lines)
+  endif
 
   let g:vim_copy = {
         \ "reg": a:reg,
@@ -1349,4 +1355,34 @@ func Test_clipboard_provider_clipboard_option()
   set clipboard&
 endfunc
 
+" Test that callback aren't called recursively
+func Test_clipboard_provider_recursive()
+  let v:clipproviders["test"] = {
+        \ "paste": {
+        \       '+': function("s:Paste"),
+        \       '*': function("s:Paste")
+        \   },
+        \ "copy": {
+        \       '+': function("s:Copy"),
+        \       '*': function("s:Copy")
+        \   }
+        \ }
+  set clipmethod=test
+
+  let g:vim_paste = "count"
+  let g:vim_paste_count = {'*': 0, '+': 0}
+  let g:vim_copy_count = {'*': 0, '+': 0}
+  let g:vim_paste_recursive = 1
+  let g:vim_copy_recursive = 1
+
+  call getreg('+')
+  call assert_equal(1, g:vim_paste_count['+'])
+  call setreg('+', 'test')
+  call assert_equal(1, g:vim_copy_count['+'])
+
+  set clipmethod&
+  unlet g:vim_paste_recursive
+  unlet g:vim_copy_recursive
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
index 2602bccd37a064a6dc7280f988b686f648b3d6fa..fa746a9ae6817f490a5ab1e212690ebba7816a28 100644 (file)
@@ -729,6 +729,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    485,
 /**/
     484,
 /**/