Skip to content

Commit 320d320

Browse files
committed
Support deleting/changing custom surrounds
1 parent bf3480d commit 320d320

File tree

1 file changed

+73
-13
lines changed

1 file changed

+73
-13
lines changed

plugin/surround.vim

+73-13
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ endfunction
5757

5858
" }}}1
5959

60-
" Wrapping functions {{{1
60+
" Wrapping/unwrapping functions {{{1
6161

6262
function! s:extractbefore(str)
6363
if a:str =~ '\r'
@@ -75,6 +75,23 @@ function! s:extractafter(str)
7575
endif
7676
endfunction
7777

78+
if exists('*trim')
79+
function! s:trim(txt) abort
80+
return trim(a:txt)
81+
endfunction
82+
else
83+
function! s:trim(txt) abort
84+
return substitute(a:txt, '\%(^\s\+\|\s\+$\)', '', 'g')
85+
endfunction
86+
endif
87+
88+
function! s:customsurroundings(char, b, trim) abort
89+
let all = s:process(get(a:b ? b: : g:, 'surround_'.char2nr(a:char)))
90+
let before = s:extractbefore(all)
91+
let after = s:extractafter(all)
92+
return a:trim ? [s:trim(before), s:trim(after)] : [before, after]
93+
endfunction
94+
7895
function! s:fixindent(str,spc)
7996
let str = substitute(a:str,'\t',repeat(' ',&sw),'g')
8097
let spc = substitute(a:spc,'\t',repeat(' ',&sw),'g')
@@ -148,13 +165,9 @@ function! s:wrap(string,char,type,removed,special)
148165
let before = ''
149166
let after = ''
150167
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)
168+
let [before, after] = s:customsurroundings(newchar, 1, 0)
154169
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)
170+
let [before, after] = s:customsurroundings(newchar, 0, 0)
158171
elseif newchar ==# "p"
159172
let before = "\n"
160173
let after = "\n\n"
@@ -306,6 +319,45 @@ function! s:wrapreg(reg,char,removed,special)
306319
let new = s:wrap(orig,a:char,type,a:removed,a:special)
307320
call setreg(a:reg,new,type)
308321
endfunction
322+
323+
function! s:escape(str) abort
324+
return escape(a:str, '!#$%&()*+,-./:;<=>?@[\]^{|}~')
325+
endfunction
326+
327+
function! s:deletecustom(char, b, count) abort
328+
let [before, after] = s:customsurroundings(a:char, a:b, 1)
329+
let [before_pat, after_pat] = ['\v\C'.s:escape(before), '\v\C'.s:escape(after)]
330+
" searchpair()'s 'c' flag matches both start and end.
331+
" Append '\zs' to the closer pattern so that it doesn't match the closer on the cursor.
332+
let found = searchpair(before_pat, '', after_pat.'\zs', 'bcW')
333+
if found <= 0
334+
return ['','']
335+
endif
336+
" Handle count/nesting only for asymmetric surroundings
337+
if before !=# after
338+
for _ in range(a:count - 1)
339+
let found = searchpair(before_pat, '', after_pat, 'bW')
340+
if found <= 0
341+
return ['','']
342+
endif
343+
endfor
344+
endif
345+
norm! v
346+
if before ==# after
347+
call search(before_pat, 'ceW')
348+
let found = search(after_pat, 'eW')
349+
else
350+
let found = searchpair(before_pat, '', after_pat, 'W')
351+
call search(after_pat, 'ceW')
352+
endif
353+
if found <= 0
354+
exe "norm! \<Esc>"
355+
return ['','']
356+
endif
357+
norm! d
358+
return [before, after]
359+
endfunction
360+
309361
" }}}1
310362

311363
function! s:insert(...) " {{{1
@@ -380,11 +432,12 @@ function! s:dosurround(...) " {{{1
380432
let char = strpart(char,1)
381433
let spc = 1
382434
endif
383-
if char == 'a'
384-
let char = '>'
385-
endif
386-
if char == 'r'
387-
let char = ']'
435+
if !exists("b:surround_".char2nr(char)) && !exists("g:surround_".char2nr(char))
436+
if char == 'a'
437+
let char = '>'
438+
elseif char == 'r'
439+
let char = ']'
440+
endif
388441
endif
389442
let newchar = ""
390443
if a:0 > 1
@@ -405,6 +458,10 @@ function! s:dosurround(...) " {{{1
405458
let strcount = (scount == 1 ? "" : scount)
406459
if char == '/'
407460
exe 'norm! '.strcount.'[/d'.strcount.']/'
461+
elseif exists("b:surround_".char2nr(char))
462+
let [before, after] = s:deletecustom(char, 1, scount)
463+
elseif exists("g:surround_".char2nr(char))
464+
let [before, after] = s:deletecustom(char, 0, scount)
408465
elseif char =~# '[[:punct:][:space:]]' && char !~# '[][(){}<>"''`]'
409466
exe 'norm! T'.char
410467
if getline('.')[col('.')-1] == char
@@ -426,7 +483,10 @@ function! s:dosurround(...) " {{{1
426483
endif
427484
let oldline = getline('.')
428485
let oldlnum = line('.')
429-
if char ==# "p"
486+
if exists("b:surround_".char2nr(char)) || exists("g:surround_".char2nr(char))
487+
call setreg('"', before.after, "c")
488+
let keeper = substitute(substitute(keeper,'\v\C^'.s:escape(before).'\s=','',''), '\v\C\s='.s:escape(after).'$', '','')
489+
elseif char ==# "p"
430490
call setreg('"','','V')
431491
elseif char ==# "s" || char ==# "w" || char ==# "W"
432492
" Do nothing

0 commit comments

Comments
 (0)