[vim/vim] Native display line move in insert mode (Issue #19870)

13 views
Skip to first unread message

Toby She

unread,
Mar 30, 2026, 2:20:12 PM (2 days ago) Mar 30
to vim/vim, Subscribed
otomn created an issue (vim/vim#19870)

So far there is no native way of moving the cursor up or down a display line in insert mode.

Request

Allow cursor to be moved one display line up or down natively in insert mode. Using either a new command or a new keybind like i_ctrl-g g j, i_ctrl-g g k that can be mapped to.

Alternatives considered

  1. <c-o>gk, it works properly, but it triggers ModeChange and invokes other auto commands.
  2. <cmd>normal gk<cr>, it works most of the time but not when the cursor is on the last char of the line.


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19870@github.com>

Christian Brabandt

unread,
Mar 30, 2026, 3:07:28 PM (2 days ago) Mar 30
to vim/vim, Subscribed
chrisbra left a comment (vim/vim#19870)

Vim is a modal editor, you can use a mapping.


Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19870/4157468102@github.com>

Toby She

unread,
Mar 30, 2026, 5:11:36 PM (2 days ago) Mar 30
to vim/vim, Subscribed
otomn left a comment (vim/vim#19870)

Vim is a modal editor, you can use a mapping.

Map to what?
Maybe I wasn't being clear. The goal is to be able to move the cursor without triggering any auto commands. I am not aware of any solution without the usage of either :normal or <c-o> but those do trigger other events.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19870/4158205932@github.com>

mattn

unread,
Mar 30, 2026, 11:54:38 PM (2 days ago) Mar 30
to vim/vim, Subscribed
mattn left a comment (vim/vim#19870)

pleaes use cursor keys or map to them.

imap <c-b><c-j> <down>
imap <c-b><c-k> <up>


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19870/4159687264@github.com>

mattn

unread,
Mar 31, 2026, 12:00:59 AM (yesterday) Mar 31
to vim/vim, Subscribed
mattn left a comment (vim/vim#19870)

You might like sub-mode mapping

imap <C-b>j <down><SID>im
imap <C-b>k <up><SID>im
inoremap <script> <SID>imj <down><SID>im
inoremap <script> <SID>imk <up><SID>im
imap <SID>im <Nop>

This enable moving with prefix <c-b> key. Try typing like <c-b>jjjjjkkkkkkjjjkjkkkkjj


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19870/4159705513@github.com>

Christian Brabandt

unread,
Mar 31, 2026, 2:44:30 AM (yesterday) Mar 31
to vim/vim, Subscribed
chrisbra left a comment (vim/vim#19870)

If you have an autocommand triggering, you should ask, why do you have such an autocommand in the first place?


Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19870/4160312282@github.com>

Toby She

unread,
Mar 31, 2026, 10:39:58 AM (yesterday) Mar 31
to vim/vim, Subscribed
otomn left a comment (vim/vim#19870)

You might like sub-mode mapping

imap <C-b>j <down><SID>im
imap <C-b>k <up><SID>im
inoremap <script> <SID>imj <down><SID>im
inoremap <script> <SID>imk <up><SID>im
imap <SID>im <Nop>

This enable moving with prefix <c-b> key. Try typing like <c-b>jjjjjkkkkkkjjjkjkkkkjj

I don't think this solves the problem.
To clarify. I have the following config to remap arrow keys to display line moves:

inoremap <up> <c-o>gk
inoremap <down> <c-o>gj

The issue I'm facing with this approach is it will trigger InsertLeave and InsertEnter in addition to just CursorMovedI.
I have lsp plugins that perform expensive operations on those two triggers as the plugin assumes no one should rapidly leave and reenter insert mode.

After setting set verbose=9 verbosefile=/dev/pts/1, I can see that InsertLeave and InsertEnter would be triggered for the above script as well.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19870/4163137804@github.com>

mattn

unread,
Mar 31, 2026, 11:33:03 AM (yesterday) Mar 31
to vim/vim, Subscribed
mattn left a comment (vim/vim#19870)

You can try this script as a workaround. It moves the cursor by display line in insert mode without triggering InsertLeave/InsertEnter:

let s:curswant = 0
let s:prev = [0, 0]

function! s:textwidth() abort
  return winwidth(0) - getwininfo(win_getid())[0].textoff
endfunction

function! s:move(dir) abort
  let tw = s:textwidth()
  let vcol = virtcol('.')
  if s:prev[0] == 0
    let s:curswant = (vcol - 1) % tw
  endif
  let screen_line = (vcol - 1) / tw
  let target_screen = screen_line + a:dir

  if target_screen >= 0 && (target_screen + 1) * tw < virtcol([line('.'), '$'])
    " Move within the same logical line
    let lnum = line('.')
    let target = target_screen * tw + 1 + s:curswant
  else
    " Move to adjacent logical line
    let lnum = line('.') + a:dir
    if lnum < 1 || lnum > line('$')
      return
    endif
    if a:dir > 0
      let target_screen = 0
    else
      let last = max([virtcol([lnum, '$']) - 1, 1])
      let target_screen = (last - 1) / tw
    endif
    let target = target_screen * tw + 1 + s:curswant
  endif

  let last = max([virtcol([lnum, '$']) - 1, 1])
  call cursor(lnum, virtcol2col(0, lnum, min([target, last])))
endfunction

function! s:on_move() abort
  let cur = [line('.'), virtcol('.')]
  if cur[0] == s:prev[0] || s:prev[0] == 0
    " Horizontal move, text input, or first move: update curswant
    let s:curswant = (cur[1] - 1) % s:textwidth()
  endif
  let s:prev = cur
endfunction

augroup insmode_gjgk
  autocmd!
  autocmd CursorMovedI * call <SID>on_move()
augroup END

inoremap <Down> <Cmd>call <SID>move(1)<CR>
inoremap <Up> <Cmd>call <SID>move(-1)<CR>

Save this as a file and :source it, or paste into your vimrc.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19870/4163526308@github.com>

Toby She

unread,
Mar 31, 2026, 8:11:00 PM (yesterday) Mar 31
to vim/vim, Subscribed
otomn left a comment (vim/vim#19870)

Thank you for your hard work. It is indeed not triggering any auto command other than cursor move.

It works 95% of time. But sometimes it would jump from the second last display line right to the next line, or jumping to a different column.

I will keep this as a workaround and improve upon it for now. Though I really believe something fundamental like moving cursor around should be a built in feature instead of having to write a such complicated workaround script. We have gk for normal mode, so it would make sense to have an equivalent of that for insert mode.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19870/4166504236@github.com>

Reply all
Reply to author
Forward
0 new messages