Reputation: 303
Given this...
function s:MyFn()
endfunction
command -range MyCommand :call s:MyFn()
...how can I tell the difference between the type of range specified to a command (or a function that it calls)? Specifically, how do I tell the difference between a range specified as a pair of line numbers, and a range specified as a pair of marks (usually '<'>). In all my attempts and things I have read, this information seems to get lots as soon as the command is called.
I checked out the following, which sort-of get close, but nether seems to get to the nub of this problem;-
How to detect existence of Visual selection in VimL script
https://vi.stackexchange.com/questions/11025/
I find that if I do this...
function s:MyFn(range)
if a:range == 0
" No range specified
elseif a:range == 1
" Single line specified
else
" a:range == 2
endif
endfunction
command -range MyCommand :call s:MyFn(<range>)
This at least solves part of the problem. But in the case of a:range == 2
, I can't find a way of determining whether the range is a pair of line numbers or a pair of marks (usually, but not necessarily, from a visual selection). If the visual selection was line-wise then the distinction is largely academic. But the distinction matters for character-wise and block-wise visual selections. If I KNOW that a visual selection is in effect then I can work out the type of selection it is. The root problem is detecting whether a visual selection was in effect at all; I cannot just assume that a visual selection was used and use the '<
and '>
markers because the range could have been specified as two line numbers and the visual selection markers could be just left-over from a previous (unrelated) use
Upvotes: 2
Views: 525
Reputation: 196751
The range is expanded to a pair of line numbers before being consumed by a command or function so the original range is effectively lost by the time you consume its expanded value.
:help getcmdline()
can be used to… get the raw command line, range included, but it can only be used in a command-line mode mapping so you will have to be a bit creative. Here is a quick and dirty snippet to get you started:
" save the current range in a global variable
" insert the name of your custom command for further typing
function! FirstStep()
let g:my_range = getcmdline()
return 'MyCommand'
endfunction
" the actual implementation of the desired functionality
" do what you have to do with g:my_range
function! SecondStep()
if g:my_range == "'<,'>"
echo "range is purely visual"
elseif g:my_range =~ '\d\+,\d\+'
echo "range is purely numerical"
else
echo "range is neither purely visual nor purely numerical"
echo "support for other ranges not yet implemented"
endif
endfunction
" expression mapping
" inserts the result of FirstStep() in the command-line
cnoremap <expr> MyCommand FirstStep()
" the actual command that calls the actual function
" that actually implements the desired functionality
command! -range=% MyCommand call SecondStep()
It looks like this:
Upvotes: 3
Reputation: 15186
After you've pressed :
(by key or by mapping) you already got into Command-line mode effectively abandoning any previous (be it Visual or Normal) mode. And so there's no way for your command / function to tell the difference between "get here from Visual or from other mode".
In fact, you have two options: either make a command always to use last visual mode (silently ignoring any range passed on command line); or start from a Visual mode mapping (maybe with "expr" or "cmd" etc.).
Upvotes: 1