blob: 9f40b019af5da1970a34336a9db61ba51aa065cf [file] [log] [blame]
Abaakouk Mehdi5fb87e72010-07-21 12:51:38 +02001" SQL filetype plugin file
2" Language: SQL (Common for Oracle, Microsoft SQL Server, Sybase)
3" Version: 4.0
4" Maintainer: David Fishburn <fishburn at ianywhere dot com>
5" Last Change: Wed 27 Feb 2008 04:35:21 PM Eastern Standard Time
6" Download: http://vim.sourceforge.net/script.php?script_id=454
7
8" For more details please use:
9" :h sql.txt
10"
11" This file should only contain values that are common to all SQL languages
12" Oracle, Microsoft SQL Server, Sybase ASA/ASE, MySQL, and so on
13" If additional features are required create:
14" vimfiles/after/ftplugin/sql.vim (Windows)
15" .vim/after/ftplugin/sql.vim (Unix)
16" to override and add any of your own settings.
17
18
19" This file also creates a command, SQLSetType, which allows you to change
20" SQL dialects on the fly. For example, if I open an Oracle SQL file, it
21" is color highlighted appropriately. If I open an Informix SQL file, it
22" will still be highlighted according to Oracles settings. By running:
23" :SQLSetType sqlinformix
24"
25" All files called sqlinformix.vim will be loaded from the indent and syntax
26" directories. This allows you to easily flip SQL dialects on a per file
27" basis. NOTE: you can also use completion:
28" :SQLSetType <tab>
29"
30" To change the default dialect, add the following to your vimrc:
31" let g:sql_type_default = 'sqlanywhere'
32
33
34" Only do this when not done yet for this buffer
35if exists("b:did_ftplugin")
36 finish
37endif
38
39let s:save_cpo = &cpo
40set cpo=
41
42" Disable autowrapping for code, but enable for comments
43" t Auto-wrap text using textwidth
44" c Auto-wrap comments using textwidth, inserting the current comment
45" leader automatically.
46setlocal formatoptions-=t
47setlocal formatoptions-=c
48
49" Functions/Commands to allow the user to change SQL syntax dialects
50" through the use of :SQLSetType <tab> for completion.
51" This works with both Vim 6 and 7.
52
53if !exists("*SQL_SetType")
54 " NOTE: You cannot use function! since this file can be
55 " sourced from within this function. That will result in
56 " an error reported by Vim.
57 function SQL_GetList(ArgLead, CmdLine, CursorPos)
58
59 if !exists('s:sql_list')
60 " Grab a list of files that contain "sql" in their names
61 let list_indent = globpath(&runtimepath, 'indent/*sql*')
62 let list_syntax = globpath(&runtimepath, 'syntax/*sql*')
63 let list_ftplugin = globpath(&runtimepath, 'ftplugin/*sql*')
64
65 let sqls = "\n".list_indent."\n".list_syntax."\n".list_ftplugin."\n"
66
67 " Strip out everything (path info) but the filename
68 " Regex
69 " From between two newline characters
70 " Non-greedily grab all characters
71 " Followed by a valid filename \w\+\.\w\+ (sql.vim)
72 " Followed by a newline, but do not include the newline
73 "
74 " Replace it with just the filename (get rid of PATH)
75 "
76 " Recursively, since there are many filenames that contain
77 " the word SQL in the indent, syntax and ftplugin directory
78 let sqls = substitute( sqls,
79 \ '[\n]\%(.\{-}\)\(\w\+\.\w\+\)\n\@=',
80 \ '\1\n',
81 \ 'g'
82 \ )
83
84 " Remove duplicates, since sqlanywhere.vim can exist in the
85 " sytax, indent and ftplugin directory, yet we only want
86 " to display the option once
87 let index = match(sqls, '.\{-}\ze\n')
88 while index > -1
89 " Get the first filename
90 let file = matchstr(sqls, '.\{-}\ze\n', index)
91 " Recursively replace any *other* occurrence of that
92 " filename with nothing (ie remove it)
93 let sqls = substitute(sqls, '\%>'.(index+strlen(file)).'c\<'.file.'\>\n', '', 'g')
94 " Move on to the next filename
95 let index = match(sqls, '.\{-}\ze\n', (index+strlen(file)+1))
96 endwhile
97
98 " Sort the list if using version 7
99 if v:version >= 700
100 let mylist = split(sqls, "\n")
101 let mylist = sort(mylist)
102 let sqls = join(mylist, "\n")
103 endif
104
105 let s:sql_list = sqls
106 endif
107
108 return s:sql_list
109
110 endfunction
111
112 function SQL_SetType(name)
113
114 " User has decided to override default SQL scripts and
115 " specify a vendor specific version
116 " (ie Oracle, Informix, SQL Anywhere, ...)
117 " So check for an remove any settings that prevent the
118 " scripts from being executed, and then source the
119 " appropriate Vim scripts.
120 if exists("b:did_ftplugin")
121 unlet b:did_ftplugin
122 endif
123 if exists("b:current_syntax")
124 " echomsg 'SQLSetType - clearing syntax'
125 syntax clear
126 endif
127 if exists("b:did_indent")
128 " echomsg 'SQLSetType - clearing indent'
129 unlet b:did_indent
130 " Set these values to their defaults
131 setlocal indentkeys&
132 setlocal indentexpr&
133 endif
134
135 " Ensure the name is in the correct format
136 let new_sql_type = substitute(a:name,
137 \ '\s*\([^\.]\+\)\(\.\w\+\)\?', '\L\1', '')
138
139 " Do not specify a buffer local variable if it is
140 " the default value
141 if new_sql_type == 'sql'
142 let new_sql_type = 'sqloracle'
143 endif
144 let b:sql_type_override = new_sql_type
145
146 " Vim will automatically source the correct files if we
147 " change the filetype. You cannot do this with setfiletype
148 " since that command will only execute if a filetype has
149 " not already been set. In this case we want to override
150 " the existing filetype.
151 let &filetype = 'sql'
152 endfunction
153 command! -nargs=* -complete=custom,SQL_GetList SQLSetType :call SQL_SetType(<q-args>)
154
155endif
156
157if exists("b:sql_type_override")
158 " echo 'sourcing buffer ftplugin/'.b:sql_type_override.'.vim'
159 if globpath(&runtimepath, 'ftplugin/'.b:sql_type_override.'.vim') != ''
160 exec 'runtime ftplugin/'.b:sql_type_override.'.vim'
161 " else
162 " echomsg 'ftplugin/'.b:sql_type_override.' not exist, using default'
163 endif
164elseif exists("g:sql_type_default")
165 " echo 'sourcing global ftplugin/'.g:sql_type_default.'.vim'
166 if globpath(&runtimepath, 'ftplugin/'.g:sql_type_default.'.vim') != ''
167 exec 'runtime ftplugin/'.g:sql_type_default.'.vim'
168 " else
169 " echomsg 'ftplugin/'.g:sql_type_default.'.vim not exist, using default'
170 endif
171endif
172
173" If the above runtime command succeeded, do not load the default settings
174if exists("b:did_ftplugin")
175 finish
176endif
177
178let b:undo_ftplugin = "setl comments<"
179
180" Don't load another plugin for this buffer
181let b:did_ftplugin = 1
182let b:current_ftplugin = 'sql'
183
184" Win32 can filter files in the browse dialog
185if has("gui_win32") && !exists("b:browsefilter")
186 let b:browsefilter = "SQL Files (*.sql)\t*.sql\n" .
187 \ "All Files (*.*)\t*.*\n"
188endif
189
190" Some standard expressions for use with the matchit strings
191let s:notend = '\%(\<end\s\+\)\@<!'
192let s:when_no_matched_or_others = '\%(\<when\>\%(\s\+\%(\%(\<not\>\s\+\)\?<matched\>\)\|\<others\>\)\@!\)'
193let s:or_replace = '\%(or\s\+replace\s\+\)\?'
194
195" Define patterns for the matchit macro
196if !exists("b:match_words")
197 " SQL is generally case insensitive
198 let b:match_ignorecase = 1
199
200 " Handle the following:
201 " if
202 " elseif | elsif
203 " else [if]
204 " end if
205 "
206 " [while condition] loop
207 " leave
208 " break
209 " continue
210 " exit
211 " end loop
212 "
213 " for
214 " leave
215 " break
216 " continue
217 " exit
218 " end loop
219 "
220 " do
221 " statements
222 " doend
223 "
224 " case
225 " when
226 " when
227 " default
228 " end case
229 "
230 " merge
231 " when not matched
232 " when matched
233 "
234 " EXCEPTION
235 " WHEN column_not_found THEN
236 " WHEN OTHERS THEN
237 "
238 " create[ or replace] procedure|function|event
239
240 let b:match_words =
241 \ '\<begin\>:\<end\>\W*$,'.
242 \
243 \ s:notend . '\<if\>:'.
244 \ '\<elsif\>\|\<elseif\>\|\<else\>:'.
245 \ '\<end\s\+if\>,'.
246 \
247 \ '\<do\>\|'.
248 \ '\<while\>\|'.
249 \ '\%(' . s:notend . '\<loop\>\)\|'.
250 \ '\%(' . s:notend . '\<for\>\):'.
251 \ '\<exit\>\|\<leave\>\|\<break\>\|\<continue\>:'.
252 \ '\%(\<end\s\+\%(for\|loop\>\)\)\|\<doend\>,'.
253 \
254 \ '\%('. s:notend . '\<case\>\):'.
255 \ '\%('.s:when_no_matched_or_others.'\):'.
256 \ '\%(\<when\s\+others\>\|\<end\s\+case\>\),' .
257 \
258 \ '\<merge\>:' .
259 \ '\<when\s\+not\s\+matched\>:' .
260 \ '\<when\s\+matched\>,' .
261 \
262 \ '\%(\<create\s\+' . s:or_replace . '\)\?'.
263 \ '\%(function\|procedure\|event\):'.
264 \ '\<returns\?\>'
265 " \ '\<begin\>\|\<returns\?\>:'.
266 " \ '\<end\>\(;\)\?\s*$'
267 " \ '\<exception\>:'.s:when_no_matched_or_others.
268 " \ ':\<when\s\+others\>,'.
269 "
270 " \ '\%(\<exception\>\|\%('. s:notend . '\<case\>\)\):'.
271 " \ '\%(\<default\>\|'.s:when_no_matched_or_others.'\):'.
272 " \ '\%(\%(\<when\s\+others\>\)\|\<end\s\+case\>\),' .
273endif
274
275" Define how to find the macro definition of a variable using the various
276" [d, [D, [_CTRL_D and so on features
277" Match these values ignoring case
278" ie DECLARE varname INTEGER
279let &l:define = '\c\<\(VARIABLE\|DECLARE\|IN\|OUT\|INOUT\)\>'
280
281
282" Mappings to move to the next BEGIN ... END block
283" \W - no characters or digits
284nmap <buffer> <silent> ]] :call search('\\c^\\s*begin\\>', 'W' )<CR>
285nmap <buffer> <silent> [[ :call search('\\c^\\s*begin\\>', 'bW' )<CR>
286nmap <buffer> <silent> ][ :call search('\\c^\\s*end\\W*$', 'W' )<CR>
287nmap <buffer> <silent> [] :call search('\\c^\\s*end\\W*$', 'bW' )<CR>
288vmap <buffer> <silent> ]] :<C-U>exec "normal! gv"<Bar>call search('\\c^\\s*begin\\>', 'W' )<CR>
289vmap <buffer> <silent> [[ :<C-U>exec "normal! gv"<Bar>call search('\\c^\\s*begin\\>', 'bW' )<CR>
290vmap <buffer> <silent> ][ :<C-U>exec "normal! gv"<Bar>call search('\\c^\\s*end\\W*$', 'W' )<CR>
291vmap <buffer> <silent> [] :<C-U>exec "normal! gv"<Bar>call search('\\c^\\s*end\\W*$', 'bW' )<CR>
292
293
294" By default only look for CREATE statements, but allow
295" the user to override
296if !exists('g:ftplugin_sql_statements')
297 let g:ftplugin_sql_statements = 'create'
298endif
299
300" Predefined SQL objects what are used by the below mappings using
301" the ]} style maps.
302" This global variable allows the users to override it's value
303" from within their vimrc.
304" Note, you cannot use \?, since these patterns can be used to search
305" backwards, you must use \{,1}
306if !exists('g:ftplugin_sql_objects')
307 let g:ftplugin_sql_objects = 'function,procedure,event,' .
308 \ '\\(existing\\\\|global\\s\\+temporary\\s\\+\\)\\\{,1}' .
309 \ 'table,trigger' .
310 \ ',schema,service,publication,database,datatype,domain' .
311 \ ',index,subscription,synchronization,view,variable'
312endif
313
314" Replace all ,'s with bars, except ones with numbers after them.
315" This will most likely be a \{,1} string.
316let s:ftplugin_sql_objects =
317 \ '\\c^\\s*' .
318 \ '\\(\\(' .
319 \ substitute(g:ftplugin_sql_statements, ',\d\@!', '\\\\\\|', 'g') .
320 \ '\\)\\s\\+\\(or\\s\\+replace\\\s\+\\)\\{,1}\\)\\{,1}' .
321 \ '\\<\\(' .
322 \ substitute(g:ftplugin_sql_objects, ',\d\@!', '\\\\\\|', 'g') .
323 \ '\\)\\>'
324
325" Mappings to move to the next CREATE ... block
326exec "nmap <buffer> <silent> ]} :call search('".s:ftplugin_sql_objects."', 'W')<CR>"
327exec "nmap <buffer> <silent> [{ :call search('".s:ftplugin_sql_objects."', 'bW')<CR>"
328" Could not figure out how to use a :call search() string in visual mode
329" without it ending visual mode
330" Unfortunately, this will add a entry to the search history
331exec 'vmap <buffer> <silent> ]} /'.s:ftplugin_sql_objects.'<CR>'
332exec 'vmap <buffer> <silent> [{ ?'.s:ftplugin_sql_objects.'<CR>'
333
334" Mappings to move to the next COMMENT
335"
336" Had to double the \ for the \| separator since this has a special
337" meaning on maps
338let b:comment_leader = '\\(--\\\|\\/\\/\\\|\\*\\\|\\/\\*\\\|\\*\\/\\)'
339" Find the start of the next comment
340let b:comment_start = '^\\(\\s*'.b:comment_leader.'.*\\n\\)\\@<!'.
341 \ '\\(\\s*'.b:comment_leader.'\\)'
342" Find the end of the previous comment
343let b:comment_end = '\\(^\\s*'.b:comment_leader.'.*\\n\\)'.
344 \ '\\(^\\s*'.b:comment_leader.'\\)\\@!'
345" Skip over the comment
346let b:comment_jump_over = "call search('".
347 \ '^\\(\\s*'.b:comment_leader.'.*\\n\\)\\@<!'.
348 \ "', 'W')"
349let b:comment_skip_back = "call search('".
350 \ '^\\(\\s*'.b:comment_leader.'.*\\n\\)\\@<!'.
351 \ "', 'bW')"
352" Move to the start and end of comments
353exec 'nnoremap <silent><buffer> ]" :call search('."'".b:comment_start."'".', "W" )<CR>'
354exec 'nnoremap <silent><buffer> [" :call search('."'".b:comment_end."'".', "W" )<CR>'
355exec 'vnoremap <silent><buffer> ]" :<C-U>exec "normal! gv"<Bar>call search('."'".b:comment_start."'".', "W" )<CR>'
356exec 'vnoremap <silent><buffer> [" :<C-U>exec "normal! gv"<Bar>call search('."'".b:comment_end."'".', "W" )<CR>'
357
358" Comments can be of the form:
359" /*
360" *
361" */
362" or
363" --
364" or
365" //
366setlocal comments=s1:/*,mb:*,ex:*/,:--,://
367
368" Set completion with CTRL-X CTRL-O to autoloaded function.
369if exists('&omnifunc')
370 " Since the SQL completion plugin can be used in conjunction
371 " with other completion filetypes it must record the previous
372 " OMNI function prior to setting up the SQL OMNI function
373 let b:sql_compl_savefunc = &omnifunc
374
375 " This is used by the sqlcomplete.vim plugin
376 " Source it for it's global functions
377 runtime autoload/syntaxcomplete.vim
378
379 setlocal omnifunc=sqlcomplete#Complete
380 " Prevent the intellisense plugin from loading
381 let b:sql_vis = 1
382 if !exists('g:omni_sql_no_default_maps')
383 " Static maps which use populate the completion list
384 " using Vim's syntax highlighting rules
385 imap <buffer> <c-c>a <C-\><C-O>:call sqlcomplete#Map('syntax')<CR><C-X><C-O>
386 imap <buffer> <c-c>k <C-\><C-O>:call sqlcomplete#Map('sqlKeyword')<CR><C-X><C-O>
387 imap <buffer> <c-c>f <C-\><C-O>:call sqlcomplete#Map('sqlFunction')<CR><C-X><C-O>
388 imap <buffer> <c-c>o <C-\><C-O>:call sqlcomplete#Map('sqlOption')<CR><C-X><C-O>
389 imap <buffer> <c-c>T <C-\><C-O>:call sqlcomplete#Map('sqlType')<CR><C-X><C-O>
390 imap <buffer> <c-c>s <C-\><C-O>:call sqlcomplete#Map('sqlStatement')<CR><C-X><C-O>
391 " Dynamic maps which use populate the completion list
392 " using the dbext.vim plugin
393 imap <buffer> <c-c>t <C-\><C-O>:call sqlcomplete#Map('table')<CR><C-X><C-O>
394 imap <buffer> <c-c>p <C-\><C-O>:call sqlcomplete#Map('procedure')<CR><C-X><C-O>
395 imap <buffer> <c-c>v <C-\><C-O>:call sqlcomplete#Map('view')<CR><C-X><C-O>
396 imap <buffer> <c-c>c <C-\><C-O>:call sqlcomplete#Map('column')<CR><C-X><C-O>
397 imap <buffer> <c-c>l <C-\><C-O>:call sqlcomplete#Map('column_csv')<CR><C-X><C-O>
398 " The next 3 maps are only to be used while the completion window is
399 " active due to the <CR> at the beginning of the map
400 imap <buffer> <c-c>L <C-Y><C-\><C-O>:call sqlcomplete#Map('column_csv')<CR><C-X><C-O>
401 " <C-Right> is not recognized on most Unix systems, so only create
402 " these additional maps on the Windows platform.
403 " If you would like to use these maps, choose a different key and make
404 " the same map in your vimrc.
405 if has('win32')
406 imap <buffer> <c-right> <C-R>=sqlcomplete#DrillIntoTable()<CR>
407 imap <buffer> <c-left> <C-R>=sqlcomplete#DrillOutOfColumns()<CR>
408 endif
409 " Remove any cached items useful for schema changes
410 imap <buffer> <c-c>R <C-\><C-O>:call sqlcomplete#Map('resetCache')<CR><C-X><C-O>
411 endif
412
413 if b:sql_compl_savefunc != ""
414 " We are changing the filetype to SQL from some other filetype
415 " which had OMNI completion defined. We need to activate the
416 " SQL completion plugin in order to cache some of the syntax items
417 " while the syntax rules for SQL are active.
418 call sqlcomplete#PreCacheSyntax()
419 endif
420endif
421
422let &cpo = s:save_cpo
423
424" vim:sw=4:
425