Allowing custom motion in a vim map? - vim

I have the following mapping that allows to paste over a word from the yank buffer. (cpw = change paste word): nmap <silent> cpw "_cw<C-R>"<Esc>
What I would like to do is allow commands such as the following:
cpiw (change paste in word -> like the 'iw' motion)
cpaw (change paste a word -> like the 'aw' motion)
for any motion {m} cp{m}
Is this possible to allow in a mapping, so I don't have to write the nmap for each motion that I want to work with it?
Thanks in advance.
EDIT: typo fixes. My solution below
After diligently looking into the map-operator I was successful in making a function that did exactly as I wanted. For any who are interested it is as follows:
"This allows for change paste motion cp{motion}
nmap <silent> cp :set opfunc=ChangePaste<CR>g#
function! ChangePaste(type, ...)
silent exe "normal! `[v`]\"_c"
silent exe "normal! p"
endfunction
EDIT - new version that might be better.
"This allows for change paste motion cp{motion}
nmap <silent> cp :set opfunc=ChangePaste<CR>g#
function! ChangePaste(type, ...)
if a:0 " Invoked from Visual mode, use '< and '> marks.
silent exe "normal! `<" . a:type . "`>\"_c" . #"
elseif a:type == 'line'
silent exe "normal! '[V']\"_c" . #"
elseif a:type == 'block'
silent exe "normal! `[\<C-V>`]\"_c" . #"
else
silent exe "normal! `[v`]\"_c" . #"
endif
endfunction

There is a way to define a custom operator, see :help :map-operator for details.

Related

Prevent grep results opening in NerdTree window

I've just started using EasyGrep . Often my NERDTree window is in focus when I am doing a search and the first search result loads in this window.
Is there a way to force EasyGrep to open the first result in the main buffers window?
Thanks!
Here is what I added in my .vimrc:
function! SearchOutsideOfNerdtree()
if &filetype == 'nerdtree'
:wincmd l
endif
:execute input("", ":Grep\<Space>")
endfunction
function! ReplaceOutsideOfNerdtree()
if &filetype == 'nerdtree'
:wincmd l
endif
:execute input("", ":Replace\<Space>")
endfunction
nnoremap <Leader>f :call SearchOutsideOfNerdtree()<CR>
nnoremap <Leader>g :call ReplaceOutsideOfNerdtree()<CR>
Basically I created a function that checks if the current filetype is nerdtree and I move to the right buffer.
Here is what I added in my .vimrc and it works:
nnoremap <silent> ,g :<C-u>wincmd w<CR>:Unite grep:. -buffer-name=search-buffer<CR>

programing diff vim function, vim diff mapping

I've found this function:
" Set up a keymapping from <Leader>df to a function call.
" (Note the function doesn't need to be defined beforehand.)
" Run this mapping silently. That is, when I call this mapping,
" don't bother showing "call DiffToggle()" on the command line.
nnoremap <silent> <Leader>df :call DiffToggle()<CR>
" Define a function called DiffToggle.
" The ! overwrites any existing definition by this name.
function! DiffToggle()
" Test the setting 'diff', to see if it's on or off.
" (Any :set option can be tested with &name.
" See :help expr-option.)
if &diff
diffoff
else
diffthis
endif
:endfunction
Now I would like to add an extra condition, if there is some selected text (visual mode) call another command instead of diffthis, Linediff
Reading the function I guess I need some extra set option to test, like they did with &dif but with the visual option. Something like:
function! DiffToggle()
if &dif
diffoff
elseif &visual
Linediff
else
diffthis
endif
:endfunction
This doesn't work, but does anyone have any clue to make it work?
Also, it would be very useful any reference about what and how many setting variables of this kind are in vim.
Edit
I ended up with this in my vimrc, (works):
"LINEDIFF/VIMDIFF
"--------------
nnoremap <silent> <Leader>df :call DiffToggle('n')<CR>
xnoremap <silent> <Leader>df :call DiffToggle('x')<CR>
function! DiffToggle(mode) range
echo "difftoggle..."
if &diff
diffoff
echo "diffoff..."
else
if a:mode=='x'
echo "linediff..."
echo a:firstline."---".a:lastline
call linediff#Linediff(a:firstline, a:lastline)
else
echo "diff..."
diffthis
endif
endif
:endfunction
Simply call a slightly different function from xnoremap <Leader>df ... ? That one will be called when you are in visual mode.
Or, pass the mode as argument to your function:
nnoremap <silent> <Leader>df :call DiffToggle('n')<CR>
xnoremap <silent> <Leader>df :call DiffToggle('x')<CR>
... and check a:mode inside your function, having the following prototype:
function! DiffToggle(mode)

How to let and execute in the same line?

