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