Various MUA related config files
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

querycommandcomplete.vim 7.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. " Query Command Complete
  2. " ======================
  3. "
  4. " Vim plugin to suggest completions with the results of an external
  5. " query command.
  6. "
  7. " The original intention is to use it as a mutt query_command wrapper
  8. " to complete addresses in the mail headers, but it can be adapted
  9. " to any other kind of functionality by modifying the exposed setting
  10. " parameters.
  11. "
  12. " Last Change: 2013 Jun 16
  13. " Author: Caio Romão (http://caioromao.com)
  14. " License: This file is placed in the public domain
  15. " Contributors:
  16. " Brian Henderson https://github.com/bhenderson
  17. " Mark Stillwell https://github.com/marklee77
  18. " Rui Abreu Ferreira http://ruiabreu.org
  19. "
  20. " Setup:
  21. " This plugin exports the completion function QueryCommandComplete,
  22. " which can be set as the complete function (or omni function) for
  23. " any filetype. If you have a working mutt setup with query_command
  24. " configured, the plugin works out of the box.
  25. "
  26. " Example:
  27. " let g:qcc_query_command='abook'
  28. " au BufRead /tmp/mutt* setlocal omnifunc=QueryCommandComplete
  29. "
  30. " Settings:
  31. " Note: Overriding settings on a buffer-basis is supported. So
  32. " b:qcc_query_command takes precedence over g:qcc_query_command
  33. "
  34. " g:qcc_query_command
  35. " External command that queries for contacts
  36. " If empty, QueryCommandComplete tries to guess what command to
  37. " run by executing `mutt -Q query_command`.
  38. "
  39. " g:qcc_line_separator
  40. " Separator for each entry in the result from the query
  41. " default: '\n'
  42. "
  43. " g:qcc_field_separator
  44. " Separator for the fields of an entry from the result
  45. " default: '\t'
  46. "
  47. " g:qcc_pattern
  48. " Pattern used to match against the current line to decide
  49. " whether to call the query command
  50. " default: '^\(To\|Cc\|Bcc\|From\|Reply-To\):'
  51. "
  52. " g:qcc_multiline
  53. " Whether to try matching g:qcc_pattern against the current
  54. " and any previous line
  55. " default: 0
  56. "
  57. " g:qcc_multiline_pattern
  58. " Pattern to match against the current line when deciding
  59. " wether to keep looking for a line that matches g:qcc_pattern
  60. " This provides finer control over the recursion, which
  61. " is useful if calling the completion on really big files.
  62. " default: '.*'
  63. "
  64. " g:qcc_format_word
  65. " Format string to be used when building the word field
  66. " of the completion (i.e.: the final result, what gets fed into
  67. " the current line when you select an option)
  68. " default: '${1} <${0}>' (as in: FirstName <email@domain.com>)
  69. "
  70. " g:qcc_format_abbr
  71. " Format string to be used when building the abbreviation
  72. " for the completion menu (i.e.: the first row in the completion
  73. " menu).
  74. " default: '${1}'
  75. "
  76. " g:qcc_format_menu
  77. " Format string for the optional second column of the completion
  78. " menu.
  79. " default: '${2}'
  80. "
  81. if exists("g:loaded_QueryCommandComplete") || &cp
  82. finish
  83. endif
  84. function! s:GetSetting(name)
  85. let global_option = 'g:qcc_' . a:name
  86. let local_option = 'b:qcc_' . a:name
  87. let result = ''
  88. if exists(local_option)
  89. let result = {local_option}
  90. elseif exists(global_option)
  91. let result = {global_option}
  92. endif
  93. return result
  94. endfunction
  95. let g:loaded_QueryCommandComplete = 1
  96. let s:save_cpo = &cpo
  97. set cpo&vim
  98. function! s:DefaultIfUnset(name, default)
  99. if !exists(a:name)
  100. let {a:name} = a:default
  101. endif
  102. endfunction
  103. call s:DefaultIfUnset('g:qcc_line_separator', '\n')
  104. call s:DefaultIfUnset('g:qcc_field_separator', '\t')
  105. call s:DefaultIfUnset('g:qcc_pattern', '^\(To\|Cc\|Bcc\|From\|Reply-To\):')
  106. call s:DefaultIfUnset('g:qcc_multiline', 0)
  107. call s:DefaultIfUnset('g:qcc_multiline_pattern', '.*')
  108. call s:DefaultIfUnset('g:qcc_format_word', '${1} <${0}>')
  109. call s:DefaultIfUnset('g:qcc_format_abbr', '${1}')
  110. call s:DefaultIfUnset('g:qcc_format_menu', '${2}')
  111. " Given a format string where the placeholders are in the format
  112. " '${index}' and index is a valid index the the given 'fields'
  113. " argument, this function returns a string with all placeholders
  114. " replaced by the corresponding data in the fields list.
  115. " FIXME I can't help but think there's a standard way to do this
  116. " but I failed finding it. Please call me a dumbass if you
  117. " know The Easy Way.
  118. function! s:ApplyFieldsToFormatString(fields, format)
  119. let result = a:format
  120. while 1
  121. let placeholder = matchstr(result, '${[0-9]}')
  122. if (empty(placeholder))
  123. break
  124. endif
  125. let index = matchstr(placeholder, '[0-9]')
  126. " If ${NUMBER} is not a valid index in a:fields,
  127. " use '' as a fallback.
  128. " FIXME Decide whether to warn/err/whatever here
  129. let content = ''
  130. if (len(a:fields) > index)
  131. let content = a:fields[index]
  132. endif
  133. let result = substitute(result, placeholder, content, 'g')
  134. endwhile
  135. return result
  136. endfunction
  137. function! s:MakeCompletionEntry(fields)
  138. let entry = {}
  139. let entry.word = s:ApplyFieldsToFormatString(a:fields, s:GetSetting('format_word'))
  140. let entry.abbr = s:ApplyFieldsToFormatString(a:fields, s:GetSetting('format_abbr'))
  141. let entry.menu = s:ApplyFieldsToFormatString(a:fields, s:GetSetting('format_menu'))
  142. let entry.icase = 1
  143. return entry
  144. endfunction
  145. function! s:FindStartingIndex()
  146. let cur_line = getline('.')
  147. " locate the start of the word
  148. let start = col('.') - 1
  149. while start > 0 && cur_line[start - 1] =~ '[^:,]'
  150. let start -= 1
  151. endwhile
  152. " lstrip()
  153. while cur_line[start] =~ '[ ]'
  154. let start += 1
  155. endwhile
  156. return start
  157. endfunction
  158. function! s:GenerateCompletions(findstart, base)
  159. if a:findstart
  160. return s:FindStartingIndex()
  161. endif
  162. let results = []
  163. let cmd = s:GetSetting('query_command')
  164. if cmd !~ '%s'
  165. let cmd .= ' %s'
  166. endif
  167. let cmd = substitute(cmd, '%s', shellescape(a:base), '')
  168. let lines = split(system(cmd), g:qcc_line_separator)
  169. for my_line in lines
  170. let fields = split(my_line, g:qcc_field_separator)
  171. let entry = s:MakeCompletionEntry(fields)
  172. call add(results, entry)
  173. endfor
  174. return results
  175. endfunction
  176. function! s:ShouldGenerateCompletions(line_number)
  177. let current_line = getline(a:line_number)
  178. if current_line =~ g:qcc_pattern
  179. return 1
  180. endif
  181. if ! g:qcc_multiline || a:line_number <= 1 || current_line !~ g:qcc_multiline_pattern
  182. return 0
  183. endif
  184. return s:ShouldGenerateCompletions(a:line_number - 1)
  185. endfunction
  186. function! s:CheckSettings()
  187. " Try to use mutt's query_command by default if nothing is set
  188. if empty(s:GetSetting('query_command'))
  189. let s:querycmd = system('mutt -Q query_command 2>/dev/null')
  190. let s:querycmd = substitute(s:querycmd, '^query_command="\(.*\)"\n', '\1','')
  191. if len(s:querycmd)
  192. let g:qcc_query_command = s:querycmd
  193. let g:qcc_multiline = 1
  194. autocmd FileType mail setlocal omnifunc=QueryCommandComplete
  195. else
  196. echoerr "QueryCommandComplete: g:qcc_query_command not set!"
  197. return 0
  198. endif
  199. endif
  200. return 1
  201. endfunction
  202. function! QueryCommandComplete(findstart, base)
  203. if s:CheckSettings() && s:ShouldGenerateCompletions(line('.'))
  204. return s:GenerateCompletions(a:findstart, a:base)
  205. endif
  206. endfunction
  207. let &cpo = s:save_cpo