commit 0229c93f941f8a933ecfd2794527c5a5b02a8f73 Author: Tim Pope Date: Sat Oct 28 00:31:44 2006 +0000 Added plugin diff --git a/plugin/surround.vim b/plugin/surround.vim new file mode 100644 index 0000000..94f2cb6 --- /dev/null +++ b/plugin/surround.vim @@ -0,0 +1,320 @@ +" surround.vim - Surroundings +" Maintainer: Tim Pope +" $Id$ +" +" Usage: +" +" "ds" is a mapping which deletes the surroundings of a text object--the +" difference between the "inner" object and "an" object. See the :help on +" text-objects for details. This is easiest to understand with some examples; +" in the following, * represents the cursor position. +" +" Old Keystroke New +" "Hello *world!" ds" Hello world! +" (123+4*56)/2 ds) 123+456/2 +"
Yo!
dst Yo! +" +" "cs" does as above, but rather than remove the surroundings, it replaces +" them with something else. It takes two arguments. Once again, examples are +" in order. (Details about the second argument, the replacement character, +" are below). +" +" Old Keystroke New +" "Hello *world!" cs"' 'Hello world!' +" "Hello *world!" cs" Hello world! +" (123+4*56)/2 cs)] [123+456]/2 +" (123+4*56)/2 cs)[ [ 123+456 ]/2 +"
Yo!
cst

Yo!

