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