Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame] | 1 | " Vim Ada plugin file |
| 2 | " Language: Ada |
| 3 | " Maintainer: Neil Bird <neil@fnxweb.com> |
Bram Moolenaar | 57657d8 | 2006-04-21 22:12:41 +0000 | [diff] [blame] | 4 | " Last Change: 2006 Apr 21 |
Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame] | 5 | " Version: $Id$ |
| 6 | " Look for the latest version at http://vim.sourceforge.net/ |
| 7 | " |
| 8 | " Perform Ada specific completion & tagging. |
| 9 | " |
| 10 | " |
| 11 | " Provides mapping overrides for tag jumping that figure out the current |
| 12 | " Ada object and tag jump to that, not the 'simple' vim word. |
| 13 | " Similarly allows <Ctrl-N> matching of full-length ada entities from tags. |
| 14 | " Exports 'AdaWord()' function to return full name of Ada entity under the |
| 15 | " cursor( or at given line/column), stripping whitespace/newlines as necessary. |
| 16 | |
Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame] | 17 | " Only do this when not done yet for this buffer |
| 18 | if exists("b:did_ftplugin") |
| 19 | finish |
| 20 | endif |
| 21 | |
| 22 | " Don't load another plugin for this buffer |
| 23 | let b:did_ftplugin = 1 |
| 24 | |
| 25 | " Temporarily set cpoptions to ensure the script loads OK |
| 26 | let s:cpoptions = &cpoptions |
| 27 | set cpo-=C |
| 28 | |
Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame] | 29 | " Ada comments |
| 30 | setlocal comments+=O:-- |
| 31 | |
Bram Moolenaar | 071d427 | 2004-06-13 20:20:40 +0000 | [diff] [blame] | 32 | " Make local tag mappings for this buffer (if not already set) |
| 33 | if mapcheck('<C-]>','n') == '' |
| 34 | nnoremap <unique> <buffer> <C-]> :call JumpToTag_ada('')<cr> |
| 35 | endif |
| 36 | if mapcheck('g<C-]>','n') == '' |
| 37 | nnoremap <unique> <buffer> g<C-]> :call JumpToTag_ada('','stj')<cr> |
| 38 | endif |
| 39 | |
| 40 | if mapcheck('<C-N>','i') == '' |
| 41 | inoremap <unique> <buffer> <C-N> <C-R>=<SID>AdaCompletion("\<lt>C-N>")<cr> |
| 42 | endif |
| 43 | if mapcheck('<C-P>','i') == '' |
| 44 | inoremap <unique> <buffer> <C-P> <C-R>=<SID>AdaCompletion("\<lt>C-P>")<cr> |
| 45 | endif |
| 46 | if mapcheck('<C-X><C-]>','i') == '' |
| 47 | inoremap <unique> <buffer> <C-X><C-]> <C-R>=<SID>AdaCompletion("\<lt>C-X>\<lt>C-]>")<cr> |
| 48 | endif |
| 49 | if mapcheck('<bs>','i') == '' |
| 50 | inoremap <silent> <unique> <buffer> <bs> <C-R>=<SID>AdaInsertBackspace()<cr> |
| 51 | endif |
| 52 | |
| 53 | |
| 54 | " Only do this when not done yet for this buffer & matchit is used |
| 55 | if ! exists("b:match_words") && exists("loaded_matchit") |
| 56 | " The following lines enable the macros/matchit.vim plugin for |
| 57 | " Ada-specific extended matching with the % key. |
| 58 | let s:notend = '\%(\<end\s\+\)\@<!' |
| 59 | let b:match_words= |
| 60 | \ s:notend . '\<if\>:\<elsif\>:\<else\>:\<end\>\s\+\<if\>,' . |
| 61 | \ s:notend . '\<case\>:\<when\>:\<end\>\s\+\<case\>,' . |
| 62 | \ '\%(\<while\>.*\|\<for\>.*\|'.s:notend.'\)\<loop\>:\<end\>\s\+\<loop\>,' . |
| 63 | \ '\%(\<do\>\|\<begin\>\):\<exception\>:\<end\>\s*\%($\|[;A-Z]\),' . |
| 64 | \ s:notend . '\<record\>:\<end\>\s\+\<record\>' |
| 65 | endif |
| 66 | |
| 67 | |
| 68 | " Prevent re-load of functions |
| 69 | if exists('s:id') |
| 70 | finish |
| 71 | endif |
| 72 | |
| 73 | " Get this script's unique id |
| 74 | map <script> <SID>?? <SID>?? |
| 75 | let s:id = substitute( maparg('<SID>??'), '^<SNR>\(.*\)_??$', '\1', '' ) |
| 76 | unmap <script> <SID>?? |
| 77 | |
| 78 | |
| 79 | " Extract current Ada word across multiple lines |
| 80 | " AdaWord( [line, column] )\ |
| 81 | let s:AdaWordRegex = '\a\w*\(\_s*\.\_s*\a\w*\)*' |
| 82 | let s:AdaComment = "\\v^(\"[^\"]*\"|'.'|[^\"']){-}\\zs\\s*--.*" |
| 83 | |
| 84 | function! AdaWord(...) |
| 85 | if a:0 > 1 |
| 86 | let linenr = a:1 |
| 87 | let colnr = a:2 - 1 |
| 88 | else |
| 89 | let linenr = line('.') |
| 90 | let colnr = col('.') - 1 |
| 91 | endif |
| 92 | let line = substitute( getline(linenr), s:AdaComment, '', '' ) |
| 93 | " Cope with tag searching for items in comments; if we are, don't loop |
| 94 | " backards looking for previous lines |
| 95 | if colnr > strlen(line) |
| 96 | " We were in a comment |
| 97 | let line = getline(linenr) |
| 98 | let search_prev_lines = 0 |
| 99 | else |
| 100 | let search_prev_lines = 1 |
| 101 | endif |
| 102 | |
| 103 | " Go backwards until we find a match (Ada ID) that *doesn't* include our |
| 104 | " location - i.e., the previous ID. This is because the current 'correct' |
| 105 | " match will toggle matching/not matching as we traverse characters |
| 106 | " backwards. Thus, we have to find the previous unrelated match, exclude |
| 107 | " it, then use the next full match (ours). |
| 108 | " Remember to convert vim column 'colnr' [1..n] to string offset [0..(n-1)] |
| 109 | " ... but start, here, one after the required char. |
| 110 | let newcol = colnr + 1 |
| 111 | while 1 |
| 112 | let newcol = newcol - 1 |
| 113 | if newcol < 0 |
| 114 | " Have to include previous line from file |
| 115 | let linenr = linenr - 1 |
| 116 | if linenr < 1 || !search_prev_lines |
| 117 | " Start of file or matching in a comment |
| 118 | let linenr = 1 |
| 119 | let newcol = 0 |
| 120 | let ourmatch = match( line, s:AdaWordRegex ) |
| 121 | break |
| 122 | endif |
| 123 | " Get previous line, and prepend it to our search string |
| 124 | let newline = substitute( getline(linenr), s:AdaComment, '', '' ) |
| 125 | let newcol = strlen(newline) - 1 |
| 126 | let colnr = colnr + newcol |
| 127 | let line = newline . line |
| 128 | endif |
| 129 | " Check to see if this is a match excluding 'us' |
| 130 | let mend = newcol + matchend( strpart(line,newcol), s:AdaWordRegex ) - 1 |
| 131 | if mend >= newcol && mend < colnr |
| 132 | " Yes |
| 133 | let ourmatch = mend+1 + match( strpart(line,mend+1), s:AdaWordRegex ) |
| 134 | break |
| 135 | endif |
| 136 | endwhile |
| 137 | |
| 138 | " Got anything? |
| 139 | if ourmatch < 0 |
| 140 | return '' |
| 141 | else |
| 142 | let line = strpart( line, ourmatch) |
| 143 | endif |
| 144 | |
| 145 | " Now simply add further lines until the match gets no bigger |
| 146 | let matchstr = matchstr( line, s:AdaWordRegex ) |
| 147 | let lastline = line('$') |
| 148 | let linenr = line('.') + 1 |
| 149 | while linenr <= lastline |
| 150 | let lastmatch = matchstr |
| 151 | let line = line . substitute( getline(linenr), s:AdaComment, '', '' ) |
| 152 | let matchstr = matchstr( line, s:AdaWordRegex ) |
| 153 | if matchstr == lastmatch |
| 154 | break |
| 155 | endif |
| 156 | endwhile |
| 157 | |
| 158 | " Strip whitespace & return |
| 159 | return substitute( matchstr, '\s\+', '', 'g' ) |
| 160 | endfunction |
| 161 | |
| 162 | |
| 163 | " Word tag - include '.' and if Ada make uppercase |
| 164 | " Name allows a common JumpToTag() to look for an ft specific JumpToTag_ft(). |
| 165 | function! JumpToTag_ada(word,...) |
| 166 | if a:word == '' |
| 167 | " Get current word |
| 168 | let word = AdaWord() |
| 169 | if word == '' |
| 170 | return |
| 171 | endif |
| 172 | else |
| 173 | let word = a:word |
| 174 | endif |
| 175 | if a:0 > 0 |
| 176 | let mode = a:1 |
| 177 | else |
| 178 | let mode = 'tj' |
| 179 | endif |
| 180 | |
| 181 | let v:errmsg = '' |
| 182 | execute 'silent!' mode word |
| 183 | if v:errmsg != '' |
| 184 | if v:errmsg =~ '^E426:' " Tag not found |
| 185 | let ignorecase = &ignorecase |
| 186 | set ignorecase |
| 187 | execute mode word |
| 188 | let &ignorecase = ignorecase |
| 189 | else |
| 190 | " Repeat to give error |
| 191 | execute mode word |
| 192 | endif |
| 193 | endif |
| 194 | endfunction |
| 195 | |
| 196 | |
| 197 | " Word completion (^N/^R/^X^]) - force '.' inclusion |
| 198 | function! s:AdaCompletion(cmd) |
| 199 | set iskeyword+=46 |
| 200 | return a:cmd . "\<C-R>=<SNR>" . s:id . "_AdaCompletionEnd()\<CR>" |
| 201 | endfunction |
| 202 | function! s:AdaCompletionEnd() |
| 203 | set iskeyword-=46 |
| 204 | return '' |
| 205 | endfunction |
| 206 | |
| 207 | |
| 208 | " Backspace at end of line after auto-inserted commentstring '-- ' wipes it |
| 209 | function! s:AdaInsertBackspace() |
| 210 | let line = getline('.') |
| 211 | if col('.') > strlen(line) && match(line,'-- $') != -1 && match(&comments,'--') != -1 |
| 212 | return "\<bs>\<bs>\<bs>" |
| 213 | else |
| 214 | return "\<bs>" |
| 215 | endif |
| 216 | endfunction |
| 217 | |
| 218 | |
| 219 | " Reset cpoptions |
| 220 | let &cpoptions = s:cpoptions |
| 221 | unlet s:cpoptions |
| 222 | |
| 223 | " vim: sts=2 sw=2 : |