Search code examples
vimvim-pluginviml

getbufline missing current line when called from an omnifunc


I'm currently trying to write a plugin for vim that will allow me to define a custom omnifunc for a given language.

I am able to get this almost working, aside from the fact that when I call out to getbufline (in order to get the contents of the current buffer), the results contain an empty line instead of the current line's contents.

Here is the function I'm currently using:

function! statemachine#GetCurrBuffContents()
  return join(getbufline(bufname('%'), 1, "$"), "\n")
endfunction

The odd part about this, is that if I call my function from vim via echom statemachine#GetCurrBuffContents() then I see the output as expected, ie, each line separated by a \n character.

Example: Buffer contains the following

input signal x
out

state State2
if x == false goto State2
end

If I hit c-x c-o (to trigger omnicompletion) while the cursor is on line 2, I see the following (I echo it out inside my plugin):

input signal x^@^@^@state State2^@if x == false goto State2^@end

If I run echom statemachine#GetCurrBuffContents(), I see the following:

input signal x^@input^@^@state State2^@if x == false goto State2^@end

Here's the relevant code: https://github.com/scottopell/vim-statemachine/blob/3c3c3803f24031cce676e3988daaff12c269142a/autoload/statemachine.vim#L33

EDIT: now that it's fixed, here is the code that I'm currently using. See Ingor's answer as to why that code exists


Solution

  • Before Vim invokes the completion function for the second time (cp. :help complete-functions) to obtain the list of candidates, Vim removes the completion base (which was determined by the first invocation). The benefit of that is a buffer search (what most completions do) doesn't include the current position (which would just complete to itself). Your example has only a single word in front of the cursor, so you see the "entire line" disappearing.

    If you really need to have the "full" buffer contents for context, you need to manually splice in the base at the current position; the base got passed back to you. But most current-buffer completions do not grab the whole buffer into a string, but rather use search() to (temporarily and invisibly) move the cursor around in the actual buffer to obtain the matches. You can look at my CompleteHelper plugin for such utility functions.

    PS: Instead of getbufline(bufname('%'), 1, "$"), you can use getline(1, "$") instead.