Can't use ENTER in vim? - vim

In my vimrc, I use ENTER to expand UltiSnips:
let g:UltiSnipsExpandTrigger = '<CR>'
But this cause I can't use ENTER in insert mode, how to solve it?

I created a solution that works for me based on some tricks described here: https://github.com/SirVer/ultisnips/issues/376
let g:ulti_expand_or_jump_res = 0
function! ExpandSnippetEx(val)
let snippet = UltiSnips#ExpandSnippetOrJump()
if g:ulti_expand_or_jump_res > 0
return snippet
else
return a:val
endif
endfunction
inoremap <expr> <CR> \<C-R>=ExpandSnippetEx('<C-V><CR>')
This attempts to expand the snippet, and if no snippet is found, instead of doing nothing, it inserts an ENTER.

Related

How can I block moving up/down with multiple j,k keystrokes?

I learned moving with hjkl by blocking arrow keys.
I'd like to do something similiar for moving up/down with jjjjjj/kkkkk.
For example whenever I press j 4 times in a row with small delays it would jump back to original position, so I'd have to think how to move smarter to the place I want.
I'm not a fan of technical solutions to this problem (I'd rather critically reflect on my own typing occasionally), but this can be done by storing subsequent keypresses in an array, and complaining if the size becomes too large:
let g:pos = []
let g:keys = []
function! RecordKey( key )
if v:count || get(g:keys, 0, '') != a:key
" Used [count], or different key; start over.
let g:keys = [a:key]
let g:pos = getpos('.')
echo
return 1
endif
call add(g:keys, a:key)
if len(g:keys) > 4
" Too many identical movements (without count).
let g:keys = [a:key]
call setpos('.', g:pos)
echohl ErrorMsg
echomsg 'Try again'
echohl None
return 0
endif
echo
return 1
endfunction
" Reset counter after a delay in movement.
autocmd CursorHold * let g:keys = []
nnoremap <silent> j :<C-u>if RecordKey('j')<Bar>execute 'normal!' (v:count ? v:count : '') . 'j'<Bar>endif<CR>
nnoremap <silent> k :<C-u>if RecordKey('k')<Bar>execute 'normal!' (v:count ? v:count : '') . 'k'<Bar>endif<CR>
" Add more movements as you wish.
(Trying this out, I'm already annoyed by this :-)
I would suggest the following mappings:
nnoremap jjjj j
nnoremap kkkk k
This will make fast movement up and down very cumbersome. Unfortunately it will also prohibit a normal 'j' from executing very fast, as Vim will wait to see whether you want to add anything else after the first keypress to complete the binding. This can be circumvented by pressing another key afterwards (e.g. switching to insert mode with i/I/a/A or the like).

How to give nmap a key variable in Vim?

I just got answer to jump to the line start with given character by typing
/ + ^[character]
But I thought it's not as fast as f to jump to character in a line. so i'm want to map it to a key combination like
go + [character]
by doing something like in the .vimrc
nmap go<expr> /^<expre>
See :help map-expression; you can query a single character with getchar():
:nnoremap <expr> go '/^' . nr2char(getchar()) . '<CR>'
it is hard to map this function directly. because the letter/character could be anything.
But this small function may work for you:
function! GoToLine()
call inputsave()
let c= input('Enter chars:')
call inputrestore()
call search ('^' . c)
let #/ = '^'.c
endfunction
you can map for example:
nnoremap <leader>go call GoToLine()
then enter chars you need, the function will bring you there. In this way you could enter more than one chars.
hope it helps.

Show function name in status line

I edit a large C, C++, or Java file, say, about 15000 lines, with pretty long function definitions, say, about 400 lines. When the cursor is in middle of a function definition, it would be cool to see the function name in Vim status line.
When we set :set ls=2 in Vim, we can get the file path (relative to the current directory), line number, etc. It would be really cool if we could see the function name too. Any ideas how to get it?
Currently I use [[ to go to start of the function and Ctrl-O to get back to the line I'm editing.
To show current function name in C programs add following in your vimrc:
fun! ShowFuncName()
let lnum = line(".")
let col = col(".")
echohl ModeMsg
echo getline(search("^[^ \t#/]\\{2}.*[^:]\s*$", 'bW'))
echohl None
call search("\\%" . lnum . "l" . "\\%" . col . "c")
endfun
map f :call ShowFuncName() <CR>
Or if you need the "f" key, just map the function to whatever you like.
You can use ctags.vim for this, it will show the current function name in the title or status bar.
SOURCE: https://superuser.com/questions/279651/how-can-i-make-vim-show-the-current-class-and-method-im-editing
Based on #manav m-n's answer
The 'n' flag in search() won't move the cursor, so a shorter version of this with the same functionality would be:
fun! ShowFuncName()
echohl ModeMsg
echo getline(search("^[^ \t#/]\\{2}.*[^:]\s*$", 'bWn'))
echohl None
endfun
map f :call ShowFuncName() <CR>
Reference: run :help search()
Having investigated this and the accepted solution, I believe the simplest solution is:
Install Universal Ctags https://ctags.io/
Install Tagbar https://github.com/preservim/tagbar
call tagbar#currenttag() when setting your statusline, e.g. in .vimrc:
:set statusline=%<%f\ %h%m%r%=%{tagbar#currenttag('%s\ ','','f')}%-.(%l,%c%V%)\ %P
Note that:
Spaces must be slash-escaped in the strings you pass to currenttag()...and it's even different between running the command inside vim and putting it in your .vimrc?? Anyway, spaces can be weird, and they're probably something you want when outputting the function name.
It took me some digging but the default statusline is
:set statusline=%<%f\ %h%m%r%=%-14.(%l,%c%V%)\ %P
There are several plugins for status line or on-demand with a mapping, e.g.:
http://www.vim.org/scripts/script.php?script_id=1094
http://www.vim.org/scripts/script.php?script_id=2805
http://www.vim.org/scripts/script.php?script_id=1553
My solution is as follows:
set stl=%f%h%m%r\ %{Options()}%=%l,%c-%v\ %{line('$')}
fu! PlusOpt(opt)
let option = a:opt
if option
return "+"
else
return "-"
endif
endf
fu! Options()
let opt="ic".PlusOpt(&ic)
let opt=opt." ".&ff
let opt=opt." ".&ft
if &ft==?"cpp" || &ft==?"perl"
let text = " {" . FindCurrentFunction() . "}"
let opt= opt.text
endif
return opt
fu! FindCurrentFunction()
let text =''
let save_cursor = getpos(".")
let opening_brace = searchpair('{','','}','bWr', '', '', 100)
if opening_brace > 0
let oldmagic = &magic
let &magic = 1
let operators='operator\s*\%((\s*)\|\[]\|[+*/%^&|~!=<>-]=\?\|[<>&|+-]\{2}\|>>=\|<<=\|->\*\|,\|->\|(\s*)\)\s*'
let class_func_string = '\(\([[:alpha:]_]\w*\)\s*::\s*\)*\s*\%(\~\2\|'.operators
let class_func_string = class_func_string . '\|[[:alpha:]_]\w*\)\ze\s*('
let searchstring = '\_^\S.\{-}\%('.operators
let searchstring = searchstring.'\|[[:alpha:]_]\w*\)\s*(.*\n\%(\_^\s.*\n\)*\_^{'
let l = search(searchstring, 'bW', line(".")-20 )
if l != 0
let line_text = getline(l)
let matched_text = matchstr(line_text, class_func_string)
let matched_text = substitute(matched_text, '\s', '', 'g')
let text = matched_text
endif
call setpos('.', save_cursor)
let &magic = oldmagic
endif
return text
endfunction
I'm actually attempting to match the C/C++/Java allowed names for functions. This generally works for me (including for overloaded operators) but assumes that the opening { is at column 0 on a line by itself.
I just noticed today that it fails if included in a namespace {}, even if otherwise formatted as expected.
I use https://github.com/mgedmin/chelper.vim for this. It doesn't needs a tags file, instead it parses the source code on the fly.
Based on #solidak solution (which was already based on another one :)
I wanted to always show the function name in the bottom of the terminal.
But I had some problems with very large function which I solved that way:
fun! ShowFuncName()
echohl ModeMsg
echo getline(search("^[^ \t#/]\\{2}.*[^:]\s*$", 'bWn'))[:winwidth('%')-3]
echohl None
endfun
augroup show_funcname
autocmd CursorMoved * :call ShowFuncName()
augroup end

Can you do interactive macros or recordings in vim?

I would like to define a vim macro that breaks for user input at certain times, is this possible?
EDIT: Turns out I ment recordings (q), not macros
It is possible to use the input command in a recording, but it's more trouble than it's worth.
I first mapped insert input escape to a key
:map <F2> a<C-R>=input('input: ')<CR>
then I made this recording in the q register
name:
and pasted it into a new tab
iname: ^[
And after the final escape I pressed <C-V><F2> making the line:
iname ^[^[OQ
That I yanked back to the q buffer then used the macro, letting me use the input function.
It works, but terribly.
Yes. See the function input({prompt}, [, {text} [, {completion}] ]). There is even
inputdialog({prompt} [, {text} [, {cancelreturn}]]), for a dialog popup.
If you use input() inside a mapping or macro, the remaining characters will be taken as input, which is not what you want. Vim offers the inputsave() and inputrestore() functions to temporarily suspend reading from the mapping character stream.
Based on mogelbrod's answer, this doesn't work; the itest is read in as input:
oBEFORE ^R=input('prompt> ')^Mitest
But this does:
function! Input()
call inputsave()
let text = input('prompt> ')
call inputrestore()
return text
endfunction
oBEFORE ^R=Input()^Mitest
Unfortunately, because <C-R> takes an expression, we cannot put the commands inline, but have to define a separate Input() function.
Unfortunately it doesn't seem to be possible. You can trigger input() inside a macro, but continuing on afterwards doesn't seem to be possible as any additional input recorded is inserted into the input prompt.
Yank the line into a named register ("qY) and run it (#q) to try it out.
Note: replace ^R and ^M with Ctrl-V Ctrl-R/M (see :help i_CTRL-V).
oBEFORE ^R=input('prompt> ') - works
oBEFORE ^R=input('prompt> ')^Mitest - works, but inserts itest into the prompt
oBEFORE ^R=input('prompt> ')<CR>test - fails
I have collected information from this and other threads and written this script:
function! MacroInterrupt()
"call inputsave()
if strlen(reg_recording()) == 0
if mode() == 'n'
call inputsave()
let tmp_col = col('.')
let tmp_line = line('.')
let text = input('input:')
let line = getline('.')
call setline('.', strpart(line, 0, col('.') - 1) . text . strpart(line, col('.') - 1))
call cursor(tmp_line, tmp_col + strlen(text))
call inputrestore()
return text
else
call inputsave()
let text = input('input:')
call inputrestore()
return text
endif
else
echo "Interrupt added to macro"
call setreg(reg_recording(), getreg(reg_recording()) . "\<F2>")
"echo getreg("q")
endif
"call inputrestore()
endfunction
map <F2> :call MacroInterrupt() <CR>
inoremap <buffer><expr> <F2> MacroInterrupt()
I hope this can help especially people attempting the same.

CamelCase Expansion in Vim like Intellij Idea?

In Intellij Idea, there's a feature. Let's say I have used a variable myCamelCase somewhere in my code. Then if I type mCC and press Ctrl-Enter or some such key combination, it expands to myCamelCase. Is there something similar in Vim?
Okay, forgive me for answering twice, but since my first attempt missed the point, I'll have another go. This is more complicated than I thought, but possibly not as complicated as I have made it (!).
This is now modified to suggest all matching variable names.
First of all, here's a function to generate the 'mCC' abbreviation from the 'myCamelCase' string:
function! Camel_Initials(camel)
let first_char = matchstr(a:camel,"^.")
let other_char = substitute(a:camel,"\\U","","g")
return first_char . other_char
endfunction
Now, here's a function that takes an abbreviation ('mCC') and scans the current buffer (backwards from the current line) for "words" that have this abbreviation. A list of all matches is returned:
function! Expand_Camel_Initials(abbrev)
let winview=winsaveview()
let candidate=a:abbrev
let matches=[]
try
let resline = line(".")
while resline >= 1
let sstr = '\<' . matchstr(a:abbrev,"^.") . '[a-zA-Z]*\>'
keepjumps let resline=search(sstr,"bW")
let candidate=expand("<cword>")
if candidate != a:abbrev && Camel_Initials(candidate) == a:abbrev
call add( matches, candidate )
endif
endwhile
finally
call winrestview(winview)
if len(matches) == 0
echo "No expansion found"
endif
return sort(candidate)
endtry
endfunction
Next, here's a custom-completion function that reads the word under the cursor and suggests the matches returned by the above functions:
function! Camel_Complete( findstart, base )
if a:findstart
let line = getline('.')
let start = col('.') - 1
while start > 0 && line[start - 1] =~ '[A-Za-z_]'
let start -= 1
endwhile
return start
else
return Expand_Camel_Initials( a:base )
endif
endfunction
To make use of this, you must define the "completefunc":
setlocal completefunc=Camel_Complete
To use insert-mode completion, type CTRL-X CTRL-U, but I usually map this to CTRL-L:
inoremap <c-l> <c-x><c-u>
With this code in your vimrc you should find that typing mCC followed by CTRL-L will make the expected replacement. If no matching expansion is found, the abbreviation is unchanged.
The code isn't water-tight, but it works in all the simple cases I tested. Hope it helps. Let me know if anything needs elucidating.
There is a plugin for this in Vim called vim-abolish. Use the map crc to expand to camel case.

Resources