Moving the cursor through long soft-wrapped lines in Vim - vim

I'm sorry if my question isn't very clear. I'm not sure how to phrase it.
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?

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

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

Have you tried the following in vim command line:
:set nowrap

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

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

Related

vim navigation for very long lines [duplicate]

This question already has answers here:
Vim: move around quickly inside of long line
(8 answers)
Closed 8 years ago.
I'm editing a text file with vim and I have wrap enabled using "set wrap". Suppose I have one very long line which has been wrapped to 10 lines. Lets say I'm on the 5th word(which is on the first line when wrapped) and I'd like to get to a word on the 7th line(when wrapped). Whats the fastest way I could get to that line. I'm not too keen on going w<a-number>l -- there is probably a better/easier way to do this, right?
gj to go to line below (same line, but wrapped)
gk to go to the above line.
I have a map in my .vimrc
map j gj
map k gk
There are several motions that specifically deal with :set wrap; mostly they are variants of the "normal" motions with g prefixed.
So there's gj and gk to move across screen lines, as well as g0, g^, g$, etc. Look them up with :help for more details.
When you know the word or see it. for example it's hello, you might search for it with /hello. That should jump there. If there is a hello before, you can use n to get to the next one.
As Paco says in his answer, you can navigate screen lines with gj and gk. If that is too much hassle, as it probably is, you can add these lines to your ~/.vimrc to have the normal arrow keys navigate in terms of screen lines instead of logical lines:
noremap <silent> <Up> gk
noremap <silent> <Down> gj
noremap <silent> <Home> g<Home>
noremap <silent> <End> g<End>
inoremap <silent> <Up> <C-o>gk
inoremap <silent> <Down> <C-o>gj
inoremap <silent> <Home> <C-o>g<Home>
inoremap <silent> <End> <C-o>g<End>

how do I conditionally bind a key to do two different actions in vim?

I'd like to bind <C-n> to do one of two things in Vim depending on the state of the editor. If I have tabs open I'd like it to switch to the next tab, otherwise I'd like it to open a new tab. I've looked at the help and come up with this, but it's not working, and I'm a viml noob.
function TabBind()
if range(tabpagenr()) < 2
nno <C-n> :tabnew
else
nno <C-n> :tabn
endif
endfunction
Is this possible? and if so how?
The idea is that you map a function that decides what to do on the fly.
function TabBind()
if tabpagenr('$') < 2
tabnew
else
tabn
endif
endfunction
nno <C-n> :call TabBind()<cr>
You can also define such simple thing as one-liners. For instance I have the following mapping to go to the next diff (in diff mode), or to the next error message otherwise.
nnoremap <expr> <silent> <F3> (&diff ? "]c:call \<sid>NextDiff()\<cr>" : ":cn\<cr>")
In your case, your mapping will be:
nnoremap <expr> <silent> <c-n> (tabpagenr('$') < 2 ? ":tabnew\<cr>" : ":tabn\<cr>")

Move visually selected text to end of line

