comparison runtime/autoload/sqlcomplete.vim @ 818:1f929f3ca806 v7.0c03

updated for version 7.0c03
author vimboss
date Wed, 29 Mar 2006 21:18:24 +0000
parents
children 23f82b5d2814
comparison
equal deleted inserted replaced
817:6897668c467f 818:1f929f3ca806
1 " Vim completion script
2 " Language: SQL
3 " Maintainer: David Fishburn <fishburn@ianywhere.com>
4 " Version: 1.0
5 " Last Change: Tue Mar 28 2006 4:39:49 PM
6
7 " Set completion with CTRL-X CTRL-O to autoloaded function.
8 " This check is in place in case this script is
9 " sourced directly instead of using the autoload feature.
10 if exists('&omnifunc')
11 " Do not set the option if already set since this
12 " results in an E117 warning.
13 if &omnifunc == ""
14 setlocal omnifunc=sqlcomplete#Complete
15 endif
16 endif
17
18 if exists('g:loaded_sql_completion')
19 finish
20 endif
21 let g:loaded_sql_completion = 1
22
23 " Maintains filename of dictionary
24 let s:sql_file_table = ""
25 let s:sql_file_procedure = ""
26 let s:sql_file_view = ""
27
28 " Define various arrays to be used for caching
29 let s:tbl_name = []
30 let s:tbl_alias = []
31 let s:tbl_cols = []
32 let s:syn_list = []
33 let s:syn_value = []
34
35 " Used in conjunction with the syntaxcomplete plugin
36 let s:save_inc = ""
37 let s:save_exc = ""
38 if exists('g:omni_syntax_group_include_sql')
39 let s:save_inc = g:omni_syntax_group_include_sql
40 endif
41 if exists('g:omni_syntax_group_exclude_sql')
42 let s:save_exc = g:omni_syntax_group_exclude_sql
43 endif
44
45 " Used with the column list
46 let s:save_prev_table = ""
47
48 " Default the option to verify table alias
49 if !exists('g:omni_sql_use_tbl_alias')
50 let g:omni_sql_use_tbl_alias = 'a'
51 endif
52
53 " This function is used for the 'omnifunc' option.
54 function! sqlcomplete#Complete(findstart, base)
55
56 " Default to table name completion
57 let compl_type = 'table'
58 " Allow maps to specify what type of object completion they want
59 if exists('b:sql_compl_type')
60 let compl_type = b:sql_compl_type
61 endif
62
63 if a:findstart
64 " Locate the start of the item, including "."
65 let line = getline('.')
66 let start = col('.') - 1
67 let lastword = -1
68 while start > 0
69 if line[start - 1] =~ '\w'
70 let start -= 1
71 elseif line[start - 1] =~ '\.' && compl_type =~ 'column\|table'
72 " If the completion type is table or column
73 " Then assume we are looking for column completion
74 " column_type can be either 'column' or 'column_csv'
75 if lastword == -1
76 let lastword = start
77 endif
78 let start -= 1
79 let b:sql_compl_type = 'column'
80 else
81 break
82 endif
83 endwhile
84
85 " Return the column of the last word, which is going to be changed.
86 " Remember the text that comes before it in s:prepended.
87 if lastword == -1
88 let s:prepended = ''
89 return start
90 endif
91 let s:prepended = strpart(line, start, lastword - start)
92 return lastword
93 endif
94
95 let base = s:prepended . a:base
96
97 let compl_list = []
98
99 " Default to table name completion
100 let compl_type = 'table'
101 " Allow maps to specify what type of object completion they want
102 if exists('b:sql_compl_type')
103 let compl_type = b:sql_compl_type
104 unlet b:sql_compl_type
105 endif
106
107 if compl_type == 'tableReset'
108 let compl_type = 'table'
109 let base = ''
110 endif
111
112 if compl_type == 'table' ||
113 \ compl_type == 'procedure' ||
114 \ compl_type == 'view'
115
116 " This type of completion relies upon the dbext.vim plugin
117 if s:SQLCCheck4dbext() == -1
118 return []
119 endif
120
121 if s:sql_file_{compl_type} == ""
122 let compl_type = substitute(compl_type, '\w\+', '\u&', '')
123 let s:sql_file_{compl_type} = DB_getDictionaryName(compl_type)
124 endif
125 let s:sql_file_{compl_type} = DB_getDictionaryName(compl_type)
126 if s:sql_file_{compl_type} != ""
127 if filereadable(s:sql_file_{compl_type})
128 let compl_list = readfile(s:sql_file_{compl_type})
129 endif
130 endif
131 elseif compl_type == 'column'
132
133 " This type of completion relies upon the dbext.vim plugin
134 if s:SQLCCheck4dbext() == -1
135 return []
136 endif
137
138 if base == ""
139 " The last time we displayed a column list we stored
140 " the table name. If the user selects a column list
141 " without a table name of alias present, assume they want
142 " the previous column list displayed.
143 let base = s:save_prev_table
144 endif
145
146 if base != ""
147 let compl_list = s:SQLCGetColumns(base, '')
148 let s:save_prev_table = base
149 let base = ''
150 endif
151 elseif compl_type == 'column_csv'
152
153 " This type of completion relies upon the dbext.vim plugin
154 if s:SQLCCheck4dbext() == -1
155 return []
156 endif
157
158 if base == ""
159 " The last time we displayed a column list we stored
160 " the table name. If the user selects a column list
161 " without a table name of alias present, assume they want
162 " the previous column list displayed.
163 let base = s:save_prev_table
164 endif
165
166 if base != ""
167 let compl_list = s:SQLCGetColumns(base, 'csv')
168 let s:save_prev_table = base
169 " Join the column array into 1 single element array
170 " but make the columns column separated
171 let compl_list = [join(compl_list, ', ')]
172 let base = ''
173 endif
174 elseif compl_type == 'resetCache'
175 " Reset all cached items
176 let s:tbl_name = []
177 let s:tbl_alias = []
178 let s:tbl_cols = []
179 let s:syn_list = []
180 let s:syn_value = []
181 return []
182 else
183 " Default to empty or not found
184 let compl_list = []
185 " Check if we have already cached the syntax list
186 let list_idx = index(s:syn_list, compl_type, 0, &ignorecase)
187 if list_idx > -1
188 " Return previously cached value
189 let compl_list = s:syn_value[list_idx]
190 else
191 " Request the syntax list items from the
192 " syntax completion plugin
193 if compl_type == 'syntax'
194 " Handle this special case. This allows the user
195 " to indicate they want all the syntax items available,
196 " so do not specify a specific include list.
197 let g:omni_syntax_group_include_sql = ''
198 else
199 " The user has specified a specific syntax group
200 let g:omni_syntax_group_include_sql = compl_type
201 endif
202 let g:omni_syntax_group_exclude_sql = ''
203 let syn_value = OmniSyntaxList()
204 let g:omni_syntax_group_include_sql = s:save_inc
205 let g:omni_syntax_group_exclude_sql = s:save_exc
206 " Cache these values for later use
207 let s:syn_list = add( s:syn_list, compl_type )
208 let s:syn_value = add( s:syn_value, syn_value )
209 let compl_list = syn_value
210 endif
211 endif
212
213 if base != ''
214 " Filter the list based on the first few characters the user
215 " entered
216 let expr = 'v:val =~ "^'.base.'"'
217 let compl_list = filter(copy(compl_list), expr)
218 endif
219
220 return compl_list
221 endfunc
222
223 function! s:SQLCWarningMsg(msg)
224 echohl WarningMsg
225 echomsg a:msg
226 echohl None
227 endfunction
228
229 function! s:SQLCErrorMsg(msg)
230 echohl ErrorMsg
231 echomsg a:msg
232 echohl None
233 endfunction
234
235 function! s:SQLCCheck4dbext()
236 if !exists('g:loaded_dbext')
237 let msg = "The dbext plugin must be loaded for dynamic SQL completion"
238 call s:SQLCErrorMsg(msg)
239 " Leave time for the user to read the error message
240 :sleep 2
241 return -1
242 elseif g:loaded_dbext < 210
243 let msg = "The dbext plugin must be at least version 2.10 " .
244 \ " for dynamic SQL completion"
245 call s:SQLCErrorMsg(msg)
246 " Leave time for the user to read the error message
247 :sleep 2
248 return -1
249 endif
250 return 1
251 endfunction
252
253 function! s:SQLCAddAlias(table_name, table_alias, cols)
254 let table_name = a:table_name
255 let table_alias = a:table_alias
256 let cols = a:cols
257
258 if g:omni_sql_use_tbl_alias != 'n'
259 if table_alias == ''
260 if 'da' =~? g:omni_sql_use_tbl_alias
261 if table_name =~ '_'
262 " Treat _ as separators since people often use these
263 " for word separators
264 let save_keyword = &iskeyword
265 setlocal iskeyword-=_
266
267 " Get the first letter of each word
268 " [[:alpha:]] is used instead of \w
269 " to catch extended accented characters
270 "
271 let table_alias = substitute(
272 \ table_name,
273 \ '\<[[:alpha:]]\+\>_\?',
274 \ '\=strpart(submatch(0), 0, 1)',
275 \ 'g'
276 \ )
277 " Restore original value
278 let &iskeyword = save_keyword
279 elseif table_name =~ '\u\U'
280 let initials = substitute(
281 \ table_name, '\(\u\)\U*', '\1', 'g')
282 else
283 let table_alias = strpart(table_name, 0, 1)
284 endif
285 endif
286 endif
287 if table_alias != ''
288 " Following a word character, make sure there is a . and no spaces
289 let table_alias = substitute(table_alias, '\w\zs\.\?\s*$', '.', '')
290 if 'a' =~? g:omni_sql_use_tbl_alias && a:table_alias == ''
291 let table_alias = inputdialog("Enter table alias:", table_alias)
292 endif
293 endif
294 if table_alias != ''
295 let cols = substitute(cols, '\<\w', table_alias.'&', 'g')
296 endif
297 endif
298
299 return cols
300 endfunction
301
302 function! s:SQLCGetColumns(table_name, list_type)
303 let table_name = matchstr(a:table_name, '^\w\+')
304 let table_cols = []
305 let table_alias = ''
306 let move_to_top = 1
307
308 if g:loaded_dbext >= 210
309 let saveSettingAlias = DB_listOption('use_tbl_alias')
310 exec 'DBSetOption use_tbl_alias=n'
311 endif
312
313 " Check if we have already cached the column list for this table
314 " by its name
315 let list_idx = index(s:tbl_name, table_name, 0, &ignorecase)
316 if list_idx > -1
317 let table_cols = split(s:tbl_cols[list_idx])
318 else
319 " Check if we have already cached the column list for this table
320 " by its alias, assuming the table_name provided was actually
321 " the alias for the table instead
322 " select *
323 " from area a
324 " where a.
325 let list_idx = index(s:tbl_alias, table_name, 0, &ignorecase)
326 if list_idx > -1
327 let table_alias = table_name
328 let table_name = s:tbl_name[list_idx]
329 let table_cols = split(s:tbl_cols[list_idx])
330 endif
331 endif
332
333 " If we have not found a cached copy of the table
334 " And the table ends in a "." or we are looking for a column list
335 " if list_idx == -1 && (a:table_name =~ '\.' || b:sql_compl_type =~ 'column')
336 " if list_idx == -1 && (a:table_name =~ '\.' || a:list_type =~ 'csv')
337 if list_idx == -1
338 let saveY = @y
339 let saveSearch = @/
340 let saveWScan = &wrapscan
341 let curline = line(".")
342 let curcol = col(".")
343
344 " Do not let searchs wrap
345 setlocal nowrapscan
346 " If . was entered, look at the word just before the .
347 " We are looking for something like this:
348 " select *
349 " from customer c
350 " where c.
351 " So when . is pressed, we need to find 'c'
352 "
353
354 " Search backwards to the beginning of the statement
355 " and do NOT wrap
356 " exec 'silent! normal! v?\<\(select\|update\|delete\|;\)\>'."\n".'"yy'
357 exec 'silent! normal! ?\<\(select\|update\|delete\|;\)\>'."\n"
358
359 " Start characterwise visual mode
360 " Advance right one character
361 " Search foward until one of the following:
362 " 1. Another select/update/delete statement
363 " 2. A ; at the end of a line (the delimiter)
364 " 3. The end of the file (incase no delimiter)
365 " Yank the visually selected text into the "y register.
366 exec 'silent! normal! vl/\(\<select\>\|\<update\>\|\<delete\>\|;\s*$\|\%$\)'."\n".'"yy'
367
368 let query = @y
369 let query = substitute(query, "\n", ' ', 'g')
370 let found = 0
371
372 " if query =~? '^\(select\|update\|delete\)'
373 if query =~? '^\(select\)'
374 let found = 1
375 " \(\(\<\w\+\>\)\.\)\? -
376 " 'from.\{-}' - Starting at the from clause
377 " '\zs\(\(\<\w\+\>\)\.\)\?' - Get the owner name (optional)
378 " '\<\w\+\>\ze' - Get the table name
379 " '\s\+\<'.table_name.'\>' - Followed by the alias
380 " '\s*\.\@!.*' - Cannot be followed by a .
381 " '\(\<where\>\|$\)' - Must be followed by a WHERE clause
382 " '.*' - Exclude the rest of the line in the match
383 let table_name_new = matchstr(@y,
384 \ 'from.\{-}'.
385 \ '\zs\(\(\<\w\+\>\)\.\)\?'.
386 \ '\<\w\+\>\ze'.
387 \ '\s\+\%(as\s\+\)\?\<'.table_name.'\>'.
388 \ '\s*\.\@!.*'.
389 \ '\(\<where\>\|$\)'.
390 \ '.*'
391 \ )
392 if table_name_new != ''
393 let table_alias = table_name
394 let table_name = table_name_new
395
396 let list_idx = index(s:tbl_name, table_name, 0, &ignorecase)
397 if list_idx > -1
398 let table_cols = split(s:tbl_cols[list_idx])
399 let s:tbl_name[list_idx] = table_name
400 let s:tbl_alias[list_idx] = table_alias
401 else
402 let list_idx = index(s:tbl_alias, table_name, 0, &ignorecase)
403 if list_idx > -1
404 let table_cols = split(s:tbl_cols[list_idx])
405 let s:tbl_name[list_idx] = table_name
406 let s:tbl_alias[list_idx] = table_alias
407 endif
408 endif
409
410 endif
411 else
412 " Simply assume it is a table name provided with a . on the end
413 let found = 1
414 endif
415
416 let @y = saveY
417 let @/ = saveSearch
418 let &wrapscan = saveWScan
419
420 " Return to previous location
421 call cursor(curline, curcol)
422
423 if found == 0
424 if g:loaded_dbext > 201
425 exec 'DBSetOption use_tbl_alias='.saveSettingAlias
426 endif
427
428 " Not a SQL statement, do not display a list
429 return []
430 endif
431 endif
432
433 if empty(table_cols)
434 " Specify silent mode, no messages to the user (tbl, 1)
435 " Specify do not comma separate (tbl, 1, 1)
436 let table_cols_str = DB_getListColumn(table_name, 1, 1)
437
438 if table_cols_str != ""
439 let s:tbl_name = add( s:tbl_name, table_name )
440 let s:tbl_alias = add( s:tbl_alias, table_alias )
441 let s:tbl_cols = add( s:tbl_cols, table_cols_str )
442 let table_cols = split(table_cols_str)
443 endif
444
445 endif
446
447 if g:loaded_dbext > 201
448 exec 'DBSetOption use_tbl_alias='.saveSettingAlias
449 endif
450
451 if a:list_type == 'csv' && !empty(table_cols)
452 let cols = join(table_cols, ', ')
453 let cols = s:SQLCAddAlias(table_name, table_alias, cols)
454 let table_cols = [cols]
455 endif
456
457 return table_cols
458 endfunction
459