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