Moving the cursor through long soft-wrapped lines in Vim
Asked Answered
R

6

31

I'd like to use VIM to write papers for some classes I'm in. The problem I'm having is with the formatting of lines in the editor. If I don't explicitly break the end of a line with the enter key, when I try to move the cursor through the text, it skips multiple lines if I have a sentence that spans more than one line.

Is there any way to make it so that the cursor will be able to move through the text akin to the way it does in most word processors?

Renie answered 7/1, 2014 at 15:48 Comment(1)
some more information here in addition to the answers: vim.wikia.com/wiki/Move_cursor_by_display_lines_when_wrappingApul
U
0

Have you tried the following in vim command line:

:set nowrap
Unstuck answered 7/1, 2014 at 15:51 Comment(4)
I also recommend :set textwidth=80 for automatic line wrapping.Paraphrastic
That command doesn't seem to be doing anything, but I can see why you'd want something like that. Any idea why it might not be working for me?Renie
The textwidth setting is only applied on new text, it does not reformat your document automatically - but you can use something like gq to do this (see :help gq). Pressing gggqG in normal mode should be fine.Tourniquet
This just disables soft line wrap and the question is specifically for soft-wrapped lines.Nippy
C
64

The problem with the often used

noremap j gj  
noremap k gk 

option is, that it breaks the <vcount> functionality, if you have lines in your text, which span across multiple lines.
Example: you want 10k (go UP 10 lines), because you use relative numbers in the sidebar, but theres a multiline with 4 lines height. Therefore you end up effectively at 6 lines (6k) above your desired line, which you read from your relative numbers. You'd have to calculate manually! Annoying... Especially if you have multiple multiline between your current position and your desired position - not Vim-istic!

I like my <vcount> function together with my :relativenumber, which is why I wrote the following functions & mapping to solve all problems related to this.
These functions let you use commands like 10j or 10k as expected, despite the presence of multilines with all the advantages of using gj and gk as your default movement mappings:

Edit: I just found the following on reddit, which is so much better then my own solution. This is shortest possible version:

nnoremap <expr> j v:count ? 'j' : 'gj'
nnoremap <expr> k v:count ? 'k' : 'gk'

(If you use noremap instead of nnoremap, then this works in both visual and normal modes)

"Longer" version for better understanding and completeness:

nnoremap <expr> k (v:count == 0 ? 'gk' : 'k')
nnoremap <expr> j (v:count == 0 ? 'gj' : 'j')

source: http://www.reddit.com/r/vim/comments/2k4cbr/problem_with_gj_and_gk/


My old solution:

nnoremap <silent> j :<C-U>call Down(v:count)<CR>
vnoremap <silent> j gj

nnoremap <silent> k :<C-U>call Up(v:count)<CR>
vnoremap <silent> k gk

function! Down(vcount)
  if a:vcount == 0
    exe "normal! gj"
  else
    exe "normal! ". a:vcount ."j"
  endif
endfunction

function! Up(vcount)
  if a:vcount == 0
    exe "normal! gk"
  else
    exe "normal! ". a:vcount ."k"
  endif
endfunction
Chinfest answered 8/1, 2014 at 15:50 Comment(2)
Is there a way to do this horizontally too?Currency
For the solution found on Reddit, you might want to use noremap instead of nnoremap so it also works on visual mode.Ferment
F
18

That's because the default j and k motions move across physical lines, not the visible, soft-wrapped screen lines (when you have :set wrap). You can use the gj and gk commands for that.

If you want to default to that behavior, you can remap the default keys by putting this into your ~/.vimrc:

noremap j gj
noremap k gk
Falbala answered 7/1, 2014 at 15:52 Comment(2)
Does not work with up/down arrowsTemper
@Temper of course it doesn't this remaps the j key to gj and k to gk If you want to have support for arrow keys, simply add those as remaps noremap <Up> gk noremap <Down> gjHamitic
S
1

I have found another version of this solution that does more than moving through physical or virtual lines, it also adds jumps bigger than 5 lines to the jump list, allowing us to use Ctrl-o and Ctrl-i.

" source: https://www.vi-improved.org/vim-tips/
nnoremap <expr> j v:count ? (v:count > 5 ? "m'" . v:count : '') . 'j' : 'gj'
nnoremap <expr> k v:count ? (v:count > 5 ? "m'" . v:count : '') . 'k' : 'gk'

It uses a nested ternary operator to add the jump to the jump list

Sempach answered 28/3, 2020 at 22:42 Comment(0)
T
1

Solution that I found on internet that works with up and down arrow:

imap <silent> <Down> <C-o>gj
imap <silent> <Up> <C-o>gk
nmap <silent> <Down> gj
nmap <silent> <Up> gk
Temper answered 21/4, 2022 at 13:52 Comment(0)
U
0

Have you tried the following in vim command line:

:set nowrap
Unstuck answered 7/1, 2014 at 15:51 Comment(4)
I also recommend :set textwidth=80 for automatic line wrapping.Paraphrastic
That command doesn't seem to be doing anything, but I can see why you'd want something like that. Any idea why it might not be working for me?Renie
The textwidth setting is only applied on new text, it does not reformat your document automatically - but you can use something like gq to do this (see :help gq). Pressing gggqG in normal mode should be fine.Tourniquet
This just disables soft line wrap and the question is specifically for soft-wrapped lines.Nippy
O
0

The neovim version would be:

vim.keymap.set('n', 'k', "v:count == 0 ? 'gk' : 'k'", { expr = true})
vim.keymap.set('n', 'j', "v:count == 0 ? 'gj' : 'j'", { expr = true})
Overestimate answered 16/5, 2024 at 7:27 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.