How to move visually selected text to end of line, which command or keys I should use?
e.g. /text3<CR> note that ** is a selected text, not part of it.
**text3** text1 text2
**text3** text1 text2
and move to this:
text1 text2 **text3**
text1 text2 **text3**
I tried: :%s/\(text3\)\(.*\)/\2 \1/ any other ways to do it?
Basically you can do it (after selecting your text visually like put the cursor on your word then hit viw) with d$p. Any you can create a macro for it, I used to go with something like this in simillar cases: qq/SEARCHTERMENTERviwd$pj0q. Now you can execute it as NUMBER(s)#q.
But as a more general solution:
:%s_\(YOUR_TEXT_TO_MOVE_TO_THE_EOL\)\(.*\)_\2\1
Should work just fine.
You could use the :global command to select lines with the matching pattern and :normal to operate on those lines. For example:
:g/^text3 /norm! dt p d0$p
Explanation
:g/^text3 /<command>
Runs the specified <command> on all lines starting with text3 followed by a space. See :help :global for more information.
norm!
Executes the following commands in normal mode. See :help :normal.
dt p d0$p
Delete to the first space, paste that after said space, move forward one character and delete to the beginning of the line. Move to the end of the line and paste.
You can use Damian Conway's dragvisuals.vim
After installation add the following (uncommented) to your .vimrc
runtime plugin/dragvisuals.vim
vmap <expr> <LEFT> DVB_Drag('left')
vmap <expr> <RIGHT> DVB_Drag('right')
vmap <expr> <DOWN> DVB_Drag('down')
vmap <expr> <UP> DVB_Drag('up')
vmap <expr> D DVB_Duplicate()
" Remove any introduced trailing whitespace after moving...
let g:DVB_TrimWS = 1
Or, if you use the arrow keys for normal motions, choose four
other keys for block dragging. For example:
vmap <expr> h DVB_Drag('left')
vmap <expr> l DVB_Drag('right')
vmap <expr> j DVB_Drag('down')
vmap <expr> k DVB_Drag('up')
Or:
vmap <expr> <S-LEFT> DVB_Drag('left')
vmap <expr> <S-RIGHT> DVB_Drag('right')
vmap <expr> <S-DOWN> DVB_Drag('down')
vmap <expr> <S-UP> DVB_Drag('up')
Or even:
vmap <expr> <LEFT><LEFT> DVB_Drag('left')
vmap <expr> <RIGHT><RIGHT> DVB_Drag('right')
vmap <expr> <DOWN><DOWN> DVB_Drag('down')
vmap <expr> <UP><UP> DVB_Drag('up')
To use
Select with visual mode and move the block with h, l, j or k etc.
The solutions involving iw will work if the text is text3, but they will fail on two words.
None of the methods involving $p will add a space, as your :s command does. You could use A <C-R>"<Esc> instead.
If you want to do it on a single line, and the text is already selected in Visual mode, then x$p is pretty easy.
If the text is "selected" in the sense that you have just searched for it, and it is highlighted with the Search highlight group, and you want to make the change on a single line, then you could use d/<C-R>//e<CR>$p. The <C-R>/ will be replaced by the current search pattern, so you will get something like d/text3/e<CR>$p.
If you want to do it on all matching lines in the buffer, then a slight simplification of your solution is
:%s/\v(<C-R>/)(.*)/\2 \1
:help i_CTRL-R
:help c_CTRL-R
:help /\v

how can i intuitively move cursor in vim?(not by line)

