Vim vmap,将所选文本作为参数发送到函数

时间:2012-10-09 18:12:11

标签: function vim

简而言之,编写了一些函数来保存输入我正在尝试设置一个vmap [ping],这将允许我选择我输入的内容,并将此选择传递给一个函数(因为在函数上键入函数调用)命令行,键入参数(带引号),以及转义反斜杠等...通过调用函数来抵消大部分时间)

对于(一个简单的)例子,假设我有以下功能

func Test(iStr)
if a:iStr[0] =~ [a-zA-z]
    echo "hello"
else
    echo "hello world"
endif
endfunc

我希望能够直观地选择一些文本,然后使用一些键映射,F2说,它将调用Test(iStr),选择作为参数iStr

我相信,通过更多的工作(即某种方式来指定我选择的内容应该在Test()中),以下

vmap <F2> :call Test()

是我追求的。事情是我尝试了很多变种(猜测加上一点点狡猾的推理来自:帮助地图)而且我没有得到任何有用的东西。更新,我尝试使用辅助函数Test2()只需

call Test(<C-W>) 

作为它的身体...不知怎的,我想我需要抓住光标下的单词(不知何故),然后我就完成了 - 因为我可以从Test2中传递给Test(...)


至于我想要调用的函数的实际示例,下面的(不完整的)函数(和辅助函数)将允许我转换表单的表达式,比如说,

f_k^{(j)}g

f_1^{(j)}g, f_2^{(j)}g, \dots, f_{n-1}^{(j)}g, f_n^{(j)}g 

就我想要的程序而言

a) type the repeated term in vim
b) visually select it
c) hit some mapping key that will call SumOrSequence(iExpression, iIndex)
d) provide "k" as a parameter
e) press enter
f) see the change made by SumOrSequence(...)

SumOrSequence(...)的代码如下:

func SumOrSequence(iExpression, iIndex)
"need to check validity of these - maybe set a default
let default = Interrogate("do with defaults? yes [y] (2,1,n,0,\",\"), yes but specify last term [d[a-Z]], no [n]")
if default == "y"
    let leftTerms = 2
    let rightTerms = 1
    let lastTermIndex = "n"
    let firstTermIndex = 0
    let operator = ","
    let dotType = "\\dots"
elseif default =~ 'd[a-zA-Z]'
    let leftTerms = 2
    let rightTerms = 1
    let lastTermIndex = default[1]
    let firstTermIndex = 0
    let operator = Interrogate("what separates terms? add [+], subtract [-], times [*], comma [,], ampersand [&]?")
    let dotType = "\\cdots"
else "so n or anything else
    let leftTerms = InterrogateNumber("how many terms before dots? ")
    let rightTerms = InterrogateNumber("how many terms after dots? ")
    let lastTermIndex = Interrogate("what is last term index?")
    let firstTermIndex = Interrogate("what is first term index?")
    let operator = Interrogate("what separates terms? add [+], subtract [-], times [*], comma [,], ampersand [&]?") "need to check only any of these provided
    let dotType = "\\cdots"
endif
if operator == ","
    let dotType = "\\dots"
endif
if operator == "*"
    let operator = "\\times"
endif
let leftCount = 0
let oExpression = ""
while leftCount < leftTerms
    if leftCount > 0
        let oExpression .= operator . " "
    endif
    let oExpression .= ReplaceIndex(a:iExpression, a:iIndex, leftCount,1)
    let leftCount += 1
endwhile
let oExpression .= operator . " " . dotType . " "
let rightCount = rightTerms-1
while rightCount > 0
    "here we are going to be counting backwards from some number denoting number of terms - may need to know if we actually have a number!
    echo "decrement: " . HandleDecrement(lastTermIndex, rightCount)
    let oExpression .= operator . " " . ReplaceIndex(a:iExpression, a:iIndex, HandleDecrement(lastTermIndex, rightCount),1)
    let rightCount -= 1
endwhile
let oExpression .= operator . " " . ReplaceIndex(a:iExpression, a:iIndex, lastTermIndex,0)
echo oExpression
endfunc

