| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- " File: surrounding.vim
- " Author: Michael Sanders
- " Description: A heavily modified, simplified fork of surround.vim by Tim Pope.
- if exists('g:did_surrounding') || &cp || version < 700
- finish
- endif
- let g:did_surrounding = 1
- nn cs :<c-u>call <SID>ModifySurround(<SID>Input(), <SID>Input())<cr>
- nn ds :<c-u>call <SID>ModifySurround(<SID>Input())<cr>
- xno s :<c-u>call <SID>AddSurround(visualmode(), 1)<cr>
- nn <silent> ys :<c-u>set opfunc=<SID>AddSurround<cr>g@
- nm yss 0ys$
- " Return next character typed by user.
- fun s:Input()
- echoh ModeMsg | echo '-- SURROUND --' | echoh None
- let c = nr2char(getchar())
- if c == ' '
- let c .= nr2char(getchar())
- endif
- echo '' | redraw
- return c == "\<esc>" || c == "\<cr>" ? '' : c
- endf
- " Surround selected text with input from user.
- " If a:0 is given, visual mode is assumed to be used; otherwise, an opfunc
- fun s:AddSurround(type, ...)
- " Deal with motions, if used in normal mode.
- if !a:0
- let sel_save = &sel | let &sel = 'inclusive'
- exe 'norm! `['.(a:type == 'char' ? 'v' : 'V')."`]\<esc>"
- let sel_save = &sel
- endif
- let char = s:Input()
- if a:type ==# 'V' " Line mode
- let chars = s:Wrap('', char) | let half = len(chars)/2
- call setline("'<", strpart(chars, 0, half).getline("'<"))
- call setline("'>", getline("'>").strpart(chars, half))
- else " Just visual mode
- let old = @"
- norm! gvc
- let @" = s:Wrap(@", char)
- exe 'norm! '.(virtcol('.') == 1 ? 'P' : 'p')
- let @" = old
- endif
- if a:0
- sil! call repeat#set('1vs'.char)
- " NOTE: This needs to be fixed -- it needs to save the motion/char used
- " An opfunc does not appear to give us access to the motion
- " used, so I'm not sure how to do this.
- sil! call repeat#set('ys')
- endif
- endf
- " Returns list with pair of characters matching given character.
- "
- " If character is not supported, a list with two empty strings ["", ""]
- " is returned.
- "
- " If character is a "t", the user is asked to input an XML tag and the
- " beginning and end tags are returned in a list. If the character is a
- " capitalized "T", the beginning and end tags returned are separated
- " by newlines.
- fun s:MatchChar(char)
- if a:char ==# 'b' || a:char == '(' || a:char == ')'
- return ['(', ')']
- elseif a:char ==# 'r' || a:char == ']' || a:char == '['
- return ['[', ']']
- elseif a:char ==# 'B' || a:char == '{' || a:char == '}'
- return ['{', '}']
- elseif a:char ==# 'a' || a:char == '<' || a:char == '>'
- return ['<', '>']
- elseif a:char == 't' " Insert tag
- if !hasmapto('>', 'c')
- let remapped = 1
- cno > <cr>
- endif
- let tag = input('<')
- if !remapped | let tag = substitute(tag, '>*$', '', '') | endif
- echo '<'.tag.'>'
- if remapped
- sil! cunmap >
- endif
- let cl = '</'.substitute(tag, ' .*', '', '').'>'
- return a:char ==# 'T' ? ['<'.tag.">\n", "\n".cl] : ['<'.tag.'>', cl]
- endif
- return a:char =~ '\W' ? [a:char, a:char] : ['', '']
- endf
- " Change or delete surrounding characters.
- " "orig" should be the original character to be changed, and a:1 should be the
- " new character is substituting or not given if deleting.
- fun s:ModifySurround(orig, ...)
- if a:orig == '' | return | endif
- if a:0 " Save position if replacing characters.
- if a:1 == '' | return | endif
- let line = line('.') | let col = col('.')
- endif
- let char = a:orig
- if len(char) > 1
- let space = ' '
- let char = strpart(char, 1)
- endif
- if char ==# 'a'
- let char = '>'
- elseif char ==# 'r'
- let char = ']'
- endif
- let old = @"
- let @" = ''
- exe 'norm! d'.v:count1.'i'.char
- " If di<char> failed, quit.
- if @" == ''
- let @" = old | return
- elseif exists('space')
- let @" = substitute(@",'^\s+\|\s+$', '', 'g')
- endif
- let oldLine = getline('.')
- let oldLnum = line('.')
- let oldLineLen = col('$')
- if char == '"' || char == "'" || char == '`'
- exe "norm! i \<esc>\"_d2i".char
- else
- exe 'norm! "_da'.char
- endif
- if a:0 | let @" = s:Wrap(@", a:1) | endif
- let endLine = col('$')
- sil exe 'norm! ""'.(col("']") == endLine && col('.')+1 == endLine ? 'p' : 'P')
- let @" = old
- if exists('space') | let char = ' '.char | endif
- if a:0
- sil! call repeat#set('cs'.char.a:1)
- call cursor(line, col)
- else
- sil! call repeat#set('ds'.char)
- endif
- endf
- " Returns string wrapped in the pair of the given character.
- " If character contains a space, it is also wrapped appropriately.
- fun s:Wrap(string, char)
- if len(a:char) > 1 " Parsing character with a space
- let space = ' '
- let chars = s:MatchChar(strpart(a:char, 1))
- else
- let space = ''
- let chars = s:MatchChar(a:char)
- endif
- return chars[0].space.a:string.space.chars[1]
- endf
- " vim:noet:sw=4:ts=4:ft=vim
|