2

I'm trying to define an insert mapping like this:

inoremap <expr><buffer> ; (Test(expand('<cWORD>'))).";"

in which the Test function is defined as:

func! Test(a)
    echom "cword: "."\"".a:a."\""
endfunction

For example, if the current position of the cursor is like:

apple|

When I type ;, I'm expecting a message saying: cword: "apple".

But currently, I can only get an empty result like: cword: ""

The question is why does the expand() function here always returns an empty string?

4
  • I'm using gvim version 8.0 Aug 28 '18 at 2:42
  • 1
    in insert mode the cursor is really located here: apple[ ]. so it's not over the word at all.
    – Mass
    Aug 28 '18 at 2:53
  • @Mass Oh, okay then. So there's a specific way to retrieve the word "before" the cursor? Or I need to manually split the word from getline(.)? Aug 28 '18 at 2:58
  • if you leave insert mode, the cursor should be on the last letter and then cword should be valid again. Aug 28 '18 at 7:03
2

As others have said, if you stay in insert mode, the cursor will be one character too far for expand('<cword>') to return anything useful.

That's why a long time ago I wrote these functions, now part of lh-vim-lib. Typically you'd be interested in

function! lh#ui#GetCurrentWord()
  let c = col ('.')-1
  let l = line('.')
  let ll = getline(l)
  let ll1 = strpart(ll,0,c)
  let ll1 = matchstr(ll1,'\S*$')
  if strlen(ll1) == 0
    return ll1
  else
    let ll2 = strpart(ll,c,strlen(ll)-c+1)
    let ll2 = strpart(ll2,0,match(ll2,'$\|\s'))
    return ll1.ll2
  endif
endfunction

The code is quite old and could be simplified.

2
  • I accidentally downvoted it and cannot undo...
    – doraemon
    Nov 23 '18 at 10:19
  • The variable names are confusing at best, incidentally.
    – D. Ben Knoble
    Dec 23 '18 at 1:54
2

Adapting the answer to another question about multibyte-aware character at current position, consider using the :help /\%v zero-width atom to perform a string match.

let l:wordBeforeCursor = matchstr(getline('.'), '\k\+\%' . virtcol('.') . 'v')
let l:WORDContainingCursor = matchstr(getline('.'), '\S*\%' . virtcol('.') . 'v\S*')

The first uses \k to match iskeyword characters (like <cword>) and will return 'apple' if your cursor is in call Foo(apple|jack). The second uses \S to match non-space (like <cWORD>) and will return Foo(apple|jack).

Note that <cword> is forward-looking, and skips space between the cursor and the next word, e.g. expand('<cword>') on apple| pie will return 'pie' rather than empty string.

1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.