How do I make j and k navigate display lines normally but physical lines when given a count?
Answer
nnoremap <expr> j v:count == 0 ? 'gj' : 'j'
Explanation
By default, j and k move by physical lines (newline-delimited), which jumps over the entire visual span of a long wrapped line in a single keystroke. The <expr> mapping attribute lets the right-hand side be a Vimscript expression evaluated at key-press time, so you can switch behavior based on whether a count was given.
How it works
nnoremap <expr>creates a normal-mode mapping whose RHS is a Vimscript expressionv:countholds the numeric count prefix typed before the key (0 if none was given)- When no count is given (
v:count == 0), the expression returns'gj'to move by display line - When a count is given (e.g.,
5j), it returns'j'to move by physical line — essential for jumping to a specific relative line number
Add both mappings to your vimrc:
nnoremap <expr> j v:count == 0 ? 'gj' : 'j'
nnoremap <expr> k v:count == 0 ? 'gk' : 'k'
Example
With a long paragraph that wraps across three display lines:
j— moves down one display line within the paragraph (same asgj)3j— jumps exactly 3 physical lines, bypassing display-line logic
Tips
- Pair with
set relativenumberso count-based jumps (5j,12k) align with the displayed line numbers - Extend to visual mode:
vnoremap <expr> j v:count == 0 ? 'gj' : 'j' - The same pattern works for any key that should behave differently with vs without a count prefix