comparison lisp/modes/ada-mode.el @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children ac2d302a0011
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 ;;; ada-mode.el - An Emacs major-mode for editing Ada source.
2 ;;; Copyright (C) 1994, 1995 Free Software Foundation, Inc.
3
4 ;;; Authors: Markus Heritsch <Markus.Heritsch@studbox.uni-stuttgart.de>
5 ;;; Rolf Ebert <ebert@inf.enst.fr>
6
7 ;;; This file is part of GNU Emacs.
8
9 ;; GNU Emacs is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 2, or (at your option)
12 ;; any later version.
13
14 ;; GNU Emacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
18
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs; see the file COPYING. If not, write to
21 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22
23 ;;; This mode is a complete rewrite of a major mode for editing Ada 83
24 ;;; and Ada 95 source code under Emacs-19. It contains completely new
25 ;;; indenting code and support for code browsing (see ada-xref).
26
27 ;;; Synched up with: FSF 19.29.
28
29 ;;; USAGE
30 ;;; =====
31 ;;; Emacs should enter ada-mode when you load an ada source (*.ad[abs]).
32 ;;;
33 ;;; When you have entered ada-mode, you may get more info by pressing
34 ;;; C-h m. You may also get online help describing various functions by:
35 ;;; C-h d <Name of function you want described>
36
37
38 ;;; HISTORY
39 ;;; =======
40 ;;; The first Ada mode for GNU Emacs was written by V. Broman in
41 ;;; 1985. He based his work on the already existing Modula-2 mode.
42 ;;; This was distributed as ada.el in versions of Emacs prior to 19.29.
43 ;;;
44 ;;; Lynn Slater wrote an extensive Ada mode in 1989. It consisted of
45 ;;; several files with support for dired commands and other nice
46 ;;; things. It is currently available from the PAL
47 ;;; (wuarchive.wustl.edu:/languages/ada) as ada-mode-1.06a.tar.Z.
48 ;;;
49 ;;; The probably very first Ada mode (called electric-ada.el) was
50 ;;; written by Steven D. Litvintchouk and Steven M. Rosen for the
51 ;;; Gosling Emacs. L. Slater based his development on ada.el and
52 ;;; electric-ada.el.
53 ;;;
54 ;;; The current Ada mode is a complete rewrite by M. Heritsch and
55 ;;; R. Ebert. Some ideas from the ada-mode mailing list have been
56 ;;; added. Some of the functionality of L. Slater's mode has not
57 ;;; (yet) been recoded in this new mode. Perhaps you prefer sticking
58 ;;; to his version.
59
60
61 ;;; KNOWN BUGS
62 ;;; ==========
63 ;;;
64 ;;; In the presence of comments and/or incorrect syntax
65 ;;; ada-format-paramlist produces weird results.
66 ;;;
67 ;;; Indenting of some tasking constructs is still buggy.
68 ;;; -------------------
69 ;;; For tagged types the problem comes from the keyword abstract:
70
71 ;;; type T2 is abstract tagged record
72 ;;; X : Integer;
73 ;;; Y : Float;
74 ;;; end record;
75 ;;; -------------------
76 ;;; In Emacs FSF 19.28, ada-mode will correctly indent comments at the
77 ;;; very beginning of the buffer (_before_ any code) when I go M-; but
78 ;;; when I press TAB I'd expect the comments to be placed at the beginning
79 ;;; of the line, just as the first line of _code_ would be indented.
80
81 ;;; This does not happen but the comment stays put :-( I end up going
82 ;;; M-; C-a M-\
83 ;;; -------------------
84 ;;; package Test is
85 ;;; -- If I hit return on the "type" line it will indent the next line
86 ;;; -- in another 3 space instead of heading out to the "(". If I hit
87 ;;; -- tab or return it reindents the line correctly but does not initially.
88 ;;; type Wait_Return is (Read_Success, Read_Timeout, Wait_Timeout,
89 ;;; Nothing_To_Wait_For_In_Wait_List);
90 ;;;
91 ;;; -- The following line will be wrongly reindented after typing it in after
92 ;;; -- the initial indent for the line was correct after type return after
93 ;;; -- this line. Subsequent lines will show the same problem.
94 ;;; Unused: constant Queue_ID := 0;
95 ;;; -------------------
96 ;;; -- If I do the following I get
97 ;;; -- "no matching procedure/function/task/declare/package"
98 ;;; -- when I do return (I reverse the mappings of ^j and ^m) after "private".
99 ;;; package Package1 is
100 ;;; package Package1_1 is
101 ;;; type The_Type is private;
102 ;;; private
103 ;;; -------------------
104 ;;; -- But what about this:
105 ;;; package G is
106 ;;; type T1 is new Integer;
107 ;;; type T2 is new Integer; --< incorrect, correct if subtype
108 ;;; package H is
109 ;;; type T3 is new Integer;
110 ;;; type --< Indentation is incorrect
111 ;;; -------------------
112
113
114
115 ;;; CREDITS
116 ;;; =======
117 ;;;
118 ;;; Many thanks to
119 ;;; Philippe Warroquiers (PW) <philippe@cfmu.eurocontrol.be> in particular,
120 ;;; woodruff@stc.llnl.gov (John Woodruff)
121 ;;; jj@ddci.dk (Jesper Joergensen)
122 ;;; gse@ocsystems.com (Scott Evans)
123 ;;; comar@LANG8.CS.NYU.EDU (Cyrille Comar)
124 ;;; and others for their valuable hints.
125
126 ;;;--------------------
127 ;;; USER OPTIONS
128 ;;;--------------------
129
130 ;; ---- configure indentation
131
132 (defvar ada-indent 3
133 "*Defines the size of Ada indentation.")
134
135 (defvar ada-broken-indent 2
136 "*# of columns to indent the continuation of a broken line.")
137
138 (defvar ada-label-indent -4
139 "*# of columns to indent a label.")
140
141 (defvar ada-stmt-end-indent 0
142 "*# of columns to indent a statement end keyword in a separate line.
143 Examples are 'is', 'loop', 'record', ...")
144
145 (defvar ada-when-indent 3
146 "*Defines the indentation for 'when' relative to 'exception' or 'case'.")
147
148 (defvar ada-indent-record-rel-type 3
149 "*Defines the indentation for 'record' relative to 'type' or 'use'.")
150
151 (defvar ada-indent-comment-as-code t
152 "*If non-nil, comment-lines get indented as ada-code.")
153
154 (defvar ada-indent-is-separate t
155 "*If non-nil, 'is separate' or 'is abstract' on a separate line are
156 indented.")
157
158 (defvar ada-indent-to-open-paren t
159 "*If non-nil, following lines get indented according to the innermost
160 open parenthesis.")
161
162 (defvar ada-search-paren-char-count-limit 3000
163 "*Search that many characters for an open parenthesis.")
164
165
166 ;; ---- other user options
167
168 (defvar ada-tab-policy 'indent-auto
169 "*Control behaviour of the TAB key.
170 Must be one of 'indent-rigidly, 'indent-auto, 'gei, 'indent-af or 'always-tab.
171
172 'indent-rigidly : always adds ada-indent blanks at the beginning of the line.
173 'indent-auto : use indentation functions in this file.
174 'gei : use David Kågedal's Generic Indentation Engine.
175 'indent-af : use Gary E. Barnes' ada-format.el
176 'always-tab : do indent-relative.")
177
178 (defvar ada-move-to-declaration nil
179 "*If non-nil, ada-move-to-start moves point to the subprog-declaration,
180 not to 'begin'.")
181
182 (defvar ada-spec-suffix ".ads"
183 "*Suffix of Ada specification files.")
184
185 (defvar ada-body-suffix ".adb"
186 "*Suffix of Ada body files.")
187
188 (defvar ada-language-version 'ada95
189 "*Do we program in 'ada83 or 'ada95?")
190
191 (defvar ada-case-keyword 'downcase-word
192 "*downcase-word, upcase-word, ada-loose-case-word or capitalize-word
193 to adjust ada keywords case.")
194
195 (defvar ada-case-identifier 'ada-loose-case-word
196 "*downcase-word, upcase-word, ada-loose-case-word or capitalize-word
197 to adjust ada identifier case.")
198
199 (defvar ada-case-attribute 'capitalize-word
200 "*downcase-word, upcase-word, ada-loose-case-word or capitalize-word
201 to adjust ada identifier case.")
202
203 (defvar ada-auto-case t
204 "*Non-nil automatically changes casing of preceeding word while typing.
205 Casing is done according to ada-case-keyword and ada-case-identifier.")
206
207 (defvar ada-clean-buffer-before-saving nil
208 "*If non-nil, remove-trailing-spaces and untabify buffer before saving.")
209
210 (defvar ada-mode-hook nil
211 "*List of functions to call when Ada Mode is invoked.
212 This is a good place to add Ada environment specific bindings.")
213
214 (defvar ada-external-pretty-print-program "aimap"
215 "*External pretty printer to call from within Ada Mode.")
216
217 (defvar ada-tmp-directory "/tmp/"
218 "*Directory to store the temporary file for the Ada pretty printer.")
219
220 (defvar ada-fill-comment-prefix "-- "
221 "*This is inserted in the first columns when filling a comment paragraph.")
222
223 (defvar ada-fill-comment-postfix " --"
224 "*This is inserted at the end of each line when filling a comment paragraph
225 with ada-fill-comment-paragraph postfix.")
226
227 (defvar ada-krunch-args "0"
228 "*Argument of gnatk8, a string containing the max number of characters.
229 Set to 0, if you dont use crunched filenames.")
230
231 ;;; ---- end of user configurable variables
232
233
234 (defvar ada-mode-abbrev-table nil
235 "Abbrev table used in Ada mode.")
236 (define-abbrev-table 'ada-mode-abbrev-table ())
237
238 (defvar ada-mode-map ()
239 "Local keymap used for ada-mode.")
240
241 (defvar ada-mode-syntax-table nil
242 "Syntax table to be used for editing Ada source code.")
243
244 (defvar ada-mode-symbol-syntax-table nil
245 "Syntax table for Ada, where `_' is a word constituent.")
246
247 (defconst ada-83-keywords
248 "\\<\\(abort\\|abs\\|accept\\|access\\|all\\|and\\|array\\|\
249 at\\|begin\\|body\\|case\\|constant\\|declare\\|delay\\|delta\\|\
250 digits\\|do\\|else\\|elsif\\|end\\|entry\\|exception\\|exit\\|for\\|\
251 function\\|generic\\|goto\\|if\\|in\\|is\\|limited\\|loop\\|mod\\|\
252 new\\|not\\|null\\|of\\|or\\|others\\|out\\|package\\|pragma\\|\
253 private\\|procedure\\|raise\\|range\\|record\\|rem\\|renames\\|\
254 return\\|reverse\\|select\\|separate\\|subtype\\|task\\|terminate\\|\
255 then\\|type\\|use\\|when\\|while\\|with\\|xor\\)\\>"
256 "regular expression for looking at Ada83 keywords.")
257
258 (defconst ada-95-keywords
259 "\\<\\(abort\\|abs\\|abstract\\|accept\\|access\\|aliased\\|\
260 all\\|and\\|array\\|at\\|begin\\|body\\|case\\|constant\\|declare\\|\
261 delay\\|delta\\|digits\\|do\\|else\\|elsif\\|end\\|entry\\|\
262 exception\\|exit\\|for\\|function\\|generic\\|goto\\|if\\|in\\|\
263 is\\|limited\\|loop\\|mod\\|new\\|not\\|null\\|of\\|or\\|others\\|\
264 out\\|package\\|pragma\\|private\\|procedure\\|protected\\|raise\\|\
265 range\\|record\\|rem\\|renames\\|requeue\\|return\\|reverse\\|\
266 select\\|separate\\|subtype\\|tagged\\|task\\|terminate\\|then\\|\
267 type\\|until\\|use\\|when\\|while\\|with\\|xor\\)\\>"
268 "regular expression for looking at Ada95 keywords.")
269
270 (defvar ada-keywords ada-95-keywords
271 "regular expression for looking at Ada keywords.")
272
273 (defvar ada-ret-binding nil
274 "Variable to save key binding of RET when casing is activated.")
275
276 (defvar ada-lfd-binding nil
277 "Variable to save key binding of LFD when casing is activated.")
278
279 ;;; ---- Regexps to find procedures/functions/packages
280
281 (defconst ada-ident-re
282 "[a-zA-Z0-9_\\.]+"
283 "Regexp matching Ada identifiers.")
284
285 (defvar ada-procedure-start-regexp
286 "^[ \t]*\\(procedure\\|function\\|task\\)[ \t\n]+\\([a-zA-Z0-9_\\.]+\\)"
287 "Regexp used to find Ada procedures/functions.")
288
289 (defvar ada-package-start-regexp
290 "^[ \t]*\\(package\\)"
291 "Regexp used to find Ada packages")
292
293
294 ;;; ---- regexps for indentation functions
295
296 (defvar ada-block-start-re
297 "\\<\\(begin\\|select\\|declare\\|private\\|or\\|generic\\|\
298 exception\\|loop\\|else\\|\
299 \\(\\(limited\\|abstract\\|tagged\\)[ \t]+\\)*record\\)\\>"
300 "Regexp for keywords starting ada-blocks.")
301
302 (defvar ada-end-stmt-re
303 "\\(;\\|=>\\|^[ \t]*separate[ \t]+([a-zA-Z0-9_\\.]+)\\|\
304 \\<\\(begin\\|else\\|record\\|loop\\|select\\|do\\|\
305 ^[ \t]*package[ \ta-zA-Z0-9_\\.]+is\\|\
306 ^[ \t]*exception\\|declare\\|generic\\|private\\)\\>\\)"
307 "Regexp of possible ends for a non-broken statement.
308 'end' means that there has to start a new statement after these.")
309
310 (defvar ada-loop-start-re
311 "\\<\\(for\\|while\\|loop\\)\\>"
312 "Regexp for the start of a loop.")
313
314 (defvar ada-subprog-start-re
315 "\\<\\(procedure\\|protected\\|package[ \t]+body\\|function\\|\
316 task\\|accept\\|entry\\)\\>"
317 "Regexp for the start of a subprogram.")
318
319
320 ;;;-------------
321 ;;; functions
322 ;;;-------------
323
324 (defun ada-xemacs ()
325 (or (string-match "Lucid" emacs-version)
326 (string-match "XEmacs" emacs-version)))
327
328 (defun ada-create-syntax-table ()
329 "Create the syntax table for ada-mode."
330 ;; There are two different syntax-tables. The standard one declares
331 ;; `_' a symbol constituent, in the second one, it is a word
332 ;; constituent. For some search and replacing routines we
333 ;; temporarily switch between the two.
334 (setq ada-mode-syntax-table (make-syntax-table))
335 (set-syntax-table ada-mode-syntax-table)
336
337 ;; define string brackets (% is alternative string bracket)
338 (modify-syntax-entry ?% "\"" ada-mode-syntax-table)
339 (modify-syntax-entry ?\" "\"" ada-mode-syntax-table)
340
341 (modify-syntax-entry ?\# "$" ada-mode-syntax-table)
342
343 (modify-syntax-entry ?: "." ada-mode-syntax-table)
344 (modify-syntax-entry ?\; "." ada-mode-syntax-table)
345 (modify-syntax-entry ?& "." ada-mode-syntax-table)
346 (modify-syntax-entry ?\| "." ada-mode-syntax-table)
347 (modify-syntax-entry ?+ "." ada-mode-syntax-table)
348 (modify-syntax-entry ?* "." ada-mode-syntax-table)
349 (modify-syntax-entry ?/ "." ada-mode-syntax-table)
350 (modify-syntax-entry ?= "." ada-mode-syntax-table)
351 (modify-syntax-entry ?< "." ada-mode-syntax-table)
352 (modify-syntax-entry ?> "." ada-mode-syntax-table)
353 (modify-syntax-entry ?$ "." ada-mode-syntax-table)
354 (modify-syntax-entry ?\[ "." ada-mode-syntax-table)
355 (modify-syntax-entry ?\] "." ada-mode-syntax-table)
356 (modify-syntax-entry ?\{ "." ada-mode-syntax-table)
357 (modify-syntax-entry ?\} "." ada-mode-syntax-table)
358 (modify-syntax-entry ?. "." ada-mode-syntax-table)
359 (modify-syntax-entry ?\\ "." ada-mode-syntax-table)
360 (modify-syntax-entry ?\' "." ada-mode-syntax-table)
361
362 ;; a single hyphen is punctuation, but a double hyphen starts a comment
363 (modify-syntax-entry ?- ". 12" ada-mode-syntax-table)
364
365 ;; and \f and \n end a comment
366 (modify-syntax-entry ?\f "> " ada-mode-syntax-table)
367 (modify-syntax-entry ?\n "> " ada-mode-syntax-table)
368
369 ;; define what belongs in ada symbols
370 (modify-syntax-entry ?_ "_" ada-mode-syntax-table)
371
372 ;; define parentheses to match
373 (modify-syntax-entry ?\( "()" ada-mode-syntax-table)
374 (modify-syntax-entry ?\) ")(" ada-mode-syntax-table)
375
376 (setq ada-mode-symbol-syntax-table (copy-syntax-table ada-mode-syntax-table))
377 (modify-syntax-entry ?_ "w" ada-mode-symbol-syntax-table)
378 )
379
380
381 ;;;###autoload
382 (defun ada-mode ()
383 "Ada Mode is the major mode for editing Ada code.
384
385 Bindings are as follows: (Note: 'LFD' is control-j.)
386
387 Indent line '\\[ada-tab]'
388 Indent line, insert newline and indent the new line. '\\[newline-and-indent]'
389
390 Re-format the parameter-list point is in '\\[ada-format-paramlist]'
391 Indent all lines in region '\\[ada-indent-region]'
392 Call external pretty printer program '\\[ada-call-pretty-printer]'
393
394 Adjust case of identifiers and keywords in region '\\[ada-adjust-case-region]'
395 Adjust case of identifiers and keywords in buffer '\\[ada-adjust-case-buffer]'
396
397 Call EXTERNAL pretty printer (if you have one) '\\[ada-call-pretty-printer]'
398
399 Fill comment paragraph '\\[ada-fill-comment-paragraph]'
400 Fill comment paragraph and justify each line '\\[ada-fill-comment-paragraph-justify]'
401 Fill comment paragraph, justify and append postfix '\\[ada-fill-comment-paragraph-postfix]'
402
403 Next func/proc/task '\\[ada-next-procedure]' Previous func/proc/task '\\[ada-previous-procedure]'
404 Next package '\\[ada-next-package]' Previous package '\\[ada-previous-package]'
405
406 Goto matching start of current 'end ...;' '\\[ada-move-to-start]'
407 Goto end of current block '\\[ada-move-to-end]'
408
409 Comments are handled using standard GNU Emacs conventions, including:
410 Start a comment '\\[indent-for-comment]'
411 Comment region '\\[comment-region]'
412 Uncomment region '\\[ada-uncomment-region]'
413 Continue comment on next line '\\[indent-new-comment-line]'
414
415 If you use imenu.el:
416 Display index-menu of functions & procedures '\\[imenu]'
417
418 If you use find-file.el:
419 Switch to other file (Body <-> Spec) '\\[ff-find-other-file]'
420 or '\\[ff-mouse-find-other-file]
421 Switch to other file in other window '\\[ada-ff-other-window]'
422 or '\\[ff-mouse-find-other-file-other-window]
423 If you use this function in a spec and no body is available, it gets created
424 with body stubs.
425
426 If you use ada-xref.el:
427 Goto declaration: '\\[ada-point-and-xref]' on the identifier
428 or '\\[ada-goto-declaration]' with point on the identifier
429 Complete identifier: '\\[ada-complete-identifier]'
430 Execute Gnatf: '\\[ada-gnatf-current]'"
431
432 (interactive)
433 (kill-all-local-variables)
434
435 (make-local-variable 'require-final-newline)
436 (setq require-final-newline t)
437
438 (make-local-variable 'comment-start)
439 (setq comment-start "-- ")
440
441 ;; comment end must be set because it may hold a wrong value if
442 ;; this buffer had been in another mode before. RE
443 (make-local-variable 'comment-end)
444 (setq comment-end "")
445
446 (make-local-variable 'comment-start-skip) ;; used by autofill
447 (setq comment-start-skip "--+[ \t]*")
448
449 (make-local-variable 'indent-line-function)
450 (setq indent-line-function 'ada-indent-current-function)
451
452 (make-local-variable 'fill-column)
453 (setq fill-column 75)
454
455 (make-local-variable 'comment-column)
456 (setq comment-column 40)
457
458 (make-local-variable 'parse-sexp-ignore-comments)
459 (setq parse-sexp-ignore-comments t)
460
461 (make-local-variable 'case-fold-search)
462 (setq case-fold-search t)
463
464 (make-local-variable 'fill-paragraph-function)
465 (setq fill-paragraph-function 'ada-fill-comment-paragraph)
466
467 (setq major-mode 'ada-mode)
468 (setq mode-name "Ada")
469
470 (setq blink-matching-paren t)
471
472 (use-local-map ada-mode-map)
473
474 (if ada-mode-syntax-table
475 (set-syntax-table ada-mode-syntax-table)
476 (ada-create-syntax-table))
477
478 (if ada-clean-buffer-before-saving
479 (progn
480 ;; remove all spaces at the end of lines in the whole buffer.
481 (add-hook 'local-write-file-hooks 'ada-remove-trailing-spaces)
482 ;; convert all tabs to the correct number of spaces.
483 (add-hook 'local-write-file-hooks 'ada-untabify-buffer)))
484
485
486 ;; add menu 'Ada' to the menu bar
487 (ada-add-ada-menu)
488
489 (run-hooks 'ada-mode-hook)
490
491 ;; the following has to be done after running the ada-mode-hook
492 ;; because users might want to set the values of these variable
493 ;; inside the hook (MH)
494
495 (cond ((eq ada-language-version 'ada83)
496 (setq ada-keywords ada-83-keywords))
497 ((eq ada-language-version 'ada95)
498 (setq ada-keywords ada-95-keywords)))
499
500 (if ada-auto-case
501 (ada-activate-keys-for-case)))
502
503
504 ;;;--------------------------
505 ;;; Fill Comment Paragraph
506 ;;;--------------------------
507
508 (defun ada-fill-comment-paragraph-justify ()
509 "Fills current comment paragraph and justifies each line as well."
510 (interactive)
511 (ada-fill-comment-paragraph t))
512
513
514 (defun ada-fill-comment-paragraph-postfix ()
515 "Fills current comment paragraph and justifies each line as well.
516 Prompts for a postfix to be appended to each line."
517 (interactive)
518 (ada-fill-comment-paragraph t t))
519
520
521 (defun ada-fill-comment-paragraph (&optional justify postfix)
522 "Fills the current comment paragraph.
523 If JUSTIFY is non-nil, each line is justified as well.
524 If POSTFIX and JUSTIFY are non-nil, ada-fill-comment-postfix is appended
525 to each filled and justified line.
526 If ada-indent-comment-as code is non-nil, the paragraph is idented."
527 (interactive "P")
528 (let ((opos (point-marker))
529 (begin nil)
530 (end nil)
531 (end-2 nil)
532 (indent nil)
533 (ada-fill-comment-old-postfix "")
534 (fill-prefix nil))
535
536 ;; check if inside comment
537 (if (not (ada-in-comment-p))
538 (error "not inside comment"))
539
540 ;; prompt for postfix if wanted
541 (if (and justify
542 postfix)
543 (setq ada-fill-comment-postfix
544 (read-from-minibuffer "enter new postfix string: "
545 ada-fill-comment-postfix)))
546
547 ;; prompt for old postfix to remove if necessary
548 (if (and justify
549 postfix)
550 (setq ada-fill-comment-old-postfix
551 (read-from-minibuffer "enter already existing postfix string: "
552 ada-fill-comment-postfix)))
553
554 ;;
555 ;; find limits of paragraph
556 ;;
557 (message "filling comment paragraph ...")
558 (save-excursion
559 (back-to-indentation)
560 ;; find end of paragraph
561 (while (and (looking-at "--.*$")
562 (not (looking-at "--[ \t]*$")))
563 (forward-line 1)
564 (back-to-indentation))
565 (beginning-of-line)
566 (setq end (point-marker))
567 (goto-char opos)
568 ;; find begin of paragraph
569 (back-to-indentation)
570 (while (and (looking-at "--.*$")
571 (not (looking-at "--[ \t]*$")))
572 (forward-line -1)
573 (back-to-indentation))
574 (forward-line 1)
575 ;; get indentation to calculate width for filling
576 (ada-indent-current)
577 (back-to-indentation)
578 (setq indent (current-column))
579 (setq begin (point-marker)))
580
581 ;; delete old postfix if necessary
582 (if (and justify
583 postfix)
584 (save-excursion
585 (goto-char begin)
586 (while (re-search-forward (concat ada-fill-comment-old-postfix
587 "\n")
588 end t)
589 (replace-match "\n"))))
590
591 ;; delete leading whitespace and uncomment
592 (save-excursion
593 (goto-char begin)
594 (beginning-of-line)
595 (while (re-search-forward "^[ \t]*--[ \t]*" end t)
596 (replace-match "")))
597
598 ;; calculate fill width
599 (setq fill-column (- fill-column indent
600 (length ada-fill-comment-prefix)
601 (if postfix
602 (length ada-fill-comment-postfix)
603 0)))
604 ;; fill paragraph
605 (fill-region begin (1- end) justify)
606 (setq fill-column (+ fill-column indent
607 (length ada-fill-comment-prefix)
608 (if postfix
609 (length ada-fill-comment-postfix)
610 0)))
611 ;; find end of second last line
612 (save-excursion
613 (goto-char end)
614 (forward-line -2)
615 (end-of-line)
616 (setq end-2 (point-marker)))
617
618 ;; re-comment and re-indent region
619 (save-excursion
620 (goto-char begin)
621 (indent-to indent)
622 (insert ada-fill-comment-prefix)
623 (while (re-search-forward "\n" (1- end-2) t)
624 (replace-match (concat "\n" ada-fill-comment-prefix))
625 (beginning-of-line)
626 (indent-to indent)))
627
628 ;; append postfix if wanted
629 (if (and justify
630 postfix
631 ada-fill-comment-postfix)
632 (progn
633 ;; append postfix up to there
634 (save-excursion
635 (goto-char begin)
636 (while (re-search-forward "\n" (1- end-2) t)
637 (replace-match (concat ada-fill-comment-postfix "\n")))
638
639 ;; fill last line and append postfix
640 (end-of-line)
641 (insert-char ?
642 (- fill-column
643 (current-column)
644 (length ada-fill-comment-postfix)))
645 (insert ada-fill-comment-postfix))))
646
647 ;; delete the extra line that gets inserted somehow(??)
648 (save-excursion
649 (goto-char (1- end))
650 (end-of-line)
651 (delete-char 1))
652
653 (message "filling comment paragraph ... done")
654 (goto-char opos))
655 t)
656
657
658 ;;;--------------------------------;;;
659 ;;; Call External Pretty Printer ;;;
660 ;;;--------------------------------;;;
661
662 (defun ada-call-pretty-printer ()
663 "Calls the external Pretty Printer.
664 The name is specified in ada-external-pretty-print-program. Saves the
665 current buffer in a directory specified by ada-tmp-directory,
666 starts the Pretty Printer as external process on that file and then
667 reloads the beautyfied program in the buffer and cleans up
668 ada-tmp-directory."
669 (interactive)
670 (let ((filename-with-path buffer-file-name)
671 (curbuf (current-buffer))
672 (orgpos (point))
673 (mesgbuf nil) ;; for byte-compiling
674 (file-path (file-name-directory buffer-file-name))
675 (filename-without-path (file-name-nondirectory buffer-file-name))
676 (tmp-file-with-directory
677 (concat ada-tmp-directory
678 (file-name-nondirectory buffer-file-name))))
679 ;;
680 ;; save buffer in temporary file
681 ;;
682 (message "saving current buffer to temporary file ...")
683 (write-file tmp-file-with-directory)
684 (auto-save-mode nil)
685 (message "saving current buffer to temporary file ... done")
686 ;;
687 ;; call external pretty printer program
688 ;;
689
690 (message "running external pretty printer ...")
691 ;; create a temporary buffer for messages of pretty printer
692 (setq mesgbuf (get-buffer-create "Pretty Printer Messages"))
693 ;; execute pretty printer on temporary file
694 (call-process ada-external-pretty-print-program
695 nil mesgbuf t
696 tmp-file-with-directory)
697 ;; display messages if there are some
698 (if (buffer-modified-p mesgbuf)
699 ;; show the message buffer
700 (display-buffer mesgbuf t)
701 ;; kill the message buffer
702 (kill-buffer mesgbuf))
703 (message "running external pretty printer ... done")
704 ;;
705 ;; kill current buffer and load pretty printer output
706 ;; or restore old buffer
707 ;;
708 (if (y-or-n-p
709 "Really replace current buffer with pretty printer output ? ")
710 (progn
711 (set-buffer-modified-p nil)
712 (kill-buffer curbuf)
713 (find-file tmp-file-with-directory))
714 (message "old buffer contents restored"))
715 ;;
716 ;; delete temporary file and restore information of current buffer
717 ;;
718 (delete-file tmp-file-with-directory)
719 (set-visited-file-name filename-with-path)
720 (auto-save-mode t)
721 (goto-char orgpos)))
722
723
724 ;;;---------------
725 ;;; auto-casing
726 ;;;---------------
727
728 ;; from Philippe Waroquiers <philippe@cfmu.eurocontrol.be>
729 ;; modifiedby RE and MH
730
731 (defun ada-after-keyword-p ()
732 ;; returns t if cursor is after a keyword.
733 (save-excursion
734 (forward-word -1)
735 (and (save-excursion
736 (or
737 (= (point) (point-min))
738 (backward-char 1))
739 (not (looking-at "_"))) ; (MH)
740 (looking-at (concat ada-keywords "[^_]")))))
741
742 (defun ada-after-char-p ()
743 ;; returns t if after ada character "'". This is interpreted as being
744 ;; in a character constant.
745 (save-excursion
746 (if (> (point) 2)
747 (progn
748 (forward-char -2)
749 (looking-at "'"))
750 nil)))
751
752
753 (defun ada-adjust-case (&optional force-identifier)
754 "Adjust the case of the word before the just-typed character,
755 according to ada-case-keyword and ada-case-identifier
756 If FORCE-IDENTIFIER is non-nil then also adjust keyword as
757 identifier." ; (MH)
758 (forward-char -1)
759 (if (and (> (point) 1) (not (or (ada-in-string-p)
760 (ada-in-comment-p)
761 (ada-after-char-p))))
762 (if (eq (char-syntax (char-after (1- (point)))) ?w)
763 (if (save-excursion
764 (forward-word -1)
765 (or (= (point) (point-min))
766 (backward-char 1))
767 (looking-at "'"))
768 (funcall ada-case-attribute -1)
769 (if (and
770 (not force-identifier) ; (MH)
771 (ada-after-keyword-p))
772 (funcall ada-case-keyword -1)
773 (funcall ada-case-identifier -1)))))
774 (forward-char 1))
775
776
777 (defun ada-adjust-case-interactive (arg)
778 (interactive "P")
779 (let ((lastk last-command-char))
780 (cond ((or (eq lastk ?\n)
781 (eq lastk ?\r))
782 ;; horrible kludge
783 (insert " ")
784 (ada-adjust-case)
785 ;; horrible dekludge
786 (delete-backward-char 1)
787 ;; some special keys and their bindings
788 (cond
789 ((eq lastk ?\n)
790 (funcall ada-lfd-binding))
791 ((eq lastk ?\r)
792 (funcall ada-ret-binding))))
793 ((eq lastk ?\C-i) (ada-tab))
794 ((self-insert-command (prefix-numeric-value arg))))
795 ;; if there is a keyword in front of the underscore
796 ;; then it should be part of an identifier (MH)
797 (if (eq lastk ?_)
798 (ada-adjust-case t)
799 (ada-adjust-case))))
800
801
802 (defun ada-activate-keys-for-case ()
803 ;; save original keybindings to allow swapping ret/lfd
804 ;; when casing is activated
805 ;; the 'or ...' is there to be sure that the value will not
806 ;; be changed again when ada-mode is called more than once (MH)
807 (or ada-ret-binding
808 (setq ada-ret-binding (key-binding "\C-M")))
809 (or ada-lfd-binding
810 (setq ada-lfd-binding (key-binding "\C-j")))
811 ;; call case modifying function after certain keys.
812 (mapcar (function (lambda(key) (define-key
813 ada-mode-map
814 (char-to-string key)
815 'ada-adjust-case-interactive)))
816 '( ?` ?~ ?! ?@ ?# ?$ ?% ?^ ?& ?* ?( ?) ?- ?= ?+ ?[ ?{ ?] ?}
817 ?_ ?\\ ?| ?\; ?: ?' ?\" ?< ?, ?. ?> ?? ?/ ?\n 32 ?\r )))
818 ;; deleted ?\t from above list
819
820 ;;
821 ;; added by MH
822 ;;
823 (defun ada-loose-case-word (&optional arg)
824 "Capitalizes the first and the letters following _
825 ARG is ignored, it's there to fit the standard casing functions' style."
826 (let ((pos (point))
827 (first t))
828 (skip-chars-backward "a-zA-Z0-9_")
829 (while (or first
830 (search-forward "_" pos t))
831 (and first
832 (setq first nil))
833 (insert-char (upcase (following-char)) 1)
834 (delete-char 1))
835 (goto-char pos)))
836
837
838 ;;
839 ;; added by MH
840 ;;
841 (defun ada-adjust-case-region (from to)
842 "Adjusts the case of all identifiers and keywords in the region.
843 ATTENTION: This function might take very long for big regions !"
844 (interactive "*r")
845 (let ((begin nil)
846 (end nil)
847 (keywordp nil)
848 (reldiff nil))
849 (unwind-protect
850 (save-excursion
851 (set-syntax-table ada-mode-symbol-syntax-table)
852 (goto-char to)
853 ;;
854 ;; loop: look for all identifiers and keywords
855 ;;
856 (while (re-search-backward
857 "[^a-zA-Z0-9_]\\([a-zA-Z0-9_]+\\)[^a-zA-Z0-9_]"
858 from
859 t)
860 ;;
861 ;; print status message
862 ;;
863 (setq reldiff (- (point) from))
864 (message (format "adjusting case ... %5d characters left"
865 (- (point) from)))
866 (forward-char 1)
867 (or
868 ;; do nothing if it is a string or comment
869 (ada-in-string-or-comment-p)
870 (progn
871 ;;
872 ;; get the identifier or keyword
873 ;;
874 (setq begin (point))
875 (setq keywordp (looking-at (concat ada-keywords "[^_]")))
876 (skip-chars-forward "a-zA-Z0-9_")
877 ;;
878 ;; casing according to user-option
879 ;;
880 (if keywordp
881 (funcall ada-case-keyword -1)
882 (funcall ada-case-identifier -1))
883 (goto-char begin))))
884 (message "adjusting case ... done"))
885 (set-syntax-table ada-mode-syntax-table))))
886
887
888 ;;
889 ;; added by MH
890 ;;
891 (defun ada-adjust-case-buffer ()
892 "Adjusts the case of all identifiers and keywords in the whole buffer.
893 ATTENTION: This function might take very long for big buffers !"
894 (interactive "*")
895 (ada-adjust-case-region (point-min) (point-max)))
896
897
898 ;;;------------------------;;;
899 ;;; Format Parameter Lists ;;;
900 ;;;------------------------;;;
901
902 (defun ada-format-paramlist ()
903 "Re-formats a parameter-list.
904 ATTENTION: 1) Comments inside the list are killed !
905 2) If the syntax is not correct (especially, if there are
906 semicolons missing), it can get totally confused !
907 In such a case, use 'undo', correct the syntax and try again."
908
909 (interactive)
910 (let ((begin nil)
911 (end nil)
912 (delend nil)
913 (paramlist nil))
914 (unwind-protect
915 (progn
916 (set-syntax-table ada-mode-symbol-syntax-table)
917
918 ;; check if really inside parameter list
919 (or (ada-in-paramlist-p)
920 (error "not in parameter list"))
921 ;;
922 ;; find start of current parameter-list
923 ;;
924 (ada-search-ignore-string-comment
925 (concat "\\<\\("
926 "procedure\\|function\\|body\\|package\\|task\\|entry\\|accept"
927 "\\)\\>") t nil)
928 (ada-search-ignore-string-comment "(" nil nil t)
929 (backward-char 1)
930 (setq begin (point))
931
932 ;;
933 ;; find end of parameter-list
934 ;;
935 (forward-sexp 1)
936 (setq delend (point))
937 (delete-char -1)
938
939 ;;
940 ;; find end of last parameter-declaration
941 ;;
942 (ada-search-ignore-string-comment "[^ \t\n]" t nil t)
943 (forward-char 1)
944 (setq end (point))
945
946 ;;
947 ;; build a list of all elements of the parameter-list
948 ;;
949 (setq paramlist (ada-scan-paramlist (1+ begin) end))
950
951 ;;
952 ;; delete the original parameter-list
953 ;;
954 (delete-region begin (1- delend))
955
956 ;;
957 ;; insert the new parameter-list
958 ;;
959 (goto-char begin)
960 (ada-insert-paramlist paramlist))
961
962 ;;
963 ;; restore syntax-table
964 ;;
965 (set-syntax-table ada-mode-syntax-table)
966 )))
967
968
969 (defun ada-scan-paramlist (begin end)
970 ;; Scans a parameter-list between BEGIN and END and returns a list
971 ;; of its contents.
972 ;; The list has the following format:
973 ;;
974 ;; Name of Param in? out? accept? Name of Type Default-Exp or nil
975 ;;
976 ;; ( ('Name_Param_1' t nil t Type_Param_1 ':= expression')
977 ;; ('Name_Param_2' nil nil t Type_Param_2 nil) )
978
979 (let ((paramlist (list))
980 (param (list))
981 (notend t)
982 (apos nil)
983 (epos nil)
984 (semipos nil)
985 (match-cons nil))
986
987 (goto-char begin)
988 ;;
989 ;; loop until end of last parameter
990 ;;
991 (while notend
992
993 ;;
994 ;; find first character of parameter-declaration
995 ;;
996 (ada-goto-next-non-ws)
997 (setq apos (point))
998
999 ;;
1000 ;; find last character of parameter-declaration
1001 ;;
1002 (if (setq match-cons
1003 (ada-search-ignore-string-comment "[ \t\n]*;" nil end t))
1004 (progn
1005 (setq epos (car match-cons))
1006 (setq semipos (cdr match-cons)))
1007 (setq epos end))
1008
1009 ;;
1010 ;; read name(s) of parameter(s)
1011 ;;
1012 (goto-char apos)
1013 (looking-at "\\([a-zA-Z0-9_, \t\n]*[a-zA-Z0-9_]\\)[ \t\n]*:[^=]")
1014
1015 (setq param (list (buffer-substring (match-beginning 1)
1016 (match-end 1))))
1017 (ada-search-ignore-string-comment ":" nil epos t)
1018
1019 ;;
1020 ;; look for 'in'
1021 ;;
1022 (setq apos (point))
1023 (setq param
1024 (append param
1025 (list
1026 (consp
1027 (ada-search-ignore-string-comment "\\<in\\>"
1028 nil
1029 epos
1030 t)))))
1031
1032 ;;
1033 ;; look for 'out'
1034 ;;
1035 (goto-char apos)
1036 (setq param
1037 (append param
1038 (list
1039 (consp
1040 (ada-search-ignore-string-comment "\\<out\\>"
1041 nil
1042 epos
1043 t)))))
1044
1045 ;;
1046 ;; look for 'accept'
1047 ;;
1048 (goto-char apos)
1049 (setq param
1050 (append param
1051 (list
1052 (consp
1053 (ada-search-ignore-string-comment "\\<accept\\>"
1054 nil
1055 epos
1056 t)))))
1057
1058 ;;
1059 ;; skip 'in'/'out'/'accept'
1060 ;;
1061 (goto-char apos)
1062 (ada-goto-next-non-ws)
1063 (while (looking-at "\\<\\(in\\|out\\|accept\\)\\>")
1064 (forward-word 1)
1065 (ada-goto-next-non-ws))
1066
1067 ;;
1068 ;; read type of parameter
1069 ;;
1070 (looking-at "\\<[a-zA-Z0-9_\\.]+\\>")
1071 (setq param
1072 (append param
1073 (list
1074 (buffer-substring (match-beginning 0)
1075 (match-end 0)))))
1076
1077 ;;
1078 ;; read default-expression, if there is one
1079 ;;
1080 (goto-char (setq apos (match-end 0)))
1081 (setq param
1082 (append param
1083 (list
1084 (if (setq match-cons
1085 (ada-search-ignore-string-comment ":="
1086 nil
1087 epos
1088 t))
1089 (buffer-substring (car match-cons)
1090 epos)
1091 nil))))
1092 ;;
1093 ;; add this parameter-declaration to the list
1094 ;;
1095 (setq paramlist (append paramlist (list param)))
1096
1097 ;;
1098 ;; check if it was the last parameter
1099 ;;
1100 (if (eq epos end)
1101 (setq notend nil)
1102 (goto-char semipos))
1103
1104 ) ; end of loop
1105
1106 (reverse paramlist)))
1107
1108
1109 (defun ada-insert-paramlist (paramlist)
1110 ;; Inserts a formatted PARAMLIST in the buffer.
1111 ;; See doc of ada-scan-paramlist for the format.
1112 (let ((i (length paramlist))
1113 (parlen 0)
1114 (typlen 0)
1115 (temp 0)
1116 (inp nil)
1117 (outp nil)
1118 (acceptp nil)
1119 (column nil)
1120 (orgpoint 0)
1121 (firstcol nil))
1122
1123 ;;
1124 ;; loop until last parameter
1125 ;;
1126 (while (not (zerop i))
1127 (setq i (1- i))
1128
1129 ;;
1130 ;; get max length of parameter-name
1131 ;;
1132 (setq parlen
1133 (if (<= parlen (setq temp
1134 (length (nth 0 (nth i paramlist)))))
1135 temp
1136 parlen))
1137
1138 ;;
1139 ;; get max length of type-name
1140 ;;
1141 (setq typlen
1142 (if (<= typlen (setq temp
1143 (length (nth 4 (nth i paramlist)))))
1144 temp
1145 typlen))
1146
1147 ;;
1148 ;; is there any 'in' ?
1149 ;;
1150 (setq inp
1151 (or inp
1152 (nth 1 (nth i paramlist))))
1153
1154 ;;
1155 ;; is there any 'out' ?
1156 ;;
1157 (setq outp
1158 (or outp
1159 (nth 2 (nth i paramlist))))
1160
1161 ;;
1162 ;; is there any 'accept' ?
1163 ;;
1164 (setq acceptp
1165 (or acceptp
1166 (nth 3 (nth i paramlist))))) ; end of loop
1167
1168 ;;
1169 ;; does paramlist already start on a separate line ?
1170 ;;
1171 (if (save-excursion
1172 (re-search-backward "^.\\|[^ \t]" nil t)
1173 (looking-at "^."))
1174 ;; yes => re-indent it
1175 (ada-indent-current)
1176 ;;
1177 ;; no => insert newline and indent it
1178 ;;
1179 (progn
1180 (ada-indent-current)
1181 (newline)
1182 (delete-horizontal-space)
1183 (setq orgpoint (point))
1184 (setq column (save-excursion
1185 (funcall (ada-indent-function) orgpoint)))
1186 (indent-to column)
1187 ))
1188
1189 (insert "(")
1190
1191 (setq firstcol (current-column))
1192 (setq i (length paramlist))
1193
1194 ;;
1195 ;; loop until last parameter
1196 ;;
1197 (while (not (zerop i))
1198 (setq i (1- i))
1199 (setq column firstcol)
1200
1201 ;;
1202 ;; insert parameter-name, space and colon
1203 ;;
1204 (insert (nth 0 (nth i paramlist)))
1205 (indent-to (+ column parlen 1))
1206 (insert ": ")
1207 (setq column (current-column))
1208
1209 ;;
1210 ;; insert 'in' or space
1211 ;;
1212 (if (nth 1 (nth i paramlist))
1213 (insert "in ")
1214 (if (and
1215 (or inp
1216 acceptp)
1217 (not (nth 3 (nth i paramlist))))
1218 (insert " ")))
1219
1220 ;;
1221 ;; insert 'out' or space
1222 ;;
1223 (if (nth 2 (nth i paramlist))
1224 (insert "out ")
1225 (if (and
1226 (or outp
1227 acceptp)
1228 (not (nth 3 (nth i paramlist))))
1229 (insert " ")))
1230
1231 ;;
1232 ;; insert 'accept'
1233 ;;
1234 (if (nth 3 (nth i paramlist))
1235 (insert "accept "))
1236
1237 (setq column (current-column))
1238
1239 ;;
1240 ;; insert type-name and, if necessary, space and default-expression
1241 ;;
1242 (insert (nth 4 (nth i paramlist)))
1243 (if (nth 5 (nth i paramlist))
1244 (progn
1245 (indent-to (+ column typlen 1))
1246 (insert (nth 5 (nth i paramlist)))))
1247
1248 ;;
1249 ;; check if it was the last parameter
1250 ;;
1251 (if (not (zerop i))
1252 ;; no => insert ';' and newline and indent
1253 (progn
1254 (insert ";")
1255 (newline)
1256 (indent-to firstcol))
1257 ;; yes
1258 (insert ")"))
1259
1260 ) ; end of loop
1261
1262 ;;
1263 ;; if anything follows, except semicolon:
1264 ;; put it in a new line and indent it
1265 ;;
1266 (if (not (looking-at "[ \t]*[;\n]"))
1267 (ada-indent-newline-indent))
1268
1269 ))
1270
1271
1272 ;;;----------------------------;;;
1273 ;;; Move To Matching Start/End ;;;
1274 ;;;----------------------------;;;
1275
1276 (defun ada-move-to-start ()
1277 "Moves point to the matching start of the current end ... around point."
1278 (interactive)
1279 (let ((pos (point)))
1280 (unwind-protect
1281 (progn
1282 (set-syntax-table ada-mode-symbol-syntax-table)
1283
1284 (message "searching for block start ...")
1285 (save-excursion
1286 ;;
1287 ;; do nothing if in string or comment or not on 'end ...;'
1288 ;; or if an error occurs during processing
1289 ;;
1290 (or
1291 (ada-in-string-or-comment-p)
1292 (and (progn
1293 (or (looking-at "[ \t]*\\<end\\>")
1294 (backward-word 1))
1295 (or (looking-at "[ \t]*\\<end\\>")
1296 (backward-word 1))
1297 (or (looking-at "[ \t]*\\<end\\>")
1298 (error "not on end ...;")))
1299 (ada-goto-matching-start 1)
1300 (setq pos (point))
1301
1302 ;;
1303 ;; on 'begin' => go on, according to user option
1304 ;;
1305 ada-move-to-declaration
1306 (looking-at "\\<begin\\>")
1307 (ada-goto-matching-decl-start)
1308 (setq pos (point))))
1309
1310 ) ; end of save-excursion
1311
1312 ;; now really move to the found position
1313 (goto-char pos)
1314 (message "searching for block start ... done"))
1315
1316 ;;
1317 ;; restore syntax-table
1318 ;;
1319 (set-syntax-table ada-mode-syntax-table))))
1320
1321
1322 (defun ada-move-to-end ()
1323 "Moves point to the matching end of the current block around point.
1324 Moves to 'begin' if in a declarative part."
1325 (interactive)
1326 (let ((pos (point))
1327 (decstart nil)
1328 (packdecl nil))
1329 (unwind-protect
1330 (progn
1331 (set-syntax-table ada-mode-symbol-syntax-table)
1332
1333 (message "searching for block end ...")
1334 (save-excursion
1335
1336 (forward-char 1)
1337 (cond
1338 ;; directly on 'begin'
1339 ((save-excursion
1340 (ada-goto-previous-word)
1341 (looking-at "\\<begin\\>"))
1342 (ada-goto-matching-end 1))
1343 ;; on first line of defun declaration
1344 ((save-excursion
1345 (and (ada-goto-stmt-start)
1346 (looking-at "\\<function\\>\\|\\<procedure\\>" )))
1347 (ada-search-ignore-string-comment "\\<begin\\>"))
1348 ;; on first line of task declaration
1349 ((save-excursion
1350 (and (ada-goto-stmt-start)
1351 (looking-at "\\<task\\>" )
1352 (forward-word 1)
1353 (ada-search-ignore-string-comment "[^ \n\t]")
1354 (not (backward-char 1))
1355 (looking-at "\\<body\\>")))
1356 (ada-search-ignore-string-comment "\\<begin\\>"))
1357 ;; accept block start
1358 ((save-excursion
1359 (and (ada-goto-stmt-start)
1360 (looking-at "\\<accept\\>" )))
1361 (ada-goto-matching-end 0))
1362 ;; package start
1363 ((save-excursion
1364 (and (ada-goto-matching-decl-start t)
1365 (looking-at "\\<package\\>")))
1366 (ada-goto-matching-end 1))
1367 ;; inside a 'begin' ... 'end' block
1368 ((save-excursion
1369 (ada-goto-matching-decl-start t))
1370 (ada-search-ignore-string-comment "\\<begin\\>"))
1371 ;; (hopefully ;-) everything else
1372 (t
1373 (ada-goto-matching-end 1)))
1374 (setq pos (point))
1375
1376 ) ; end of save-excursion
1377
1378 ;; now really move to the found position
1379 (goto-char pos)
1380 (message "searching for block end ... done"))
1381
1382 ;;
1383 ;; restore syntax-table
1384 ;;
1385 (set-syntax-table ada-mode-syntax-table))))
1386
1387
1388 ;;;-----------------------------;;;
1389 ;;; Functions For Indentation ;;;
1390 ;;;-----------------------------;;;
1391
1392 ;; ---- main functions for indentation
1393
1394 (defun ada-indent-region (beg end)
1395 "Indents the region using ada-indent-current on each line."
1396 (interactive "*r")
1397 (goto-char beg)
1398 (let ((block-done 0)
1399 (lines-remaining (count-lines beg end))
1400 (msg (format "indenting %4d lines %%4d lines remaining ..."
1401 (count-lines beg end)))
1402 (endmark (copy-marker end)))
1403 ;; catch errors while indenting
1404 (condition-case err
1405 (while (< (point) endmark)
1406 (if (> block-done 9)
1407 (progn (message (format msg lines-remaining))
1408 (setq block-done 0)))
1409 (if (looking-at "^$") nil
1410 (ada-indent-current))
1411 (forward-line 1)
1412 (setq block-done (1+ block-done))
1413 (setq lines-remaining (1- lines-remaining)))
1414 ;; show line number where the error occured
1415 (error
1416 (error (format "line %d: %s"
1417 (1+ (count-lines (point-min) (point)))
1418 err) nil)))
1419 (message "indenting ... done")))
1420
1421
1422 (defun ada-indent-newline-indent ()
1423 "Indents the current line, inserts a newline and then indents the new line."
1424 (interactive "*")
1425 (let ((column)
1426 (orgpoint))
1427
1428 (ada-indent-current)
1429 (newline)
1430 (delete-horizontal-space)
1431 (setq orgpoint (point))
1432
1433 (unwind-protect
1434 (progn
1435 (set-syntax-table ada-mode-symbol-syntax-table)
1436
1437 (setq column (save-excursion
1438 (funcall (ada-indent-function) orgpoint))))
1439
1440 ;;
1441 ;; restore syntax-table
1442 ;;
1443 (set-syntax-table ada-mode-syntax-table))
1444
1445 (indent-to column)
1446
1447 ;; The following is needed to ensure that indentation will still be
1448 ;; correct if something follows behind point when typing LFD
1449 ;; For example: Imagine point to be there (*) when LFD is typed:
1450 ;; while cond loop
1451 ;; null; *end loop;
1452 ;; Result without the following statement would be:
1453 ;; while cond loop
1454 ;; null;
1455 ;; *end loop;
1456 ;; You would then have to type TAB to correct it.
1457 ;; If that doesn't bother you, you can comment out the following
1458 ;; statement to speed up indentation a LITTLE bit.
1459
1460 (if (not (looking-at "[ \t]*$"))
1461 (ada-indent-current))
1462 ))
1463
1464
1465 (defun ada-indent-current ()
1466 "Indents current line as Ada code.
1467 This works by two steps:
1468 1) It moves point to the end of the previous code-line.
1469 Then it calls the function to calculate the indentation for the
1470 following line as if a newline would be inserted there.
1471 The calculated column # is saved and the old position of point
1472 is restored.
1473 2) Then another function is called to calculate the indentation for
1474 the current line, based on the previously calculated column #."
1475
1476 (interactive)
1477
1478 (unwind-protect
1479 (progn
1480 (set-syntax-table ada-mode-symbol-syntax-table)
1481
1482 (let ((line-end)
1483 (orgpoint (point-marker))
1484 (cur-indent)
1485 (prev-indent)
1486 (prevline t))
1487
1488 ;;
1489 ;; first step
1490 ;;
1491 (save-excursion
1492 (if (ada-goto-prev-nonblank-line t)
1493 ;;
1494 ;; we are not in the first accessible line in the buffer
1495 ;;
1496 (progn
1497 ;;(end-of-line)
1498 ;;(forward-char 1)
1499 ;; we are already at the BOL
1500 (forward-line 1)
1501 (setq line-end (point))
1502 (setq prev-indent
1503 (save-excursion
1504 (funcall (ada-indent-function) line-end))))
1505 (setq prevline nil)))
1506
1507 (if prevline
1508 ;;
1509 ;; we are not in the first accessible line in the buffer
1510 ;;
1511 (progn
1512 ;;
1513 ;; second step
1514 ;;
1515 (back-to-indentation)
1516 (setq cur-indent (ada-get-current-indent prev-indent))
1517 (delete-horizontal-space)
1518 (indent-to cur-indent)
1519
1520 ;;
1521 ;; restore position of point
1522 ;;
1523 (goto-char orgpoint)
1524 (if (< (current-column) (current-indentation))
1525 (back-to-indentation))))))
1526
1527 ;;
1528 ;; restore syntax-table
1529 ;;
1530 (set-syntax-table ada-mode-syntax-table)))
1531
1532
1533 (defun ada-get-current-indent (prev-indent)
1534 ;; Returns the column # to indent the current line to.
1535 ;; PREV-INDENT is the indentation resulting from the previous lines.
1536 (let ((column nil)
1537 (pos nil)
1538 (match-cons nil))
1539
1540 (cond
1541 ;;
1542 ;; in open parenthesis, but not in parameter-list
1543 ;;
1544 ((and
1545 ada-indent-to-open-paren
1546 (not (ada-in-paramlist-p))
1547 (setq column (ada-in-open-paren-p)))
1548 ;; check if we have something like this (Table_Component_Type =>
1549 ;; Source_File_Record,)
1550 (save-excursion
1551 (if (and (ada-search-ignore-string-comment "[^ \t]" t nil)
1552 (looking-at "\n")
1553 (ada-search-ignore-string-comment "[^ \t\n]" t nil)
1554 (looking-at ">"))
1555 (setq column (+ ada-broken-indent column))))
1556 column)
1557
1558 ;;
1559 ;; end
1560 ;;
1561 ((looking-at "\\<end\\>")
1562 (save-excursion
1563 (ada-goto-matching-start 1)
1564
1565 ;;
1566 ;; found 'loop' => skip back to 'while' or 'for'
1567 ;; if 'loop' is not on a separate line
1568 ;;
1569 (if (and
1570 (looking-at "\\<loop\\>")
1571 (save-excursion
1572 (back-to-indentation)
1573 (not (looking-at "\\<loop\\>"))))
1574 (if (save-excursion
1575 (and
1576 (setq match-cons
1577 (ada-search-ignore-string-comment
1578 ada-loop-start-re t nil))
1579 (not (looking-at "\\<loop\\>"))))
1580 (goto-char (car match-cons))))
1581
1582 (current-indentation)))
1583 ;;
1584 ;; exception
1585 ;;
1586 ((looking-at "\\<exception\\>")
1587 (save-excursion
1588 (ada-goto-matching-start 1)
1589 (current-indentation)))
1590 ;;
1591 ;; when
1592 ;;
1593 ((looking-at "\\<when\\>")
1594 (save-excursion
1595 (ada-goto-matching-start 1)
1596 (+ (current-indentation) ada-when-indent)))
1597 ;;
1598 ;; else
1599 ;;
1600 ((looking-at "\\<else\\>")
1601 (if (save-excursion
1602 (ada-goto-previous-word)
1603 (looking-at "\\<or\\>"))
1604 prev-indent
1605 (save-excursion
1606 (ada-goto-matching-start 1 nil t)
1607 (current-indentation))))
1608 ;;
1609 ;; elsif
1610 ;;
1611 ((looking-at "\\<elsif\\>")
1612 (save-excursion
1613 (ada-goto-matching-start 1 nil t)
1614 (current-indentation)))
1615 ;;
1616 ;; then
1617 ;;
1618 ((looking-at "\\<then\\>")
1619 (if (save-excursion
1620 (ada-goto-previous-word)
1621 (looking-at "\\<and\\>"))
1622 prev-indent
1623 (save-excursion
1624 (ada-search-ignore-string-comment "\\<elsif\\>\\|\\<if\\>" t nil)
1625 (+ (current-indentation) ada-stmt-end-indent))))
1626 ;;
1627 ;; loop
1628 ;;
1629 ((looking-at "\\<loop\\>")
1630 (setq pos (point))
1631 (save-excursion
1632 (goto-char (match-end 0))
1633 (ada-goto-stmt-start)
1634 (if (looking-at "\\<loop\\>\\|\\<if\\>")
1635 prev-indent
1636 (progn
1637 (if (not (looking-at ada-loop-start-re))
1638 (ada-search-ignore-string-comment ada-loop-start-re
1639 nil pos))
1640 (if (looking-at "\\<loop\\>")
1641 prev-indent
1642 (+ (current-indentation) ada-stmt-end-indent))))))
1643 ;;
1644 ;; begin
1645 ;;
1646 ((looking-at "\\<begin\\>")
1647 (save-excursion
1648 (if (ada-goto-matching-decl-start t)
1649 (current-indentation)
1650 (progn
1651 (message "no matching declaration start")
1652 prev-indent))))
1653 ;;
1654 ;; is
1655 ;;
1656 ((looking-at "\\<is\\>")
1657 (if (and
1658 ada-indent-is-separate
1659 (save-excursion
1660 (goto-char (match-end 0))
1661 (ada-goto-next-non-ws (save-excursion
1662 (end-of-line)
1663 (point)))
1664 (looking-at "\\<abstract\\>\\|\\<separate\\>")))
1665 (save-excursion
1666 (ada-goto-stmt-start)
1667 (+ (current-indentation) ada-indent))
1668 (save-excursion
1669 (ada-goto-stmt-start)
1670 (+ (current-indentation) ada-stmt-end-indent))))
1671 ;;
1672 ;; record
1673 ;;
1674 ((looking-at "\\<record\\>")
1675 (save-excursion
1676 (ada-search-ignore-string-comment
1677 "\\<\\(type\\|use\\)\\>" t nil)
1678 (if (looking-at "\\<use\\>")
1679 (ada-search-ignore-string-comment "\\<for\\>" t nil))
1680 (+ (current-indentation) ada-indent-record-rel-type)))
1681 ;;
1682 ;; or as statement-start
1683 ;;
1684 ((ada-looking-at-semi-or)
1685 (save-excursion
1686 (ada-goto-matching-start 1)
1687 (current-indentation)))
1688 ;;
1689 ;; private as statement-start
1690 ;;
1691 ((ada-looking-at-semi-private)
1692 (save-excursion
1693 (ada-goto-matching-decl-start)
1694 (current-indentation)))
1695 ;;
1696 ;; new/abstract/separate
1697 ;;
1698 ((looking-at "\\<\\(new\\|abstract\\|separate\\)\\>")
1699 (- prev-indent ada-indent (- ada-broken-indent)))
1700 ;;
1701 ;; return
1702 ;;
1703 ((looking-at "\\<return\\>")
1704 (save-excursion
1705 (forward-sexp -1)
1706 (if (and (looking-at "(")
1707 (save-excursion
1708 (backward-sexp 2)
1709 (looking-at "\\<function\\>")))
1710 (1+ (current-column))
1711 prev-indent)))
1712 ;;
1713 ;; do
1714 ;;
1715 ((looking-at "\\<do\\>")
1716 (save-excursion
1717 (ada-goto-stmt-start)
1718 (+ (current-indentation) ada-stmt-end-indent)))
1719 ;;
1720 ;; package/function/procedure
1721 ;;
1722 ((and (looking-at "\\<\\(package\\|function\\|procedure\\)\\>")
1723 (save-excursion
1724 (forward-char 1)
1725 (ada-goto-stmt-start)
1726 (looking-at "\\<\\(package\\|function\\|procedure\\)\\>")))
1727 (save-excursion
1728 ;; look for 'generic'
1729 (if (and (ada-goto-matching-decl-start t)
1730 (looking-at "generic"))
1731 (current-column)
1732 prev-indent)))
1733 ;;
1734 ;; label
1735 ;;
1736 ((looking-at "\\<[a-zA-Z0-9_]+[ \t\n]*:[^=]")
1737 (if (ada-in-decl-p)
1738 prev-indent
1739 (+ prev-indent ada-label-indent)))
1740 ;;
1741 ;; identifier and other noindent-statements
1742 ;;
1743 ((looking-at "\\<[a-zA-Z0-9_]+[ \t\n]*")
1744 prev-indent)
1745 ;;
1746 ;; beginning of a parameter list
1747 ;;
1748 ((looking-at "(")
1749 prev-indent)
1750 ;;
1751 ;; end of a parameter list
1752 ;;
1753 ((looking-at ")")
1754 (save-excursion
1755 (forward-char 1)
1756 (backward-sexp 1)
1757 (current-column)))
1758 ;;
1759 ;; comment
1760 ;;
1761 ((looking-at "--")
1762 (if ada-indent-comment-as-code
1763 prev-indent
1764 (current-indentation)))
1765 ;;
1766 ;; unknown syntax - maybe this should signal an error ?
1767 ;;
1768 (t
1769 prev-indent))))
1770
1771
1772 (defun ada-indent-function (&optional nomove)
1773 ;; Returns the function to calculate the indentation for the current
1774 ;; line according to the previous statement, ignoring the contents
1775 ;; of the current line after point. Moves point to the beginning of
1776 ;; the current statement, if NOMOVE is nil.
1777
1778 (let ((orgpoint (point))
1779 (func nil)
1780 (stmt-start nil))
1781 ;;
1782 ;; inside a parameter-list
1783 ;;
1784 (if (ada-in-paramlist-p)
1785 (setq func 'ada-get-indent-paramlist)
1786 (progn
1787 ;;
1788 ;; move to beginning of current statement
1789 ;;
1790 (if (not nomove)
1791 (setq stmt-start (ada-goto-stmt-start)))
1792 ;;
1793 ;; no beginning found => don't change indentation
1794 ;;
1795 (if (and
1796 (eq orgpoint (point))
1797 (not nomove))
1798 (setq func 'ada-get-indent-nochange)
1799
1800 (cond
1801 ;;
1802 ((and
1803 ada-indent-to-open-paren
1804 (ada-in-open-paren-p))
1805 (setq func 'ada-get-indent-open-paren))
1806 ;;
1807 ((looking-at "\\<end\\>")
1808 (setq func 'ada-get-indent-end))
1809 ;;
1810 ((looking-at ada-loop-start-re)
1811 (setq func 'ada-get-indent-loop))
1812 ;;
1813 ((looking-at ada-subprog-start-re)
1814 (setq func 'ada-get-indent-subprog))
1815 ;;
1816 ((looking-at "\\<package\\>")
1817 (setq func 'ada-get-indent-subprog)) ; maybe it needs a
1818 ; special function
1819 ; sometimes ?
1820 ;;
1821 ((looking-at ada-block-start-re)
1822 (setq func 'ada-get-indent-block-start))
1823 ;;
1824 ((looking-at "\\<type\\>")
1825 (setq func 'ada-get-indent-type))
1826 ;;
1827 ((looking-at "\\<\\(els\\)?if\\>")
1828 (setq func 'ada-get-indent-if))
1829 ;;
1830 ((looking-at "\\<case\\>")
1831 (setq func 'ada-get-indent-case))
1832 ;;
1833 ((looking-at "\\<when\\>")
1834 (setq func 'ada-get-indent-when))
1835 ;;
1836 ((looking-at "--")
1837 (setq func 'ada-get-indent-comment))
1838 ;;
1839 ((looking-at "[a-zA-Z0-9_]+[ \t\n]*:[^=]")
1840 (setq func 'ada-get-indent-label))
1841 ;;
1842 ((looking-at "\\<separate\\>")
1843 (setq func 'ada-get-indent-nochange))
1844 (t
1845 (setq func 'ada-get-indent-noindent))))))
1846
1847 func))
1848
1849
1850 ;; ---- functions to return indentation for special cases
1851
1852 (defun ada-get-indent-open-paren (orgpoint)
1853 ;; Returns the indentation (column #) for the new line after ORGPOINT.
1854 ;; Assumes point to be behind an open paranthesis not yet closed.
1855 (ada-in-open-paren-p))
1856
1857
1858 (defun ada-get-indent-nochange (orgpoint)
1859 ;; Returns the indentation (column #) of the current line.
1860 (save-excursion
1861 (forward-line -1)
1862 (current-indentation)))
1863
1864
1865 (defun ada-get-indent-paramlist (orgpoint)
1866 ;; Returns the indentation (column #) for the new line after ORGPOINT.
1867 ;; Assumes point to be inside a parameter-list.
1868 (save-excursion
1869 (ada-search-ignore-string-comment "[^ \t\n]" t nil t)
1870 (cond
1871 ;;
1872 ;; in front of the first parameter
1873 ;;
1874 ((looking-at "(")
1875 (goto-char (match-end 0))
1876 (current-column))
1877 ;;
1878 ;; in front of another parameter
1879 ;;
1880 ((looking-at ";")
1881 (goto-char (cdr (ada-search-ignore-string-comment "(\\|;" t nil t)))
1882 (ada-goto-next-non-ws)
1883 (current-column))
1884 ;;
1885 ;; inside a parameter declaration
1886 ;;
1887 (t
1888 (goto-char (cdr (ada-search-ignore-string-comment "(\\|;" t nil t)))
1889 (ada-goto-next-non-ws)
1890 (+ (current-column) ada-broken-indent)))))
1891
1892
1893 (defun ada-get-indent-end (orgpoint)
1894 ;; Returns the indentation (column #) for the new line after ORGPOINT.
1895 ;; Assumes point to be at the beginning of an end-statement.
1896 ;; Therefore it has to find the corresponding start. This can be a little
1897 ;; slow, if it has to search through big files with many nested blocks.
1898 ;; Signals an error if the corresponding block-start doesn't match.
1899 (let ((defun-name nil)
1900 (indent nil))
1901 ;;
1902 ;; is the line already terminated by ';' ?
1903 ;;
1904 (if (save-excursion
1905 (ada-search-ignore-string-comment ";" nil orgpoint))
1906 ;;
1907 ;; yes, look what's following 'end'
1908 ;;
1909 (progn
1910 (forward-word 1)
1911 (ada-goto-next-non-ws)
1912 (cond
1913 ;;
1914 ;; loop/select/if/case/record/select
1915 ;;
1916 ((looking-at "\\<\\(loop\\|select\\|if\\|case\\|record\\)\\>")
1917 (save-excursion
1918 (ada-check-matching-start
1919 (buffer-substring (match-beginning 0)
1920 (match-end 0)))
1921 (if (looking-at "\\<\\(loop\\|record\\)\\>")
1922 (progn
1923 (forward-word 1)
1924 (ada-goto-stmt-start)))
1925 ;; a label ? => skip it
1926 (if (looking-at "[a-zA-Z0-9_]+[ \n\t]+:")
1927 (progn
1928 (goto-char (match-end 0))
1929 (ada-goto-next-non-ws)))
1930 ;; really looking-at the right thing ?
1931 (or (looking-at (concat "\\<\\("
1932 "loop\\|select\\|if\\|case\\|"
1933 "record\\|while\\|type\\)\\>"))
1934 (progn
1935 (ada-search-ignore-string-comment
1936 (concat "\\<\\("
1937 "loop\\|select\\|if\\|case\\|"
1938 "record\\|while\\|type\\)\\>")))
1939 (backward-word 1))
1940 (current-indentation)))
1941 ;;
1942 ;; a named block end
1943 ;;
1944 ((looking-at ada-ident-re)
1945 (setq defun-name (buffer-substring (match-beginning 0)
1946 (match-end 0)))
1947 (save-excursion
1948 (ada-goto-matching-start 0)
1949 (ada-check-defun-name defun-name)
1950 (current-indentation)))
1951 ;;
1952 ;; a block-end without name
1953 ;;
1954 ((looking-at ";")
1955 (save-excursion
1956 (ada-goto-matching-start 0)
1957 (if (looking-at "\\<begin\\>")
1958 (progn
1959 (setq indent (current-column))
1960 (if (ada-goto-matching-decl-start t)
1961 (current-indentation)
1962 indent)))))
1963 ;;
1964 ;; anything else - should maybe signal an error ?
1965 ;;
1966 (t
1967 (+ (current-indentation) ada-broken-indent))))
1968
1969 (+ (current-indentation) ada-broken-indent))))
1970
1971
1972 (defun ada-get-indent-case (orgpoint)
1973 ;; Returns the indentation (column #) for the new line after ORGPOINT.
1974 ;; Assumes point to be at the beginning of an case-statement.
1975 (let ((cur-indent (current-indentation))
1976 (match-cons nil)
1977 (opos (point)))
1978 (cond
1979 ;;
1980 ;; case..is..when..=>
1981 ;;
1982 ((save-excursion
1983 (setq match-cons (ada-search-ignore-string-comment
1984 "[ \t\n]+=>" nil orgpoint)))
1985 (save-excursion
1986 (goto-char (car match-cons))
1987 (if (not (ada-search-ignore-string-comment "\\<when\\>" t opos))
1988 (error "missing 'when' between 'case' and '=>'"))
1989 (+ (current-indentation) ada-indent)))
1990 ;;
1991 ;; case..is..when
1992 ;;
1993 ((save-excursion
1994 (setq match-cons (ada-search-ignore-string-comment
1995 "\\<when\\>" nil orgpoint)))
1996 (goto-char (cdr match-cons))
1997 (+ (current-indentation) ada-broken-indent))
1998 ;;
1999 ;; case..is
2000 ;;
2001 ((save-excursion
2002 (setq match-cons (ada-search-ignore-string-comment
2003 "\\<is\\>" nil orgpoint)))
2004 (+ (current-indentation) ada-when-indent))
2005 ;;
2006 ;; incomplete case
2007 ;;
2008 (t
2009 (+ (current-indentation) ada-broken-indent)))))
2010
2011
2012 (defun ada-get-indent-when (orgpoint)
2013 ;; Returns the indentation (column #) for the new line after ORGPOINT.
2014 ;; Assumes point to be at the beginning of an when-statement.
2015 (let ((cur-indent (current-indentation)))
2016 (if (ada-search-ignore-string-comment
2017 "[ \t\n]+=>" nil orgpoint)
2018 (+ cur-indent ada-indent)
2019 (+ cur-indent ada-broken-indent))))
2020
2021
2022 (defun ada-get-indent-if (orgpoint)
2023 ;; Returns the indentation (column #) for the new line after ORGPOINT.
2024 ;; Assumes point to be at the beginning of an if-statement.
2025 (let ((cur-indent (current-indentation))
2026 (match-cons nil))
2027 ;;
2028 ;; if..then ?
2029 ;;
2030 (if (ada-search-but-not
2031 "\\<then\\>" "\\<and\\>[ \t\n]+\\<then\\>" nil orgpoint)
2032
2033 (progn
2034 ;;
2035 ;; 'then' first in separate line ?
2036 ;; => indent according to 'then'
2037 ;;
2038 (if (save-excursion
2039 (back-to-indentation)
2040 (looking-at "\\<then\\>"))
2041 (setq cur-indent (current-indentation)))
2042 (forward-word 1)
2043 ;;
2044 ;; something follows 'then' ?
2045 ;;
2046 (if (setq match-cons
2047 (ada-search-ignore-string-comment
2048 "[^ \t\n]" nil orgpoint))
2049 (progn
2050 (goto-char (car match-cons))
2051 (+ ada-indent
2052 (- cur-indent (current-indentation))
2053 (funcall (ada-indent-function t) orgpoint)))
2054
2055 (+ cur-indent ada-indent)))
2056
2057 (+ cur-indent ada-broken-indent))))
2058
2059
2060 (defun ada-get-indent-block-start (orgpoint)
2061 ;; Returns the indentation (column #) for the new line after
2062 ;; ORGPOINT. Assumes point to be at the beginning of a block start
2063 ;; keyword.
2064 (let ((cur-indent (current-indentation))
2065 (pos nil))
2066 (cond
2067 ((save-excursion
2068 (forward-word 1)
2069 (setq pos (car (ada-search-ignore-string-comment
2070 "[^ \t\n]" nil orgpoint))))
2071 (goto-char pos)
2072 (save-excursion
2073 (funcall (ada-indent-function t) orgpoint)))
2074 ;;
2075 ;; nothing follows the block-start
2076 ;;
2077 (t
2078 (+ (current-indentation) ada-indent)))))
2079
2080
2081 (defun ada-get-indent-subprog (orgpoint)
2082 ;; Returns the indentation (column #) for the new line after ORGPOINT.
2083 ;; Assumes point to be at the beginning of a subprog-/package-declaration.
2084 (let ((match-cons nil)
2085 (cur-indent (current-indentation))
2086 (foundis nil)
2087 (addind 0)
2088 (fstart (point)))
2089 ;;
2090 ;; is there an 'is' in front of point ?
2091 ;;
2092 (if (save-excursion
2093 (setq match-cons
2094 (ada-search-ignore-string-comment
2095 "\\<is\\>\\|\\<do\\>" nil orgpoint)))
2096 ;;
2097 ;; yes, then skip to its end
2098 ;;
2099 (progn
2100 (setq foundis t)
2101 (goto-char (cdr match-cons)))
2102 ;;
2103 ;; no, then goto next non-ws, if there is one in front of point
2104 ;;
2105 (progn
2106 (if (ada-search-ignore-string-comment "[^ \t\n]" nil orgpoint)
2107 (ada-goto-next-non-ws)
2108 (goto-char orgpoint))))
2109
2110 (cond
2111 ;;
2112 ;; nothing follows 'is'
2113 ;;
2114 ((and
2115 foundis
2116 (save-excursion
2117 (not (ada-search-ignore-string-comment
2118 "[^ \t\n]" nil orgpoint t))))
2119 (+ cur-indent ada-indent))
2120 ;;
2121 ;; is abstract/separate/new ...
2122 ;;
2123 ((and
2124 foundis
2125 (save-excursion
2126 (setq match-cons
2127 (ada-search-ignore-string-comment
2128 "\\<\\(separate\\|new\\|abstract\\)\\>"
2129 nil orgpoint))))
2130 (goto-char (car match-cons))
2131 (ada-search-ignore-string-comment (concat ada-subprog-start-re
2132 "\\|\\<package\\>") t)
2133 (ada-get-indent-noindent orgpoint))
2134 ;;
2135 ;; something follows 'is'
2136 ;;
2137 ((and
2138 foundis
2139 (save-excursion
2140 (ada-search-ignore-string-comment "[^ \t\n]" nil orgpoint))
2141 (ada-goto-next-non-ws)
2142 (funcall (ada-indent-function t) orgpoint)))
2143 ;;
2144 ;; no 'is' but ';'
2145 ;;
2146 ((save-excursion
2147 (ada-search-ignore-string-comment ";" nil orgpoint))
2148 cur-indent)
2149 ;;
2150 ;; no 'is' or ';'
2151 ;;
2152 (t
2153 (+ cur-indent ada-broken-indent)))))
2154
2155
2156 (defun ada-get-indent-noindent (orgpoint)
2157 ;; Returns the indentation (column #) for the new line after ORGPOINT.
2158 ;; Assumes point to be at the beginning of a 'noindent statement'.
2159 (if (save-excursion
2160 (ada-search-ignore-string-comment ";" nil orgpoint))
2161 (current-indentation)
2162 (+ (current-indentation) ada-broken-indent)))
2163
2164
2165 (defun ada-get-indent-label (orgpoint)
2166 ;; Returns the indentation (column #) for the new line after ORGPOINT.
2167 ;; Assumes point to be at the beginning of a label or variable declaration.
2168 ;; Checks the context to decide if it's a label or a variable declaration.
2169 ;; This check might be a bit slow.
2170 (let ((match-cons nil)
2171 (cur-indent (current-indentation)))
2172 (goto-char (cdr (ada-search-ignore-string-comment ":")))
2173 (cond
2174 ;;
2175 ;; loop label
2176 ;;
2177 ((save-excursion
2178 (setq match-cons (ada-search-ignore-string-comment
2179 ada-loop-start-re nil orgpoint)))
2180 (goto-char (car match-cons))
2181 (ada-get-indent-loop orgpoint))
2182 ;;
2183 ;; declare label
2184 ;;
2185 ((save-excursion
2186 (setq match-cons (ada-search-ignore-string-comment
2187 "\\<declare\\>" nil orgpoint)))
2188 (save-excursion
2189 (goto-char (car match-cons))
2190 (+ (current-indentation) ada-indent)))
2191 ;;
2192 ;; complete statement following colon
2193 ;;
2194 ((save-excursion
2195 (ada-search-ignore-string-comment ";" nil orgpoint))
2196 (if (ada-in-decl-p)
2197 cur-indent ; variable-declaration
2198 (- cur-indent ada-label-indent))) ; label
2199 ;;
2200 ;; broken statement
2201 ;;
2202 ((save-excursion
2203 (ada-search-ignore-string-comment "[^ \t\n]" nil orgpoint))
2204 (if (ada-in-decl-p)
2205 (+ cur-indent ada-broken-indent)
2206 (+ cur-indent ada-broken-indent (- ada-label-indent))))
2207 ;;
2208 ;; nothing follows colon
2209 ;;
2210 (t
2211 (if (ada-in-decl-p)
2212 (+ cur-indent ada-broken-indent) ; variable-declaration
2213 (- cur-indent ada-label-indent)))))) ; label
2214
2215
2216 (defun ada-get-indent-loop (orgpoint)
2217 ;; Returns the indentation (column #) for the new line after ORGPOINT.
2218 ;; Assumes point to be at the beginning of a loop statement
2219 ;; or (unfortunately) also a for ... use statement.
2220 (let ((match-cons nil)
2221 (pos (point)))
2222 (cond
2223
2224 ;;
2225 ;; statement complete
2226 ;;
2227 ((save-excursion
2228 (ada-search-ignore-string-comment ";" nil orgpoint))
2229 (current-indentation))
2230 ;;
2231 ;; simple loop
2232 ;;
2233 ((looking-at "loop\\>")
2234 (ada-get-indent-block-start orgpoint))
2235
2236 ;;
2237 ;; 'for'- loop (or also a for ... use statement)
2238 ;;
2239 ((looking-at "for\\>")
2240 (cond
2241 ;;
2242 ;; for ... use
2243 ;;
2244 ((save-excursion
2245 (and
2246 (goto-char (match-end 0))
2247 (ada-search-ignore-string-comment "[^ /n/t]" nil orgpoint)
2248 (not (backward-char 1))
2249 (not (zerop (skip-chars-forward "_a-zA-Z0-9'")))
2250 (ada-search-ignore-string-comment "[^ /n/t]" nil orgpoint)
2251 (not (backward-char 1))
2252 (looking-at "\\<use\\>")
2253 ;;
2254 ;; check if there is a 'record' before point
2255 ;;
2256 (progn
2257 (setq match-cons (ada-search-ignore-string-comment
2258 "\\<record\\>" nil orgpoint))
2259 t)))
2260 (if match-cons
2261 (goto-char (car match-cons)))
2262 (+ (current-indentation) ada-indent))
2263 ;;
2264 ;; for..loop
2265 ;;
2266 ((save-excursion
2267 (setq match-cons (ada-search-ignore-string-comment
2268 "\\<loop\\>" nil orgpoint)))
2269 (goto-char (car match-cons))
2270 ;;
2271 ;; indent according to 'loop', if it's first in the line;
2272 ;; otherwise to 'for'
2273 ;;
2274 (if (not (save-excursion
2275 (back-to-indentation)
2276 (looking-at "\\<loop\\>")))
2277 (goto-char pos))
2278 (+ (current-indentation) ada-indent))
2279 ;;
2280 ;; for-statement is broken
2281 ;;
2282 (t
2283 (+ (current-indentation) ada-broken-indent))))
2284
2285 ;;
2286 ;; 'while'-loop
2287 ;;
2288 ((looking-at "while\\>")
2289 ;;
2290 ;; while..loop ?
2291 ;;
2292 (if (save-excursion
2293 (setq match-cons (ada-search-ignore-string-comment
2294 "\\<loop\\>" nil orgpoint)))
2295
2296 (progn
2297 (goto-char (car match-cons))
2298 ;;
2299 ;; indent according to 'loop', if it's first in the line;
2300 ;; otherwise to 'while'.
2301 ;;
2302 (if (not (save-excursion
2303 (back-to-indentation)
2304 (looking-at "\\<loop\\>")))
2305 (goto-char pos))
2306 (+ (current-indentation) ada-indent))
2307
2308 (+ (current-indentation) ada-broken-indent))))))
2309
2310
2311 (defun ada-get-indent-type (orgpoint)
2312 ;; Returns the indentation (column #) for the new line after ORGPOINT.
2313 ;; Assumes point to be at the beginning of a type statement.
2314 (let ((match-dat nil))
2315 (cond
2316 ;;
2317 ;; complete record declaration
2318 ;;
2319 ((save-excursion
2320 (and
2321 (setq match-dat (ada-search-ignore-string-comment "\\<end\\>"
2322 nil
2323 orgpoint))
2324 (ada-goto-next-non-ws)
2325 (looking-at "\\<record\\>")
2326 (forward-word 1)
2327 (ada-goto-next-non-ws)
2328 (looking-at ";")))
2329 (goto-char (car match-dat))
2330 (current-indentation))
2331 ;;
2332 ;; record type
2333 ;;
2334 ((save-excursion
2335 (setq match-dat (ada-search-ignore-string-comment "\\<record\\>"
2336 nil
2337 orgpoint)))
2338 (goto-char (car match-dat))
2339 (+ (current-indentation) ada-indent))
2340 ;;
2341 ;; complete type declaration
2342 ;;
2343 ((save-excursion
2344 (ada-search-ignore-string-comment ";" nil orgpoint))
2345 (current-indentation))
2346 ;;
2347 ;; "type ... is", but not "type ... is ...", which is broken
2348 ;;
2349 ((save-excursion
2350 (and
2351 (ada-search-ignore-string-comment "\\<is\\>" nil orgpoint)
2352 (not (ada-search-ignore-string-comment "[^ \t\n]" nil orgpoint))))
2353 (+ (current-indentation) ada-indent))
2354 ;;
2355 ;; broken statement
2356 ;;
2357 (t
2358 (+ (current-indentation) ada-broken-indent)))))
2359
2360
2361 ;;; ---- support-functions for indentation
2362
2363 ;;; ---- searching and matching
2364
2365 (defun ada-goto-stmt-start (&optional limit)
2366 ;; Moves point to the beginning of the statement that point is in or
2367 ;; after. Returns the new position of point. Beginnings are found
2368 ;; by searching for 'ada-end-stmt-re' and then moving to the
2369 ;; following non-ws that is not a comment. LIMIT is actually not
2370 ;; used by the indentation functions.
2371 (let ((match-dat nil)
2372 (orgpoint (point)))
2373
2374 (setq match-dat (ada-search-prev-end-stmt limit))
2375 (if match-dat
2376 ;;
2377 ;; found a previous end-statement => check if anything follows
2378 ;;
2379 (progn
2380 (if (not
2381 (save-excursion
2382 (goto-char (cdr match-dat))
2383 (ada-search-ignore-string-comment
2384 "[^ \t\n]" nil orgpoint)))
2385 ;;
2386 ;; nothing follows => it's the end-statement directly in
2387 ;; front of point => search again
2388 ;;
2389 (setq match-dat (ada-search-prev-end-stmt limit)))
2390 ;;
2391 ;; if found the correct end-stetement => goto next non-ws
2392 ;;
2393 (if match-dat
2394 (goto-char (cdr match-dat)))
2395 (ada-goto-next-non-ws))
2396
2397 ;;
2398 ;; no previous end-statement => we are at the beginning of the
2399 ;; accessible part of the buffer
2400 ;;
2401 (progn
2402 (goto-char (point-min))
2403 ;;
2404 ;; skip to the very first statement, if there is one
2405 ;;
2406 (if (setq match-dat
2407 (ada-search-ignore-string-comment
2408 "[^ \t\n]" nil orgpoint))
2409 (goto-char (car match-dat))
2410 (goto-char orgpoint))))
2411
2412
2413 (point)))
2414
2415
2416 (defun ada-search-prev-end-stmt (&optional limit)
2417 ;; Moves point to previous end-statement. Returns a cons cell whose
2418 ;; car is the beginning and whose cdr the end of the match.
2419 ;; End-statements are defined by 'ada-end-stmt-re'. Checks for
2420 ;; certain keywords if they follow 'end', which means they are no
2421 ;; end-statement there.
2422 (let ((match-dat nil)
2423 (pos nil)
2424 (found nil))
2425 ;;
2426 ;; search until found or beginning-of-buffer
2427 ;;
2428 (while
2429 (and
2430 (not found)
2431 (setq match-dat (ada-search-ignore-string-comment ada-end-stmt-re
2432 t
2433 limit)))
2434
2435 (goto-char (car match-dat))
2436
2437 (if (not (ada-in-open-paren-p))
2438 ;;
2439 ;; check if there is an 'end' in front of the match
2440 ;;
2441 (if (not (and
2442 (looking-at "\\<\\(record\\|loop\\|select\\)\\>")
2443 (save-excursion
2444 (ada-goto-previous-word)
2445 (looking-at "\\<end\\>"))))
2446 (setq found t)
2447
2448 (backward-word 1)))) ; end of loop
2449
2450 (if found
2451 match-dat
2452 nil)))
2453
2454
2455 (defun ada-goto-next-non-ws (&optional limit)
2456 ;; Skips whitespaces, newlines and comments to next non-ws
2457 ;; character. Signals an error if there is no more such character
2458 ;; and limit is nil.
2459 (let ((match-cons nil))
2460 (setq match-cons (ada-search-ignore-string-comment
2461 "[^ \t\n]" nil limit t))
2462 (if match-cons
2463 (goto-char (car match-cons))
2464 (if (not limit)
2465 (error "no more non-ws")
2466 nil))))
2467
2468
2469 (defun ada-goto-stmt-end (&optional limit)
2470 ;; Moves point to the end of the statement that point is in or
2471 ;; before. Returns the new position of point or nil if not found.
2472 (if (ada-search-ignore-string-comment ada-end-stmt-re nil limit)
2473 (point)
2474 nil))
2475
2476
2477 (defun ada-goto-previous-word ()
2478 ;; Moves point to the beginning of the previous word of ada-code.
2479 ;; Returns the new position of point or nil if not found.
2480 (let ((match-cons nil)
2481 (orgpoint (point)))
2482 (if (setq match-cons
2483 (ada-search-ignore-string-comment "[^ \t\n]" t nil t))
2484 ;;
2485 ;; move to the beginning of the word found
2486 ;;
2487 (progn
2488 (goto-char (cdr match-cons))
2489 (skip-chars-backward "_a-zA-Z0-9")
2490 (point))
2491 ;;
2492 ;; if not found, restore old position of point
2493 ;;
2494 (progn
2495 (goto-char orgpoint)
2496 'nil))))
2497
2498
2499 (defun ada-check-matching-start (keyword)
2500 ;; Signals an error if matching block start is not KEYWORD.
2501 ;; Moves point to the matching block start.
2502 (ada-goto-matching-start 0)
2503 (if (not (looking-at (concat "\\<" keyword "\\>")))
2504 (error (concat
2505 "matching start is not '"
2506 keyword "'"))))
2507
2508
2509 (defun ada-check-defun-name (defun-name)
2510 ;; Checks if the name of the matching defun really is DEFUN-NAME.
2511 ;; Assumes point to be already positioned by 'ada-goto-matching-start'.
2512 ;; Moves point to the beginning of the declaration.
2513
2514 ;;
2515 ;; 'accept' or 'package' ?
2516 ;;
2517 (if (not (looking-at "\\<\\(accept\\|package\\|task\\|protected\\)\\>"))
2518 (ada-goto-matching-decl-start))
2519 ;;
2520 ;; 'begin' of 'procedure'/'function'/'task' or 'declare'
2521 ;;
2522 (save-excursion
2523 ;;
2524 ;; a named 'declare'-block ?
2525 ;;
2526 (if (looking-at "\\<declare\\>")
2527 (ada-goto-stmt-start)
2528 ;;
2529 ;; no, => 'procedure'/'function'/'task'/'protected'
2530 ;;
2531 (progn
2532 (forward-word 2)
2533 (backward-word 1)
2534 ;;
2535 ;; skip 'body' 'protected' 'type'
2536 ;;
2537 (if (looking-at "\\<\\(body\\|type\\)\\>")
2538 (forward-word 1))
2539 (forward-sexp 1)
2540 (backward-sexp 1)))
2541 ;;
2542 ;; should be looking-at the correct name
2543 ;;
2544 (if (not (looking-at (concat "\\<" defun-name "\\>")))
2545 (error
2546 (concat
2547 "matching defun has different name: "
2548 (buffer-substring
2549 (point)
2550 (progn
2551 (forward-sexp 1)
2552 (point))))))))
2553
2554
2555 (defun ada-goto-matching-decl-start (&optional noerror nogeneric)
2556 ;; Moves point to the matching declaration start of the current 'begin'.
2557 ;; If NOERROR is non-nil, it only returns nil if no match was found.
2558 (let ((nest-count 1)
2559 (pos nil)
2560 (first t)
2561 (flag nil))
2562 ;;
2563 ;; search backward for interesting keywords
2564 ;;
2565 (while (and
2566 (not (zerop nest-count))
2567 (ada-search-ignore-string-comment
2568 (concat "\\<\\("
2569 "is\\|separate\\|end\\|declare\\|new\\|begin\\|generic"
2570 "\\)\\>") t))
2571 ;;
2572 ;; calculate nest-depth
2573 ;;
2574 (cond
2575 ;;
2576 ((looking-at "end")
2577 (ada-goto-matching-start 1 noerror)
2578 (if (looking-at "begin")
2579 (setq nest-count (1+ nest-count))))
2580 ;;
2581 ((looking-at "declare\\|generic")
2582 (setq nest-count (1- nest-count))
2583 (setq first nil))
2584 ;;
2585 ((looking-at "is")
2586 ;; check if it is only a type definition
2587 (if (save-excursion
2588 (ada-goto-previous-word)
2589 (skip-chars-backward "a-zA-Z0-9_.'")
2590 (if (save-excursion
2591 (backward-char 1)
2592 (looking-at ")"))
2593 (progn
2594 (forward-char 1)
2595 (backward-sexp 1)
2596 (skip-chars-backward "a-zA-Z0-9_.'")
2597 ))
2598 (ada-goto-previous-word)
2599 (looking-at "\\<type\\>")) ; end of save-excursion
2600 (goto-char (match-beginning 0))
2601 (progn
2602 (setq nest-count (1- nest-count))
2603 (setq first nil))))
2604
2605 ;;
2606 ((looking-at "new")
2607 (if (save-excursion
2608 (ada-goto-previous-word)
2609 (looking-at "is"))
2610 (goto-char (match-beginning 0))))
2611 ;;
2612 ((and first
2613 (looking-at "begin"))
2614 (setq nest-count 0)
2615 (setq flag t))
2616 ;;
2617 (t
2618 (setq nest-count (1+ nest-count))
2619 (setq first nil)))
2620
2621 ) ;; end of loop
2622
2623 ;; check if declaration-start is really found
2624 (if (not
2625 (and
2626 (zerop nest-count)
2627 (not flag)
2628 (progn
2629 (if (looking-at "is")
2630 (ada-search-ignore-string-comment
2631 ada-subprog-start-re t)
2632 (looking-at "declare\\|generic")))))
2633 (if noerror nil
2634 (error "no matching procedure/function/task/declare/package"))
2635 t)))
2636
2637
2638 (defun ada-goto-matching-start (&optional nest-level noerror gotothen)
2639 ;; Moves point to the beginning of a block-start. Which block
2640 ;; depends on the value of NEST-LEVEL, which defaults to zero. If
2641 ;; NOERROR is non-nil, it only returns nil if no matching start was
2642 ;; found. If GOTOTHEN is non-nil, point moves to the 'then'
2643 ;; following 'if'.
2644 (let ((nest-count (if nest-level nest-level 0))
2645 (found nil)
2646 (pos nil))
2647
2648 ;;
2649 ;; search backward for interesting keywords
2650 ;;
2651 (while (and
2652 (not found)
2653 (ada-search-ignore-string-comment
2654 (concat "\\<\\("
2655 "end\\|loop\\|select\\|begin\\|case\\|do\\|"
2656 "if\\|task\\|package\\|record\\|protected\\)\\>")
2657 t))
2658
2659 ;;
2660 ;; calculate nest-depth
2661 ;;
2662 (cond
2663 ;; found block end => increase nest depth
2664 ((looking-at "end")
2665 (setq nest-count (1+ nest-count)))
2666 ;; found loop/select/record/case/if => check if it starts or
2667 ;; ends a block
2668 ((looking-at "loop\\|select\\|record\\|case\\|if")
2669 (setq pos (point))
2670 (save-excursion
2671 ;;
2672 ;; check if keyword follows 'end'
2673 ;;
2674 (ada-goto-previous-word)
2675 (if (looking-at "\\<end\\>")
2676 ;; it ends a block => increase nest depth
2677 (progn
2678 (setq nest-count (1+ nest-count))
2679 (setq pos (point)))
2680 ;; it starts a block => decrease nest depth
2681 (setq nest-count (1- nest-count))))
2682 (goto-char pos))
2683 ;; found package start => check if it really is a block
2684 ((looking-at "package")
2685 (save-excursion
2686 (ada-search-ignore-string-comment "\\<is\\>")
2687 (ada-goto-next-non-ws)
2688 ;; ignore it if it is only a declaration with 'new'
2689 (if (not (looking-at "\\<new\\>"))
2690 (setq nest-count (1- nest-count)))))
2691 ;; found task start => check if it has a body
2692 ((looking-at "task")
2693 (save-excursion
2694 (forward-word 1)
2695 (ada-goto-next-non-ws)
2696 ;; ignore it if it has no body
2697 (if (not (looking-at "\\<body\\>"))
2698 (setq nest-count (1- nest-count)))))
2699 ;; all the other block starts
2700 (t
2701 (setq nest-count (1- nest-count)))) ; end of 'cond'
2702
2703 ;; match is found, if nest-depth is zero
2704 ;;
2705 (setq found (zerop nest-count))) ; end of loop
2706
2707 (if found
2708 ;;
2709 ;; match found => is there anything else to do ?
2710 ;;
2711 (progn
2712 (cond
2713 ;;
2714 ;; found 'if' => skip to 'then', if it's on a separate line
2715 ;; and GOTOTHEN is non-nil
2716 ;;
2717 ((and
2718 gotothen
2719 (looking-at "if")
2720 (save-excursion
2721 (ada-search-ignore-string-comment "\\<then\\>" nil nil)
2722 (back-to-indentation)
2723 (looking-at "\\<then\\>")))
2724 (goto-char (match-beginning 0)))
2725 ;;
2726 ;; found 'do' => skip back to 'accept'
2727 ;;
2728 ((looking-at "do")
2729 (if (not (ada-search-ignore-string-comment "\\<accept\\>" t nil))
2730 (error "missing 'accept' in front of 'do'"))))
2731 (point))
2732
2733 (if noerror
2734 nil
2735 (error "no matching start")))))
2736
2737
2738 (defun ada-goto-matching-end (&optional nest-level noerror)
2739 ;; Moves point to the end of a block. Which block depends on the
2740 ;; value of NEST-LEVEL, which defaults to zero. If NOERROR is
2741 ;; non-nil, it only returns nil if found no matching start.
2742 (let ((nest-count (if nest-level nest-level 0))
2743 (found nil))
2744
2745 ;;
2746 ;; search forward for interesting keywords
2747 ;;
2748 (while (and
2749 (not found)
2750 (ada-search-ignore-string-comment
2751 (concat "\\<\\(end\\|loop\\|select\\|begin\\|case\\|"
2752 "if\\|task\\|package\\|record\\|do\\)\\>")))
2753
2754 ;;
2755 ;; calculate nest-depth
2756 ;;
2757 (backward-word 1)
2758 (cond
2759 ;; found block end => decrease nest depth
2760 ((looking-at "\\<end\\>")
2761 (setq nest-count (1- nest-count))
2762 ;; skip the following keyword
2763 (if (progn
2764 (skip-chars-forward "end")
2765 (ada-goto-next-non-ws)
2766 (looking-at "\\<\\(loop\\|select\\|record\\|case\\|if\\)\\>"))
2767 (forward-word 1)))
2768 ;; found package start => check if it really starts a block
2769 ((looking-at "\\<package\\>")
2770 (ada-search-ignore-string-comment "\\<is\\>")
2771 (ada-goto-next-non-ws)
2772 ;; ignore and skip it if it is only a 'new' package
2773 (if (not (looking-at "\\<new\\>"))
2774 (setq nest-count (1+ nest-count))
2775 (skip-chars-forward "new")))
2776 ;; all the other block starts
2777 (t
2778 (setq nest-count (1+ nest-count))
2779 (forward-word 1))) ; end of 'cond'
2780
2781 ;; match is found, if nest-depth is zero
2782 ;;
2783 (setq found (zerop nest-count))) ; end of loop
2784
2785 (if (not found)
2786 (if noerror
2787 nil
2788 (error "no matching end"))
2789 t)))
2790
2791
2792 (defun ada-forward-sexp-ignore-comment ()
2793 ;; Skips one sexp forward, ignoring comments.
2794 (while (looking-at "[ \t\n]*--")
2795 (skip-chars-forward "[ \t\n]")
2796 (end-of-line))
2797 (forward-sexp 1))
2798
2799
2800 (defun ada-search-ignore-string-comment
2801 (search-re &optional backward limit paramlists)
2802 ;; Regexp-Search for SEARCH-RE, ignoring comments, strings and
2803 ;; parameter lists, if PARAMLISTS is nil. Returns a cons cell of
2804 ;; begin and end of match data or nil, if not found.
2805 (let ((found nil)
2806 (begin nil)
2807 (end nil)
2808 (pos nil)
2809 (search-func
2810 (if backward 're-search-backward
2811 're-search-forward)))
2812
2813 ;;
2814 ;; search until found or end-of-buffer
2815 ;;
2816 (while (and (not found)
2817 (funcall search-func search-re limit 1))
2818 (setq begin (match-beginning 0))
2819 (setq end (match-end 0))
2820
2821 (cond
2822 ;;
2823 ;; found in comment => skip it
2824 ;;
2825 ((ada-in-comment-p)
2826 (if backward
2827 (progn
2828 (re-search-backward "--" nil 1)
2829 (goto-char (match-beginning 0)))
2830 (progn
2831 (forward-line 1)
2832 (beginning-of-line))))
2833 ;;
2834 ;; found in string => skip it
2835 ;;
2836 ((ada-in-string-p)
2837 (if backward
2838 (progn
2839 (re-search-backward "\"" nil 1) ; "\"\\|#" don't treat #
2840 (goto-char (match-beginning 0))))
2841 (re-search-forward "\"" nil 1))
2842 ;;
2843 ;; found character constant => ignore it
2844 ;;
2845 ((save-excursion
2846 (setq pos (- (point) (if backward 1 2)))
2847 (and (char-after pos)
2848 (= (char-after pos) ?')
2849 (= (char-after (+ pos 2)) ?')))
2850 ())
2851 ;;
2852 ;; found a parameter-list but should ignore it => skip it
2853 ;;
2854 ((and (not paramlists)
2855 (ada-in-paramlist-p))
2856 (if backward
2857 (ada-search-ignore-string-comment "(" t nil t)))
2858 ;;
2859 ;; directly in front of a comment => skip it, if searching forward
2860 ;;
2861 ((save-excursion
2862 (goto-char begin)
2863 (looking-at "--"))
2864 (if (not backward)
2865 (progn
2866 (forward-line 1)
2867 (beginning-of-line))))
2868 ;;
2869 ;; found what we were looking for
2870 ;;
2871 (t
2872 (setq found t)))) ; end of loop
2873
2874 (if found
2875 (cons begin end)
2876 nil)))
2877
2878
2879 (defun ada-search-but-not (search-re not-search-re &optional backward limit)
2880 ;; Searches SEARCH-RE, ignoring parts of NOT-SEARCH-RE, strings,
2881 ;; comments and parameter-lists.
2882 (let ((begin nil)
2883 (end nil)
2884 (begin-not nil)
2885 (begin-end nil)
2886 (end-not nil)
2887 (ret-cons nil)
2888 (found nil))
2889
2890 ;;
2891 ;; search until found or end-of-buffer
2892 ;;
2893 (while (and
2894 (not found)
2895 (save-excursion
2896 (setq ret-cons
2897 (ada-search-ignore-string-comment search-re
2898 backward limit))
2899 (if (consp ret-cons)
2900 (progn
2901 (setq begin (car ret-cons))
2902 (setq end (cdr ret-cons))
2903 t)
2904 nil)))
2905
2906 (if (or
2907 ;;
2908 ;; if no NO-SEARCH-RE was found
2909 ;;
2910 (not
2911 (save-excursion
2912 (setq ret-cons
2913 (ada-search-ignore-string-comment not-search-re
2914 backward nil))
2915 (if (consp ret-cons)
2916 (progn
2917 (setq begin-not (car ret-cons))
2918 (setq end-not (cdr ret-cons))
2919 t)
2920 nil)))
2921 ;;
2922 ;; or this NO-SEARCH-RE is not a part of the SEARCH-RE
2923 ;; found before.
2924 ;;
2925 (or
2926 (<= end-not begin)
2927 (>= begin-not end)))
2928
2929 (setq found t)
2930
2931 ;;
2932 ;; not found the correct match => skip this match
2933 ;;
2934 (goto-char (if backward
2935 begin
2936 end)))) ; end of loop
2937
2938 (if found
2939 (progn
2940 (goto-char begin)
2941 (cons begin end))
2942 nil)))
2943
2944
2945 (defun ada-goto-prev-nonblank-line ( &optional ignore-comment)
2946 ;; Moves point to the beginning of previous non-blank line,
2947 ;; ignoring comments if IGNORE-COMMENT is non-nil.
2948 ;; It returns t if a matching line was found.
2949 (let ((notfound t)
2950 (newpoint nil))
2951
2952 (save-excursion
2953 ;;
2954 ;; backward one line, if there is one
2955 ;;
2956 (if (zerop (forward-line -1))
2957 ;;
2958 ;; there is some kind of previous line
2959 ;;
2960 (progn
2961 (beginning-of-line)
2962 (setq newpoint (point))
2963
2964 ;;
2965 ;; search until found or beginning-of-buffer
2966 ;;
2967 (while (and (setq notfound
2968 (or (looking-at "[ \t]*$")
2969 (and (looking-at "[ \t]*--")
2970 ignore-comment)))
2971 (not (ada-in-limit-line-p)))
2972 (forward-line -1)
2973 ;;(beginning-of-line)
2974 (setq newpoint (point))) ; end of loop
2975
2976 )) ; end of if
2977
2978 ) ; end of save-excursion
2979
2980 (if notfound nil
2981 (progn
2982 (goto-char newpoint)
2983 t))))
2984
2985
2986 (defun ada-goto-next-nonblank-line ( &optional ignore-comment)
2987 ;; Moves point to next non-blank line,
2988 ;; ignoring comments if IGNORE-COMMENT is non-nil.
2989 ;; It returns t if a matching line was found.
2990 (let ((notfound t)
2991 (newpoint nil))
2992
2993 (save-excursion
2994 ;;
2995 ;; forward one line
2996 ;;
2997 (if (zerop (forward-line 1))
2998 ;;
2999 ;; there is some kind of previous line
3000 ;;
3001 (progn
3002 (beginning-of-line)
3003 (setq newpoint (point))
3004
3005 ;;
3006 ;; search until found or end-of-buffer
3007 ;;
3008 (while (and (setq notfound
3009 (or (looking-at "[ \t]*$")
3010 (and (looking-at "[ \t]*--")
3011 ignore-comment)))
3012 (not (ada-in-limit-line-p)))
3013 (forward-line 1)
3014 (beginning-of-line)
3015 (setq newpoint (point))) ; end of loop
3016
3017 )) ; end of if
3018
3019 ) ; end of save-excursion
3020
3021 (if notfound nil
3022 (progn
3023 (goto-char newpoint)
3024 t))))
3025
3026
3027 ;; ---- boolean functions for indentation
3028
3029 (defun ada-in-decl-p ()
3030 ;; Returns t if point is inside a declarative part.
3031 ;; Assumes point to be at the end of a statement.
3032 (or
3033 (ada-in-paramlist-p)
3034 (save-excursion
3035 (ada-goto-matching-decl-start t))))
3036
3037
3038 (defun ada-looking-at-semi-or ()
3039 ;; Returns t if looking-at an 'or' following a semicolon.
3040 (save-excursion
3041 (and (looking-at "\\<or\\>")
3042 (progn
3043 (forward-word 1)
3044 (ada-goto-stmt-start)
3045 (looking-at "\\<or\\>")))))
3046
3047
3048 (defun ada-looking-at-semi-private ()
3049 ;; Returns t if looking-at an 'private' following a semicolon.
3050 (save-excursion
3051 (and (looking-at "\\<private\\>")
3052 (progn
3053 (forward-word 1)
3054 (ada-goto-stmt-start)
3055 (looking-at "\\<private\\>")))))
3056
3057
3058 ;;; make a faster??? ada-in-limit-line-p not using count-lines
3059 (defun ada-in-limit-line-p ()
3060 ;; return t if point is in first or last accessible line.
3061 (or (save-excursion (beginning-of-line) (= (point-min) (point)))
3062 (save-excursion (end-of-line) (= (point-max) (point)))))
3063
3064
3065 (defun ada-in-comment-p ()
3066 ;; Returns t if inside a comment.
3067 (save-excursion (and (re-search-backward "\\(--\\|\n\\)" nil 1)
3068 (looking-at "-"))))
3069
3070
3071 (defun ada-in-string-p ()
3072 ;; Returns t if point is inside a string
3073 ;; (Taken from pascal-mode.el, modified by MH).
3074 (save-excursion
3075 (and
3076 (nth 3 (parse-partial-sexp
3077 (save-excursion
3078 (beginning-of-line)
3079 (point)) (point)))
3080 ;; check if 'string quote' is only a character constant
3081 (progn
3082 (re-search-backward "\"" nil t) ; # not a string delimiter anymore
3083 (not (= (char-after (1- (point))) ?'))))))
3084
3085
3086 (defun ada-in-string-or-comment-p ()
3087 ;; Returns t if point is inside a string or a comment.
3088 (or (ada-in-comment-p)
3089 (ada-in-string-p)))
3090
3091
3092 (defun ada-in-paramlist-p ()
3093 ;; Returns t if point is inside a parameter-list
3094 ;; following 'function'/'procedure'/'package'.
3095 (save-excursion
3096 (and
3097 (re-search-backward "(\\|)" nil t)
3098 ;; inside parentheses ?
3099 (looking-at "(")
3100 (backward-word 2)
3101 ;; right keyword before paranthesis ?
3102 (looking-at (concat "\\<\\("
3103 "procedure\\|function\\|body\\|package\\|"
3104 "task\\|entry\\|accept\\)\\>"))
3105 (re-search-forward ")\\|:" nil t)
3106 ;; at least one ':' inside the parentheses ?
3107 (not (backward-char 1))
3108 (looking-at ":"))))
3109
3110
3111 ;; not really a boolean function ...
3112 (defun ada-in-open-paren-p ()
3113 ;; If point is somewhere behind an open parenthesis not yet closed,
3114 ;; it returns the column # of the first non-ws behind this open
3115 ;; parenthesis, otherwise nil."
3116
3117 (let ((start (if (< (point) ada-search-paren-char-count-limit)
3118 1
3119 (- (point) ada-search-paren-char-count-limit)))
3120 parse-result
3121 (col nil))
3122 (setq parse-result (parse-partial-sexp start (point)))
3123 (if (nth 1 parse-result)
3124 (save-excursion
3125 (goto-char (1+ (nth 1 parse-result)))
3126 (if (save-excursion
3127 (re-search-forward "[^ \t]" nil 1)
3128 (backward-char 1)
3129 (and
3130 (not (looking-at "\n"))
3131 (setq col (current-column))))
3132 col
3133 (current-column)))
3134 nil)))
3135
3136
3137
3138 ;;;----------------------;;;
3139 ;;; Behaviour Of TAB Key ;;;
3140 ;;;----------------------;;;
3141
3142 (defun ada-tab ()
3143 "Do indenting or tabbing according to `ada-tab-policy'."
3144 (interactive)
3145 (cond ((eq ada-tab-policy 'indent-and-tab) (error "not implemented"))
3146 ;; ada-indent-and-tab
3147 ((eq ada-tab-policy 'indent-rigidly) (ada-tab-hard))
3148 ((eq ada-tab-policy 'indent-auto) (ada-indent-current))
3149 ((eq ada-tab-policy 'gei) (ada-tab-gei))
3150 ((eq ada-tab-policy 'indent-af) (af-indent-line)) ; GEB
3151 ((eq ada-tab-policy 'always-tab) (error "not implemented"))
3152 ))
3153
3154
3155 (defun ada-untab (arg)
3156 "Delete leading indenting according to `ada-tab-policy'."
3157 (interactive "P")
3158 (cond ((eq ada-tab-policy 'indent-rigidly) (ada-untab-hard))
3159 ((eq ada-tab-policy 'indent-af) (backward-delete-char-untabify ; GEB
3160 (prefix-numeric-value arg) ; GEB
3161 arg)) ; GEB
3162 ((eq ada-tab-policy 'indent-auto) (error "not implemented"))
3163 ((eq ada-tab-policy 'always-tab) (error "not implemented"))
3164 ))
3165
3166
3167 (defun ada-indent-current-function ()
3168 "Ada Mode version of the indent-line-function."
3169 (interactive "*")
3170 (let ((starting-point (point-marker)))
3171 (ada-beginning-of-line)
3172 (ada-tab)
3173 (if (< (point) starting-point)
3174 (goto-char starting-point))
3175 (set-marker starting-point nil)
3176 ))
3177
3178
3179 (defun ada-tab-hard ()
3180 "Indent current line to next tab stop."
3181 (interactive)
3182 (save-excursion
3183 (beginning-of-line)
3184 (insert-char ? ada-indent))
3185 (if (save-excursion (= (point) (progn (beginning-of-line) (point))))
3186 (forward-char ada-indent)))
3187
3188
3189 (defun ada-untab-hard ()
3190 "indent current line to previous tab stop."
3191 (interactive)
3192 (let ((bol (save-excursion (progn (beginning-of-line) (point))))
3193 (eol (save-excursion (progn (end-of-line) (point)))))
3194 (indent-rigidly bol eol (- 0 ada-indent))))
3195
3196
3197
3198 ;;;---------------;;;
3199 ;;; Miscellaneous ;;;
3200 ;;;---------------;;;
3201
3202 (defun ada-remove-trailing-spaces ()
3203 ;; remove all trailing spaces at the end of lines.
3204 "remove trailing spaces in the whole buffer."
3205 (interactive)
3206 (save-excursion
3207 (goto-char (point-min))
3208 (while (re-search-forward "[ \t]+$" nil t)
3209 (replace-match "" nil nil))))
3210
3211
3212 (defun ada-untabify-buffer ()
3213 ;; change all tabs to spaces
3214 (save-excursion
3215 (untabify (point-min) (point-max))))
3216
3217
3218 (defun ada-uncomment-region (beg end)
3219 "delete comment-start at the beginning of a line in the region."
3220 (interactive "r")
3221 (comment-region beg end -1))
3222
3223
3224 ;; define a function to support find-file.el if loaded
3225 (defun ada-ff-other-window ()
3226 "Find other file in other window using ff-find-other-file."
3227 (interactive)
3228 (and (fboundp 'ff-find-other-file)
3229 (ff-find-other-file t)))
3230
3231
3232 ;;;-------------------------------;;;
3233 ;;; Moving To Procedures/Packages ;;;
3234 ;;;-------------------------------;;;
3235
3236 (defun ada-next-procedure ()
3237 "Moves point to next procedure."
3238 (interactive)
3239 (end-of-line)
3240 (if (re-search-forward ada-procedure-start-regexp nil t)
3241 (goto-char (match-beginning 1))
3242 (error "No more functions/procedures/tasks")))
3243
3244 (defun ada-previous-procedure ()
3245 "Moves point to previous procedure."
3246 (interactive)
3247 (beginning-of-line)
3248 (if (re-search-backward ada-procedure-start-regexp nil t)
3249 (goto-char (match-beginning 1))
3250 (error "No more functions/procedures/tasks")))
3251
3252 (defun ada-next-package ()
3253 "Moves point to next package."
3254 (interactive)
3255 (end-of-line)
3256 (if (re-search-forward ada-package-start-regexp nil t)
3257 (goto-char (match-beginning 1))
3258 (error "No more packages")))
3259
3260 (defun ada-previous-package ()
3261 "Moves point to previous package."
3262 (interactive)
3263 (beginning-of-line)
3264 (if (re-search-backward ada-package-start-regexp nil t)
3265 (goto-char (match-beginning 1))
3266 (error "No more packages")))
3267
3268
3269 ;;;-----------------------
3270 ;;; define keymap for Ada
3271 ;;;-----------------------
3272
3273 (if (not ada-mode-map)
3274 (progn
3275 (setq ada-mode-map (make-sparse-keymap))
3276
3277 ;; Indentation and Formatting
3278 (define-key ada-mode-map "\C-j" 'ada-indent-newline-indent)
3279 (define-key ada-mode-map "\t" 'ada-tab)
3280 (define-key ada-mode-map "\C-c\C-l" 'ada-indent-region)
3281 (if (ada-xemacs)
3282 (define-key ada-mode-map '(shift tab) 'ada-untab)
3283 (define-key ada-mode-map [S-tab] 'ada-untab))
3284 (define-key ada-mode-map "\C-c\C-f" 'ada-format-paramlist)
3285 (define-key ada-mode-map "\C-c\C-p" 'ada-call-pretty-printer)
3286 ;;; We don't want to make meta-characters case-specific.
3287 ;;; (define-key ada-mode-map "\M-Q" 'ada-fill-comment-paragraph-justify)
3288 (define-key ada-mode-map "\M-\C-q" 'ada-fill-comment-paragraph-postfix)
3289
3290 ;; Movement
3291 ;;; It isn't good to redefine these. What should be done instead? -- rms.
3292 ;;; (define-key ada-mode-map "\M-e" 'ada-next-package)
3293 ;;; (define-key ada-mode-map "\M-a" 'ada-previous-package)
3294 (define-key ada-mode-map "\M-\C-e" 'ada-next-procedure)
3295 (define-key ada-mode-map "\M-\C-a" 'ada-previous-procedure)
3296 (define-key ada-mode-map "\C-c\C-a" 'ada-move-to-start)
3297 (define-key ada-mode-map "\C-c\C-e" 'ada-move-to-end)
3298
3299 ;; Compilation
3300 (define-key ada-mode-map "\C-c\C-c" 'compile)
3301
3302 ;; Casing
3303 (define-key ada-mode-map "\C-c\C-r" 'ada-adjust-case-region)
3304 (define-key ada-mode-map "\C-c\C-b" 'ada-adjust-case-buffer)
3305
3306 (define-key ada-mode-map "\177" 'backward-delete-char-untabify)
3307
3308 ;; Use predefined function of emacs19 for comments (RE)
3309 (define-key ada-mode-map "\C-c;" 'comment-region)
3310 (define-key ada-mode-map "\C-c:" 'ada-uncomment-region)
3311
3312 ;; Change basic functionality
3313
3314 ;; substitute-key-definition is not defined equally in GNU Emacs
3315 ;; and XEmacs, you cannot put in an optional 4th parameter in
3316 ;; XEmacs. I don't think it's necessary, so I leave it out for
3317 ;; GNU Emacs as well. If you encounter any problems with the
3318 ;; following three functions, please tell me. RE
3319 (mapcar (function (lambda (pair)
3320 (substitute-key-definition (car pair) (cdr pair)
3321 ada-mode-map)))
3322 '((beginning-of-line . ada-beginning-of-line)
3323 (end-of-line . ada-end-of-line)
3324 (forward-to-indentation . ada-forward-to-indentation)
3325 ))
3326 ;; else GNU Emacs
3327 ;;(mapcar (lambda (pair)
3328 ;; (substitute-key-definition (car pair) (cdr pair)
3329 ;; ada-mode-map global-map))
3330
3331 ))
3332
3333
3334 ;;;-------------------
3335 ;;; define menu 'Ada'
3336 ;;;-------------------
3337
3338 (require 'easymenu)
3339
3340 (defun ada-add-ada-menu ()
3341 "Adds the menu 'Ada' to the menu-bar in Ada Mode."
3342 (easy-menu-define ada-mode-menu ada-mode-map "Menu keymap for Ada mode."
3343 '("Ada"
3344 ["Next Package" ada-next-package t]
3345 ["Previous Package" ada-previous-package t]
3346 ["Next Procedure" ada-next-procedure t]
3347 ["Previous Procedure" ada-previous-procedure t]
3348 ["Goto Start" ada-move-to-start t]
3349 ["Goto End" ada-move-to-end t]
3350 ["------------------" nil nil]
3351 ["Indent Current Line (TAB)"
3352 ada-indent-current-function t]
3353 ["Indent Lines in Region" ada-indent-region t]
3354 ["Format Parameter List" ada-format-paramlist t]
3355 ["Pretty Print Buffer" ada-call-pretty-printer t]
3356 ["------------" nil nil]
3357 ["Fill Comment Paragraph"
3358 ada-fill-comment-paragraph t]
3359 ["Justify Comment Paragraph"
3360 ada-fill-comment-paragraph-justify t]
3361 ["Postfix Comment Paragraph"
3362 ada-fill-comment-paragraph-postfix t]
3363 ["------------" nil nil]
3364 ["Adjust Case Region" ada-adjust-case-region t]
3365 ["Adjust Case Buffer" ada-adjust-case-buffer t]
3366 ["----------" nil nil]
3367 ["Comment Region" comment-region t]
3368 ["Uncomment Region" ada-uncomment-region t]
3369 ["----------------" nil nil]
3370 ["Compile" compile (fboundp 'compile)]
3371 ["Next Error" next-error (fboundp 'next-error)]
3372 ["---------------" nil nil]
3373 ["Index" imenu (fboundp 'imenu)]
3374 ["--------------" nil nil]
3375 ["Other File Other Window" ada-ff-other-window
3376 (fboundp 'ff-find-other-file)]
3377 ["Other File" ff-find-other-file
3378 (fboundp 'ff-find-other-file)]))
3379 (if (ada-xemacs) (progn
3380 (easy-menu-add ada-mode-menu)
3381 (setq mode-popup-menu (cons "Ada Mode" ada-mode-menu)))))
3382
3383
3384
3385 ;;;-------------------------------
3386 ;;; Define Some Support Functions
3387 ;;;-------------------------------
3388
3389 (defun ada-beginning-of-line (&optional arg)
3390 (interactive "P")
3391 (cond
3392 ((eq ada-tab-policy 'indent-af) (af-beginning-of-line arg))
3393 (t (beginning-of-line arg))
3394 ))
3395
3396 (defun ada-end-of-line (&optional arg)
3397 (interactive "P")
3398 (cond
3399 ((eq ada-tab-policy 'indent-af) (af-end-of-line arg))
3400 (t (end-of-line arg))
3401 ))
3402
3403 (defun ada-current-column ()
3404 (cond
3405 ((eq ada-tab-policy 'indent-af) (af-current-column))
3406 (t (current-column))
3407 ))
3408
3409 (defun ada-forward-to-indentation (&optional arg)
3410 (interactive "P")
3411 (cond
3412 ((eq ada-tab-policy 'indent-af) (af-forward-to-indentation arg))
3413 (t (forward-to-indentation arg))
3414 ))
3415
3416 ;;;---------------------------------------------------
3417 ;;; support for find-file
3418 ;;;---------------------------------------------------
3419
3420
3421 ;;;###autoload
3422 (defun ada-make-filename-from-adaname (adaname)
3423 "determine the filename of a package/procedure from its own Ada name."
3424 ;; this is done simply by calling gkrunch, when we work with GNAT. It
3425 ;; must be a more complex function in other compiler environments.
3426 (interactive "s")
3427
3428 ;; things that should really be done by the external process
3429 ;; since gnat-2.0, gnatk8 can do these things. If you still use a
3430 ;; previous version, just uncomment the following lines.
3431 (let (krunch-buf)
3432 (setq krunch-buf (generate-new-buffer "*gkrunch*"))
3433 (save-excursion
3434 (set-buffer krunch-buf)
3435 ; (insert (downcase adaname))
3436 ; (goto-char (point-min))
3437 ; (while (search-forward "." nil t)
3438 ; (replace-match "-" nil t))
3439 ; (setq adaname (buffer-substring (point-min)
3440 ; (progn
3441 ; (goto-char (point-min))
3442 ; (end-of-line)
3443 ; (point))))
3444 ; ;; clean the buffer
3445 ; (delete-region (point-min) (point-max))
3446 ;; send adaname to external process "gnatk8"
3447 (call-process "gnatk8" nil krunch-buf nil
3448 adaname ada-krunch-args)
3449 ;; fetch output of that process
3450 (setq adaname (buffer-substring
3451 (point-min)
3452 (progn
3453 (goto-char (point-min))
3454 (end-of-line)
3455 (point))))
3456 (kill-buffer krunch-buf)))
3457 (setq adaname adaname) ;; can I avoid this statement?
3458 )
3459
3460
3461 ;;; functions for placing the cursor on the corresponding subprogram
3462 (defun ada-which-function-are-we-in ()
3463 "Determine whether we are on a function definition/declaration and remember
3464 the name of that function."
3465
3466 (setq ff-function-name nil)
3467
3468 (save-excursion
3469 (if (re-search-backward ada-procedure-start-regexp nil t)
3470 (setq ff-function-name (buffer-substring (match-beginning 0)
3471 (match-end 0)))
3472 ; we didn't find a procedure start, perhaps there is a package
3473 (if (re-search-backward ada-package-start-regexp nil t)
3474 (setq ff-function-name (buffer-substring (match-beginning 0)
3475 (match-end 0)))
3476 ))))
3477
3478
3479 ;;;---------------------------------------------------
3480 ;;; support for imenu
3481 ;;;---------------------------------------------------
3482
3483 (defun imenu-create-ada-index (&optional regexp)
3484 "create index alist for Ada files."
3485 (let ((index-alist '())
3486 prev-pos char)
3487 (goto-char (point-min))
3488 ;(imenu-progress-message prev-pos 0)
3489 ;; Search for functions/procedures
3490 (save-match-data
3491 (while (re-search-forward
3492 (or regexp ada-procedure-start-regexp)
3493 nil t)
3494 ;(imenu-progress-message prev-pos)
3495 ;; do not store forward definitions
3496 ;; right now we store them. We want to avoid them only in
3497 ;; package bodies, not in the specs!! ???RE???
3498 (save-match-data
3499 ; (if (not (looking-at (concat
3500 ; "[ \t\n]*" ; WS
3501 ; "\([^)]+\)" ; parameterlist
3502 ; "\\([ \n\t]+return[ \n\t]+"; potential return
3503 ; "[a-zA-Z0-9_\\.]+\\)?"
3504 ; "[ \t]*" ; WS
3505 ; ";" ;; THIS is what we really look for
3506 ; )))
3507 ; ; (push (imenu-example--name-and-position) index-alist)
3508 (setq index-alist (cons (imenu-example--name-and-position)
3509 index-alist))
3510 ; )
3511 )
3512 ;(imenu-progress-message 100)
3513 ))
3514 (nreverse index-alist)))
3515
3516 ;;;---------------------------------------------------
3517 ;;; support for font-lock
3518 ;;;---------------------------------------------------
3519
3520 ;; Strings are a real pain in Ada because both ' and " can appear in a
3521 ;; non-string quote context (the former as an operator, the latter as
3522 ;; a character string). We follow the least losing solution, in which
3523 ;; only " is a string quote. Therefore a character string of the form
3524 ;; '"' will throw fontification off on the wrong track.
3525
3526 (defconst ada-font-lock-keywords-1
3527 (list
3528 ;;
3529 ;; accept, entry, function, package (body), protected (body|type),
3530 ;; pragma, procedure, task (body) plus name.
3531 (list (concat
3532 "\\<\\("
3533 "accept\\|"
3534 "entry\\|"
3535 "function\\|"
3536 "package\\|"
3537 "package[ \t]+body\\|"
3538 "procedure\\|"
3539 "protected\\|"
3540 "protected[ \t]+body\\|"
3541 "protected[ \t]+type\\|"
3542 ;; "p\\(\\(ackage\\|rotected\\)\\(\\|[ \t]+\\(body\\|type\\)\\)\
3543 ;;\\|r\\(agma\\|ocedure\\)\\)\\|"
3544 "task\\|"
3545 "task[ \t]+body\\|"
3546 "task[ \t]+type"
3547 ;; "task\\(\\|[ \t]+body\\)"
3548 "\\)\\>[ \t]*"
3549 "\\(\\sw+\\(\\.\\sw*\\)*\\)?")
3550 '(1 font-lock-keyword-face) '(2 font-lock-function-name-face nil t)))
3551 "For consideration as a value of `ada-font-lock-keywords'.
3552 This does fairly subdued highlighting.")
3553
3554 (defconst ada-font-lock-keywords-2
3555 (append ada-font-lock-keywords-1
3556 (list
3557 ;;
3558 ;; Main keywords, except those treated specially below.
3559 (concat "\\<\\("
3560 ; ("abort" "abs" "abstract" "accept" "access" "aliased" "all"
3561 ; "and" "array" "at" "begin" "case" "declare" "delay" "delta"
3562 ; "digits" "do" "else" "elsif" "entry" "exception" "exit" "for"
3563 ; "generic" "if" "in" "is" "limited" "loop" "mod" "not"
3564 ; "null" "or" "others" "private" "protected"
3565 ; "range" "record" "rem" "renames" "requeue" "return" "reverse"
3566 ; "select" "separate" "tagged" "task" "terminate" "then" "until"
3567 ; "while" "xor")
3568 "a\\(b\\(ort\\|s\\(\\|tract\\)\\)\\|cce\\(pt\\|ss\\)\\|"
3569 "l\\(iased\\|l\\)\\|nd\\|rray\\|t\\)\\|begin\\|case\\|"
3570 "d\\(e\\(clare\\|l\\(ay\\|ta\\)\\)\\|igits\\|o\\)\\|"
3571 "e\\(ls\\(e\\|if\\)\\|ntry\\|x\\(ception\\|it\\)\\)\\|for\\|"
3572 "generic\\|i[fns]\\|l\\(imited\\|oop\\)\\|mod\\|n\\(ot\\|ull\\)\\|"
3573 "o\\(r\\|thers\\|ut\\)\\|pr\\(ivate\\|otected\\)\\|"
3574 "r\\(ange\\|e\\(cord\\|m\\|names\\|queue\\|turn\\|verse\\)\\)\\|"
3575 "se\\(lect\\|parate\\)\\|"
3576 "t\\(agged\\|erminate\\|hen\\)\\|until\\|" ; task removed
3577 "wh\\(ile\\|en\\)\\|xor" ; "when" added
3578 "\\)\\>")
3579 ;;
3580 ;; Anything following end and not already fontified is a body name.
3581 '("\\<\\(end\\)\\>[ \t]+\\(\\sw+\\)?"
3582 (1 font-lock-keyword-face) (2 font-lock-function-name-face nil t))
3583 ;;
3584 ;; Variable name plus optional keywords followed by a type name. Slow.
3585 ; (list (concat "\\<\\(\\sw+\\)\\>[ \t]*:?[ \t]*"
3586 ; "\\(access\\|constant\\|in\\|in[ \t]+out\\|out\\)?[ \t]*"
3587 ; "\\(\\sw+\\)?")
3588 ; '(1 font-lock-variable-name-face)
3589 ; '(2 font-lock-keyword-face nil t) '(3 font-lock-type-face nil t))
3590 ;;
3591 ;; Optional keywords followed by a type name.
3592 (list (concat ; ":[ \t]*"
3593 "\\<\\(access\\|constant\\|in\\|in[ \t]+out\\|out\\)\\>"
3594 "[ \t]*"
3595 "\\(\\sw+\\)?")
3596 '(1 font-lock-keyword-face nil t) '(2 font-lock-type-face nil t))
3597 ;;
3598 ;; Keywords followed by a type or function name.
3599 (list (concat "\\<\\("
3600 "new\\|of\\|subtype\\|type"
3601 "\\)\\>[ \t]*\\(\\sw+\\)?[ \t]*\\((\\)?")
3602 '(1 font-lock-keyword-face)
3603 '(2 (if (match-beginning 4)
3604 'font-lock-function-name-face
3605 'font-lock-type-face) nil t))
3606 ;;
3607 ;; Keywords followed by a (comma separated list of) reference.
3608 (list (concat "\\<\\(goto\\|raise\\|use\\|with\\)\\>" ; "when" removed
3609 ; "[ \t]*\\(\\sw+\\(\\.\\sw*\\)*\\)?") ; RE
3610 "[ \t]*\\([a-zA-Z0-9_\\.\\|, ]+\\)\\W")
3611 '(1 font-lock-keyword-face) '(2 font-lock-reference-face nil t))
3612 ;;
3613 ;; Goto tags.
3614 '("<<\\(\\sw+\\)>>" 1 font-lock-reference-face)
3615 ))
3616 "For consideration as a value of `ada-font-lock-keywords'.
3617 This does a lot more highlighting.")
3618
3619 ;(defconst ada-font-lock-keywords (purecopy
3620 ; (let ((ident "\\(\\(\\sw\\|\\s_\\)+\\)") ; indent is 2nd capture
3621 ; (decl-1 "\\(procedure\\|function\\|package\\)[ \t]+") ; 1 ()
3622 ; (decl-2 "\\(task\\|package\\)[ \t]+body[ \t]+") ; 1()
3623 ; (kwords-1 ; "normal" keywords
3624 ; '("abort" "abs" "accept" "access" "array" "begin" "body" "case"
3625 ; "constant" "declare" "delay" "delta" "digits" "else" "elsif"
3626 ; "entry" "exception" "exit" "function" "generic" "goto" "if"
3627 ; "others" "limited" "loop" "mod" "new" "null" "out" "subtype"
3628 ; "package" "pragma" "private" "procedure" "raise" "range" "record"
3629 ; "rem" "renames" "return" "reverse" "select" "separate" "task"
3630 ; "terminate" "then" "type" "when" "while" "with" "xor"))
3631 ; (kwords-2 ; keywords that may appear at the end of a word AND
3632 ; ; may also be preceeded by a non-space.
3633 ; '("and" "at" "do" "end" "for" "in" "is" "not" "of" "or" "use"))
3634 ; )
3635 ; (list
3636 ; ;;'("\\(--.*\\)" 1 font-lock-comment-face t) ; syntax table should do this
3637 ; (list (concat "^[ \t]*" decl-2 ident) 3 'font-lock-function-name-face)
3638 ; (list (concat "^[ \t]*" decl-1 ident) 3 'font-lock-function-name-face)
3639 ; (cons (concat "\\(" (mapconcat 'identity kwords-1 "\\|") "\\)[ \n\t;(]")
3640 ; 1)
3641 ; (cons (concat "[ \t+=*/---]\\(" (mapconcat 'identity kwords-2 "\\|")
3642 ; "\\)[ \n\t;(]")
3643 ; 1)
3644 ; (cons "^\\(end\\)[ \n\t;(]" 1)
3645 ; (cons "\\.\\(all\\)" 1)
3646 ; )))
3647 ; "Expressions to highlight in Ada buffers.")
3648
3649 (defvar ada-font-lock-keywords (if font-lock-maximum-decoration
3650 ada-font-lock-keywords-2
3651 ada-font-lock-keywords-1)
3652 "*Expressions to highlight in Ada mode.")
3653
3654 (put 'ada-mode 'font-lock-defaults
3655 '(ada-font-lock-keywords nil t ((?\_ . "w"))))
3656
3657 ;;;
3658 ;;; ????
3659 ;;;
3660 (defun ada-gen-comment-until-proc ()
3661 ;; comment until spec of a procedure or a function.
3662 (forward-line 1)
3663 (set-mark-command (point))
3664 (if (re-search-forward ada-procedure-start-regexp nil t)
3665 (progn (goto-char (match-beginning 1))
3666 (comment-region (mark) (point)))
3667 (error "No more functions/procedures")))
3668
3669
3670 (defun ada-gen-treat-proc (match)
3671 ;; make dummy body of a procedure/function specification.
3672 ;; MATCH is a cons cell containing the start and end location of the
3673 ;; last search for ada-procedure-start-regexp.
3674 (goto-char (car match))
3675 (let (proc-found func-found)
3676 (cond
3677 ((or (setq proc-found (looking-at "^[ \t]*procedure"))
3678 (setq func-found (looking-at "^[ \t]*function")))
3679 ;; treat it as a proc/func
3680 (forward-word 2)
3681 (forward-word -1)
3682 (setq procname (buffer-substring (point) (cdr match))) ; store proc name
3683
3684 ;; goto end of procname
3685 (goto-char (cdr match))
3686
3687 ;; skip over parameterlist
3688 (forward-sexp)
3689 ;; if function, skip over 'return' and result type.
3690 (if func-found
3691 (progn
3692 (forward-word 1)
3693 (skip-chars-forward " \t\n")
3694 (setq functype (buffer-substring (point)
3695 (progn
3696 (skip-chars-forward
3697 "a-zA-Z0-9_\.")
3698 (point))))))
3699 ;; look for next non WS
3700 (cond
3701 ((looking-at "[ \t]*;")
3702 (delete-region (match-beginning 0) (match-end 0)) ;; delete the ';'
3703 (ada-indent-newline-indent)
3704 (insert " is")
3705 (ada-indent-newline-indent)
3706 (if func-found
3707 (progn
3708 (insert "Result : ")
3709 (insert functype)
3710 (insert ";")
3711 (ada-indent-newline-indent)))
3712 (insert "begin -- ")
3713 (insert procname)
3714 (ada-indent-newline-indent)
3715 (insert "null;")
3716 (ada-indent-newline-indent)
3717 (if func-found
3718 (progn
3719 (insert "return Result;")
3720 (ada-indent-newline-indent)))
3721 (insert "end ")
3722 (insert procname)
3723 (insert ";")
3724 (ada-indent-newline-indent)
3725 )
3726 ;; else
3727 ((looking-at "[ \t\n]*is")
3728 ;; do nothing
3729 )
3730 ((looking-at "[ \t\n]*rename")
3731 ;; do nothing
3732 )
3733 (t
3734 (message "unknown syntax")))
3735 ))))
3736
3737
3738 (defun ada-make-body ()
3739 "Create an Ada package body in the current buffer.
3740 The potential old buffer contents is deleted first, then we copy the
3741 spec buffer in here and modify it to make it a body.
3742
3743 This function typically is to be hooked into `ff-file-created-hooks'."
3744 (interactive)
3745 (delete-region (point-min) (point-max))
3746 (insert-buffer (car (cdr (buffer-list))))
3747 (ada-mode)
3748
3749 (let (found)
3750 (if (setq found
3751 (ada-search-ignore-string-comment ada-package-start-regexp))
3752 (progn (goto-char (cdr found))
3753 (insert " body")
3754 ;; (forward-line -1)
3755 ;;(comment-region (point-min) (point))
3756 )
3757 (error "No package"))
3758
3759 ;; (comment-until-proc)
3760 ;; does not work correctly
3761 ;; must be done by hand
3762
3763 (while (setq found
3764 (ada-search-ignore-string-comment ada-procedure-start-regexp))
3765 (ada-gen-treat-proc found))))
3766
3767
3768 ;;; provide ourself
3769
3770 (provide 'ada-mode)
3771
3772 ;;; ada-mode.el ends here