diff options
author | Bram Moolenaar <Bram@vim.org> | 2006-03-09 22:27:48 +0000 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2006-03-09 22:27:48 +0000 |
commit | 0fd9289de3079583cd19c88425277b99b5a15253 (patch) | |
tree | 065beae578d42ca17b8e9f96807d3cc06fff8a85 | |
parent | a3227e2b15600b2303e3aac070803021e76ed6d5 (diff) |
updated for version 7.0219
-rw-r--r-- | runtime/autoload/README.txt | 12 | ||||
-rw-r--r-- | runtime/autoload/paste.vim | 39 | ||||
-rw-r--r-- | runtime/doc/Makefile | 2 | ||||
-rw-r--r-- | runtime/doc/netbeans.txt | 22 | ||||
-rw-r--r-- | runtime/ftplugin/sql.vim | 248 | ||||
-rw-r--r-- | runtime/indent/sql.vim | 39 | ||||
-rw-r--r-- | runtime/indent/sqlanywhere.vim | 384 | ||||
-rw-r--r-- | runtime/macmap.vim | 83 | ||||
-rw-r--r-- | runtime/plugin/netrwPlugin.vim | 5 | ||||
-rw-r--r-- | src/netbeans.c | 163 | ||||
-rw-r--r-- | src/normal.c | 2 | ||||
-rw-r--r-- | src/os_mac.h | 114 | ||||
-rw-r--r-- | src/spell.c | 1 | ||||
-rw-r--r-- | src/vim.h | 6 |
14 files changed, 885 insertions, 235 deletions
diff --git a/runtime/autoload/README.txt b/runtime/autoload/README.txt index 2038fa224e..dcefbf033d 100644 --- a/runtime/autoload/README.txt +++ b/runtime/autoload/README.txt @@ -4,12 +4,18 @@ These are functions used by plugins and for general use. They will be loaded automatically when the function is invoked. See ":help autoload". gzip.vim for editing compressed files -netrw.vim browsing (remote) directories and editing remote files +netrw*.vim browsing (remote) directories and editing remote files tar.vim browsing tar files zip.vim browsing zip files +paste.vim common code for mswin.vim, menu.vim and macmap.vim +spellfile.vim downloading of a missing spell file -Occult completion files: +Omni completion files: ccomplete.vim C csscomplete.vim HTML / CSS htmlcomplete.vim HTML - +javascriptcomplete.vim Javascript +phpcomplete.vim PHP +pycomplete.vim Python +syntaxcomplete.vim from syntax highlighting +xmlcomplete.vim XML (uses files in the xml directory) diff --git a/runtime/autoload/paste.vim b/runtime/autoload/paste.vim new file mode 100644 index 0000000000..435c5e6235 --- /dev/null +++ b/runtime/autoload/paste.vim @@ -0,0 +1,39 @@ +" Vim support file to help with paste mappings and menus +" Maintainer: Bram Moolenaar <Bram@vim.org> +" Last Change: 2006 Mar 09 + +" Define the string to use for items that are present both in Edit, Popup and +" Toolbar menu. Also used in mswin.vim and macmap.vim. + +" Pasting blockwise and linewise selections is not possible in Insert and +" Visual mode without the +virtualedit feature. They are pasted as if they +" were characterwise instead. Add to that some tricks to leave the cursor in +" the right position, also for "gi". +if has("virtualedit") + let paste#paste_cmd = {'n': ":call paste#Paste()<CR>"} + let paste#paste_cmd['v'] = '"-c<Esc>' . paste#paste_cmd['n'] + let paste#paste_cmd['i'] = '<Esc>' . paste#paste_cmd['n'] . 'gi' + + func! paste#Paste() + let ove = &ve + set ve=all + normal! `^ + if @+ != '' + normal! "+gP + endif + let c = col(".") + normal! i + if col(".") < c " compensate for i<ESC> moving the cursor left + normal! l + endif + let &ve = ove + endfunc +else + let paste#paste_cmd = {'n': "\"=@+.'xy'<CR>gPFx\"_2x"} + let paste#paste_cmd['v'] = '"-c<Esc>gix<Esc>' . paste#paste_cmd['n'] . '"_x' + let paste#paste_cmd['i'] = 'x<Esc>' . paste#paste_cmd['n'] . '"_s' +endif + +if has("virtualedit") +else +endif diff --git a/runtime/doc/Makefile b/runtime/doc/Makefile index 70cb7a8a11..9ebce3c7e1 100644 --- a/runtime/doc/Makefile +++ b/runtime/doc/Makefile @@ -89,6 +89,7 @@ DOCS = \ sponsor.txt \ starting.txt \ spell.txt \ + sql.txt \ syntax.txt \ tabpage.txt \ tagsrch.txt \ @@ -213,6 +214,7 @@ HTMLS = \ sponsor.html \ starting.html \ spell.html \ + sql.html \ syntax.html \ tabpage.html \ tagsrch.html \ diff --git a/runtime/doc/netbeans.txt b/runtime/doc/netbeans.txt index 71f8f8e170..9d851cce29 100644 --- a/runtime/doc/netbeans.txt +++ b/runtime/doc/netbeans.txt @@ -1,4 +1,4 @@ -*netbeans.txt* For Vim version 7.0aa. Last change: 2006 Feb 05 +*netbeans.txt* For Vim version 7.0aa. Last change: 2006 Mar 09 VIM REFERENCE MANUAL by Gordon Prieur @@ -259,10 +259,19 @@ problems and has been fixed in 2.2. To decrease the likelihood of this confusion happening again, netbeans_saved() has been renamed to netbeans_save_buffer(). +We are now at version 2.3. For the differences between 2.2 and 2.3 search for +"2.3" below. + The messages are currently sent over a socket. Since the messages are in plain UTF-8 text this protocol could also be used with any other communication mechanism. +To see an example implementation look at the gvim tool in Agide. Currently +found here: + http://cvs.sf.net/viewcvs.py/a-a-p/Agide/Tools/GvimTool.py?view=markup + + + 10.1 Kinds of messages |nb-messages| 10.2 Terms |nb-terms| 10.3 Commands |nb-commands| @@ -612,11 +621,22 @@ getText Return the contents of the buffer as a string. insert off text Insert "text" before position "off". "text" is a string argument, "off" a number. + "off" should have a "\n" (newline) at the end of each line. + Or "\r\n" when 'fileformat' is "dos". When using "insert" in + an empty buffer Vim will set 'fileformat' accordingly. + When "off" points to the start of a line the text is inserted + above this line. Thus when "off" is zero lines are inserted + before the first line. + When "off" points after the start of a line, possibly on the + NUL at the end of a line, the first line of text is appended + to this line. Further lines come below it. Possible replies: 123 no problem 123 !message failed Note that the message in the reply is not quoted. Also sets the current buffer, if necessary. + Does not move the cursor to the changed text. + Resets undo information. remove off length Delete "length" bytes of text at position "off". Both diff --git a/runtime/ftplugin/sql.vim b/runtime/ftplugin/sql.vim index efccebdf16..d2e6ee5217 100644 --- a/runtime/ftplugin/sql.vim +++ b/runtime/ftplugin/sql.vim @@ -1,10 +1,13 @@ " SQL filetype plugin file " Language: SQL (Common for Oracle, Microsoft SQL Server, Sybase) -" Version: 0.08 +" Version: 1.0 " Maintainer: David Fishburn <fishburn at ianywhere dot com> -" Last Change: Mon Feb 21 2005 7:27:36 AM +" Last Change: Wed Jan 11 2006 10:04:55 AM " Download: http://vim.sourceforge.net/script.php?script_id=454 +" For more details please use: +" :h sql.txt +" " This file should only contain values that are common to all SQL languages " Oracle, Microsoft SQL Server, Sybase ASA/ASE, MySQL, and so on " If additional features are required create: @@ -12,6 +15,22 @@ " .vim/after/ftplugin/sql.vim (Unix) " to override and add any of your own settings. + +" This file also creates a command, SQLSetType, which allows you to change +" SQL dialects on the fly. For example, if I open an Oracle SQL file, it +" is color highlighted appropriately. If I open an Informix SQL file, it +" will still be highlighted according to Oracles settings. By running: +" :SQLSetType sqlinformix +" +" All files called sqlinformix.vim will be loaded from the indent and syntax +" directories. This allows you to easily flip SQL dialects on a per file +" basis. NOTE: you can also use completion: +" :SQLSetType <tab> +" +" To change the default dialect, add the following to your vimrc: +" let g:sql_type_default = 'sqlanywhere' + + " Only do this when not done yet for this buffer if exists("b:did_ftplugin") finish @@ -20,8 +39,146 @@ endif let s:save_cpo = &cpo set cpo= +" Functions/Commands to allow the user to change SQL syntax dialects +" through the use of :SQLSetType <tab> for completion. +" This works with both Vim 6 and 7. + +if !exists("*SQL_SetType") + " NOTE: You cannot use function! since this file can be + " sourced from within this function. That will result in + " an error reported by Vim. + function SQL_GetList(ArgLead, CmdLine, CursorPos) + + if !exists('s:sql_list') + " Grab a list of files that contain "sql" in their names + let list_indent = globpath(&runtimepath, 'indent/*sql*') + let list_syntax = globpath(&runtimepath, 'syntax/*sql*') + let list_ftplugin = globpath(&runtimepath, 'ftplugin/*sql*') + + let sqls = "\n".list_indent."\n".list_syntax."\n".list_ftplugin."\n" + + " Strip out everything (path info) but the filename + " Regex + " From between two newline characters + " Non-greedily grab all characters + " Followed by a valid filename \w\+\.\w\+ (sql.vim) + " Followed by a newline, but do not include the newline + " + " Replace it with just the filename (get rid of PATH) + " + " Recursively, since there are many filenames that contain + " the word SQL in the indent, syntax and ftplugin directory + let sqls = substitute( sqls, + \ '[\n]\%(.\{-}\)\(\w\+\.\w\+\)\n\@=', + \ '\1\n', + \ 'g' + \ ) + + " Remove duplicates, since sqlanywhere.vim can exist in the + " sytax, indent and ftplugin directory, yet we only want + " to display the option once + let index = match(sqls, '.\{-}\ze\n') + while index > -1 + " Get the first filename + let file = matchstr(sqls, '.\{-}\ze\n', index) + " Recursively replace any *other* occurrence of that + " filename with nothing (ie remove it) + let sqls = substitute(sqls, '\%>'.(index+strlen(file)).'c\<'.file.'\>\n', '', 'g') + " Move on to the next filename + let index = match(sqls, '.\{-}\ze\n', (index+strlen(file)+1)) + endwhile + + " Sort the list if using version 7 + if v:version >= 700 + let mylist = split(sqls, "\n") + let mylist = sort(mylist) + let sqls = join(mylist, "\n") + endif + + let s:sql_list = sqls + endif + + return s:sql_list + + endfunction + + function SQL_SetType(name) + + " User has decided to override default SQL scripts and + " specify a vendor specific version + " (ie Oracle, Informix, SQL Anywhere, ...) + " So check for an remove any settings that prevent the + " scripts from being executed, and then source the + " appropriate Vim scripts. + if exists("b:did_ftplugin") + unlet b:did_ftplugin + endif + if exists("b:current_syntax") + " echomsg 'SQLSetType - clearing syntax' + syntax clear + endif + if exists("b:did_indent") + " echomsg 'SQLSetType - clearing indent' + unlet b:did_indent + " Set these values to their defaults + setlocal indentkeys& + setlocal indentexpr& + endif + + " Ensure the name is in the correct format + let new_sql_type = substitute(a:name, + \ '\s*\([^\.]\+\)\(\.\w\+\)\?', '\L\1', '') + + " Do not specify a buffer local variable if it is + " the default value + if new_sql_type == 'sql' + let new_sql_type = 'sqloracle' + endif + let b:sql_type_override = new_sql_type + + " Vim will automatically source the correct files if we + " change the filetype. You cannot do this with setfiletype + " since that command will only execute if a filetype has + " not already been set. In this case we want to override + " the existing filetype. + let &filetype = 'sql' + endfunction + command! -nargs=* -complete=custom,SQL_GetList SQLSetType :call SQL_SetType(<q-args>) + +endif + +if exists("b:sql_type_override") + " echo 'sourcing buffer ftplugin/'.b:sql_type_override.'.vim' + if globpath(&runtimepath, 'ftplugin/'.b:sql_type_override.'.vim') != '' + exec 'runtime ftplugin/'.b:sql_type_override.'.vim' + " else + " echomsg 'ftplugin/'.b:sql_type_override.' not exist, using default' + endif +elseif exists("g:sql_type_default") + " echo 'sourcing global ftplugin/'.g:sql_type_default.'.vim' + if globpath(&runtimepath, 'ftplugin/'.g:sql_type_default.'.vim') != '' + exec 'runtime ftplugin/'.g:sql_type_default.'.vim' + " else + " echomsg 'ftplugin/'.g:sql_type_default.'.vim not exist, using default' + endif +endif + +" If the above runtime command succeeded, do not load the default settings +if exists("b:did_ftplugin") + finish +endif + +let b:undo_ftplugin = "setl comments<" + " Don't load another plugin for this buffer -let b:did_ftplugin = 1 +let b:did_ftplugin = 1 +let b:current_ftplugin = 'sql' + +" Win32 can filter files in the browse dialog +if has("gui_win32") && !exists("b:browsefilter") + let b:browsefilter = "SQL Files (*.sql)\t*.sql\n" . + \ "All Files (*.*)\t*.*\n" +endif " Some standard expressions for use with the matchit strings let s:notend = '\%(\<end\s\+\)\@<!' @@ -112,69 +269,78 @@ endif " [d, [D, [_CTRL_D and so on features " Match these values ignoring case " ie DECLARE varname INTEGER -let &l:define = '\c\(DECLARE\|IN\|OUT\|INOUT\)\s*' +let &l:define = '\c\<\(VARIABLE\|DECLARE\|IN\|OUT\|INOUT\)\>' " Mappings to move to the next BEGIN ... END block " \W - no characters or digits -nmap <buffer> <silent> ]] :call search('\c^\s*begin\>', 'W' )<CR> -nmap <buffer> <silent> [[ :call search('\c^\s*begin\>', 'bW' )<CR> -nmap <buffer> <silent> ][ :call search('\c^\s*end\W*$', 'W' )<CR> -nmap <buffer> <silent> [] :call search('\c^\s*end\W*$', 'bW' )<CR> -vmap <buffer> <silent> ]] /\c^\s*begin\><CR> -vmap <buffer> <silent> [[ ?\c^\s*begin<CR> -vmap <buffer> <silent> ][ /\c^\s*end\W*$<CR> -vmap <buffer> <silent> [] ?\c^\s*end\W*$<CR> +nmap <buffer> <silent> ]] :call search('\\c^\\s*begin\\>', 'W' )<CR> +nmap <buffer> <silent> [[ :call search('\\c^\\s*begin\\>', 'bW' )<CR> +nmap <buffer> <silent> ][ :call search('\\c^\\s*end\\W*$', 'W' )<CR> +nmap <buffer> <silent> [] :call search('\\c^\\s*end\\W*$', 'bW' )<CR> +vmap <buffer> <silent> ]] /\\c^\\s*begin\\><CR> +vmap <buffer> <silent> [[ ?\\c^\\s*begin\\><CR> +vmap <buffer> <silent> ][ /\\c^\\s*end\\W*$<CR> +vmap <buffer> <silent> [] ?\\c^\\s*end\\W*$<CR> + +" By default only look for CREATE statements, but allow +" the user to override +if !exists('g:ftplugin_sql_statements') + let g:ftplugin_sql_statements = 'create' +endif " Predefined SQL objects what are used by the below mappings using " the ]} style maps. " This global variable allows the users to override it's value " from within their vimrc. +" Note, you cannot use \?, since these patterns can be used to search +" backwards, you must use \{,1} if !exists('g:ftplugin_sql_objects') let g:ftplugin_sql_objects = 'function,procedure,event,' . - \ '\(existing\\|global\s\+temporary\s\+\)\?table,trigger' . + \ '\\(existing\\\\|global\\s\\+temporary\\s\\+\\)\\\{,1}' . + \ 'table,trigger' . \ ',schema,service,publication,database,datatype,domain' . \ ',index,subscription,synchronization,view,variable' endif +" Replace all ,'s with bars, except ones with numbers after them. +" This will most likely be a \{,1} string. let s:ftplugin_sql_objects = - \ '\c^\s*' . - \ '\(create\s\+\(or\s\+replace\s\+\)\?\)\?' . - \ '\<\(' . - \ substitute(g:ftplugin_sql_objects, ',', '\\\\|', 'g') . - \ '\)\>' + \ '\\c^\\s*' . + \ '\\(\\(' . + \ substitute(g:ftplugin_sql_statements, ',\d\@!', '\\\\\\|', 'g') . + \ '\\)\\s\\+\\(or\\s\\+replace\\\s\+\\)\\{,1}\\)\\{,1}' . + \ '\\<\\(' . + \ substitute(g:ftplugin_sql_objects, ',\d\@!', '\\\\\\|', 'g') . + \ '\\)\\>' " Mappings to move to the next CREATE ... block -" map <buffer> <silent> ]} :call search(g:ftplugin_sql_objects, 'W' )<CR> -" nmap <buffer> <silent> [{ :call search('\c^\s*\(create\s\+\(or\s\+replace\s\+\)\?\)\?\<\(function\\|procedure\\|event\\|table\\|trigger\\|schema\)\>', 'bW' )<CR> -" exec 'nmap <buffer> <silent> ]} /'.s:ftplugin_sql_objects.'<CR>' exec "nmap <buffer> <silent> ]} :call search('".s:ftplugin_sql_objects."', 'W')<CR>" exec "nmap <buffer> <silent> [{ :call search('".s:ftplugin_sql_objects."', 'bW')<CR>" " Could not figure out how to use a :call search() string in visual mode " without it ending visual mode +" Unfortunately, this will add a entry to the search history exec 'vmap <buffer> <silent> ]} /'.s:ftplugin_sql_objects.'<CR>' exec 'vmap <buffer> <silent> [{ ?'.s:ftplugin_sql_objects.'<CR>' -" vmap <buffer> <silent> ]} /\c^\s*\(create\s\+\(or\s\+replace\s\+\)\?\)\?\<\(function\\|procedure\\|event\\|table\\|trigger\\|schema\)\><CR> -" vmap <buffer> <silent> [{ ?\c^\s*\(create\s\+\(or\s\+replace\s\+\)\?\)\?\<\(function\\|procedure\\|event\\|table\\|trigger\\|schema\)\><CR> " Mappings to move to the next COMMENT " " Had to double the \ for the \| separator since this has a special " meaning on maps -let b:comment_leader = '\(--\\|\/\/\\|\*\\|\/\*\\|\*\/\)' +let b:comment_leader = '\\(--\\\|\\/\\/\\\|\\*\\\|\\/\\*\\\|\\*\\/\\)' " Find the start of the next comment -let b:comment_start = '^\(\s*'.b:comment_leader.'.*\n\)\@<!'. - \ '\(\s*'.b:comment_leader.'\)' +let b:comment_start = '^\\(\\s*'.b:comment_leader.'.*\\n\\)\\@<!'. + \ '\\(\\s*'.b:comment_leader.'\\)' " Find the end of the previous comment -let b:comment_end = '\(^\s*'.b:comment_leader.'.*\n\)'. - \ '\(^\s*'.b:comment_leader.'\)\@!' +let b:comment_end = '\\(^\\s*'.b:comment_leader.'.*\\n\\)'. + \ '\\(^\\s*'.b:comment_leader.'\\)\\@!' " Skip over the comment let b:comment_jump_over = "call search('". - \ '^\(\s*'.b:comment_leader.'.*\n\)\@<!'. + \ '^\\(\\s*'.b:comment_leader.'.*\\n\\)\\@<!'. \ "', 'W')" let b:comment_skip_back = "call search('". - \ '^\(\s*'.b:comment_leader.'.*\n\)\@<!'. + \ '^\\(\\s*'.b:comment_leader.'.*\\n\\)\\@<!'. \ "', 'bW')" " Move to the start and end of comments exec 'nnoremap <silent><buffer> ]" /'.b:comment_start.'<CR>' @@ -187,11 +353,29 @@ exec 'vnoremap <silent><buffer> [" /'.b:comment_end.'<CR>' " * " */ " or -" // -" or " -- +" or +" // setlocal comments=s1:/*,mb:*,ex:*/,:--,:// +" Set completion with CTRL-X CTRL-O to autoloaded function. +if exists('&omnifunc') + " This is used by the sqlcomplete.vim plugin + " Source it for it's global functions + runtime autoload/syntaxcomplete.vim + + setlocal omnifunc=sqlcomplete#Complete + " Prevent the intellisense plugin from loading + let b:sql_vis = 1 + imap <buffer> <c-space>t <C-O>:let b:sql_compl_type='table'<CR><C-X><C-O> + imap <buffer> <c-space>p <C-O>:let b:sql_compl_type='procedure'<CR><C-X><C-O> + imap <buffer> <c-space>v <C-O>:let b:sql_compl_type='view'<CR><C-X><C-O> + imap <buffer> <c-space>c <C-O>:let b:sql_compl_type='column'<CR><C-X><C-O> + imap <buffer> <c-space>f <C-O>:let b:sql_compl_type='function'<CR><C-X><C-O> + imap <buffer> <c-space>o <C-O>:let b:sql_compl_type='option'<CR><C-X><C-O> + imap <buffer> <c-right> <C-O>:let b:sql_compl_type='column'<CR><C-X><C-O> +endif + let &cpo = s:save_cpo " vim:sw=4:ff=unix: diff --git a/runtime/indent/sql.vim b/runtime/indent/sql.vim new file mode 100644 index 0000000000..490d652ae1 --- /dev/null +++ b/runtime/indent/sql.vim @@ -0,0 +1,39 @@ +" Vim indent file loader +" Language: SQL +" Maintainer: David Fishburn <fishburn at ianywhere dot com> +" Last Change: Thu Sep 15 2005 10:27:51 AM +" Version: 1.0 +" Download: http://vim.sourceforge.net/script.php?script_id=495 + +" Description: Checks for a: +" buffer local variable, +" global variable, +" If the above exist, it will source the type specified. +" If none exist, it will source the default sqlanywhere.vim file. + + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif + +" Default to the standard Vim distribution file +let filename = 'sqlanywhere' + +" Check for overrides. Buffer variables have the highest priority. +if exists("b:sql_type_override") + " Check the runtimepath to see if the file exists + if globpath(&runtimepath, 'indent/'.b:sql_type_override.'.vim') != '' + let filename = b:sql_type_override + endif +elseif exists("g:sql_type_default") + if globpath(&runtimepath, 'indent/'.g:sql_type_default.'.vim') != '' + let filename = g:sql_type_default + endif +endif + +" Source the appropriate file +exec 'runtime indent/'.filename.'.vim' + + +" vim:sw=4:ff=unix: diff --git a/runtime/indent/sqlanywhere.vim b/runtime/indent/sqlanywhere.vim new file mode 100644 index 0000000000..65d711383a --- /dev/null +++ b/runtime/indent/sqlanywhere.vim @@ -0,0 +1,384 @@ +" Vim indent file +" Language: SQL +" Maintainer: David Fishburn <fishburn at ianywhere dot com> +" Last Change: Wed Sep 14 2005 10:21:15 PM +" Version: 1.4 +" Download: http://vim.sourceforge.net/script.php?script_id=495 + +" Notes: +" Indenting keywords are based on Oracle and Sybase Adaptive Server +" Anywhere (ASA). Test indenting was done with ASA stored procedures and +" fuctions and Oracle packages which contain stored procedures and +" functions. +" This has not been tested against Microsoft SQL Server or +" Sybase Adaptive Server Enterprise (ASE) which use the Transact-SQL +" syntax. That syntax does not have end tags for IF's, which makes +" indenting more difficult. +" +" Known Issues: +" The Oracle MERGE statement does not have an end tag associated with +" it, this can leave the indent hanging to the right one too many. + +" Only load this indent file when no other was loaded. +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 +let b:current_indent = "sqlanywhere" + +setlocal indentkeys-=0{ +setlocal indentkeys-=0} +setlocal indentkeys-=: +setlocal indentkeys-=0# +setlocal indentkeys-=e + +" This indicates formatting should take place when one of these +" expressions is used. These expressions would normally be something +" you would type at the BEGINNING of a line +" SQL is generally case insensitive, so this files assumes that +" These keywords are something that would trigger an indent LEFT, not +" an indent right, since the SQLBlockStart is used for those keywords +setlocal indentkeys+==~end,=~else,=~elseif,=~elsif,0=~when,0=) + +" GetSQLIndent is executed whenever one of the expressions +" in the indentkeys is typed +setlocal indentexpr=GetSQLIndent() + +" Only define the functions once. +if exists("*GetSQLIndent") + finish +endif + +" List of all the statements that start a new block. +" These are typically words that start a line. +" IS is excluded, since it is difficult to determine when the +" ending block is (especially for procedures/functions). +let s:SQLBlockStart = '^\s*\%('. + \ 'if\|else\|elseif\|elsif\|'. + \ 'while\|loop\|do\|'. + \ 'begin\|'. + \ 'case\|when\|merge\|exception'. + \ '\)\>' +let s:SQLBlockEnd = '^\s*\(end\)\>' + +" The indent level is also based on unmatched paranethesis +" If a line has an extra "(" increase the indent +" If a line has an extra ")" decrease the indent +function s:CountUnbalancedParan( line, paran_to_check ) + let l = a:line + let lp = substitute(l, '[^(]', '', 'g') + let l = a:line + let rp = substitute(l, '[^)]', '', 'g') + + if a:paran_to_check =~ ')' + " echom 'CountUnbalancedParan ) returning: ' . + " \ (strlen(rp) - strlen(lp)) + return (strlen(rp) - strlen(lp)) + elseif a:paran_to_check =~ '(' + " echom 'CountUnbalancedParan ( returning: ' . + " \ (strlen(lp) - strlen(rp)) + return (strlen(lp) - strlen(rp)) + else + " echom 'CountUnbalancedParan unknown paran to check: ' . + " \ a:paran_to_check + return 0 + endif +endfunction + +" Unindent commands based on previous indent level +function s:CheckToIgnoreRightParan( prev_lnum, num_levels ) + let lnum = a:prev_lnum + let line = getline(lnum) + let ends = 0 + let num_right_paran = a:num_levels + let ignore_paran = 0 + let vircol = 1 + + while num_right_paran > 0 + silent! exec 'norm! '.lnum."G\<bar>".vircol."\<bar>" + let right_paran = search( ')', 'W' ) + if right_paran != lnum + " This should not happen since there should be at least + " num_right_paran matches for this line + break + endif + let vircol = virtcol(".") + + " if getline(".") =~ '^)' + let matching_paran = searchpair('(', '', ')', 'bW', + \ 'IsColComment(line("."), col("."))') + + if matching_paran < 1 + " No match found + " echom 'CTIRP - no match found, ignoring' + break + endif + + if matching_paran == lnum + " This was not an unmatched parantenses, start the search again + " again after this column + " echom 'CTIRP - same line match, ignoring' + continue + endif + + " echom 'CTIRP - match: ' . line(".") . ' ' . getline(".") + + if getline(matching_paran) =~? '\(if\|while\)\>' + " echom 'CTIRP - if/while ignored: ' . line(".") . ' ' . getline(".") + let ignore_paran = ignore_paran + 1 + endif + + " One match found, decrease and check for further matches + let num_right_paran = num_right_paran - 1 + + endwhile + + " Fallback - just move back one + " return a:prev_indent - &sw + return ignore_paran +endfunction + +" Based on the keyword provided, loop through previous non empty +" non comment lines to find the statement that initated the keyword. +" Return its indent level +" CASE .. +" WHEN ... +" Should return indent level of CASE +" EXCEPTION .. +" WHEN ... +" something; +" WHEN ... +" Should return indent level of exception. +function s:GetStmtStarterIndent( keyword, curr_lnum ) + let lnum = a:curr_lnum + + " Default - reduce indent by 1 + let ind = indent(a:curr_lnum) - &sw + + if a:keyword =~? 'end' + exec 'normal! ^' + let stmts = '^\s*\%('. + \ '\<begin\>\|' . + \ '\%(\%(\<end\s\+\)\@<!\<loop\>\)\|' . + \ '\%(\%(\<end\s\+\)\@<!\<case\>\)\|' . + \ '\%(\%(\<end\s\+\)\@<!\<for\>\)\|' . + \ '\%(\%(\<end\s\+\)\@<!\<if\>\)'. + \ '\)' + let matching_lnum = searchpair(stmts, '', '\<end\>\zs', 'bW', + \ 'IsColComment(line("."), col(".")) == 1') + exec 'normal! $' + if matching_lnum > 0 && matching_lnum < a:curr_lnum + let ind = indent(matching_lnum) + endif + elseif a:keyword =~? 'when' + exec 'normal! ^' + let matching_lnum = searchpair( + \ '\%(\<end\s\+\)\@<!\<case\>\|\<exception\>\|\<merge\>', + \ '', + \ '\%(\%(\<when\s\+others\>\)\|\%(\<end\s\+case\>\)\)', + \ 'bW', + \ 'IsColComment(line("."), col(".")) == 1') + exec 'normal! $' + if matching_lnum > 0 && matching_lnum < a:curr_lnum + let ind = indent(matching_lnum) + else + let ind = indent(a:curr_lnum) + endif + endif + + return ind +endfunction + + +" Check if the line is a comment +function IsLineComment(lnum) + let rc = synIDattr( + \ synID(a:lnum, + \ match(getline(a:lnum), '\S')+1, 0) + \ , "name") + \ =~? "comment" + + return rc +endfunction + + +" Check if the column is a comment +function IsColComment(lnum, cnum) + let rc = synIDattr(synID(a:lnum, a:cnum, 0), "name") + \ =~? "comment" + + return rc +endfunction + + +" Check if the column is a comment +function ModuloIndent(ind) + let ind = a:ind + + if ind > 0 + let modulo = ind % &shiftwidth + + if modulo > 0 + let ind = ind - modulo + endif + endif + + return ind +endfunction + + +" Find correct indent of a new line based upon the previous line +function GetSQLIndent() + let lnum = v:lnum + let ind = indent(lnum) + + " If the current line is a comment, leave the indent as is + " Comment out this additional check since it affects the + " indenting of =, and will not reindent comments as it should + " if IsLineComment(lnum) == 1 + " return ind + " endif + + " while 1 + " Get previous non-blank line + let prevlnum = prevnonblank(lnum - 1) + if prevlnum <= 0 + return ind + endif + + if IsLineComment(prevlnum) == 1 + if getline(v:lnum) =~ '^\s*\*' + let ind = ModuloIndent(indent(prevlnum)) + return ind + 1 + endif + " If the previous line is a comment, then return -1 + " to tell Vim to use the formatoptions setting to determine + " the indent to use + " But only if the next line is blank. This would be true if + " the user is typing, but it would not be true if the user + " is reindenting the file + if getline(v:lnum) =~ '^\s*$' + return -1 + endif + endif + + " let prevline = getline(prevlnum) + " if prevline !~ '^\s*$' + " " echom 'previous non blank - break: ' . prevline + " break + " endif + " endwhile + + " echom 'PREVIOUS INDENT: ' . indent(prevlnum) . ' LINE: ' . getline(prevlnum) + + " This is the line you just hit return on, it is not the current line + " which is new and empty + " Based on this line, we can determine how much to indent the new + " line + + " Get default indent (from prev. line) + let ind = indent(prevlnum) + let prevline = getline(prevlnum) + + " Now check what's on the previous line to determine if the indent + " should be changed, for example IF, BEGIN, should increase the indent + " where END IF, END, should decrease the indent. + if prevline =~? s:SQLBlockStart + " Move indent in + let ind = ind + &sw + " echom 'prevl - SQLBlockStart - indent ' . ind . ' line: ' . prevline + elseif prevline =~ '[()]' + if prevline =~ '(' + let num_unmatched_left = s:CountUnbalancedParan( prevline, '(' ) + else + let num_unmatched_left = 0 + endif + if prevline =~ ')' + let num_unmatched_right = s:CountUnbalancedParan( prevline, ')' ) + else + let num_unmatched_right = 0 + " let num_unmatched_right = s:CountUnbalancedParan( prevline, ')' ) + endif + if num_unmatched_left > 0 + " There is a open left paranethesis + " increase indent + let ind = ind + ( &sw * num_unmatched_left ) + elseif num_unmatched_right > 0 + " if it is an unbalanced paranethesis only unindent if + " it was part of a command (ie create table(..) ) + " instead of part of an if (ie if (....) then) which should + " maintain the indent level + let ignore = s:CheckToIgnoreRightParan( prevlnum, num_unmatched_right ) + " echom 'prevl - ) unbalanced - CTIRP - ignore: ' . ignore + + if prevline =~ '^\s*)' + let ignore = ignore + 1 + " echom 'prevl - begins ) unbalanced ignore: ' . ignore + endif + + if (num_unmatched_right - ignore) > 0 + let ind = ind - ( &sw * (num_unmatched_right - ignore) ) + endif + + endif + endif + + + " echom 'CURRENT INDENT: ' . ind . ' LINE: ' . getline(v:lnum) + + " This is a new blank line since we just typed a carriage return + " Check current line; search for simplistic matching start-of-block + let line = getline(v:lnum) + + if line =~? '^\s*els' + " Any line when you type else will automatically back up one + " ident level (ie else, elseif, elsif) + let ind = ind - &sw + " echom 'curr - else - indent ' . ind + elseif line =~? '^\s*end\>' + let ind = s:GetStmtStarterIndent('end', v:lnum) + " General case for end + " let ind = ind - &sw + " echom 'curr - end - indent ' . ind + elseif line =~? '^\s*when\>' + let ind = s:GetStmtStarterIndent('when', v:lnum) + " If the WHEN clause is used with a MERGE or EXCEPTION + " clause, do not change the indent level, since these + " statements do not have a corresponding END statement. + " if stmt_starter =~? 'case' + " let ind = ind - &sw + " endif + " elseif line =~ '^\s*)\s*;\?\s*$' + " elseif line =~ '^\s*)' + elseif line =~ '^\s*)' + let num_unmatched_right = s:CountUnbalancedParan( line, ')' ) + let ignore = s:CheckToIgnoreRightParan( v:lnum, num_unmatched_right ) + " If the line ends in a ), then |