func ReplaceIndex(iExpression, iIndex, iReplacement, iInsertBraces)
"the game we play here is to search for iIndex in such form that it is not part of any other string
"We should expect this to be the case if the character to the left or right of the index is not in [A-z] (or just to the right if a greek char)
let oExpression = ""
let strEndPosition = strlen(a:iExpression) - 1
let currPosition = 0
let indexLen = strlen(a:iIndex)
while currPosition <= strEndPosition
    let indexCounter = 0
    let foundIndex = 1
    while indexCounter < indexLen
        if a:iExpression[currPosition + indexCounter] == a:iIndex[indexCounter]
            if a:iExpression[currPosition + indexLen] =~ '[a-zA-Z]'
                let foundIndex = 0
                let indexCounter = indexLen
            elseif a:iExpression[currPosition -1] =~ '[a-zA-Z]' && a:iExpression[currPosition] != "\\"
                let foundIndex = 0
                let indexCounter = indexLen
            else
               let indexCounter+=1
            endif
        else
            let indexCounter = indexLen
            let foundIndex = 0
        endif
    endwhile
    if foundIndex == 0
        let oExpression .= a:iExpression[currPosition]
        let currPosition+=1
    else
        if a:iInsertBraces == 1
            let oExpression .= "{" . a:iReplacement . "}"
        else
            let oExpression .= a:iReplacement
        endif
        let currPosition+=indexLen
    endif
endwhile
    echo "oExpression: " . oExpression
return oExpression
endfunc

func HandleIncrement(iExpression, iIncrement)
"and what about negative numbers for iExpression!??? not handling these yet :[
let oExpression = ""
if !(a:iExpression[0] =~ '[0-9]') || a:iExpression < 10 && strlen(a:iExpression) > 1
    let oExpression = a:iExpression . " + " . a:iIncrement
else
    let oExpression = a:iExpression + a:iIncrement
endif
echo oExpression
return oExpression
endfunc

func HandleDecrement(iExpression, iIncrement)
"TODO and what about negative numbers for iExpression!??? not handling these yet :[
let oExpression = ""
if !(a:iExpression[0] =~ '[0-9]') || a:iExpression < 10 && strlen(a:iExpression) > 1
    let oExpression = a:iExpression . " - " . a:iIncrement
else
    let oExpression = a:iExpression - a:iIncrement
endif
echo oExpression
return oExpression
endfunc


func Interrogate(iQuestion)
    call inputsave()
    let answer = input(a:iQuestion)
    call inputrestore()
    return answer
endfunc

func InterrogateNumber(iQuestion)
    call inputsave()
    let answer = input(a:iQuestion)
    call inputrestore()
    "TODO what if negative number??
    if !(answer[0] =~ '[0-9]')
        let answer = InterrogateNumber(a:iQuestion . " you didn't enter a numerical value ")
    endif
    return answer
endfunc

关于映射位,我知道看起来我没有做太多工作,但假设我有更多的挖掘工作在我前面找到答案,有人可以帮忙吗?


更新。好吧,我有一些笨拙的东西,即如果我定义了以下的辅助函数:

func SumOrSequenceHelper()
    let oIndex = Interrogate("index variable? ")
    "go to last thing visually selected (I think!), yank it (putting it in the " register), then fetch it via oParam. Then pass this off to SumOrSequence
    execute "normal! gvy"
    let oExpression = getreg('"')
    call SumOrSequence(oExpression, oIndex)
endfunc

vnoremap <F6> :call SumOrSequenceHelper()

然后一切都很好,我可以执行一个执行命令来替换我从SumOrSequence(...)

获得的内容

对任何改进都会感激不尽,但是无论如何都要解决这个问题:]

2 个答案:

答案 0 :(得分:2)

您可以使用这样的辅助函数:

func! GetSelectedText()
  normal gv"xy
  let result = getreg("x")
  normal gv
  return result
endfunc

vnoremap <F6> :call MyFunc(GetSelectedText())<cr>

还有:com -range,它可以注册一个操作选择的自定义命令,但界面是面向行的。

答案 1 :(得分:1)

使用选择寄存器以视觉选择的任何方式调用该函数。

vnoremap <F6> :call Test(@*)<CR>

如果您只想在普通模式下抓住光标下的单词,可以使用它,然后猛拉到选择寄存器然后使用该值。 (你可以改为任何命名的寄存器,例如a注册"ay@a。)

noremap <S-F6> "*yaw:call Test(@*)<CR>

顺便说一下这些不适用于你的Test函数,但只是调用它似乎也不起作用?

:call Test("fred")
Error detected while processing function Test:
line    1:
E121: Undefined variable: a
E15: Invalid expression: a:iStr[0] =~ [a-zA-z]

他们使用此测试功能:

function Test(iStr)
    echo a:iStr
endfunction