xref: /vim-8.2.3635/runtime/ftplugin/ada.vim (revision 4a85b415)
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