if some lines are too long, it will be forced to be newlined.
for example, normally a long line will looks like this
1 first line
2 this is the long second line of the file
3 third line.
but, if the window of a vim are too narrow, it will looks like this
1 first line
2 this is the long
second line of the file
3 third line
the problem arise from this.
let's assume the vim cursor are located at before 't' in 'third line'. if i type 'k', cursor will move to before 's' in 'second line of the file'. after that, if i type 'k' again, cursor will move to 'f' in 'first line'!, not 't' in 'this is the long'. what i want is that the cursor move to 't' in 'this is the long', it is more intuitive process for me. how can set my vim to works like this?
In Vim, the gj and gk commands move by line on the screen rather than by line in the file. This sounds like it probably matches your description.
You can modify your keys like this:
:map j gj
:map k gk
No, if some lines are too long and you have set wrap on they will be shown on "two lines", so to say, but there won't be a newline character between them. If you turn off wrap with set nowrap you'll see the effect.
Normally, k and j move you up and down. If you want to navigate wrapped lines use gk or gj, or just as some like it, map it to for example, the cursor keys.
nmap <up> gk
nmap <down> gj
To move in vim in a natural way is possible.
What I did was, and I suggest you, to modify (or create) your "~/.vimrc" and add these two lines:
map <C-Up> g<Up>
map <C-Down> g<Down>
This will map you control-up and control-down to the movements commands (this is coherent with control-right and control-left to move around long lines)
If you add these other two lines, you can use the same command to move in insertmode:
imap <C-Up> <C-[> g<Up> i
imap <C-Down> <C-[> g<Down> i
(VIM is great !)
Greg Ruo
This answer is derived from #mario-rossi 's answer (Kudo to him), with minor midification.
I use the normal UP and DOWN arrow key, rather than CTRL+up and CTRL+down. And somehow I need to remove one excess space in the INSERT mode mapping to avoid an off-by-one behavior.
Put the following into your ~/.vimrc:
" When a long line is wrapped, the "gk" and "gj" allow you to move up and down
" a visual line, while normal "k" and "j" move a physical line.
" The following settings map "gk" and "gj" to cursor <up> and <down>.
map <up> gk
map <down> gj
" And the following lines enables same <up> and <down> behavior in INSERT mode
imap <up> <C-[> <up>i
imap <down> <C-[> <down>i
Took this from vim.fandom.com:
There are several cases to remap up and down movements. First, you probably should remap both k/j and / arrows. Second, you should coose vim modes that requires remap. Basic modes are Normal (nmap), Insert (as after i command, imap) and Select (as after v command, vmap). To remap all three:
nnoremap j gj
nnoremap k gk
vnoremap j gj
vnoremap k gk
nnoremap <Down> gj
nnoremap <Up> gk
vnoremap <Down> gj
vnoremap <Up> gk
inoremap <Down> <C-o>gj
inoremap <Up> <C-o>gk
There's also one significant Operator mode (as in dj or, to say, y4k), remapping operator (omap) breaks vim experience/habits dramatically and not recommended.
Personally I prefer to remap Insert mode only, to keep my editorial habits intact.

How do I configure matchit.vim to use <tab> instead of %?

I'm a big fan of the matchit.vim plugin, but I prefer to jump between matching delimiters with the <tab> key. However, it seems that matchit is hard-coded to activate when pressing the % key.
My first thought would be that I would simply put this line in my .vimrc, and change '%' to '<tab>', thus binding the Match_wrapper call to the tab key:
nnoremap <silent> % :<C-U>call <SID>Match_wrapper('',1,'n') <CR>
However, this doesn't seem to work; I'm guessing it has got something to do with the <SID> (which as far as I understand is an ID unique to the script?) or the fact that Match_wrapper is script-local. (I'm pretty new to Vimscript)
Thus far I've managed to get by mapping <tab> to % with 'nmap', but it's a pretty fragile hack.
Anyway, any help would be greatly appreciated! :)
Well, if you know that % will always be remapped, then using
map <Tab> %
is safe (absence of n in front is intentional: % is defined in all modes covered by :map). But what you can always do is to replace <SID> with <SNR>{N}_ where {N} is the number of the matchit script in the outputs of :scriptnames. In a newer vim you can also use maparg('%', 'n', 0, 1), it will output a dictionary that among other values contains lhs and sid. In this case code may look like this:
for s:mode in ['n', 'v', 'o']
let s:map=maparg('%', s:mode, 0, 1)
execute s:mode.'noremap <Tab> '.substitute(s:map.lhs, '<SID>', '<SNR>'.s:map.sid.'_', 'g')
endfor
In this case
for s:mode in ['n', 'v', 'o']
execute s:mode.'noremap <Tab> '.maparg('%', s:mode)
endfor
is also acceptable as “old” (without fourth argument) behavior of maparg is to expand <SID>.
Here's what I did:
" <C-I> and <TAB> are the same thing.
" So, I changed <C-I> to <C-O><C-I> and <C-O> to <C-O><C-O> to match.
" I didn't want to lose the <C-I> jump functionality.
noremap <C-O><C-O> <C-O>
noremap <C-O><C-I> <C-I>
" This is what the plugin sets on %. I just set it on <TAB>
onoremap <TAB> :<C-U>call <SNR>41_Match_wrapper('',1,'o')<CR>
nnoremap <TAB> :<C-U>call <SNR>41_Match_wrapper('',1,'n')<CR>
vnoremap <TAB> :<C-U>call <SNR>41_Match_wrapper('',1,'v')<CR>m'gv``
Or, just in case, you can also use these mapping (tested with Vim 8.0):
nnoremap <silent> <Tab> :normal %<CR>
xnoremap <silent> <Tab> :normal %<CR>m`gv``

Resources