dotfiles

<-- duh.
git clone https://hhvn.uk/dotfiles
git clone git://hhvn.uk/dotfiles
Log | Files | Refs | Submodules | LICENSE

surround.vim (17329B)


      1 " surround.vim - Surroundings
      2 " Author:       Tim Pope <http://tpo.pe/>
      3 " Version:      2.1
      4 " GetLatestVimScripts: 1697 1 :AutoInstall: surround.vim
      5 
      6 if exists("g:loaded_surround") || &cp || v:version < 700
      7   finish
      8 endif
      9 let g:loaded_surround = 1
     10 
     11 " Input functions {{{1
     12 
     13 function! s:getchar()
     14   let c = getchar()
     15   if c =~ '^\d\+$'
     16     let c = nr2char(c)
     17   endif
     18   return c
     19 endfunction
     20 
     21 function! s:inputtarget()
     22   let c = s:getchar()
     23   while c =~ '^\d\+$'
     24     let c .= s:getchar()
     25   endwhile
     26   if c == " "
     27     let c .= s:getchar()
     28   endif
     29   if c =~ "\<Esc>\|\<C-C>\|\0"
     30     return ""
     31   else
     32     return c
     33   endif
     34 endfunction
     35 
     36 function! s:inputreplacement()
     37   let c = s:getchar()
     38   if c == " "
     39     let c .= s:getchar()
     40   endif
     41   if c =~ "\<Esc>" || c =~ "\<C-C>"
     42     return ""
     43   else
     44     return c
     45   endif
     46 endfunction
     47 
     48 function! s:beep()
     49   exe "norm! \<Esc>"
     50   return ""
     51 endfunction
     52 
     53 function! s:redraw()
     54   redraw
     55   return ""
     56 endfunction
     57 
     58 " }}}1
     59 
     60 " Wrapping functions {{{1
     61 
     62 function! s:extractbefore(str)
     63   if a:str =~ '\r'
     64     return matchstr(a:str,'.*\ze\r')
     65   else
     66     return matchstr(a:str,'.*\ze\n')
     67   endif
     68 endfunction
     69 
     70 function! s:extractafter(str)
     71   if a:str =~ '\r'
     72     return matchstr(a:str,'\r\zs.*')
     73   else
     74     return matchstr(a:str,'\n\zs.*')
     75   endif
     76 endfunction
     77 
     78 function! s:fixindent(str,spc)
     79   let str = substitute(a:str,'\t',repeat(' ',&sw),'g')
     80   let spc = substitute(a:spc,'\t',repeat(' ',&sw),'g')
     81   let str = substitute(str,'\(\n\|\%^\).\@=','\1'.spc,'g')
     82   if ! &et
     83     let str = substitute(str,'\s\{'.&ts.'\}',"\t",'g')
     84   endif
     85   return str
     86 endfunction
     87 
     88 function! s:process(string)
     89   let i = 0
     90   for i in range(7)
     91     let repl_{i} = ''
     92     let m = matchstr(a:string,nr2char(i).'.\{-\}\ze'.nr2char(i))
     93     if m != ''
     94       let m = substitute(strpart(m,1),'\r.*','','')
     95       let repl_{i} = input(match(m,'\w\+$') >= 0 ? m.': ' : m)
     96     endif
     97   endfor
     98   let s = ""
     99   let i = 0
    100   while i < strlen(a:string)
    101     let char = strpart(a:string,i,1)
    102     if char2nr(char) < 8
    103       let next = stridx(a:string,char,i+1)
    104       if next == -1
    105         let s .= char
    106       else
    107         let insertion = repl_{char2nr(char)}
    108         let subs = strpart(a:string,i+1,next-i-1)
    109         let subs = matchstr(subs,'\r.*')
    110         while subs =~ '^\r.*\r'
    111           let sub = matchstr(subs,"^\r\\zs[^\r]*\r[^\r]*")
    112           let subs = strpart(subs,strlen(sub)+1)
    113           let r = stridx(sub,"\r")
    114           let insertion = substitute(insertion,strpart(sub,0,r),strpart(sub,r+1),'')
    115         endwhile
    116         let s .= insertion
    117         let i = next
    118       endif
    119     else
    120       let s .= char
    121     endif
    122     let i += 1
    123   endwhile
    124   return s
    125 endfunction
    126 
    127 function! s:wrap(string,char,type,removed,special)
    128   let keeper = a:string
    129   let newchar = a:char
    130   let s:input = ""
    131   let type = a:type
    132   let linemode = type ==# 'V' ? 1 : 0
    133   let before = ""
    134   let after  = ""
    135   if type ==# "V"
    136     let initspaces = matchstr(keeper,'\%^\s*')
    137   else
    138     let initspaces = matchstr(getline('.'),'\%^\s*')
    139   endif
    140   let pairs = "b()B{}r[]a<>"
    141   let extraspace = ""
    142   if newchar =~ '^ '
    143     let newchar = strpart(newchar,1)
    144     let extraspace = ' '
    145   endif
    146   let idx = stridx(pairs,newchar)
    147   if newchar == ' '
    148     let before = ''
    149     let after  = ''
    150   elseif exists("b:surround_".char2nr(newchar))
    151     let all    = s:process(b:surround_{char2nr(newchar)})
    152     let before = s:extractbefore(all)
    153     let after  =  s:extractafter(all)
    154   elseif exists("g:surround_".char2nr(newchar))
    155     let all    = s:process(g:surround_{char2nr(newchar)})
    156     let before = s:extractbefore(all)
    157     let after  =  s:extractafter(all)
    158   elseif newchar ==# "p"
    159     let before = "\n"
    160     let after  = "\n\n"
    161   elseif newchar ==# 's'
    162     let before = ' '
    163     let after  = ''
    164   elseif newchar ==# ':'
    165     let before = ':'
    166     let after = ''
    167   elseif newchar =~# "[tT\<C-T><]"
    168     let dounmapp = 0
    169     let dounmapb = 0
    170     if !maparg(">","c")
    171       let dounmapb = 1
    172       " Hide from AsNeeded
    173       exe "cn"."oremap > ><CR>"
    174     endif
    175     let default = ""
    176     if newchar ==# "T"
    177       if !exists("s:lastdel")
    178         let s:lastdel = ""
    179       endif
    180       let default = matchstr(s:lastdel,'<\zs.\{-\}\ze>')
    181     endif
    182     let tag = input("<",default)
    183     if dounmapb
    184       silent! cunmap >
    185     endif
    186     let s:input = tag
    187     if tag != ""
    188       let keepAttributes = ( match(tag, ">$") == -1 )
    189       let tag = substitute(tag,'>*$','','')
    190       let attributes = ""
    191       if keepAttributes
    192         let attributes = matchstr(a:removed, '<[^ \t\n]\+\zs\_.\{-\}\ze>')
    193       endif
    194       let s:input = tag . '>'
    195       if tag =~ '/$'
    196         let tag = substitute(tag, '/$', '', '')
    197         let before = '<'.tag.attributes.' />'
    198         let after = ''
    199       else
    200         let before = '<'.tag.attributes.'>'
    201         let after  = '</'.substitute(tag,' .*','','').'>'
    202       endif
    203       if newchar == "\<C-T>"
    204         if type ==# "v" || type ==# "V"
    205           let before .= "\n\t"
    206         endif
    207         if type ==# "v"
    208           let after  = "\n". after
    209         endif
    210       endif
    211     endif
    212   elseif newchar ==# 'l' || newchar == '\'
    213     " LaTeX
    214     let env = input('\begin{')
    215     if env != ""
    216       let s:input = env."\<CR>"
    217       let env = '{' . env
    218       let env .= s:closematch(env)
    219       echo '\begin'.env
    220       let before = '\begin'.env
    221       let after  = '\end'.matchstr(env,'[^}]*').'}'
    222     endif
    223   elseif newchar ==# 'f' || newchar ==# 'F'
    224     let fnc = input('function: ')
    225     if fnc != ""
    226       let s:input = fnc."\<CR>"
    227       let before = substitute(fnc,'($','','').'('
    228       let after  = ')'
    229       if newchar ==# 'F'
    230         let before .= ' '
    231         let after = ' ' . after
    232       endif
    233     endif
    234   elseif newchar ==# "\<C-F>"
    235     let fnc = input('function: ')
    236     let s:input = fnc."\<CR>"
    237     let before = '('.fnc.' '
    238     let after = ')'
    239   elseif idx >= 0
    240     let spc = (idx % 3) == 1 ? " " : ""
    241     let idx = idx / 3 * 3
    242     let before = strpart(pairs,idx+1,1) . spc
    243     let after  = spc . strpart(pairs,idx+2,1)
    244   elseif newchar == "\<C-[>" || newchar == "\<C-]>"
    245     let before = "{\n\t"
    246     let after  = "\n}"
    247   elseif newchar !~ '\a'
    248     let before = newchar
    249     let after  = newchar
    250   else
    251     let before = ''
    252     let after  = ''
    253   endif
    254   let after  = substitute(after ,'\n','\n'.initspaces,'g')
    255   if type ==# 'V' || (a:special && type ==# "v")
    256     let before = substitute(before,' \+$','','')
    257     let after  = substitute(after ,'^ \+','','')
    258     if after !~ '^\n'
    259       let after  = initspaces.after
    260     endif
    261     if keeper !~ '\n$' && after !~ '^\n'
    262       let keeper .= "\n"
    263     elseif keeper =~ '\n$' && after =~ '^\n'
    264       let after = strpart(after,1)
    265     endif
    266     if keeper !~ '^\n' && before !~ '\n\s*$'
    267       let before .= "\n"
    268       if a:special
    269         let before .= "\t"
    270       endif
    271     elseif keeper =~ '^\n' && before =~ '\n\s*$'
    272       let keeper = strcharpart(keeper,1)
    273     endif
    274     if type ==# 'V' && keeper =~ '\n\s*\n$'
    275       let keeper = strcharpart(keeper,0,strchars(keeper) - 1)
    276     endif
    277   endif
    278   if type ==# 'V'
    279     let before = initspaces.before
    280   endif
    281   if before =~ '\n\s*\%$'
    282     if type ==# 'v'
    283       let keeper = initspaces.keeper
    284     endif
    285     let padding = matchstr(before,'\n\zs\s\+\%$')
    286     let before  = substitute(before,'\n\s\+\%$','\n','')
    287     let keeper = s:fixindent(keeper,padding)
    288   endif
    289   if type ==# 'V'
    290     let keeper = before.keeper.after
    291   elseif type =~ "^\<C-V>"
    292     " Really we should be iterating over the buffer
    293     let repl = substitute(before,'[\\~]','\\&','g').'\1'.substitute(after,'[\\~]','\\&','g')
    294     let repl = substitute(repl,'\n',' ','g')
    295     let keeper = substitute(keeper."\n",'\(.\{-\}\)\(\n\)',repl.'\n','g')
    296     let keeper = substitute(keeper,'\n\%$','','')
    297   else
    298     let keeper = before.extraspace.keeper.extraspace.after
    299   endif
    300   return keeper
    301 endfunction
    302 
    303 function! s:wrapreg(reg,char,removed,special)
    304   let orig = getreg(a:reg)
    305   let type = substitute(getregtype(a:reg),'\d\+$','','')
    306   let new = s:wrap(orig,a:char,type,a:removed,a:special)
    307   call setreg(a:reg,new,type)
    308 endfunction
    309 " }}}1
    310 
    311 function! s:insert(...) " {{{1
    312   " Optional argument causes the result to appear on 3 lines, not 1
    313   let linemode = a:0 ? a:1 : 0
    314   let char = s:inputreplacement()
    315   while char == "\<CR>" || char == "\<C-S>"
    316     " TODO: use total count for additional blank lines
    317     let linemode += 1
    318     let char = s:inputreplacement()
    319   endwhile
    320   if char == ""
    321     return ""
    322   endif
    323   let cb_save = &clipboard
    324   set clipboard-=unnamed clipboard-=unnamedplus
    325   let reg_save = @@
    326   call setreg('"',"\r",'v')
    327   call s:wrapreg('"',char,"",linemode)
    328   " If line mode is used and the surrounding consists solely of a suffix,
    329   " remove the initial newline.  This fits a use case of mine but is a
    330   " little inconsistent.  Is there anyone that would prefer the simpler
    331   " behavior of just inserting the newline?
    332   if linemode && match(getreg('"'),'^\n\s*\zs.*') == 0
    333     call setreg('"',matchstr(getreg('"'),'^\n\s*\zs.*'),getregtype('"'))
    334   endif
    335   " This can be used to append a placeholder to the end
    336   if exists("g:surround_insert_tail")
    337     call setreg('"',g:surround_insert_tail,"a".getregtype('"'))
    338   endif
    339   if &ve != 'all' && col('.') >= col('$')
    340     if &ve == 'insert'
    341       let extra_cols = virtcol('.') - virtcol('$')
    342       if extra_cols > 0
    343         let [regval,regtype] = [getreg('"',1,1),getregtype('"')]
    344         call setreg('"',join(map(range(extra_cols),'" "'),''),'v')
    345         norm! ""p
    346         call setreg('"',regval,regtype)
    347       endif
    348     endif
    349     norm! ""p
    350   else
    351     norm! ""P
    352   endif
    353   if linemode
    354     call s:reindent()
    355   endif
    356   norm! `]
    357   call search('\r','bW')
    358   let @@ = reg_save
    359   let &clipboard = cb_save
    360   return "\<Del>"
    361 endfunction " }}}1
    362 
    363 function! s:reindent() " {{{1
    364   if exists("b:surround_indent") ? b:surround_indent : (!exists("g:surround_indent") || g:surround_indent)
    365     silent norm! '[=']
    366   endif
    367 endfunction " }}}1
    368 
    369 function! s:dosurround(...) " {{{1
    370   let scount = v:count1
    371   let char = (a:0 ? a:1 : s:inputtarget())
    372   let spc = ""
    373   if char =~ '^\d\+'
    374     let scount = scount * matchstr(char,'^\d\+')
    375     let char = substitute(char,'^\d\+','','')
    376   endif
    377   if char =~ '^ '
    378     let char = strpart(char,1)
    379     let spc = 1
    380   endif
    381   if char == 'a'
    382     let char = '>'
    383   endif
    384   if char == 'r'
    385     let char = ']'
    386   endif
    387   let newchar = ""
    388   if a:0 > 1
    389     let newchar = a:2
    390     if newchar == "\<Esc>" || newchar == "\<C-C>" || newchar == ""
    391       return s:beep()
    392     endif
    393   endif
    394   let cb_save = &clipboard
    395   set clipboard-=unnamed clipboard-=unnamedplus
    396   let append = ""
    397   let original = getreg('"')
    398   let otype = getregtype('"')
    399   call setreg('"',"")
    400   let strcount = (scount == 1 ? "" : scount)
    401   if char == '/'
    402     exe 'norm! '.strcount.'[/d'.strcount.']/'
    403   elseif char =~# '[[:punct:][:space:]]' && char !~# '[][(){}<>"''`]'
    404     exe 'norm! T'.char
    405     if getline('.')[col('.')-1] == char
    406       exe 'norm! l'
    407     endif
    408     exe 'norm! dt'.char
    409   else
    410     exe 'norm! d'.strcount.'i'.char
    411   endif
    412   let keeper = getreg('"')
    413   let okeeper = keeper " for reindent below
    414   if keeper == ""
    415     call setreg('"',original,otype)
    416     let &clipboard = cb_save
    417     return ""
    418   endif
    419   let oldline = getline('.')
    420   let oldlnum = line('.')
    421   if char ==# "p"
    422     call setreg('"','','V')
    423   elseif char ==# "s" || char ==# "w" || char ==# "W"
    424     " Do nothing
    425     call setreg('"','')
    426   elseif char =~ "[\"'`]"
    427     exe "norm! i \<Esc>d2i".char
    428     call setreg('"',substitute(getreg('"'),' ','',''))
    429   elseif char == '/'
    430     norm! "_x
    431     call setreg('"','/**/',"c")
    432     let keeper = substitute(substitute(keeper,'^/\*\s\=','',''),'\s\=\*$','','')
    433   elseif char =~# '[[:punct:][:space:]]' && char !~# '[][(){}<>]'
    434     exe 'norm! F'.char
    435     exe 'norm! df'.char
    436   else
    437     " One character backwards
    438     call search('\m.', 'bW')
    439     exe "norm! da".char
    440   endif
    441   let removed = getreg('"')
    442   let rem2 = substitute(removed,'\n.*','','')
    443   let oldhead = strpart(oldline,0,strlen(oldline)-strlen(rem2))
    444   let oldtail = strpart(oldline,  strlen(oldline)-strlen(rem2))
    445   let regtype = getregtype('"')
    446   if char =~# '[\[({<T]' || spc
    447     let keeper = substitute(keeper,'^\s\+','','')
    448     let keeper = substitute(keeper,'\s\+$','','')
    449   endif
    450   if col("']") == col("$") && col('.') + 1 == col('$')
    451     if oldhead =~# '^\s*$' && a:0 < 2
    452       let keeper = substitute(keeper,'\%^\n'.oldhead.'\(\s*.\{-\}\)\n\s*\%$','\1','')
    453     endif
    454     let pcmd = "p"
    455   else
    456     let pcmd = "P"
    457   endif
    458   if line('.') + 1 < oldlnum && regtype ==# "V"
    459     let pcmd = "p"
    460   endif
    461   call setreg('"',keeper,regtype)
    462   if newchar != ""
    463     let special = a:0 > 2 ? a:3 : 0
    464     call s:wrapreg('"',newchar,removed,special)
    465   endif
    466   silent exe 'norm! ""'.pcmd.'`['
    467   if removed =~ '\n' || okeeper =~ '\n' || getreg('"') =~ '\n'
    468     call s:reindent()
    469   endif
    470   if getline('.') =~ '^\s\+$' && keeper =~ '^\s*\n'
    471     silent norm! cc
    472   endif
    473   call setreg('"',original,otype)
    474   let s:lastdel = removed
    475   let &clipboard = cb_save
    476   if newchar == ""
    477     silent! call repeat#set("\<Plug>Dsurround".char,scount)
    478   else
    479     silent! call repeat#set("\<Plug>C".(a:0 > 2 && a:3 ? "S" : "s")."urround".char.newchar.s:input,scount)
    480   endif
    481 endfunction " }}}1
    482 
    483 function! s:changesurround(...) " {{{1
    484   let a = s:inputtarget()
    485   if a == ""
    486     return s:beep()
    487   endif
    488   let b = s:inputreplacement()
    489   if b == ""
    490     return s:beep()
    491   endif
    492   call s:dosurround(a,b,a:0 && a:1)
    493 endfunction " }}}1
    494 
    495 function! s:opfunc(type, ...) abort " {{{1
    496   if a:type ==# 'setup'
    497     let &opfunc = matchstr(expand('<sfile>'), '<SNR>\w\+$')
    498     return 'g@'
    499   endif
    500   let char = s:inputreplacement()
    501   if char == ""
    502     return s:beep()
    503   endif
    504   let reg = '"'
    505   let sel_save = &selection
    506   let &selection = "inclusive"
    507   let cb_save  = &clipboard
    508   set clipboard-=unnamed clipboard-=unnamedplus
    509   let reg_save = getreg(reg)
    510   let reg_type = getregtype(reg)
    511   let type = a:type
    512   if a:type == "char"
    513     silent exe 'norm! v`[o`]"'.reg.'y'
    514     let type = 'v'
    515   elseif a:type == "line"
    516     silent exe 'norm! `[V`]"'.reg.'y'
    517     let type = 'V'
    518   elseif a:type ==# "v" || a:type ==# "V" || a:type ==# "\<C-V>"
    519     let &selection = sel_save
    520     let ve = &virtualedit
    521     if !(a:0 && a:1)
    522       set virtualedit=
    523     endif
    524     silent exe 'norm! gv"'.reg.'y'
    525     let &virtualedit = ve
    526   elseif a:type =~ '^\d\+$'
    527     let type = 'v'
    528     silent exe 'norm! ^v'.a:type.'$h"'.reg.'y'
    529     if mode() ==# 'v'
    530       norm! v
    531       return s:beep()
    532     endif
    533   else
    534     let &selection = sel_save
    535     let &clipboard = cb_save
    536     return s:beep()
    537   endif
    538   let keeper = getreg(reg)
    539   if type ==# "v" && a:type !=# "v"
    540     let append = matchstr(keeper,'\_s\@<!\s*$')
    541     let keeper = substitute(keeper,'\_s\@<!\s*$','','')
    542   endif
    543   call setreg(reg,keeper,type)
    544   call s:wrapreg(reg,char,"",a:0 && a:1)
    545   if type ==# "v" && a:type !=# "v" && append != ""
    546     call setreg(reg,append,"ac")
    547   endif
    548   silent exe 'norm! gv'.(reg == '"' ? '' : '"' . reg).'p`['
    549   if type ==# 'V' || (getreg(reg) =~ '\n' && type ==# 'v')
    550     call s:reindent()
    551   endif
    552   call setreg(reg,reg_save,reg_type)
    553   let &selection = sel_save
    554   let &clipboard = cb_save
    555   if a:type =~ '^\d\+$'
    556     silent! call repeat#set("\<Plug>Y".(a:0 && a:1 ? "S" : "s")."surround".char.s:input,a:type)
    557   else
    558     silent! call repeat#set("\<Plug>SurroundRepeat".char.s:input)
    559   endif
    560 endfunction
    561 
    562 function! s:opfunc2(...) abort
    563   if !a:0 || a:1 ==# 'setup'
    564     let &opfunc = matchstr(expand('<sfile>'), '<SNR>\w\+$')
    565     return 'g@'
    566   endif
    567   call s:opfunc(a:1, 1)
    568 endfunction " }}}1
    569 
    570 function! s:closematch(str) " {{{1
    571   " Close an open (, {, [, or < on the command line.
    572   let tail = matchstr(a:str,'.[^\[\](){}<>]*$')
    573   if tail =~ '^\[.\+'
    574     return "]"
    575   elseif tail =~ '^(.\+'
    576     return ")"
    577   elseif tail =~ '^{.\+'
    578     return "}"
    579   elseif tail =~ '^<.+'
    580     return ">"
    581   else
    582     return ""
    583   endif
    584 endfunction " }}}1
    585 
    586 nnoremap <silent> <Plug>SurroundRepeat .
    587 nnoremap <silent> <Plug>Dsurround  :<C-U>call <SID>dosurround(<SID>inputtarget())<CR>
    588 nnoremap <silent> <Plug>Csurround  :<C-U>call <SID>changesurround()<CR>
    589 nnoremap <silent> <Plug>CSurround  :<C-U>call <SID>changesurround(1)<CR>
    590 nnoremap <expr>   <Plug>Yssurround '^'.v:count1.<SID>opfunc('setup').'g_'
    591 nnoremap <expr>   <Plug>YSsurround <SID>opfunc2('setup').'_'
    592 nnoremap <expr>   <Plug>Ysurround  <SID>opfunc('setup')
    593 nnoremap <expr>   <Plug>YSurround  <SID>opfunc2('setup')
    594 vnoremap <silent> <Plug>VSurround  :<C-U>call <SID>opfunc(visualmode(),visualmode() ==# 'V' ? 1 : 0)<CR>
    595 vnoremap <silent> <Plug>VgSurround :<C-U>call <SID>opfunc(visualmode(),visualmode() ==# 'V' ? 0 : 1)<CR>
    596 inoremap <silent> <Plug>Isurround  <C-R>=<SID>insert()<CR>
    597 inoremap <silent> <Plug>ISurround  <C-R>=<SID>insert(1)<CR>
    598 
    599 if !exists("g:surround_no_mappings") || ! g:surround_no_mappings
    600   nmap ds  <Plug>Dsurround
    601   nmap cs  <Plug>Csurround
    602   nmap cS  <Plug>CSurround
    603   nmap ys  <Plug>Ysurround
    604   nmap yS  <Plug>YSurround
    605   nmap yss <Plug>Yssurround
    606   nmap ySs <Plug>YSsurround
    607   nmap ySS <Plug>YSsurround
    608   xmap S   <Plug>VSurround
    609   xmap gS  <Plug>VgSurround
    610   if !exists("g:surround_no_insert_mappings") || ! g:surround_no_insert_mappings
    611     if !hasmapto("<Plug>Isurround","i") && "" == mapcheck("<C-S>","i")
    612       imap    <C-S> <Plug>Isurround
    613     endif
    614     imap      <C-G>s <Plug>Isurround
    615     imap      <C-G>S <Plug>ISurround
    616   endif
    617 endif
    618 
    619 " vim:set ft=vim sw=2 sts=2 et: