1" Vim Ada plugin file 2" Language: Ada 3" Maintainer: Neil Bird <[email protected]> 4" Last Change: 2006 Apr 21 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 17" Only do this when not done yet for this buffer 18if exists("b:did_ftplugin") 19 finish 20endif 21 22" Don't load another plugin for this buffer 23let b:did_ftplugin = 1 24 25" Temporarily set cpoptions to ensure the script loads OK 26let s:cpoptions = &cpoptions 27set cpo-=C 28 29" Ada comments 30setlocal comments+=O:-- 31 32" Make local tag mappings for this buffer (if not already set) 33if mapcheck('<C-]>','n') == '' 34 nnoremap <unique> <buffer> <C-]> :call JumpToTag_ada('')<cr> 35endif 36if mapcheck('g<C-]>','n') == '' 37 nnoremap <unique> <buffer> g<C-]> :call JumpToTag_ada('','stj')<cr> 38endif 39 40if mapcheck('<C-N>','i') == '' 41 inoremap <unique> <buffer> <C-N> <C-R>=<SID>AdaCompletion("\<lt>C-N>")<cr> 42endif 43if mapcheck('<C-P>','i') == '' 44 inoremap <unique> <buffer> <C-P> <C-R>=<SID>AdaCompletion("\<lt>C-P>")<cr> 45endif 46if mapcheck('<C-X><C-]>','i') == '' 47 inoremap <unique> <buffer> <C-X><C-]> <C-R>=<SID>AdaCompletion("\<lt>C-X>\<lt>C-]>")<cr> 48endif 49if mapcheck('<bs>','i') == '' 50 inoremap <silent> <unique> <buffer> <bs> <C-R>=<SID>AdaInsertBackspace()<cr> 51endif 52 53 54" Only do this when not done yet for this buffer & matchit is used 55if ! 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\>' 65endif 66 67 68" Prevent re-load of functions 69if exists('s:id') 70 finish 71endif 72 73" Get this script's unique id 74map <script> <SID>?? <SID>?? 75let s:id = substitute( maparg('<SID>??'), '^<SNR>\(.*\)_??$', '\1', '' ) 76unmap <script> <SID>?? 77 78 79" Extract current Ada word across multiple lines 80" AdaWord( [line, column] )\ 81let s:AdaWordRegex = '\a\w*\(\_s*\.\_s*\a\w*\)*' 82let s:AdaComment = "\\v^(\"[^\"]*\"|'.'|[^\"']){-}\\zs\\s*--.*" 83 84function! 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' ) 160endfunction 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(). 165function! 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 194endfunction 195 196 197" Word completion (^N/^R/^X^]) - force '.' inclusion 198function! s:AdaCompletion(cmd) 199 set iskeyword+=46 200 return a:cmd . "\<C-R>=<SNR>" . s:id . "_AdaCompletionEnd()\<CR>" 201endfunction 202function! s:AdaCompletionEnd() 203 set iskeyword-=46 204 return '' 205endfunction 206 207 208" Backspace at end of line after auto-inserted commentstring '-- ' wipes it 209function! 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 216endfunction 217 218 219" Reset cpoptions 220let &cpoptions = s:cpoptions 221unlet s:cpoptions 222 223" vim: sts=2 sw=2 : 224