Vim: 如何检测命令中的范围类型?
Vim: How to detect type of range within a command?
鉴于此...
function s:MyFn()
endfunction
command -range MyCommand :call s:MyFn()
...如何区分指定给命令(或它调用的函数)的范围类型?具体来说,如何区分指定为一对行号的范围和指定为一对标记(通常为“<”>)的范围。在我所有的尝试和阅读的内容中,一旦调用命令,这些信息似乎就会得到很多。
我检查了以下内容,比较接近,但似乎还没有触及这个问题的核心;-
https://vi.stackexchange.com/questions/11025/
我发现如果我这样做...
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>)
这样至少解决了一部分问题。但是在 a:range == 2
的情况下,我找不到确定范围是一对行号还是一对标记的方法(通常但不一定来自视觉选择)。如果视觉选择是逐行的,那么区别主要是学术上的。但这种区别对于字符式和块式视觉选择很重要。如果我知道视觉选择有效,那么我可以计算出它是什么类型的选择。根本问题是检测视觉选择是否有效;我不能假设使用了视觉选择并使用 '<
和 '>
标记,因为范围可以指定为两个行号,并且视觉选择标记可能只是前一个遗留的(无关)使用
在您按下 :
(按键或映射)后,您已经进入命令行模式,有效地放弃了之前的任何(可视或普通)模式。因此,您的命令/函数无法区分“从 Visual 或其他模式获取”之间的区别。
事实上,您有两个选择:要么使命令始终使用最后一个可视模式(默默地忽略命令行上传递的任何范围);要么或从可视化模式映射开始(可能使用“expr”或“cmd”等)。
在命令或函数使用之前,范围扩展为一对行号,因此当您使用其扩展值时,原始范围实际上已经丢失。
:help getcmdline()
可用于……获取原始命令行,包括范围,但它只能用于命令行模式映射,因此您必须有点创意。这是一个快速而粗略的片段,可以帮助您入门:
" 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()
看起来像这样:
鉴于此...
function s:MyFn()
endfunction
command -range MyCommand :call s:MyFn()
...如何区分指定给命令(或它调用的函数)的范围类型?具体来说,如何区分指定为一对行号的范围和指定为一对标记(通常为“<”>)的范围。在我所有的尝试和阅读的内容中,一旦调用命令,这些信息似乎就会得到很多。
我检查了以下内容,比较接近,但似乎还没有触及这个问题的核心;-
https://vi.stackexchange.com/questions/11025/
我发现如果我这样做...
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>)
这样至少解决了一部分问题。但是在 a:range == 2
的情况下,我找不到确定范围是一对行号还是一对标记的方法(通常但不一定来自视觉选择)。如果视觉选择是逐行的,那么区别主要是学术上的。但这种区别对于字符式和块式视觉选择很重要。如果我知道视觉选择有效,那么我可以计算出它是什么类型的选择。根本问题是检测视觉选择是否有效;我不能假设使用了视觉选择并使用 '<
和 '>
标记,因为范围可以指定为两个行号,并且视觉选择标记可能只是前一个遗留的(无关)使用
在您按下 :
(按键或映射)后,您已经进入命令行模式,有效地放弃了之前的任何(可视或普通)模式。因此,您的命令/函数无法区分“从 Visual 或其他模式获取”之间的区别。
事实上,您有两个选择:要么使命令始终使用最后一个可视模式(默默地忽略命令行上传递的任何范围);要么或从可视化模式映射开始(可能使用“expr”或“cmd”等)。
在命令或函数使用之前,范围扩展为一对行号,因此当您使用其扩展值时,原始范围实际上已经丢失。
:help getcmdline()
可用于……获取原始命令行,包括范围,但它只能用于命令行模式映射,因此您必须有点创意。这是一个快速而粗略的片段,可以帮助您入门:
" 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()
看起来像这样: