AndrewRadev / switch.vim

A simple Vim plugin to switch segments of text with predefined replacements
http://www.vim.org/scripts/script.php?script_id=4172
MIT License
645 stars 30 forks source link

Patch to allow reverse action (and count) in lambda substitutions #86

Closed amerlyq closed 4 months ago

amerlyq commented 4 months ago

In continuation of #78 :

{ '\d{10}':  {m -> cvt(m[0], fmt='fname'},  ... }

It didn't support SwitchReverse (and now it does).

I needed a way to switch faster between group of time representations:

For which I basically use "reverse" option as an optional lambda argument, to match same pattern into two different operations directions based on either <CR> or <BS> was pressed.

{ '\d{10}':  {m,r -> cvt(m[0], fmt=(r?'iso':'fname'))},  ... }

In same way, if I have multiple possible commands on same pattern -- I can pass <count> as 3rd arg to pick one of them, if all of them are different. Or place all possible conversions into a list around lambda definitions, and directly pick necessary item from list by without pressing <CR> multiple times.

tsfmts = {ts: '\d{10}',  fname: XXX, ymd3hms: XXX, isolocal: XXX}
tsring = split('ts fname ymd3hms isolocal')   " my preferred order
g:switch_custom_definitions = [{}]
for x in tsring
g:switch_custom_definitions[0][tsfmts[x]] = {m,r,c -> cvt(m[0], from=x, to=tsring[c?c: (index(tsring)+(r?-1:1))%len(tsring)]},  ... }
endfor

Full patch below, I hope you will apply and push it soon :) P.S. of course, for v:count support, I needed to fix opfunc call first.

add: pass reverse and count to lambda

diff --git a/autoload/switch.vim b/autoload/switch.vim
index e682bd5..8bc426a 100644
--- a/autoload/switch.vim
+++ b/autoload/switch.vim
@@ -35,7 +35,7 @@ function! switch#Switch(...)
     endfor

     if !min_match.IsNull()
-      call min_match.Replace()
+      call min_match.Replace(options)
       return 1
     else
       return 0
@@ -46,12 +46,12 @@ function! switch#Switch(...)
 endfunction

 function! switch#OpfuncForward(type)
-  silent call switch#Switch()
+  silent call switch#Switch({'count': v:count})
   return ''
 endfunction

 function! switch#OpfuncReverse(type)
-  silent call switch#Switch({'reverse': 1})
+  silent call switch#Switch({'reverse': 1, 'count': v:count})
   return ''
 endfunction

diff --git a/autoload/switch/mapping.vim b/autoload/switch/mapping.vim
index 91943b4..8bc5706 100644
--- a/autoload/switch/mapping.vim
+++ b/autoload/switch/mapping.vim
@@ -98,7 +98,7 @@ endfunction
 " Replaces the pattern from the match data with its Replacement. Takes care of
 " both simple replacements and nested ones.
 "
-function! switch#mapping#Replace(match) dict
+function! switch#mapping#Replace(match, options) dict
   let pattern     = a:match.pattern
   let Replacement = self.definitions[pattern]
   let oldsearch   = @/
@@ -128,7 +128,9 @@ function! switch#mapping#Replace(match) dict
     let g:Switch_replacer = Replacement
     let submatch_expression = join(map(range(0, 9), '"submatch(".v:val.")"'), ',')

-    let Replacement = '\=call(g:Switch_replacer, [['.submatch_expression.']])'
+    let rev = get(a:options, 'reverse')
+    let cnt = get(a:options, 'count')
+    let Replacement = '\=call(g:Switch_replacer, [['.submatch_expression.'],'.rev.','.cnt.'])'
     exe 's/'.pattern.'/'.Replacement.'/'

     unlet g:Switch_replacer
diff --git a/autoload/switch/match.vim b/autoload/switch/match.vim
index a9ab7e1..5decc9c 100644
--- a/autoload/switch/match.vim
+++ b/autoload/switch/match.vim
@@ -43,8 +43,8 @@ function! switch#match#IsBetter(other) dict
   endif
 endfunction

-function! switch#match#Replace() dict
-  call self.mapping.Replace(self)
+function! switch#match#Replace(...) dict
+  call self.mapping.Replace(self, get(a:,1))
 endfunction

 function! switch#match#IsNull() dict
diff --git a/plugin/switch.vim b/plugin/switch.vim
index b6dc3dd..9fb1f37 100644
--- a/plugin/switch.vim
+++ b/plugin/switch.vim
@@ -251,8 +251,8 @@ function! s:SwitchReverse()
   silent! call repeat#set(":SwitchReverse\<cr>")
 endfunction

-nnoremap <silent> <Plug>(Switch)        :set opfunc=switch#OpfuncForward<cr>g@l
-nnoremap <silent> <Plug>(SwitchReverse) :set opfunc=switch#OpfuncReverse<cr>g@l
+nnoremap <silent><expr>  <Plug>(Switch)         execute("set opfunc=switch#OpfuncForward").'g@l'
+nnoremap <silent><expr>  <Plug>(SwitchReverse)  execute("set opfunc=switch#OpfuncReverse").'g@l'

 command! -nargs=* SwitchExtend call s:SwitchExtend(<args>)
 fun! s:SwitchExtend(...)
AndrewRadev commented 4 months ago

It generally looks reasonable, but could you submit it as a pull request, so it's easier for me to review?

amerlyq commented 4 months ago

I really-really didn't want to fork the repo only to make a PR for short patch, and then wait merge to delete that repo :( But here you go. As for the docs -- if needed you can copy some descriptions from this issue into PR.

AndrewRadev commented 4 months ago

Merged