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