ZyX
ZyX

Reputation: 53674

Discarding count in <expr> mappings

For example, I have the following expression mapping:

    function! DelNthSpace()
        let col=match(getline('.'), '[[:blank:] ]', col('.'), v:count1)
        return virtcol([line('.'), col+1])."|s \e"
    endfunction
    nnoremap  s DelNthSpace()
You see, v:count1 is already handled here. But if I try to replace second space with such function that is located, for example, at virtual column 35 (it will be if you place cursor on the return statement), then this tries to go to column 235 and replace it because this will be transformed from 2s to 2{DelNthSpace()} -> 235|s ^[. Now I am prepending bare useless | at the start of return statement which consumes unneeded count, but I do not like this solution as it uses two movements instead of one.

UPDATE: I should have provided more context:

function! ToNthSpace()
    let col=match(getline('.'), '[[:blank:] ]', col('.'), v:count1)
    return virtcol([line('.'), col+1])."|"
endfunction
noremap <expr> s ToNthSpace()

There are a bunch of functions that are using these, one imitates replace command, but transliterates its argument (so, while calling r$ii will replace character with $ and insert i, \tr$ii will replace character with , same relation between t and \tt and some others), others are motions. As these functions define motions, I can't use :<C-u>, it will leave visual mode (or I will have to add a hack which will tell from which mode function was called). I do not know this hack and I can't define different mappings for normal and visual modes.

Upvotes: 4

Views: 550

Answers (2)

doraemon
doraemon

Reputation: 2522

To summarize what is mentioned by @Alexey and also my test on operator-pending mode, you can do the following

nnoremap <expr> s "@_" . ToNthSpace()
vnoremap <expr> s "@_" . ToNthSpace()
onoremap <expr> s printf(":normal %s\<cr>", ToNthSpace())

Then the 2 already typed in your example will have no effect

Upvotes: 1

too much php
too much php

Reputation: 91068

There is no way to make vim ignore the count for the <expr> mapping, however you can easily change your mapping to make your function work:

nnoremap s :<C-U>exe 'normal!' DelNthSpace()<CR>

See :help v:count for info about using CTRL+U to erase the count.

Upvotes: 2

Related Questions