Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vim line completion with external file

Tags:

vim

Can line completion Ctrl+X Ctrl+L be used to show line completions from a specific external file instead of "only" from the current buffer? Something like dictionaries, but for lines.

Update:

To test I did following:

  • created a file tt.txt with some test lines
  • placed the file in D:\t1\ (I'm on windows)
  • included the file with :set path+=D:\\t1\\tt.txt
  • :set complete ? returns complete =.,w,b,u,t,i
  • :set path ? returns path=.,,,D:\t1\tt.txt
  • checkpath returns: All included files were found
  • typing a line which should be completed with the matching content from tt.txt with Ctrl+X Ctrl+L returns pattern not found

What am I missing?

like image 748
vbd Avatar asked Dec 26 '22 22:12

vbd


2 Answers

I think the only way to achieve what you want is with a custom complete-function. See help complete-functions for the (very useful!) documentation. Here's my attempt at a solution:

First you need a separate function to silently grep a file for a string (if you just call the naked vimgrep function you will get an ugly error if there are no matches).

function! SilentFileGrep( leader, file )
    try
        exe 'vimgrep /^\s*' . a:leader . '.*/j ' . a:file
    catch /.*/
        echo "no matches"
    endtry
endfunction

Now, here's your completion function. Note that the path to the file you want to search is hard-coded in here, but you could change it to use a variable if you so wish. We call SilentFileGrep(), which dumps the results in the quickfix list. Then we extract the results from the qflist (trimming the leading whitespace) and clear the qflist before returning the results.

function! LineCompleteFromFile(findstart,base)
    if a:findstart
        " column to begin searching from (first non-whitespace column):
        return match(getline("."),'\S')
    else
        " grep the file and build list of results:
        let path = <path_to_file>
        call SilentFileGrep( a:base, path )
        let matches = []
        for thismatch in getqflist()
            " trim leading whitespace
            call add(matches, matchstr(thismatch.text,'\S.*'))
        endfor
        call setqflist([])
        return matches
    endif
endfunction

To use this function, you need to set the completefunc option to point at it:

set completefunc=LineCompleteFromFile

Then you can use <C-X><C-U> to invoke the completion, which you could easily map to <C-X><C-L>.

This seems to work pretty well for me, but it is not exhaustively tested.

like image 131
Prince Goulash Avatar answered Dec 28 '22 18:12

Prince Goulash


In Vim help for line completion it's written that it only works for loaded buffers. As a workaround, you may open your "dictionary" file in another buffer and Vim will suggest lines from this buffer.

like image 40
rpeshkov Avatar answered Dec 28 '22 18:12

rpeshkov