caio.co/de/querycommandcomplete.vim


Update documentation with new options and stats by Caio 11 years ago (log)

Blob plugin/querycommandcomplete.vim

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
" Query Command Complete
" ======================
"
" Vim plugin to suggest completions with the results of an external
" query command.
"
" The original intention is to use it as a mutt query_command wrapper
" to complete addresses in the mail headers, but it can be adapted
" to any other kind of functionality by modifying the exposed setting
" parameters.
"
" Last Change: 2012 Dec 29
" Author: Caio Romão <caioromao@gmail.com>
" License: This file is placed in the public domain
" Contributors:
"   Brian Henderson <https://github.com/bhenderson>
"   Mark Stillwell <https://github.com/marklee77>
"
" Setup:
"   This plugin exports the completion function QueryCommandComplete,
"   which can be set as the complete function (or omni function) for
"   any filetype. If you have a working mutt setup with query_command
"   configured, the plugin works out of the box.
"
"   Example:
"       let g:qcc_query_command='abook'
"       au BufRead /tmp/mutt* setlocal omnifunc=QueryCommandComplete
"
" Settings:
"   g:qcc_query_command
"       External command that queries for contacts
"       If empty, QueryCommandComplete tries to guess what command to
"       run by executing `mutt -Q query_command`.
"
"   g:qcc_line_separator
"       Separator for each entry in the result from the query
"       default: '\n'
"
"   g:qcc_field_separator
"       Separator for the fields of an entry from the result
"       default: '\t'
"
"   g:qcc_pattern
"       Pattern used to match against the current line to decide
"       whether to call the query command
"       default: '^\(To\|Cc\|Bcc\|From\|Reply-To\):'
"
"   g:qcc_multiline
"       Whether to try matching g:qcc_pattern against the current
"       and any previous line
"       default: 0
"
"   g:qcc_multiline_pattern
"       Pattern to match against the current line when deciding
"       wether to keep looking for a line that matches g:qcc_pattern
"       This provides finer control over the recursion, which
"       is useful if calling the completion on really big files.
"       default: '.*'

if exists("g:loaded_QueryCommandComplete") || &cp
  finish
endif

" Try to use mutt's query_command by default if nothing is set
if !exists("g:qcc_query_command")
    let s:querycmd = system('mutt -Q query_command 2>/dev/null')
    let s:querycmd = substitute(s:querycmd, '^query_command="\(.*\)"\n', '\1','')

    if len(s:querycmd)
        let g:qcc_query_command = s:querycmd
        let g:qcc_multiline = 1
        autocmd FileType mail setlocal omnifunc=QueryCommandComplete
    else
        echoerr "QueryCommandComplete: g:qcc_query_command not set!"
        finish
    endif
endif

let g:loaded_QueryCommandComplete = 1
let s:save_cpo = &cpo
set cpo&vim

function! s:DefaultIfUnset(name, default)
    if !exists(a:name)
        let {a:name} = a:default
    endif
endfunction

call s:DefaultIfUnset('g:qcc_line_separator', '\n')
call s:DefaultIfUnset('g:qcc_field_separator', '\t')
call s:DefaultIfUnset('g:qcc_pattern', '^\(To\|Cc\|Bcc\|From\|Reply-To\):')
call s:DefaultIfUnset('g:qcc_multiline', 0)
call s:DefaultIfUnset('g:qcc_multiline_pattern', '.*')

function! s:MakeCompletionEntry(name, email, other)
    let entry = {}
    let entry.word = a:name . ' <' . a:email . '>'
    let entry.abbr = a:name
    let entry.menu = a:other
    let entry.icase = 1
    return entry
endfunction

function! s:FindStartingIndex()
    let cur_line = getline('.')

    " locate the start of the word
    let start = col('.') - 1
    while start > 0 && cur_line[start - 1] =~ '[^:,]'
        let start -= 1
    endwhile

    " lstrip()
    while cur_line[start] =~ '[ ]'
        let start += 1
    endwhile

    return start
endfunction

function! s:GenerateCompletions(findstart, base)
    if a:findstart
        return s:FindStartingIndex()
    endif

    let results = []
    let cmd = g:qcc_query_command
    if cmd !~ '%s'
        let cmd .= ' %s'
    endif
    let cmd = substitute(cmd, '%s', shellescape(a:base), '')
    let lines = split(system(cmd), g:qcc_line_separator)

    for my_line in lines
        let fields = split(my_line, g:qcc_field_separator)

        if (len(fields) < 2)
            continue
        endif

        let email = fields[0]
        let name = fields[1]
        let other = ''

        if (len(fields) > 2)
            let other = fields[2]
        endif

        let contact = s:MakeCompletionEntry(name, email, other)

        call add(results, contact)
    endfor

    return results
endfunction

function! s:ShouldGenerateCompletions(line_number)
    let current_line = getline(a:line_number)

    if current_line =~ g:qcc_pattern
        return 1
    endif

    if ! g:qcc_multiline || a:line_number <= 1 || current_line !~ g:qcc_multiline_pattern
        return 0
    endif

    return s:ShouldGenerateCompletions(a:line_number - 1)
endfunction

function! QueryCommandComplete(findstart, base)
    if s:ShouldGenerateCompletions(line('.'))
        return s:GenerateCompletions(a:findstart, a:base)
    endif
endfunction

let &cpo = s:save_cpo