9

When declaring a mapping with omap or onoremap i would like to be able to handle the case where the motion will be blockwise, linewise or standard.

For example let's consider the following block:

abcd
efgh
ijkl
mnop

Cursor is on the letter f. Suppose that I define an operator map from K to :normal! vjl (go to letter k).

onoremap K :normal! vjl<cr>

Interestingly enough when I run dvK, dK, d^VK I get respectively

abcd   abcd   abcd
el     el     eh
mnop   mnop   il
              mnop

But when I run dVK it won't work, I get exactly the same as with dvK.

I tried to use visualmode() (mapping defined as @=visualmode()<cr>jl<cr> but this does not work. It seems that the return value of this function is not immediately affected when you use v, V or CTRL-V in operator-pending mode.

Does anyone have a clue please?
Thank you

Benoit
  • 76,634
  • 23
  • 210
  • 236
  • When you start a visual selection you can change it to the other types of visual selections by hitting their corresponding command (`` -> `v` -> `` -> `v` -> whatever). Is it possible that you start a line-wise visual selection with the `V` in `dVK` but change its type to character-wise with the `v` in `vjl`? – romainl Dec 19 '11 at 17:14
  • @romainl: you are right! but it does not explain why it behaves differently for V. – Benoit Dec 19 '11 at 17:21
  • Do you want to obtain two lines with `abcd` and `mnop`? – romainl Dec 19 '11 at 17:21
  • @romainl: yes exactly. And if I remove the `v` from the mapping it works. – Benoit Dec 19 '11 at 17:22
  • Yes, if you change your mapping to `Vjl` it's `dvK` that doesn't work anymore. – romainl Dec 19 '11 at 17:28
  • What is the output you want / would expect as a result of dVk? I'd like to help solve. – kikuchiyo Jan 20 '12 at 04:32
  • @kikuchiyo, I would like it to work linewise, therefore it should delete two lines, and I should hage `abcd`,`mnop`. – Benoit Jan 20 '12 at 06:52
  • Cool. It's the original mapping. I think it over-rides your 'V'. If you do a onoremap K :normal! Vjl, then you get the result you want. As romainl notes, however, dvK no longer works. For a little proof of concept of v overriding V, you can do this manually and note the change from '-- VISUAL LINE --' to '-- VISUAL --'. I think you got this licked by just leaving the 'v' out of onoremap K :normal! vjl. You could either make three seperate mappings for the three modes or else use a function. If you want to try a function let me know and I'll try to help. – kikuchiyo Jan 20 '12 at 07:23

2 Answers2

1

To achieve what you desired, you can simply define

onoremap K :<c-u>normal! jl<cr>

Note this motion, as formed by a ex-command, is always characterwise (see :h movement

Then you can freely use dv, or dV, or d^V to force the motion to be another type and get what you want.

doraemon
  • 2,296
  • 1
  • 17
  • 36
0

I've written some answers on operator pending mappings. In one of them1 I sketched an outline of a function that should handle the various cases (char,line,block wise selections) according to the docs:

 g@{motion}     Call the function set by the 'operatorfunc' option.
        The '[ mark is positioned at the start of the text
        moved over by {motion}, the '] mark on the last
        character of the text.
        The function is called with one String argument:
            "line"  {motion} was |linewise|
            "char"  {motion} was |characterwise|
            "block" {motion} was |blockwise-visual|
        Although "block" would rarely appear, since it can
        only result from Visual mode where "g@" is not useful.
        {not available when compiled without the |+eval|
        feature}

Here is an example that counts the number of spaces with <F4>: >

nmap <silent> <F4> :set opfunc=CountSpaces<CR>g@
vmap <silent> <F4> :<C-U>call CountSpaces(visualmode(), 1)<CR>

function! CountSpaces(type, ...)
  let sel_save = &selection
  let &selection = "inclusive"
  let reg_save = @@

  if a:0  " Invoked from Visual mode, use '< and '> marks.
    silent exe "normal! `<" . a:type . "`>y"
  elseif a:type == 'line'
    silent exe "normal! '[V']y"
  elseif a:type == 'block'
    silent exe "normal! `[\<C-V>`]y"
  else
    silent exe "normal! `[v`]y"
  endif

  echomsg strlen(substitute(@@, '[^ ]', '', 'g'))

  let &selection = sel_save
  let @@ = reg_save
endfunction

1 vim call a function from inside a vmap

Community
  • 1
  • 1
sehe
  • 374,641
  • 47
  • 450
  • 633
  • 1
    I granted the bounty because I feel that this answer is close to it (and there was no other answer). But if this can be useful to define a new, arbitrary command that will expect any motion, I fail to see how I can use it to define a new, arbitrary motion that might be either blockwise, linewise, or characterwise. Could you expand please? – Benoit Jan 25 '12 at 13:55
  • 1
    Possibly useful / of interest: https://github.com/kana/vim-operator-user – Kvass Aug 19 '19 at 01:26