vbd
vbd

Reputation: 3557

Vim line completion with external file

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:

What am I missing?

Upvotes: 4

Views: 821

Answers (5)

romainl
romainl

Reputation: 196809

  • 'path' is supposed to be a list of directories so (assuming that's the correct syntax on Windows) :set path+=D:\\t1\\tt.txt should be :set path+=D:\\t1\\ or :set path+=D:\\t1.

  • The i in 'complete' means that the completion candidates are chosen from current and included files. You must include a file for completion to work: it won't if you don't explicitly include that file.

    Say that you have created ~/test/testfile with this single line:

    lorem ipsum dolor sit amet
    

    You add it to Vim's 'path' with:

    :set path+=~/test
    

    To use it as completion source in a C++ file you would do:

    #include <testfile>
    

    and be able to do:

    lore<C-x><C-f>
    

    to get:

    lorem ipsum dolor sit amet
    

As far as I know, it doesn't work with languages that don't have an include mechanism like C or C++ so you can forget about it for Markdown, JavaScript, plain text or, if my tests are any indication, even PHP which does have include.

If you want a more generic mechanism, just add that file to the arglist: it will automatically be used as a completion source:

:argadd ~/test/testfile

Upvotes: 1

Prince Goulash
Prince Goulash

Reputation: 15735

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.

Upvotes: 7

Nikita Kouevda
Nikita Kouevda

Reputation: 5756

As @black_wizard points out, the other file must be loaded in a buffer. With set hidden, you can use the following to load another file and return to the previous buffer:

command! -nargs=? XL silent edit <args> | silent bprevious

To load tt.txt into another buffer and return to the previous one:

:XL tt.txt

Upvotes: 0

rpeshkov
rpeshkov

Reputation: 5057

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.

Upvotes: 2

jbr
jbr

Reputation: 6258

If you do

:set dictionary=<some file>

then you can use ctrl + x followed by ctrl + k to complete from <some file>

See

:help ins-completion

for more info.

Upvotes: 0

Related Questions