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