So I am trying to create a Lua function to move the visual selection elsewhere. For question simplicity, lets assume 1 line above the current visual selection position.

This question is not about moving the text itself, that's trivial. It is about moving the selection cursors back to the now moved text.

First, something like vim.api.nvim_input('koko') doesn't work because doesn't support arbitrary positions. It also doesn't work because it seems there is a race condition and the move hasn't occurred yet and it just destroys the selection.


local pos1 = vim.fn.getpos('v')                                                                     
local pos2 = vim.fn.getpos('.')

pos1[2] = pos1[2] - 1 
pos2[2] = pos2[2] - 1

vim.fn.setpos('.', pos2)
vim.fn.setpos('v', pos1)

doesn't work because it says "illegal argument" in the error prompt. Apparently, moving v isn't supported. Using '</'> doesn't work because it's not the same thing.

This also doesn't work and I have no idea why:

vim.api.nvim_win_set_cursor(0, pos2)
vim.api.nvim_win_set_cursor(0, pos1)

So, how can I set the visual selection using the API in a way that's not horrible and also reliable?

  • Welcome to Vi and Vim! What is the context in which you're calling this code? In many contexts, you'll be out of Visual mode already (for example, if you use : you go to Command-line mode.) If you're creating a mapping, then something simple such as xnoremap <Up> koko seems to work fine... Is that what you wanted?
    – filbranden
    Jan 1 at 20:27
  • I call vim.api.nvim_command(row_begin..",".. row_end .."move "..(row_begin-2)) before trying to restore the selection. I called getpos before executing the command above and confirmed the row/col are both correct using print(). I also tried to call <esc><esc>v and it didn't work. Is this because calling nvim_win_set_cursor or setpos leaves the visual mode and magically return to it?
    – Elv13
    Jan 1 at 22:00
  • A :move will preserve marks, including those of the selection itself... How about xnoremap <silent> <Up> :m -2<CR>gv ?
    – filbranden
    Jan 1 at 22:38
  • Maybe I missed something, but this doesn't seem to neither move the text nor correctly move the cursor. If I mix it with the line in my previous comment, it moves the text, but the selection gets destroyed. Also, isn't there some sort of better APIs (I could not find any). I am trying to avoid using nvim_input because it doesn't have a noremap mode. It isn't reliable when called from a (lua) script function. I understand the v mode isn't the most beloved feature by Vim users, but I find it strange it is so damn near impossible to move a line up while preserving the selection...
    – Elv13
    Jan 2 at 3:25
  • That mapping works for me to move the text and keep the selection (so you can keep tapping the key again to keep moving the block around.) See for example vim.fandom.com/wiki/… which recommends that tip, actually together with a gv=gv command, with the = reinfecting the block when necessary... Note that this only works in Visual mode (it's a xnoremap)!
    – filbranden
    Jan 2 at 3:44


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.