Is it possible to cycle around marks in vim? - vim

I am starting to use [' and ]' to jump between my marks in a file, as mentioned here:
http://vim.wikia.com/wiki/Using_marks
However, when I get to the last mark in the file these commands don't wrap around to the top.
I searched around for "cycling" or "wrapping" when it comes to navigating marks but everything I see mentions Ctrl-o and Ctrl-i which is nice but doesn't answer my question.
Is it possible to set an option to wrap top-to-bottom or bottom-to-top when using these shortcuts?

You can create a function to check if you have moved, and if not then go to the beginning of the file and call ]' again. Like this:
nnoremap ]' :call CycleMarksForward()<cr>
function! CycleMarksForward()
let currentPos = getpos(".")
execute "normal! ]'"
let newPos = getpos(".")
if newPos == currentPos
execute "normal! gg]'"
endif
endfunction
You'll need to the same thing for [` ]` and [', although there is probably a way to come up with a generic solution.
Fleshed out:
nnoremap <silent> ]' :call CycleMarks("]'")<cr>
nnoremap <silent> [' :call CycleMarks("['")<cr>
nnoremap <silent> ]` :call CycleMarks("]`")<cr>
nnoremap <silent> [` :call CycleMarks("[`")<cr>
function! CycleMarks(arg)
let currentPos = getpos(".")
execute "normal! " . a:arg
let newPos = getpos(".")
if newPos == currentPos
if a:arg == "]'" || a:arg == "]`"
execute "normal! gg0" . a:arg
else
execute "normal! G$" . a:arg
endif
endif
endfunction
Note: this solution does not handle marks on the first and last line very well, i.e. marks on the last line will be skipped when cycling backwards and marks on the first line will be skipped when cycling forward.

Related

vimscript replace line not working

Newcomer to VimL trying to write a mapping that does the following:
foo
|----> cursor
bar
baz
lr2j should repalce foo with baz.
" replace the current line with a line given by a linewise motion
function! s:LineReplace(type)
if a:type !=# 'line'
return
endif
let saved_register = ##
silent execute "normal! S\<esc>my`]dd'yPjddk^ :delmarks y"
let ## = saved_register
endfunction
nnoremap lr :set operatorfunc=<SID>LineReplace<cr>g#
Instead I get
Error detected while processing function <SNR>108_LineReplace: line 5: E20: Mark not set
I've tried different permutations of execute "normal! ..." command to no avail. Can anyone spot the error?
I should note that when I test out the normal commands everything works fine and the mark 'y exists.
Use :move and :delete to simply things:
" replace the current line with a line given by a linewise motion
function! s:LineReplace(type)
if a:type !=# 'line'
return
endif
']move '[
-delete_
endfunction
nnoremap lr :set operatorfunc=<SID>LineReplace<cr>g#
For more help see:
:h :d
:h :m
:h :range
#xaizek is right; the correct way is to store the mark from the motion:
" replace the current line with a line given by a linewise motion
function! s:LineReplace(type)
if a:type !=# 'line'
return
endif
let lnum = getpos("']")[1]
let saved_register = ##
silent execute "normal S\<esc>my" . lnum . "Gdd'yPjddk^ :delmarks y"
let ## = saved_register
endfunction
nnoremap lr :set operatorfunc=<SID>LineReplace<cr>g#

How do one add custom verbs to VIM?

I would like to define a new verb to vim (say 'o') which can operate on any of the existing vim textobjects. Any pointers on how I can go about doing this?
Thanks
AB
These verbs are called operators (see :h operator). If you want to build your own operator you must use the 'operatorfunc' setting then execute g#. The vim documentation explains it best on how to do this, please see (:h :map-operator) Here is the example from the vim documentation:
nmap <silent> <F4> :set opfunc=CountSpaces<CR>g#
vmap <silent> <F4> :<C-U>call CountSpaces(visualmode(), 1)<CR>
function! CountSpaces(type, ...)
let sel_save = &selection
let &selection = "inclusive"
let reg_save = ##
if a:0 " Invoked from Visual mode, use '< and '> marks.
silent exe "normal! `<" . a:type . "`>y"
elseif a:type == 'line'
silent exe "normal! '[V']y"
elseif a:type == 'block'
silent exe "normal! `[\<C-V>`]y"
else
silent exe "normal! `[v`]y"
endif
echomsg strlen(substitute(##, '[^ ]', '', 'g'))
let &selection = sel_save
let ## = reg_save
endfunction
If you want another example please see take a look at Tim Pope's commentary plugin.
For more help
:h operator
:h :map-operator
:h 'opfunc'
:h g#

how vim map two command

I am wondering how to use one hotkey mapping two command in vim.
for exmpale, I already have those two mapping
map <silent> <F7> zM
map <silent> <F8> zR
But, I just want to use F8 to toggle between zM and zR.
Hoping anyone can give me solution.
Thanks a lot.
Won't zA do what you wanted...?
If it won't then we need to go deeper. http://www.vim.org/scripts/script.php?script_id=1494 tells you what to do, here's the relevant script:
map <buffer> F8 :call ToggleFold()<CR>
let b:folded = 1
function! ToggleFold()
if( b:folded == 0 )
exec "normal! zM"
let b:folded = 1
else
exec "normal! zR"
let b:folded = 0
endif
endfunction

Can we create a new op-pending command in Vim?

Does anyone know if it's possible to create a new op-pending command?
e.g. I'd like to replace a sequence such as vf(r<space>w with ,cf(. Specifically here, the idea is to "clear" the text from the cursor position up to and including the next opening brace and then put the cursor at the beginning of the next word.
I may just be missing something in the help files (or my Google-fu is off today), so a pointer to the right place would be much appreciated.
You want to use :set opfunc and g#. The documentation is pretty good, :h g#.
nnoremap <silent> ,c :set opfunc=Clearing<cr>g#
vnoremap <silent> ,c :<c-u>set opfunc=Clearing<cr>g#
function! Clearing(type, ...)
let sel_save = &selection
let &selection = "inclusive"
let reg_save = ##
if a:0 " Invoked from Visual mode, use '< and '> marks.
silent exe "normal! `<" . a:type . "`>r "
elseif a:type == 'line'
silent exe "normal! '[V']r "
elseif a:type == 'block'
silent exe "normal! `[\<C-V>`]r "
else
silent exe "normal! `[v`]r "
endif
norm! `]w
let &selection = sel_save
let ## = reg_save
endfunction
I think :h map-operator is what you're looking for.

Turn off the highlight feature in the Limp

I am using the Limp in my VIM. But there is a problem, when the cursor move to a "(" or ")", it would highlight a block of code in this pair.I can not see the code clearly. Is there any way to turn off or delete this feature?
Best Regards,
I'm also using Limp but I have modified it somewhat to work better for my tastes.
Inside the main limp folder there is a vim subfolder, open the file limp.vim and at the end you can see several runtime commands, just comment out the one that loads the highlight.vim file:
"runtime ftplugin/lisp/limp/highlight.vim
I also like to disable the autoclose.vim plugin, I find it very annoying.
"runtime ftplugin/lisp/limp/autoclose.vim
Then, open the file mode.vim and around line number 58 you can see the function call to initialize the highlighting mode; comment it out:
"call LimpHighlight_start()
then around line number 68, under the function LimpMode_stop() you will also need to comment the call to stop the highlightning.
"call LimpHighlight_stop()
Of course, if you also disabled the autoclose.vim plugin you'll also have to comment the calls to start/stop it.
Annoying colors
If the colors that Limp sets up out of the box annoys you as they did with me, you can disable that and continue using your default colorscheme; around line number 30:
"set t_Co=256
"if !exists("g:colors_name")
"colorscheme desertEx
"endif
And change the highlight groups to match your colorscheme (use :high to quickly see a list of color combinations). For example, I use the "desertEx" colorscheme and changed this two lines to match it:
hi BracketsBlock ctermbg=235 guibg=grey22
hi StatusLine ctermbg=black ctermfg=160
Other options
I didn't like the set of options that Limp sets, especially the old Vi Lisp indentation. I also dislike the folding so I disabled that too. My current set of options look like this:
syntax on
setlocal nocompatible nocursorline
setlocal lisp syntax=lisp
setlocal ls=2 bs=2 et sw=2 ts=2 "tw=0
setlocal statusline=%<%f\ \(%{LimpBridge_connection_status()}\)\ %h%m%r%=%-14.(%l,%c%V%)\ %P
"setlocal iskeyword=&,*,+,45,/,48-57,:,<,=,>,#,A-Z,a-z,_
"setlocal cpoptions=-mp
"setlocal foldmethod=marker foldmarker=(,) foldminlines=1
setlocal foldcolumn=0
set lispwords+=defgeneric,block,catch,with-gensyms
"-----------
"Taken from the bundled lisp.vim file in VIM
"(/usr/share/vim/vim72/ftplugin/lisp.vim)
setl comments=:;
setl define=^\\s*(def\\k*
setl formatoptions-=t
setl iskeyword+=+,-,*,/,%,<,=,>,:,$,?,!,#-#,94
setl comments^=:;;;,:;;,sr:#\|,mb:\|,ex:\|#
setl formatoptions+=croql
"-----------
" This allows gf and :find to work. Fix path to your needs
setlocal suffixesadd=.lisp,.cl path+=/home/gajon/Lisp/**
Notice I disabled the tw=0, modified the statusline, disabled folding, copied the options that come bundled with Vim (they are a lot better), added some symbols to lispwords, and added a missing dot to suffixesadd (cl extension was missing a dot).
Disabling the transposing of sexps.
Limp binds they keys { and } to functions that transpose the current sexp with the previous/next sexp. But they don't work reliably and I think they are unnecessary when you can just as easily use dab and p at the proper place. Besides the default Vim {} bindings are quite useful to move to other top-level forms.
In file keys.vim:
"nmap <buffer> { <Plug>SexpMoveBack
"nmap <buffer> } <Plug>SexpMoveForward
Bug when connecting to a running REPL
There's a bug that prevents Limp from reconnecting to an already running REPL. In file bridge.vim inside the vim subfolder, around line number 13:
let cmd = s:Limp_location . "/bin/lisp.sh ".core_opt." -s ".styfile." -b ".name
A space was missing between ".core_opt." and -s.
Additional Goodies!
You should be able to figure out how to use these new mappings.
In file bridge.vim add the following lines after line number 265:
nnoremap <silent> <buffer> <Plug>EvalUndefine :call LimpBridge_send_to_lisp("(fmakunbound '".expand("<cword>").")")<CR>
nnoremap <silent> <buffer> <Plug>EvalAddWord :let &lispwords.=',' . expand("<cword>")<cr>
nnoremap <silent> <buffer> <Plug>DebugTrace :call LimpBridge_send_to_lisp("(trace ".expand("<cword>").")")<CR>
nnoremap <silent> <buffer> <Plug>DebugUnTrace :call LimpBridge_send_to_lisp("(untrace ".expand("<cword>").")")<CR>
nnoremap <silent> <buffer> <Plug>DebugInspectObject :call LimpBridge_inspect_expression()<CR>
nnoremap <silent> <buffer> <Plug>DebugInspectLast :call LimpBridge_send_to_lisp("(inspect *)")<CR>
nnoremap <silent> <buffer> <Plug>DebugDisassemble :call LimpBridge_send_to_lisp("(disassemble #'".expand("<cword>").")")<CR>
nnoremap <silent> <buffer> <Plug>DebugMacroExpand :call LimpBridge_macroexpand_current_form( "macroexpand" )<CR>
nnoremap <silent> <buffer> <Plug>DebugMacroExpand1 :call LimpBridge_macroexpand_current_form( "macroexpand-1" )<CR>
nnoremap <silent> <buffer> <Plug>ProfileSet :call LimpBridge_send_to_lisp("(sb-profile:profile ".expand("<cword>").")")<CR>
nnoremap <silent> <buffer> <Plug>ProfileUnSet :call LimpBridge_send_to_lisp("(sb-profile:unprofile ".expand("<cword>").")")<CR>
nnoremap <silent> <buffer> <Plug>ProfileShow :call LimpBridge_send_to_lisp("(sb-profile:profile)")<CR>
nnoremap <silent> <buffer> <Plug>ProfileUnSetAll :call LimpBridge_send_to_lisp("(sb-profile:unprofile)")<CR>
nnoremap <silent> <buffer> <Plug>ProfileReport :call LimpBridge_send_to_lisp("(sb-profile:report)")<CR>
nnoremap <silent> <buffer> <Plug>ProfileReset :call LimpBridge_send_to_lisp("(sb-profile:reset)")<CR>
And at the end add these two functions:
function! LimpBridge_inspect_expression()
let whatwhat = input("Inspect: ")
call LimpBridge_send_to_lisp( "(inspect " . whatwhat . ")" )
endfun
function! LimpBridge_macroexpand_current_form(command)
" save position
let pos = LimpBridge_get_pos()
" find & yank current s-exp
normal! [(
let sexp = LimpBridge_yank( "%" )
call LimpBridge_send_to_lisp( "(" . a:command . " '" . sexp . ")" )
call LimpBridge_goto_pos( pos )
endfunction
Then in file keys.vim add the following mappings:
" Undefine: Undefine a function or macro.
nmap <buffer> <LocalLeader>eu <Plug>EvalUndefine
" Add Word: Append word to 'lispwords' option
nmap <buffer> <LocalLeader>ea <Plug>EvalAddWord
" Trace: Set tracing for function.
" Untrace: Remove tracing for a function.
nmap <buffer> <LocalLeader>dt <Plug>DebugTrace
nmap <buffer> <LocalLeader>du <Plug>DebugUnTrace
" Inspect: Inspect object
" InspectPrev: Inspect last value evaled.
nmap <buffer> <LocalLeader>di <Plug>DebugInspectObject
nmap <buffer> <LocalLeader>dI <Plug>DebugInspectLast
" Disassemble:
nmap <buffer> <LocalLeader>dd <Plug>DebugDisassemble
" Macroexpand:
" Macroexpand1:
nmap <buffer> <LocalLeader>ma <Plug>DebugMacroExpand
nmap <buffer> <LocalLeader>m1 <Plug>DebugMacroExpand1
" Profile: Set profiling.
" Unprofile: Remove profiling.
nmap <buffer> <LocalLeader>pr <Plug>ProfileSet
nmap <buffer> <LocalLeader>pu <Plug>ProfileUnSet
" Show Profiling: Show profiling.
" Unprofile All: Remove all profiling.
nmap <buffer> <LocalLeader>pp <Plug>ProfileShow
nmap <buffer> <LocalLeader>pa <Plug>ProfileUnSetAll
" Profile Report: Show report.
" Profile Reset: Reset profile data.
nmap <buffer> <LocalLeader>ps <Plug>ProfileReport
nmap <buffer> <LocalLeader>p- <Plug>ProfileReset
" Sexp Close Open Parenthesis:
nmap <buffer> <LocalLeader>cp <Plug>SexpCloseParenthesis
imap <buffer> <C-X>0 <C-O><LocalLeader>cp
Then in file sexp.vim add this mapping:
" Sexp Close Open Parenthesis:
nnoremap <silent> <buffer> <Plug>SexpCloseParenthesis :call SlimvCloseForm()<CR>
and these two functions:
"-------------------------------------------------------------------
" Close open parenthesis
" Taken from the Slimv plugin by Tamas Kovacs. Released in the
" public domain by the original author.
"-------------------------------------------------------------------
" Count the opening and closing parens or brackets to determine if they match
function! s:GetParenCount( lines )
let paren = 0
let inside_string = 0
let i = 0
while i < len( a:lines )
let inside_comment = 0
let j = 0
while j < len( a:lines[i] )
if inside_string
" We are inside a string, skip parens, wait for closing '"'
if a:lines[i][j] == '"'
let inside_string = 0
endif
elseif inside_comment
" We are inside a comment, skip parens, wait for end of line
else
" We are outside of strings and comments, now we shall count parens
if a:lines[i][j] == '"'
let inside_string = 1
endif
if a:lines[i][j] == ';'
let inside_comment = 1
endif
if a:lines[i][j] == '(' || a:lines[i][j] == '['
let paren = paren + 1
endif
if a:lines[i][j] == ')' || a:lines[i][j] == ']'
let paren = paren - 1
if paren < 0
" Oops, too many closing parens in the middle
return paren
endif
endif
endif
let j = j + 1
endwhile
let i = i + 1
endwhile
return paren
endfunction
" Close current top level form by adding the missing parens
function! SlimvCloseForm()
let l2 = line( '.' )
normal 99[(
let l1 = line( '.' )
let form = []
let l = l1
while l <= l2
call add( form, getline( l ) )
let l = l + 1
endwhile
let paren = s:GetParenCount( form )
if paren > 0
" Add missing parens
let lastline = getline( l2 )
while paren > 0
let lastline = lastline . ')'
let paren = paren - 1
endwhile
call setline( l2, lastline )
endif
normal %
endfunction
Hope this helps you better use Limp.

Resources