0

Inspired by this answer (quoted below), I wanted to make a similar mapping using Lua.

nnoremap <expr> * v:count ? '*' : '<Cmd>silent keepjumps normal! *<CR><Cmd>call winrestview(' .. string(winsaveview()) .. ')<CR>'

However, I tried the code below and it didn't work.

vim.keymap.set('n', '*',
    function()
         -- execute * normally if a count was supplied
        if vim.v.count > 0 then
            return '*'
        end

        -- save current window view
        local windowView = vim.fn.winsaveview()

        -- execute normal *
        vim.api.nvim_feedkeys('*', 'n', false)
        -- NOTE: vim.cmd([[silent keepjumps normal! *<CR>]]) doesn't work here*

        -- reset the window
        vim.fn.winresetview(windowView)

        return ''
    end,
    { expr = true }
)

* Executing a normal command from within a keymap callback doesn't work I guess. I get an error saying E5108: Error executing lua: vim/_editor.lua:0: nvim_exec2(): Vim(normal):E523: Not allowed here

When I used the above code, the window was not restored and the cursor just jumped to the next instance of the word.

Did I miss something about the vim.fn.winrestview() function? Shouldn't it restore my cursor position?

3
  • The normal command is not allowed inside expression-mappings. I think that is your feedkeys() call. Dec 11, 2023 at 20:13
  • Hi, thanks for the comment. What about my feedkeys() call?
    – nullromo
    Dec 11, 2023 at 20:15
  • Oh, normal isn't allowed specifically when expr = true. I changed the mapping to not use expr = true and the normal command is allowed now.
    – nullromo
    Dec 11, 2023 at 20:17

1 Answer 1

1

The vim.fn.winsaveview() and vim.fn.winrestview() functions are being used correctly.

The issue is that you can't use normal commands inside of a mapping callback when expr = true (read :help map-expression for more details).

Here is a solution:

vim.keymap.set('n', '*',
    function()
        -- if a count was supplied, execute * normally and exit
        if vim.v.count > 0 then
            vim.cmd('normal! ' .. vim.v.count .. '*<CR>')
            return
        end

        -- save current window view
        local windowView = vim.fn.winsaveview()

        -- execute * normally
        vim.cmd('silent keepjumps normal! *<CR>')

        -- restore the window view
        if windowView ~= nil then
            vim.fn.winrestview(windowView)
        end
    end
)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.