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."\""

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


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?

  • I'm using gvim version 8.0 Aug 28, 2018 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, 2018 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, 2018 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, 2018 at 7:03

2 Answers 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
    let ll2 = strpart(ll,c,strlen(ll)-c+1)
    let ll2 = strpart(ll2,0,match(ll2,'$\|\s'))
    return ll1.ll2

The code is quite old and could be simplified.

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

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.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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