+" +" "ys" takes a motion or text object as the first object, and wraps it using +" the second argument as with "cs". +" +" Old Keystroke New +" Hello w*orld! ysiw) Hello (world)! +" +" As a special case, "yss" operates on the current line, ignoring leading +" whitespace. +" +" Old Keystroke New +" Hello w*orld! yssB {Hello world!} +" +" Finally, in visual mode, a simple "s" with an argument wraps the selection. +" Note that "s" already has a valid meaning in visual mode, but it is +" identical to "c". If you have muscle memory for "s" and would like to use a +" different key, add your own mapping and the existing one will be disabled. +" +" vmap S VSurround +" +" Replacements: +" +" A replacement argument is a single character. The default behavior is to +" insert that character before and after the text. +" +" If ")", "]", "}", or ">" are used, the text is wrapped in the appropriate +" open/close pair of characters. "(", "[", and "{" behave similarly but add +" an additional space to the inside. "B" and "b" are synonymous with "}" and +" ")". +" +" If "t" or "<" is used, Vim prompts for an HTML/XML tag to insert. You may +" specify attributes here and they will be stripped from the closing tag. +" End your input by pressing "" or ">". +" +" Customizing: +" +" The following adds a potential replacement on "-" (ASCII 45) in PHP files. +" (To determine the ASCII code to use, :echo char2nr("-")). The newline will +" be replaced by the original text. +" +" autocmd FileType php let b:surround_45 = "" +" +" This can be used in a PHP file as in the following example. +" +" Old Keystroke New +" print "Hello *world!" yss- +" +" Additionally, one can use a global variable for globally available +" replacements. +" +" let g:surround_45 = "<% \n %>" +" +" Issues: +" +" Vim could potentially get confused when deleting/changing occurs at the very +" end of the line. Report any repeatable instances of this. +" +" Do we need to use inputsave() / inputrestore() with the tag replacement? +" +" Customization isn't very flexible. Need a system that allows for prompting +" similar to with tags. +" +" Reindenting is handled haphazardly. Need to decide the most appropriate +" behavior and implement it. + +" ============================================================================ + +" Exit quickly when: +" - this plugin was already loaded (or disabled) +" - when 'compatible' is set +if (exists("g:loaded_surround") && g:loaded_surround) || &cp + finish +endif +let g:loaded_surround = 1 + +let s:cpo_save = &cpo +set cpo&vim + +function! s:wrap(string,char,...) " {{{1 + let keeper = a:string + let newchar = a:char + let linemode = a:0 ? a:1 : 0 + " Duplicate b's are just placeholders + let pairs = "b()B{}b[]b<>" + let idx = stridx(pairs,newchar) + if exists("b:surround_".char2nr(newchar)) + let before = matchstr(b:surround_{char2nr(newchar)},'.*\ze\n') + let after = matchstr(b:surround_{char2nr(newchar)},'\n\zs.*') + elseif exists("g:surround_".char2nr(newchar)) + let before = matchstr(g:surround_{char2nr(newchar)},'.*\ze\n') + let after = matchstr(g:surround_{char2nr(newchar)},'\n\zs.*') + elseif newchar == "p" + let before = "\n" + let after = "\n\n" + elseif newchar == "t" || newchar == "<" + let dounmapr = 0 + let dounmapb = 0 + if !mapcheck("","c") + let dounmapr = 1 + cnoremap > + endif + if !mapcheck(">","c") + let dounmapb= 1 + cnoremap > > + endif + let tag = input("<") + if dounmapr + silent! cunmap + endif + if dounmapb + silent! cunmap > + endif + if tag != "" + let tag = substitute(tag,'>$','','') + let before = "<".tag.">" + let after = "" + else + let before = "" + let after = "" + endif + elseif idx >= 0 + let spc = (idx % 3) == 1 ? " " : "" + let idx = idx / 3 * 3 + let before = strpart(pairs,idx+1,1) . spc + let after = spc . strpart(pairs,idx+2,1) + else + let before = newchar + let after = newchar + endif + if linemode || keeper =~ '\%^\s*\n' + let before = substitute(before,'\s*\%$','','') + endif + if linemode || keeper =~ '\n\s*\%$' + let after = substitute(after,'\%^\s*','','') + endif + if linemode + let initspaces = matchstr(keeper,'\%^\s*') + let keeper = initspaces.before."\n".keeper."\n".initspaces.after + else + let keeper = before.keeper.after + endif + return keeper +endfunction " }}}1 + +function! s:dosurround(...) " {{{1 + let char = nr2char(a:0 ? a:1 : getchar()) + let newchar = a:0 > 1 ? nr2char(a:2) : "" + if newchar == "\" || newchar == "\" + return s:beep() + endif + let append = "" + let original = @@ + let @@ = "" + exe "norm di".char + "exe "norm vi".char."d" + let keeper = @@ + if @@ == "" + let @@ = original + return "" + endif + let oldline = getline('.') + let oldlnum = line('.') + if char == "p" + let append = matchstr(keeper,'\n*\%$') + let keeper = substitute(keeper,'\n*\%$','','') + let @@ = "" + elseif char == "s" + " Do nothing + let @@ = "" + elseif char =~ "[\"'`]" + exe "norm! i \d2i".char + let @@ = substitute(@@,' ','','') + else + exe "norm! da".char + endif + let removed = @@ + let rem2 = substitute(removed,'\n.*','','') + let oldhead = strpart(oldline,0,strlen(oldline)-strlen(rem2)) + let oldtail = strpart(oldline, strlen(oldline)-strlen(rem2)) + "let g:oldhead = oldhead + "let g:oldtail = oldtail + "let g:rem2 = rem2 + "let g:keeper = keeper + let regtype = getregtype('"') + if oldtail == rem2 && col('.') + 1 == col('$') + if oldhead =~# '^\s*$' && a:0 < 2 + "let keeper = substitute(keeper,'\n\s*','\n','') + let keeper = substitute(keeper,oldhead.'\%$','','') + let keeper = substitute(keeper,'\%^\n'.oldhead.'\(\s*.\{-\}\)\n\s*\%$','\1','') + endif + let pcmd = "p" + else + if oldhead == "" && a:0 < 2 + let keeper = substitute(keeper,'\%^\n\(.*\)\n\%$','\1','') + endif + let pcmd = "P" + endif + if line('.') < oldlnum && regtype == "V" + let pcmd = "p" + endif + if removed =~ '\n$' + let keeper = keeper."\n" + let removed = substitute(removed,'\n$','','') + endif + " Originally was done twice on purpose + "if removed =~ '\n' + "let keeper = keeper . "\n" + "let removed = substitute(removed,'\n','','') + "endif + "let g:removed = removed + if newchar != "" + let keeper = s:wrap(keeper,newchar,char == "p") . append + endif + let @@ = substitute(keeper,'\n\s+\n','\n\n','g') + call setreg('"','','a'.regtype) + silent exe "norm! ".(a:0 < 2 ? "" : "").pcmd.'`[' + "if @@ =~ '\n' + "silent norm! '[='] + "endif + if getline('.') =~ '^\s\+$' && keeper =~ '^\s*\n' + silent norm! cc + endif + let @@ = removed +endfunction " }}}1 + +function! s:beep() + exe "norm! \" + return "" +endfunction + +function! s:opfunc(type) " {{{1 + let char = nr2char(getchar()) + let g:count = v:count1 + if char == "\" || char == "\" + return s:beep() + endif + let sel_save = &selection + let &selection = "inclusive" + let reg_save = @@ + let linemode = (a:type == "line" || a:type == "V") + if a:type == "char" + silent norm! `[v`]y + elseif a:type == "line" + silent norm! '[V']y + elseif a:type == "v" || a:type == "V" + silent norm! gvy + elseif a:type =~ '^\d\+$' + silent exe 'norm! ^v'.a:type.'$hy' + else + let &selection = sel_save + return s:beep() + endif + let keeper = @@ + let append = "" + if linemode + let append = matchstr(keeper,'\n*$') + let keeper = substitute(keeper,'\n*$','','') + else + let append = matchstr(keeper,'\s*$') + let keeper = substitute(keeper,'\s*$','','') + endif + let keeper = s:wrap(keeper,char,linemode) . append + let @@ = keeper + silent norm! gvp`[ + "if linemode + "silent norm! '[='] + "endif + let @@ = reg_save + let &selection = sel_save +endfunction " }}}1 + +function! s:yss() range + echo a:firstline." ".a:lastline +endfunction +nnoremap DSurround :call dosurround(getchar()) +nnoremap CSurround :call dosurround(getchar(),getchar()) +nnoremap YSurround :set opfunc=opfuncg@ +nnoremap YSurroundS : call opfunc(v:count1) +nnoremap