blob: 13fa8f93f475f84fccd799541de8d553eb1a4185 [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001" Vim Ada plugin file
2" Language: Ada
3" Maintainer: Neil Bird <neil@fnxweb.com>
Bram Moolenaar57657d82006-04-21 22:12:41 +00004" Last Change: 2006 Apr 21
Bram Moolenaar071d4272004-06-13 20:20:40 +00005" 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 Moolenaar071d4272004-06-13 20:20:40 +000017" 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
Bram Moolenaar071d4272004-06-13 20:20:40 +000029" Ada comments
30setlocal comments+=O:--
31
Bram Moolenaar071d4272004-06-13 20:20:40 +000032" 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 :