I use neovim 0.3.1 only. I define the following function and map to do a test for getpos in visual mode:

function! show_position()
  echo getpos("'<") getpos("'>") getpos(".") getpos("v") getcurpos()
vmap ;j :<c-u>call show_position()<cr>gv

The test file contains (please ignore : and | for now)


I then enter visual mode using v, V or <c-v>, move around and then press ;j to get the position of various markers. I have two cases tested (we can press o in visual mode to switch the case):

  1. When : is the place I started the visual selection and | is the current cursor place,
  2. When | is the place I started the visual selection and : is the current cursor place,

In both cases, the result shows that getcurpos() == getpos(".") == getpos("v") == upper left corner of the selection, which I feel contradicts with common sense as well as the doc :h line

      .   the cursor position
      $   the last line in the current buffer
      'x  position of mark x (if the mark is not set, 0 is
      v   In Visual mode: the start of the Visual area (the
          cursor is the end).  When not in Visual mode
          returns the cursor position.  Differs from |'<| in
          that it's updated right away.

How to get the current cursor position in visual mode?

1 Answer 1


The problem you're having here is that by the time show_position() is running you're already out of visual mode, since the : switched to command-line mode before that function gets called.

If you call getpos("v") before you leave visual mode, it will correctly return where you actually started the visual selection, instead of the top of the selection ('<).

You can use a vmap <expr> ... to be able to evaluate the expressions before leaving visual mode. For example:

function! show_position()
  return ":\<c-u>echo 'start=" . string(getpos("v")) . " end=" . string(getpos(".")) . "'\<cr>gv"
vmap <expr> ;j show_position()

When I start the visual selection on : and end it at |, ;j tells me:

start=[0, 2, 6, 0] end=[0, 6, 6, 0]

On the other hand, starting at | and going up to : gives me:

start=[0, 6, 6, 0] end=[0, 2, 6, 0]

(Note: I'm on VIM 8.0, but I'd expect NeoVim would behave the same here.)

  • 3
    Thanks. This works very well. I just find for neovim, there is an more flexible choice which is to start the command by <Cmd> instead of using <expr>. Using <expr> has a lot of restrictions.
    – doraemon
    Sep 10, 2018 at 1:05

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.