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