Using "z=" in a mapping - vim

If I use <Esc>[s1z=`]a in an inoremap mapping (jump to normal mode, find previous spelling error, replace it with the first choice, jump back to last edit and append), everything works fine. The problem is I often don't want the first spelling choice. If I remove the 1 I will be given the spelling menu, but the `]a seems to get swallowed up and lands me at the first character of the corrected word still in normal mode. The mapping itself shouldn't be looking for input, perse, as the z= itself should handle the menu entry. Indeed if I run these commands manually (without the 1, it works as expected. I have tried making named marks and jumping back to those, but it seems z= and everything after it gets consumed as one thing. Does anyone have any suggestion as to how to make the mapping continue after I make a spelling menu selection? Thanks.

I think that Vim stops processing the right-hand side of the mapping as soon as it presses z= because it's not a complete command (you have to provide the index of a suggestion in the menu for it to be complete).
The :normal command has the same issue:
:norm[al][!] {commands}
...
{commands} should be a complete command. If
{commands} does not finish a command, the last one
will be aborted as if <Esc> or <C-C> was typed.
As an alternative, you could invoke the feedkeys() function to press z=.
For example:
ino <c-j> <c-r>=<sid>fix_typo()<cr>
fu! s:fix_typo() abort
let spell_save = &l:spell
try
setl spell
call feedkeys("\e\e[sz=", 'int')
augroup fix_typo
au!
au TextChanged * call feedkeys('`]a', 'int')
\ | exe 'au! fix_typo'
\ | aug! fix_typo
augroup END
finally
call timer_start(0, {-> execute('let &l:spell = '.spell_save)})
endtry
return ''
endfu
This code installs a mapping in insert mode using the C-j key. You could use another key if you don't like this one.
The mapping calls the s:fix_typo() function which:
temporarily enables 'spell' to avoid the error E756
presses the keys Esc Esc [s z= to prompt the suggestions
installs a fire-once autocmd listening to TextChanged to press the keys `]a once you've selected a word in the menu
restores the original value of 'spell'

Related

Enter insert mode between two tags after command in vim

I'm looking to change the following vim command so that after entering the :%s/temp123//g part it will put me into insert mode between the \begin and \end tags.
inoremap \\beg \begin{temp123}<enter><enter>\end{temp123}<enter><esc>:%s/temp123//g<left><left>
I have been able to use :startinsert to get into go into insert mode after entering the search/replace command but I am not able to place the cursor between the \begin and \end tags.
Any help/solutions/improvements would be appreciated.
TL;DR: can't.
:star[tinsert][!] Start Insert mode just after executing this command.
Works like typing "i" in Normal mode. When the ! is
included it works like "A", append to the line.
Otherwise insertion starts at the cursor position.
Note that when using this command in a function or
script, the insertion only starts after the function
or script is finished.
This command does not work from :normal.
I was trying to get the following line working:
nnoremap <MiddleMouse> :set paste<cr>:startinsert<MiddleMouse><esc>
What this means is that all of my commands that I put after :startinsert instead run immediately before :startinsert and then :startinsert runs and changes the mode to insert (Note: this appears to hold true for using i instead of :startinsert as well).
My next step was to try to make a nested function, where I had one function that calls another function, and the second function runs :startinsert and then returns to the first function, which then completes the paste:
function! Paste()
call InsertMode()<cr>
:set paste<cr>
<S-Insert>
:set nopaste<cr>
<esc>
endfunction
function! InsertMode()
:startinsert<cr>
endfunction
nnoremap <MiddleMouse> call Paste()<cr>
But this did not work either. I also tried using the "+p and "*p registers without :startinsert with nnoremap <MiddleMouse> :set paste<cr>"+p:set nopaste<cr>, but this again just pastes directly as if I were typing it in, it does not enter insert mode first. I am willing to believe this would work on a version of Vim compiled with +clipboard, but that is not the version I have. Link to my original question and answer
Yep, you're looking for an interactive substitution, but :s/new/old/gc doesn't let you edit each match. For this kind of work, switch to the gn command + . recipe:
First search for {temp123} (or whatever you wish to replace) with /
Then press cgn to change the visually selected next match
Once done, go back to normal mode to commit your edits.
If the next edit is the same as the last, press only . otherwise cgn
Rise and repeat.
For more ideas, see this vimcast: gn command
This is the solution I am now using.
function TexBegin()
let currline = line(".")
call inputsave()
let tagname = input("enter tag name: ")
call inputrestore()
call setline(currline, "\\begin{" . tagname . " }")
normal o
normal o
call setline(currline + 2, "\\end{" . tagname . "}")
normal l
startinsert
normal o<Esc>
endfunction
inoremap \\beg <Esc>:call TexBegin()<CR>

open a completion popup from normal mode

Gived this script (packages suggestion was simplified, original takes care of <cword>)
function! CompleteImport()
let packages = ['java.util.Vector','java.lang.String']
call complete(col('.'),packages)
return ''
endfunction
inoremap <F8> import <C-R>=CompleteImport()<CR>
while on insert mode you can add an import and choose between suggested packages pressing F8
But I want to be enable to reach that popup selection from normal mode
function! InsertImport()
exe "normal iimport \<C-R>=CompleteImport()\<CR>"
"this commented line would work too
"exe "normal i\<F8>"
endfunction
map <Leader>ji :call InsertImport()<CR>
so from normal mode ,ji (stands for java import) add an import to word under cursor if it is found
(Move to right position is not a problem so I ommit here)
By now ,ji adds first suggestion from popup and exists insert mode
I have tried :startinsert but no luck.
see on http://vimdoc.sourceforge.net/htmldoc/eval.html#:execute there is a suggested code:
:execute "normal ixxx\<Esc>"
but that final Esc doesn't matter at all (for my vim install at least) This do exactly the same for me:
:execute "normal ixxx"
I would think this is not possible if I haven't found that on docs. So, it's possible to stay on a popup calling from a function?
Other interested docs:
http://vimdoc.sourceforge.net/htmldoc/various.html#:normal
http://vimdoc.sourceforge.net/htmldoc/insert.html#:startinsert
:startinsert usually is the right approach, but it indeed gives control back to the user, so you cannot automatically trigger the completion.
Through the feedkeys() function, you can send arbitrary keys "as if typed". This allows you to start insert mode and trigger the completion:
function! InsertImport()
call feedkeys("iimport \<C-R>=CompleteImport()\<CR>", 't')
endfunction
nnoremap <Leader>ji :call InsertImport()<CR>
PS: You should use :noremap for the normal mode mapping, too; it makes the mapping immune to remapping and recursion.

How to make z= look like ctrl-x s in vim spell check

So in insert mode if you hit ctrl-x s on a misspelled word you get a nicely formatted popup menu of spelling suggestions. This is awesome.
The comparable command in normal mode (z=), however, gives a bland plain-text list that eats the whole screen.
I've partially solved this by adding the following keybinding in my .vimrc:
nnoremap <Leader>s ea<C-X><C-S>
This works perfectly and hitting s in normal mode gives me the same drop down... The only problem is I'm now left in insert mode at the end of everything. Is there some way to get the drop down style selection and end up in normal mode after the replace is all said and done?
You can't do it directly. The popup menu you're thinking of is specifically referred to as "insert mode completion".
However, you're halfway there, by mapping a key that enters insert mode and starts the completion. Now all you need is to map a key that selects the entry (like the 'enter' key) to also exit insert mode.
You should test the return value of pumvisible() in your mapping, to prevent it firing when you don't want. Example (from comments):
inoremap <expr> <CR> pumvisible() ? "\<C-y><Esc>" : "\<CR>"
Perhaps you could also set a variable or something, or use a key you won't use to end actual insert mode completion.

How to prevent <Esc> from waiting for more input in Insert Mode

When I leave insert mode by pressing Esc, there is a half-second pause before Vim actually returns to normal mode.
Normally this wouldn't be an issue, since pressing a normal mode command like j after pressing Esc executes the normal-mode command immediately (without the above-mentioned wait), but I have the mapping inoremap <Esc> <Esc>:w<CR>, so that every time I leave insert mode the file is written. I would like the write to occur immediately when I press Esc, but instead there is that half-second pause.
I'm assuming that the pause is because Vim is waiting for more input before it decides that I just meant to type a single, simple Esc. This must be because there is a mapping somewhere who's first character is <Esc>, but I've looked in my .vimrc and there is no such mapping.
Furthermore, I even ran :map <Esc>, and it returned No such mapping. So, if there is no such mapping, why does Vim appear to be waiting for more input, and how can I avoid that behavior?
Extra Information
It appears that this is not reproduceable, so here is some more information in case anyone really wants to get to the bottom of this:
I am using Steve Francia's spf13 distribution of Vim, with my own .vimrc.local on top of it. I have also installed several additional plugins using Vundle.
Notes: .vimrc.local is sourced last in .vimrc.
UPDATE (3/19/2014)
I found a far better solution than trying to hunt down all the mappings that start with <Esc>, courtesy of Powerline, from the Tips & Tricks section of the docs. Put this somewhere in your .vimrc:
" leave insert mode quickly
if ! has('gui_running')
set ttimeoutlen=10
augroup FastEscape
autocmd!
au InsertEnter * set timeoutlen=0
au InsertLeave * set timeoutlen=1000
augroup END
endif
Note that this will make it impossible to use mappings that start with <Esc> while in insert mode, but there shouldn't be any of those anyway, because of the problem this solves.
I found the lines in spf13's .vimrc that were causing the problem:
" Fix home and end keybindings for screen, particularly on mac
" - for some reason this fixes the arrow keys too. huh.
map ^[F $
imap ^[F $
map ^[H g0
imap ^[H g0
The reason I couldn't find them before is because they weren't mapped using <Esc>, but ^[ instead. Very irritating! Hope this helps some equally disgruntled spf13 user :)
UPDATE:
If removing those mappings doesn't work, then it's probably a mapping from a plugin.
Type :verbose map <Esc> to get a list of all mappings involving Esc. The verbose part instructs Vim to print where the mapping was set. That should help find out what's causing the problem.
Also, the command unmap <Esc> might be useful—it removes any mappings for the Esc key.
Note that unmap does not remove mappings in all modes; type :h unmap for more info.
In my case, it was tmux injecting that delay (this came as a complete surprise for me!).
I fixed it by adding set -g escape-time 0 to my tmux.conf.
This may not strictly help the author, but this question comes up first when searching for this issue with many different keyword combinations, so I hope it helps someone.
Source: first comment from here.
I'm not exactly sure what the problem is with the mapping you describe, in my opinion it should be fine. However, I think that what you want to accomplish can be reached in a better way. Your mapping is basically an attempt at creating a InsertLeave event, which Vim actually already has built in!
Try adding something like this to your .vimrc:
au InsertLeave * if &mod && expand('%')!=''|write|endif
As an added bonus, this one only saves your buffer if it has a filename and was actually modified.
set timeoutlen=1000 ttimeoutlen=0
timeoutlen - mapping delays.
ttimeoutlen - key code delays.
Source

move the text after the cursor to a new line

I am Vim newbie, and I'm using MacVim on OSX Snow Leopard. One of the most common actions I have to take is to move the cursor to a new line but also move the text after the cursor to the new line. I know that pressing 'o' in normal or visual mode moves the cursor to a new line and switches the mode to insert.
What I'd like to do is move the cursor to a new line, and move the text after the cursor to that new line as well, preferably staying in the normal mode? Is this possible? How can I accomplish this task?
If the cursor is on a <space> as in ([] marks the cursor):
lorem ipsum[ ]dolor sit amet
the simplest is to do r<CR>, that is "replace the current character with a linebreak".
Otherwise, use #knittl's solution.
So you want to move everything in the current line, which comes after the cursor to the next line? Read: insert a line break??
(move cursor)
i (or a)
<return>
<esc> (or ^C)
To map this sequence of keystrokes to a single key, follow #thb's suggestion and use the :map command:
:map <F2> i<CR><ESC>
:map <F2> i<CR>
This keeps vi in insert mode.
As I answered in this post, How do I insert a linebreak where the cursor is without entering into insert mode in Vim?.
Please try Control + j.
The code below achieves the same behavior as "normal" editors (for the lack of better terms on the top of my mind) except that you'd have to press "enter" twice instead of once.
I also wanted to get rid of the space if it's right before my current character.
There might be an easier way and I totally welcome edits :-)
" in ~/.vimrc or ~/.vimrc.after if you're using janus
nnoremap <cr><cr> :call ReturnToNewLine()<cr>
function ReturnToNewLine()
let previous_char = getline(".")[col(".")-2]
" if there's a space before our current position, get rid of it first
if previous_char == ' '
execute "normal! \<bs>\<esc>"
endif
execute "normal! i\<cr>\<esc>"
endfunction
This remaps pressing enter twice to going to insert mode, placing a carriage return and escaping.
The reason I'm using this mapping (enter twice) is because I was used to this functionality with other text editors by pressing a enter; also, typing enter twice is fast.
Another thing that I found useful in this context was allowing vim to move right after the last character (in case I wanted to move the last character to a new line). So I have the following in my ~/.vimrc as well.
set virtualedit=onemore
Note that I'm using nnoremap (normal mode non-recursive) instead of map (which is VERY dangerous) (check this out for more information on the differences http://learnvimscriptthehardway.stevelosh.com/chapters/05.html)
You need to map some keys to do a line break at the cursor,
I found the following mapping easy to use, just go to your vimrc and add this line:
:map <silent> bl i<CR><ESC>
to assign a line break at cursor to "bl" combo

Resources