I was trying to make a simple setup for Perl in Vim and used this:
function! PerlEnvSetup()
nnoremap <F10> :let f=expand("%")|vnew|execute '.!perl "' . f . '"'<CR>
endf
autocmd FileType perl :call PerlEnvSetup()<CR>
But when I do vim XX.pl, the error in the bottom saying:
Error detected while processing function PerlEnvSetup:
line 1:
E121: Undefined variable: f
E15: Invalid expression: '.!perl "' . f . '"'<CR>
Error detected while processing FileType Auto commands for "perl":
E488: Trailing characters
And the window splits into two (which should not happen unless I press F10). What am I doing wrong here?
What you are seeing, is that the | is used to separate commands (and therefore explicitly ends your :nnoremap command.
You therefore want to use the special idiom <Bar> as described by the help below :h map_bar
Here's another option:
function! PerlExecuteCurrentFile()
let f=expand("%")
vnew
execute '.!perl "' . f . '"'
endf
function! PerlEnvSetup()
nnoremap <F10> :call PerlExecuteCurrentFile()<CR>
endf

How to map VIM to run current RSpec file in console?

I'm trying this:
inoremap <F2> :!rspec %
But it doesn't work. Can anyone help?
The "i" in inoremap means "insert mode": your mapping is an insert mode mapping so it obviously won't work in normal mode.
Try nnoremap ("n" for "normal mode") instead and add <CR> at the end to actually execute the command:
inoremap <F2> :!rspec %<CR>
Since we are at it, you could also modify it to "write and run":
nnoremap <F2> :update<bar>!rspec %<CR>
Maybe this is a better solution to check the file with rspec (put these lines in to your .vimrc, it needs nocompatible to be set, works in insert mode):
" Open quickfix window after :make if there was errors.
autocmd QuickFixCmdPost * botright cwindow
inoremap <F2> :call Rspec()<CR>
" Check the file with rspec, don't forget to save it before calling.
function Rspec()
let save_makeprg = &makeprg
compiler rspec
let &makeprg = 'rspec "' . expand( '%' ) . '"'
echo expand( &makeprg )
silent make
let &makeprg = save_makeprg
redraw!
endfunction
It will list the errors in quickfix window.

Vim: open a temporary buffer displaying executable's output

I have found the :cwindow command to be very useful and I was wondering if I could get similar functionality using the output of my compiled code. I'd the output of :!./a.out to appear in a "quickfix" style buffer.
I've also noticed that even after taking the standard steps to prevent the "Press Enter to continue" message, it still happens at least once on :make and :!./a.out - using :silent to suppress this causes my tmux to go completely blank. My current workaround involves a mapping with a lot of carriage returns, is there another way?
Sure, you can use vim's preview window with a short function to execute the command, try this in your .vimrc:
fun! Runcmd(cmd)
silent! exe "noautocmd botright pedit ".a:cmd
noautocmd wincmd P
set buftype=nofile
exe "noautocmd r! ".a:cmd
noautocmd wincmd p
endfun
com! -nargs=1 Runcmd :call Runcmd("<args>")
Then you can:
:Runcmd ls
And see the results of ls in your preview window
I found this:
" Shell ------------------------------------------------------------------- {{{
function! s:ExecuteInShell(command) " {{{
let command = join(map(split(a:command), 'expand(v:val)'))
let winnr = bufwinnr('^' . command . '$')
silent! execute winnr < 0 ? 'botright vnew ' . fnameescape(command) : winnr . 'wincmd w'
setlocal buftype=nowrite bufhidden=wipe nobuflisted noswapfile nowrap nonumber
echo 'Execute ' . command . '...'
silent! execute 'silent %!'. command
silent! redraw
silent! execute 'au BufUnload <buffer> execute bufwinnr(' . bufnr('#') . ') . ''wincmd w'''
silent! execute 'nnoremap <silent> <buffer> <LocalLeader>r :call <SID>ExecuteInShell(''' . command . ''')<CR>:AnsiEsc<CR>'
silent! execute 'nnoremap <silent> <buffer> q :q<CR>'
silent! execute 'AnsiEsc'
echo 'Shell command ' . command . ' executed.'
endfunction " }}}
command! -complete=shellcmd -nargs=+ Shell call s:ExecuteInShell(<q-args>)
nnoremap <leader>! :Shell
" }}}
in steve losh's .vimrc - see which I shamelessly copied.
I have just discovered the :read command, which puts the output of a shell command into a window.
I went looking for this because I often want to grep for a file in the current directory which contains a certain string (and then open it into my current VIM).
Here is a shortcut I have in my $MYVIMRC:
noremap <leader>g :new<CR>:read ! grep -rn "
With this, when I press \g I get a new buffer created in a split window and find
:read ! grep -rn "
sitting waiting for me in the command area. Now I just type my search string, close the double quotes and hit <Enter> and the buffer fills with the command output.
Once done, a simple
:bw!
in that new buffer will kill it.
First open a preview window, and set it to autoread a file:
:botr pedit +:setl\ autoread /tmp/out.log
Now just run your command, and send the output to the file.
:!date > /tmp/out.log 2>&1
The result of your command should appear in the preview window.
However, we are still getting the "Press ENTER" prompt. A simple way to avoid that is to make a mapping that presses Enter for us:
:nmap <Leader>r :exec '!date > /tmp/out.log 2>&1'<CR><CR><CR>
I thought only two <CR>s would be needed but then found myself needing three.

Resources