Repository: neovim
Issue: v:lua opfunc cannot be repeated
Labels: bug,lua

### Neovim version (nvim -v)

NVIM v0.6.1

### Vim (not Nvim) behaves the same?

not applicable

### Operating system/version

Linux Debian 11

### Terminal name/version

xfce4-terminal-emulator

### $TERM environment variable

xterm-256color

### Installation

appimage

### How to reproduce the issue

Example of lua operator function (`.` repeat doesn't work here):
```vim
nnoremap  <silent> <expr> s  v:lua.require'rc.operators'.replace(v:count, v:register, v:false)
nnoremap  <silent> <expr> sq v:lua.require'rc.operators'.replace(v:count, v:register, v:true)
```
```lua
-------------------------------------------------------------------------------
-- Replace operator
-------------------------------------------------------------------------------

local cu = vim.api.nvim_replace_termcodes('<c-u>', true, true, true)
local cr = vim.api.nvim_replace_termcodes('<cr>', true, true, true)

local repl_reg, repl_reindent

function M.replace(count, reg, reindent)
  repl_reg = reg == '_' and '"' or reg
  repl_reindent = reindent
  vim.o.opfunc = 'v:lua.Vimrc.ops.replace_opfunc'
  return ':' .. cu .. cr .. (count > 0 and count or '') .. 'g@'
end

function M.replace_opfunc(tp)
  local oldreg = vim.fn.getreg('"')
  local oldvmode = vim.o.virtualedit
  vim.o.virtualedit = 'onemore'
  if tp == 'line' then
    vim.cmd 'keepjumps normal! `[V`]'
  else
    vim.cmd 'keepjumps normal! `[v`]'
  end
  local r = repl_reindent and '`[=`]' or ''
  vim.cmd ('normal! "' .. repl_reg .. 'p`]' .. r)
  vim.o.virtualedit = oldvmode
  vim.fn.setreg('"', oldreg)
end
```

Same operator in vimscript (`.` repeat works):
```vim
nnoremap  <silent> <expr> s  Replace(v:count, v:register, v:false)
nnoremap  <silent> <expr> sq Replace(v:count, v:register, v:true)

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Replace operator
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
fun! Replace(count, register, reindent)
    let s:repl_reg = a:register == "_" ? '"' : a:register
    let s:repl_reindent = a:reindent
    let n = a:count>1? string(a:count) : ''
    set opfunc=ReplaceOpfunc
    return ":\<c-u>\<cr>" . n . "g@"
endfun

fun! ReplaceOpfunc(type)
    let oldreg = [getreg('"'), getregtype('"')]
    let oldvmode = &virtualedit
    set virtualedit=onemore
    if a:type == 'line' | keepjumps normal! `[V`]
    else                | keepjumps normal! `[v`]
    endif
    let r = s:repl_reindent ? '`[=`]' : ''
    execute "normal! \"" . s:repl_reg . "p`]".r
    let &virtualedit = oldvmode
    call setreg('"', oldreg[0], oldreg[1])
endfun
```
---

Locally this patch seems to fix it, but I'm not sure it's the right way to do it.

```diff
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 029e7eb66..549b41a56 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -15,6 +15,7 @@
 #include "nvim/buffer_defs.h"
 #include "nvim/change.h"
 #include "nvim/cursor.h"
+#include "nvim/edit.h"
 #include "nvim/eval/userfunc.h"
 #include "nvim/event/loop.h"
 #include "nvim/event/time.h"
@@ -36,6 +37,7 @@
 #include "nvim/msgpack_rpc/channel.h"
 #include "nvim/os/os.h"
 #include "nvim/screen.h"
+#include "nvim/search.h"
 #include "nvim/undo.h"
 #include "nvim/version.h"
 #include "nvim/vim.h"
@@ -904,6 +906,8 @@ void nlua_typval_call(const char *str, size_t len, typval_T *const args, int arg
 {
 #define CALLHEADER "return "
 #define CALLSUFFIX "(...)"
+  bool did_save_redo = false;
+  save_redo_T save_redo;
   const size_t lcmd_len = sizeof(CALLHEADER) - 1 + len + sizeof(CALLSUFFIX) - 1;
   char *lcmd;
   if (lcmd_len < IOSIZE) {
@@ -918,8 +922,21 @@ void nlua_typval_call(const char *str, size_t len, typval_T *const args, int arg
 #undef CALLHEADER
 #undef CALLSUFFIX
 
+  // Save search patterns and redo buffer.
+  save_search_patterns();
+  if (!ins_compl_active()) {
+    saveRedobuff(&save_redo);
+    did_save_redo = true;
+  }
+
   nlua_typval_exec(lcmd, lcmd_len, "v:lua", args, argcount, false, ret_tv);
 
+  // restore search patterns and redo buffer
+  if (did_save_redo) {
+    restoreRedobuff(&save_redo);
+  }
+  restore_search_patterns();
+
   if (lcmd != (char *)IObuff) {
     xfree(lcmd);
   }
```

### Expected behavior

Can repeat operators with `.` if `&opfunc` is a `v:lua` function.

### Actual behavior

They're not repeatable.