]> code.delx.au - gnu-emacs/blob - lisp/progmodes/ada-mode.el
* progmodes/ada-mode.el (ada-mode):
[gnu-emacs] / lisp / progmodes / ada-mode.el
1 ;;; ada-mode.el --- major-mode for editing Ada sources
2
3 ;; Copyright (C) 1994, 95, 97, 98, 99, 2000, 2001, 2002, 03, 2004
4 ;; Free Software Foundation, Inc.
5
6 ;; Author: Rolf Ebert <ebert@inf.enst.fr>
7 ;; Markus Heritsch <Markus.Heritsch@studbox.uni-stuttgart.de>
8 ;; Emmanuel Briot <briot@gnat.com>
9 ;; Maintainer: Emmanuel Briot <briot@gnat.com>
10 ;; Ada Core Technologies's version: Revision: 1.188
11 ;; Keywords: languages ada
12
13 ;; This file is part of GNU Emacs.
14
15 ;; GNU Emacs is free software; you can redistribute it and/or modify
16 ;; it under the terms of the GNU General Public License as published by
17 ;; the Free Software Foundation; either version 2, or (at your option)
18 ;; any later version.
19
20 ;; GNU Emacs is distributed in the hope that it will be useful,
21 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
22 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 ;; GNU General Public License for more details.
24
25 ;; You should have received a copy of the GNU General Public License
26 ;; along with GNU Emacs; see the file COPYING. If not, write to the
27 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
28 ;; Boston, MA 02111-1307, USA.
29
30 ;;; Commentary:
31 ;;; This mode is a major mode for editing Ada83 and Ada95 source code.
32 ;;; This is a major rewrite of the file packaged with Emacs-20. The
33 ;;; ada-mode is composed of four lisp files, ada-mode.el, ada-xref.el,
34 ;;; ada-prj.el and ada-stmt.el. Only this file (ada-mode.el) is
35 ;;; completely independent from the GNU Ada compiler Gnat, distributed
36 ;;; by Ada Core Technologies. All the other files rely heavily on
37 ;;; features provided only by Gnat.
38 ;;;
39 ;;; Note: this mode will not work with Emacs 19. If you are on a VMS
40 ;;; system, where the latest version of Emacs is 19.28, you will need
41 ;;; another file, called ada-vms.el, that provides some required
42 ;;; functions.
43
44 ;;; Usage:
45 ;;; Emacs should enter Ada mode automatically when you load an Ada file.
46 ;;; By default, the valid extensions for Ada files are .ads, .adb or .ada
47 ;;; If the ada-mode does not start automatically, then simply type the
48 ;;; following command :
49 ;;; M-x ada-mode
50 ;;;
51 ;;; By default, ada-mode is configured to take full advantage of the GNAT
52 ;;; compiler (the menus will include the cross-referencing features,...).
53 ;;; If you are using another compiler, you might want to set the following
54 ;;; variable in your .emacs (Note: do not set this in the ada-mode-hook, it
55 ;;; won't work) :
56 ;;; (setq ada-which-compiler 'generic)
57 ;;;
58 ;;; This mode requires find-file.el to be present on your system.
59
60 ;;; History:
61 ;;; The first Ada mode for GNU Emacs was written by V. Broman in
62 ;;; 1985. He based his work on the already existing Modula-2 mode.
63 ;;; This was distributed as ada.el in versions of Emacs prior to 19.29.
64 ;;;
65 ;;; Lynn Slater wrote an extensive Ada mode in 1989. It consisted of
66 ;;; several files with support for dired commands and other nice
67 ;;; things. It is currently available from the PAL
68 ;;; (wuarchive.wustl.edu:/languages/ada) as ada-mode-1.06a.tar.Z.
69 ;;;
70 ;;; The probably very first Ada mode (called electric-ada.el) was
71 ;;; written by Steven D. Litvintchouk and Steven M. Rosen for the
72 ;;; Gosling Emacs. L. Slater based his development on ada.el and
73 ;;; electric-ada.el.
74 ;;;
75 ;;; A complete rewrite by M. Heritsch and R. Ebert has been done.
76 ;;; Some ideas from the Ada mode mailing list have been
77 ;;; added. Some of the functionality of L. Slater's mode has not
78 ;;; (yet) been recoded in this new mode. Perhaps you prefer sticking
79 ;;; to his version.
80 ;;;
81 ;;; A complete rewrite for Emacs-20 / Gnat-3.11 has been done by Ada Core
82 ;;; Technologies. Please send bugs to briot@gnat.com
83
84 ;;; Credits:
85 ;;; Many thanks to John McCabe <john@assen.demon.co.uk> for sending so
86 ;;; many patches included in this package.
87 ;;; Christian Egli <Christian.Egli@hcsd.hac.com>:
88 ;;; ada-imenu-generic-expression
89 ;;; Many thanks also to the following persons that have contributed one day
90 ;;; to the ada-mode
91 ;;; Philippe Waroquiers (PW) <philippe@cfmu.eurocontrol.be> in particular,
92 ;;; woodruff@stc.llnl.gov (John Woodruff)
93 ;;; jj@ddci.dk (Jesper Joergensen)
94 ;;; gse@ocsystems.com (Scott Evans)
95 ;;; comar@gnat.com (Cyrille Comar)
96 ;;; stephen.leake@gsfc.nasa.gov (Stephen Leake)
97 ;;; robin-reply@reagans.org
98 ;;; and others for their valuable hints.
99
100 ;;; Code:
101 ;;; Note: Every function in this package is compiler-independent.
102 ;;; The names start with ada-
103 ;;; The variables that the user can edit can all be modified through
104 ;;; the customize mode. They are sorted in alphabetical order in this
105 ;;; file.
106
107 ;;; Supported packages.
108 ;;; This package supports a number of other Emacs modes. These other modes
109 ;;; should be loaded before the ada-mode, which will then setup some variables
110 ;;; to improve the support for Ada code.
111 ;;; Here is the list of these modes:
112 ;;; `which-function-mode': Display the name of the subprogram the cursor is
113 ;;; in in the mode line.
114 ;;; `outline-mode': Provides the capability to collapse or expand the code
115 ;;; for specific language constructs, for instance if you want to hide the
116 ;;; code corresponding to a subprogram
117 ;;; `align': This mode is now provided with Emacs 21, but can also be
118 ;;; installed manually for older versions of Emacs. It provides the
119 ;;; capability to automatically realign the selected region (for instance
120 ;;; all ':=', ':' and '--' will be aligned on top of each other.
121 ;;; `imenu': Provides a menu with the list of entities defined in the current
122 ;;; buffer, and an easy way to jump to any of them
123 ;;; `speedbar': Provides a separate file browser, and the capability for each
124 ;;; file to see the list of entities defined in it and to jump to them
125 ;;; easily
126 ;;; `abbrev-mode': Provides the capability to define abbreviations, which
127 ;;; are automatically expanded when you type them. See the Emacs manual.
128
129 (eval-when-compile
130 (require 'ispell nil t)
131 (require 'find-file nil t)
132 (require 'align nil t)
133 (require 'which-func nil t)
134 (require 'compile nil t))
135
136 ;; this function is needed at compile time
137 (eval-and-compile
138 (defun ada-check-emacs-version (major minor &optional is-xemacs)
139 "Returns t if Emacs's version is greater or equal to MAJOR.MINOR.
140 If IS-XEMACS is non-nil, check for XEmacs instead of Emacs."
141 (let ((xemacs-running (or (string-match "Lucid" emacs-version)
142 (string-match "XEmacs" emacs-version))))
143 (and (or (and is-xemacs xemacs-running)
144 (not (or is-xemacs xemacs-running)))
145 (or (> emacs-major-version major)
146 (and (= emacs-major-version major)
147 (>= emacs-minor-version minor)))))))
148
149
150 ;; This call should not be made in the release that is done for the
151 ;; official Emacs, since it does nothing useful for the latest version
152 ;;(if (not (ada-check-emacs-version 21 1))
153 ;; (require 'ada-support))
154
155 (defvar ada-mode-hook nil
156 "*List of functions to call when Ada mode is invoked.
157 This hook is automatically executed after the `ada-mode' is
158 fully loaded.
159 This is a good place to add Ada environment specific bindings.")
160
161 (defgroup ada nil
162 "Major mode for editing Ada source in Emacs."
163 :group 'languages)
164
165 (defcustom ada-auto-case t
166 "*Non-nil means automatically change case of preceding word while typing.
167 Casing is done according to `ada-case-keyword', `ada-case-identifier'
168 and `ada-case-attribute'."
169 :type 'boolean :group 'ada)
170
171 (defcustom ada-broken-decl-indent 0
172 "*Number of columns to indent a broken declaration.
173
174 An example is :
175 declare
176 A,
177 >>>>>B : Integer; -- from ada-broken-decl-indent"
178 :type 'integer :group 'ada)
179
180 (defcustom ada-broken-indent 2
181 "*Number of columns to indent the continuation of a broken line.
182
183 An example is :
184 My_Var : My_Type := (Field1 =>
185 >>>>>>>>>Value); -- from ada-broken-indent"
186 :type 'integer :group 'ada)
187
188 (defcustom ada-continuation-indent ada-broken-indent
189 "*Number of columns to indent the continuation of broken lines in
190 parenthesis.
191
192 An example is :
193 Func (Param1,
194 >>>>>Param2);"
195 :type 'integer :group 'ada)
196
197 (defcustom ada-case-attribute 'ada-capitalize-word
198 "*Function to call to adjust the case of Ada attributes.
199 It may be `downcase-word', `upcase-word', `ada-loose-case-word',
200 `ada-capitalize-word' or `ada-no-auto-case'."
201 :type '(choice (const downcase-word)
202 (const upcase-word)
203 (const ada-capitalize-word)
204 (const ada-loose-case-word)
205 (const ada-no-auto-case))
206 :group 'ada)
207
208 (defcustom ada-case-exception-file
209 (list (convert-standard-filename' "~/.emacs_case_exceptions"))
210 "*List of special casing exceptions dictionaries for identifiers.
211 The first file is the one where new exceptions will be saved by Emacs
212 when you call `ada-create-case-exception'.
213
214 These files should contain one word per line, that gives the casing
215 to be used for that word in Ada files. If the line starts with the
216 character *, then the exception will be used for substrings that either
217 start at the beginning of a word or after a _ character, and end either
218 at the end of the word or at a _ character. Each line can be terminated by
219 a comment."
220 :type '(repeat (file))
221 :group 'ada)
222
223 (defcustom ada-case-keyword 'downcase-word
224 "*Function to call to adjust the case of an Ada keywords.
225 It may be `downcase-word', `upcase-word', `ada-loose-case-word' or
226 `ada-capitalize-word'."
227 :type '(choice (const downcase-word)
228 (const upcase-word)
229 (const ada-capitalize-word)
230 (const ada-loose-case-word)
231 (const ada-no-auto-case))
232 :group 'ada)
233
234 (defcustom ada-case-identifier 'ada-loose-case-word
235 "*Function to call to adjust the case of an Ada identifier.
236 It may be `downcase-word', `upcase-word', `ada-loose-case-word' or
237 `ada-capitalize-word'."
238 :type '(choice (const downcase-word)
239 (const upcase-word)
240 (const ada-capitalize-word)
241 (const ada-loose-case-word)
242 (const ada-no-auto-case))
243 :group 'ada)
244
245 (defcustom ada-clean-buffer-before-saving t
246 "*Non-nil means remove trailing spaces and untabify the buffer before saving."
247 :type 'boolean :group 'ada)
248
249 (defcustom ada-indent 3
250 "*Size of Ada indentation.
251
252 An example is :
253 procedure Foo is
254 begin
255 >>>>>>>>>>null; -- from ada-indent"
256 :type 'integer :group 'ada)
257
258 (defcustom ada-indent-after-return t
259 "*Non-nil means automatically indent after RET or LFD."
260 :type 'boolean :group 'ada)
261
262 (defcustom ada-indent-align-comments t
263 "*Non-nil means align comments on previous line comments, if any.
264 If nil, indentation is calculated as usual.
265 Note that indentation is calculated only if `ada-indent-comment-as-code' is t.
266
267 For instance:
268 A := 1; -- A multi-line comment
269 -- aligned if ada-indent-align-comments is t"
270 :type 'boolean :group 'ada)
271
272 (defcustom ada-indent-comment-as-code t
273 "*Non-nil means indent comment lines as code.
274 nil means do not auto-indent comments."
275 :type 'boolean :group 'ada)
276
277 (defcustom ada-indent-handle-comment-special nil
278 "*Non-nil if comment lines should be handled specially inside
279 parenthesis.
280 By default, if the line that contains the open parenthesis has some
281 text following it, then the following lines will be indented in the
282 same column as this text. This will not be true if the first line is
283 a comment and `ada-indent-handle-comment-special' is t.
284
285 type A is
286 ( Value_1, -- common behavior, when not a comment
287 Value_2);
288
289 type A is
290 ( -- `ada-indent-handle-comment-special' is nil
291 Value_1,
292 Value_2);
293
294 type A is
295 ( -- `ada-indent-handle-comment-special' is non-nil
296 Value_1,
297 Value_2);"
298 :type 'boolean :group 'ada)
299
300 (defcustom ada-indent-is-separate t
301 "*Non-nil means indent 'is separate' or 'is abstract' if on a single line."
302 :type 'boolean :group 'ada)
303
304 (defcustom ada-indent-record-rel-type 3
305 "*Indentation for 'record' relative to 'type' or 'use'.
306
307 An example is:
308 type A is
309 >>>>>>>>>>>record -- from ada-indent-record-rel-type"
310 :type 'integer :group 'ada)
311
312 (defcustom ada-indent-renames ada-broken-indent
313 "*Indentation for renames relative to the matching function statement.
314 If ada-indent-return is null or negative, the indentation is done relative to
315 the open parenthesis (if there is no parenthesis, ada-broken-indent is used).
316
317 An example is:
318 function A (B : Integer)
319 return C; -- from ada-indent-return
320 >>>renames Foo; -- from ada-indent-renames"
321 :type 'integer :group 'ada)
322
323 (defcustom ada-indent-return 0
324 "*Indentation for 'return' relative to the matching 'function' statement.
325 If ada-indent-return is null or negative, the indentation is done relative to
326 the open parenthesis (if there is no parenthesis, ada-broken-indent is used).
327
328 An example is:
329 function A (B : Integer)
330 >>>>>return C; -- from ada-indent-return"
331 :type 'integer :group 'ada)
332
333 (defcustom ada-indent-to-open-paren t
334 "*Non-nil means indent according to the innermost open parenthesis."
335 :type 'boolean :group 'ada)
336
337 (defcustom ada-fill-comment-prefix "-- "
338 "*Text inserted in the first columns when filling a comment paragraph.
339 Note: if you modify this variable, you will have to invoke `ada-mode'
340 again to take account of the new value."
341 :type 'string :group 'ada)
342
343 (defcustom ada-fill-comment-postfix " --"
344 "*Text inserted at the end of each line when filling a comment paragraph.
345 with `ada-fill-comment-paragraph-postfix'."
346 :type 'string :group 'ada)
347
348 (defcustom ada-label-indent -4
349 "*Number of columns to indent a label.
350
351 An example is:
352 procedure Foo is
353 begin
354 >>>>>>>>>>>>Label: -- from ada-label-indent
355
356 This is also used for <<..>> labels"
357 :type 'integer :group 'ada)
358
359 (defcustom ada-language-version 'ada95
360 "*Do we program in `ada83' or `ada95'?"
361 :type '(choice (const ada83) (const ada95)) :group 'ada)
362
363 (defcustom ada-move-to-declaration nil
364 "*Non-nil means `ada-move-to-start' moves point to the subprogram declaration,
365 not to 'begin'."
366 :type 'boolean :group 'ada)
367
368 (defcustom ada-popup-key '[down-mouse-3]
369 "*Key used for binding the contextual menu.
370 If nil, no contextual menu is available."
371 :type '(restricted-sexp :match-alternatives (stringp vectorp))
372 :group 'ada)
373
374 (defcustom ada-search-directories
375 (append '(".")
376 (split-string (or (getenv "ADA_INCLUDE_PATH") "") ":")
377 '("/usr/adainclude" "/usr/local/adainclude"
378 "/opt/gnu/adainclude"))
379 "*List of directories to search for Ada files.
380 See the description for the `ff-search-directories' variable. This variable
381 is the initial value of this variable, and is copied and modified in
382 `ada-search-directories-internal'."
383 :type '(repeat (choice :tag "Directory"
384 (const :tag "default" nil)
385 (directory :format "%v")))
386 :group 'ada)
387
388 (defvar ada-search-directories-internal ada-search-directories
389 "Internal version of `ada-search-directories'.
390 Its value is the concatenation of the search path as read in the project file
391 and the standard runtime location, and the value of the user-defined
392 ada-search-directories.")
393
394 (defcustom ada-stmt-end-indent 0
395 "*Number of columns to indent the end of a statement on a separate line.
396
397 An example is:
398 if A = B
399 >>>>>>>>>>>then -- from ada-stmt-end-indent"
400 :type 'integer :group 'ada)
401
402 (defcustom ada-tab-policy 'indent-auto
403 "*Control the behavior of the TAB key.
404 Must be one of :
405 `indent-rigidly' : always adds ada-indent blanks at the beginning of the line.
406 `indent-auto' : use indentation functions in this file.
407 `always-tab' : do indent-relative."
408 :type '(choice (const indent-auto)
409 (const indent-rigidly)
410 (const always-tab))
411 :group 'ada)
412
413 (defcustom ada-use-indent ada-broken-indent
414 "*Indentation for the lines in a 'use' statement.
415
416 An example is:
417 use Ada.Text_IO,
418 >>>>>Ada.Numerics; -- from ada-use-indent"
419 :type 'integer :group 'ada)
420
421 (defcustom ada-when-indent 3
422 "*Indentation for 'when' relative to 'exception' or 'case'.
423
424 An example is:
425 case A is
426 >>>>>>>>when B => -- from ada-when-indent"
427 :type 'integer :group 'ada)
428
429 (defcustom ada-with-indent ada-broken-indent
430 "*Indentation for the lines in a 'with' statement.
431
432 An example is:
433 with Ada.Text_IO,
434 >>>>>Ada.Numerics; -- from ada-with-indent"
435 :type 'integer :group 'ada)
436
437 (defcustom ada-which-compiler 'gnat
438 "*Name of the compiler to use.
439 This will determine what features are made available through the ada-mode.
440 The possible choices are :
441 `gnat': Use Ada Core Technologies' Gnat compiler. Add some cross-referencing
442 features
443 `generic': Use a generic compiler"
444 :type '(choice (const gnat)
445 (const generic))
446 :group 'ada)
447
448
449 ;;; ---- end of user configurable variables
450 \f
451
452 (defvar ada-body-suffixes '(".adb")
453 "List of possible suffixes for Ada body files.
454 The extensions should include a `.' if needed.")
455
456 (defvar ada-spec-suffixes '(".ads")
457 "List of possible suffixes for Ada spec files.
458 The extensions should include a `.' if needed.")
459
460 (defvar ada-mode-menu (make-sparse-keymap "Ada")
461 "Menu for ada-mode.")
462
463 (defvar ada-mode-map (make-sparse-keymap)
464 "Local keymap used for Ada mode.")
465
466 (defvar ada-mode-abbrev-table nil
467 "Local abbrev table for Ada mode.")
468
469 (defvar ada-mode-syntax-table nil
470 "Syntax table to be used for editing Ada source code.")
471
472 (defvar ada-mode-symbol-syntax-table nil
473 "Syntax table for Ada, where `_' is a word constituent.")
474
475 (eval-when-compile
476 (defconst ada-83-string-keywords
477 '("abort" "abs" "accept" "access" "all" "and" "array" "at" "begin"
478 "body" "case" "constant" "declare" "delay" "delta" "digits" "do"
479 "else" "elsif" "end" "entry" "exception" "exit" "for" "function"
480 "generic" "goto" "if" "in" "is" "limited" "loop" "mod" "new"
481 "not" "null" "of" "or" "others" "out" "package" "pragma" "private"
482 "procedure" "raise" "range" "record" "rem" "renames" "return"
483 "reverse" "select" "separate" "subtype" "task" "terminate" "then"
484 "type" "use" "when" "while" "with" "xor")
485 "List of Ada keywords.
486 This variable is used to define `ada-83-keywords' and `ada-95-keywords'"))
487
488 (defvar ada-ret-binding nil
489 "Variable to save key binding of RET when casing is activated.")
490
491 (defvar ada-case-exception '()
492 "Alist of words (entities) that have special casing.")
493
494 (defvar ada-case-exception-substring '()
495 "Alist of substrings (entities) that have special casing.
496 The substrings are detected for word constituant when the word
497 is not itself in ada-case-exception, and only for substrings that
498 either are at the beginning or end of the word, or start after '_'.")
499
500 (defvar ada-lfd-binding nil
501 "Variable to save key binding of LFD when casing is activated.")
502
503 (defvar ada-other-file-alist nil
504 "Variable used by find-file to find the name of the other package.
505 See `ff-other-file-alist'.")
506
507 (defvar ada-align-list
508 '(("[^:]\\(\\s-*\\):[^:]" 1 t)
509 ("[^=]\\(\\s-+\\)=[^=]" 1 t)
510 ("\\(\\s-*\\)use\\s-" 1)
511 ("\\(\\s-*\\)--" 1))
512 "Ada support for align.el <= 2.2
513 This variable provides regular expressions on which to align different lines.
514 See `align-mode-alist' for more information.")
515
516 (defvar ada-align-modes
517 '((ada-declaration
518 (regexp . "[^:]\\(\\s-*\\):[^:]")
519 (valid . (lambda() (not (ada-in-comment-p))))
520 (modes . '(ada-mode)))
521 (ada-assignment
522 (regexp . "[^=]\\(\\s-+\\)=[^=]")
523 (valid . (lambda() (not (ada-in-comment-p))))
524 (modes . '(ada-mode)))
525 (ada-comment
526 (regexp . "\\(\\s-*\\)--")
527 (modes . '(ada-mode)))
528 (ada-use
529 (regexp . "\\(\\s-*\\)use\\s-")
530 (valid . (lambda() (not (ada-in-comment-p))))
531 (modes . '(ada-mode)))
532 )
533 "Ada support for align.el >= 2.8
534 This variable defines several rules to use to align different lines.")
535
536 (defconst ada-align-region-separate
537 (concat
538 "^\\s-*\\($\\|\\("
539 "begin\\|"
540 "declare\\|"
541 "else\\|"
542 "end\\|"
543 "exception\\|"
544 "for\\|"
545 "function\\|"
546 "generic\\|"
547 "if\\|"
548 "is\\|"
549 "procedure\\|"
550 "record\\|"
551 "return\\|"
552 "type\\|"
553 "when"
554 "\\)\\>\\)")
555 "see the variable `align-region-separate' for more information.")
556
557 ;;; ---- Below are the regexp used in this package for parsing
558
559 (defconst ada-83-keywords
560 (eval-when-compile
561 (concat "\\<" (regexp-opt ada-83-string-keywords t) "\\>"))
562 "Regular expression for looking at Ada83 keywords.")
563
564 (defconst ada-95-keywords
565 (eval-when-compile
566 (concat "\\<" (regexp-opt
567 (append
568 '("abstract" "aliased" "protected" "requeue"
569 "tagged" "until")
570 ada-83-string-keywords) t) "\\>"))
571 "Regular expression for looking at Ada95 keywords.")
572
573 (defvar ada-keywords ada-95-keywords
574 "Regular expression for looking at Ada keywords.")
575
576 (defconst ada-ident-re
577 "\\(\\sw\\|[_.]\\)+"
578 "Regexp matching Ada (qualified) identifiers.")
579
580 ;; "with" needs to be included in the regexp, so that we can insert new lines
581 ;; after the declaration of the parameter for a generic.
582 (defvar ada-procedure-start-regexp
583 (concat
584 "^[ \t]*\\(with[ \t]+\\)?\\(procedure\\|function\\|task\\)[ \t\n]+"
585
586 ;; subprogram name: operator ("[+/=*]")
587 "\\("
588 "\\(\"[^\"]+\"\\)"
589
590 ;; subprogram name: name
591 "\\|"
592 "\\(\\(\\sw\\|[_.]\\)+\\)"
593 "\\)")
594 "Regexp used to find Ada procedures/functions.")
595
596 (defvar ada-package-start-regexp
597 "^[ \t]*\\(package\\)"
598 "Regexp used to find Ada packages.")
599
600
601 ;;; ---- regexps for indentation functions
602
603 (defvar ada-block-start-re
604 (eval-when-compile
605 (concat "\\<\\(" (regexp-opt '("begin" "declare" "else"
606 "exception" "generic" "loop" "or"
607 "private" "select" ))
608 "\\|\\(\\(limited\\|abstract\\|tagged\\)[ \t\n]+\\)*record\\)\\>"))
609 "Regexp for keywords starting Ada blocks.")
610
611 (defvar ada-end-stmt-re
612 (eval-when-compile
613 (concat "\\("
614 ";" "\\|"
615 "=>[ \t]*$" "\\|"
616 "^[ \t]*separate[ \t]*(\\(\\sw\\|[_.]\\)+)" "\\|"
617 "\\<" (regexp-opt '("begin" "declare" "is" "do" "else" "generic"
618 "loop" "private" "record" "select"
619 "then abort" "then") t) "\\>" "\\|"
620 "^[ \t]*" (regexp-opt '("function" "package" "procedure")
621 t) "\\>\\(\\sw\\|[ \t_.]\\)+\\<is\\>" "\\|"
622 "^[ \t]*exception\\>"
623 "\\)") )
624 "Regexp of possible ends for a non-broken statement.
625 A new statement starts after these.")
626
627 (defvar ada-matching-start-re
628 (eval-when-compile
629 (concat "\\<"
630 (regexp-opt
631 '("end" "loop" "select" "begin" "case" "do"
632 "if" "task" "package" "record" "protected") t)
633 "\\>"))
634 "Regexp used in ada-goto-matching-start.")
635
636 (defvar ada-matching-decl-start-re
637 (eval-when-compile
638 (concat "\\<"
639 (regexp-opt
640 '("is" "separate" "end" "declare" "if" "new" "begin" "generic" "when") t)
641 "\\>"))
642 "Regexp used in ada-goto-matching-decl-start.")
643
644 (defvar ada-loop-start-re
645 "\\<\\(for\\|while\\|loop\\)\\>"
646 "Regexp for the start of a loop.")
647
648 (defvar ada-subprog-start-re
649 (eval-when-compile
650 (concat "\\<" (regexp-opt '("accept" "entry" "function" "package" "procedure"
651 "protected" "task") t) "\\>"))
652 "Regexp for the start of a subprogram.")
653
654 (defvar ada-named-block-re
655 "[ \t]*\\(\\sw\\|_\\)+[ \t]*:[^=]"
656 "Regexp of the name of a block or loop.")
657
658 (defvar ada-contextual-menu-on-identifier nil
659 "Set to true when the right mouse button was clicked on an identifier.")
660
661 (defvar ada-contextual-menu-last-point nil
662 "Position of point just before displaying the menu.
663 This is a list (point buffer).
664 Since `ada-popup-menu' moves the point where the user clicked, the region
665 is modified. Therefore no command from the menu knows what the user selected
666 before displaying the contextual menu.
667 To get the original region, restore the point to this position before
668 calling `region-end' and `region-beginning'.
669 Modify this variable if you want to restore the point to another position.")
670
671 (easy-menu-define ada-contextual-menu nil
672 "Menu to use when the user presses the right mouse button.
673 The variable `ada-contextual-menu-on-identifier' will be set to t before
674 displaying the menu if point was on an identifier."
675 '("Ada"
676 ["Goto Declaration/Body" ada-point-and-xref
677 :included ada-contextual-menu-on-identifier]
678 ["Goto Body" ada-point-and-xref-body
679 :included ada-contextual-menu-on-identifier]
680 ["Goto Previous Reference" ada-xref-goto-previous-reference]
681 ["List References" ada-find-references
682 :included ada-contextual-menu-on-identifier]
683 ["List Local References" ada-find-local-references
684 :included ada-contextual-menu-on-identifier]
685 ["-" nil nil]
686 ["Other File" ff-find-other-file]
687 ["Goto Parent Unit" ada-goto-parent]))
688
689 \f
690 ;;------------------------------------------------------------------
691 ;; Support for imenu (see imenu.el)
692 ;;------------------------------------------------------------------
693
694 (defconst ada-imenu-comment-re "\\([ \t]*--.*\\)?")
695
696 (defconst ada-imenu-subprogram-menu-re
697 (concat "^[ \t]*\\(procedure\\|function\\)[ \t\n]+"
698 "\\(\\(\\sw\\|_\\)+\\)[ \t\n]*\\([ \t\n]\\|([^)]+)"
699 ada-imenu-comment-re
700 "\\)[ \t\n]*"
701 "\\(return[ \t\n]+\\(\\sw\\|[_.]\\)+[ \t\n]*\\)?is[ \t\n]"))
702
703 (defvar ada-imenu-generic-expression
704 (list
705 (list nil ada-imenu-subprogram-menu-re 2)
706 (list "*Specs*"
707 (concat
708 "^[ \t]*\\(procedure\\|function\\)[ \t\n]+\\(\\(\\sw\\|_\\)+\\)"
709 "\\("
710 "\\(" ada-imenu-comment-re "[ \t\n]+\\|[ \t\n]*([^)]+)"
711 ada-imenu-comment-re "\\)";; parameter list or simple space
712 "\\([ \t\n]*return[ \t\n]+\\(\\sw\\|[_.]\\)+[ \t\n]*\\)?"
713 "\\)?;") 2)
714 '("*Tasks*" "^[ \t]*task[ \t]+\\(type[ \t]+\\)?\\(\\(body[ \t]+\\)?\\(\\sw\\|_\\)+\\)" 2)
715 '("*Type Defs*" "^[ \t]*\\(sub\\)?type[ \t]+\\(\\(\\sw\\|_\\)+\\)" 2)
716 '("*Protected*"
717 "^[ \t]*protected[ \t]+\\(type[ \t]+\\)?\\(\\(body[ \t]+\\)?\\(\\sw\\|_\\)+\\)" 2)
718 '("*Packages*" "^[ \t]*package[ \t]+\\(\\(body[ \t]+\\)?\\(\\sw\\|[_.]\\)+\\)" 1))
719 "Imenu generic expression for Ada mode.
720 See `imenu-generic-expression'. This variable will create several submenus for
721 each type of entity that can be found in an Ada file.")
722
723 \f
724 ;;------------------------------------------------------------
725 ;; Support for compile.el
726 ;;------------------------------------------------------------
727
728 (defun ada-compile-mouse-goto-error ()
729 "Mouse interface for ada-compile-goto-error."
730 (interactive)
731 (mouse-set-point last-input-event)
732 (ada-compile-goto-error (point))
733 )
734
735 (defun ada-compile-goto-error (pos)
736 "Replaces `compile-goto-error' from compile.el.
737 If POS is on a file and line location, go to this position. It adds to
738 compile.el the capacity to go to a reference in an error message.
739 For instance, on this line:
740 foo.adb:61:11: [...] in call to size declared at foo.ads:11
741 both file locations can be clicked on and jumped to."
742 (interactive "d")
743 (goto-char pos)
744
745 (skip-chars-backward "-a-zA-Z0-9_:./\\")
746 (cond
747 ;; special case: looking at a filename:line not at the beginning of a line
748 ((and (not (bolp))
749 (looking-at
750 "\\([-_.a-zA-Z0-9]+\\):\\([0-9]+\\)\\(:\\([0-9]+\\)\\)?"))
751 (let ((line (match-string 2))
752 file
753 (error-pos (point-marker))
754 source)
755 (save-excursion
756 (save-restriction
757 (widen)
758 ;; Use funcall so as to prevent byte-compiler warnings
759 ;; `ada-find-file' is not defined if ada-xref wasn't loaded. But
760 ;; if we can find it, we should use it instead of
761 ;; `compilation-find-file', since the latter doesn't know anything
762 ;; about source path.
763
764 (if (functionp 'ada-find-file)
765 (setq file (funcall (symbol-function 'ada-find-file)
766 (match-string 1)))
767 (setq file (funcall (symbol-function 'compilation-find-file)
768 (point-marker) (match-string 1)
769 "./")))
770 (set-buffer file)
771
772 (if (stringp line)
773 (goto-line (string-to-number line)))
774 (setq source (point-marker))))
775 (funcall (symbol-function 'compilation-goto-locus)
776 (cons source error-pos))
777 ))
778
779 ;; otherwise, default behavior
780 (t
781 (funcall (symbol-function 'compile-goto-error)))
782 )
783 (recenter))
784
785 \f
786 ;;-------------------------------------------------------------------------
787 ;; Grammar related function
788 ;; The functions below work with the syntax class of the characters in an Ada
789 ;; buffer. Two syntax tables are created, depending on whether we want '_'
790 ;; to be considered as part of a word or not.
791 ;; Some characters may have multiple meanings depending on the context:
792 ;; - ' is either the beginning of a constant character or an attribute
793 ;; - # is either part of a based litteral or a gnatprep statement.
794 ;; - " starts a string, but not if inside a constant character.
795 ;; - ( and ) should be ignored if inside a constant character.
796 ;; Thus their syntax property is changed automatically, and we can still use
797 ;; the standard Emacs functions for sexp (see `ada-in-string-p')
798 ;;
799 ;; On Emacs, this is done through the `syntax-table' text property. The
800 ;; modification is done automatically each time the user as typed a new
801 ;; character. This is already done in `font-lock-mode' (in
802 ;; `font-lock-syntactic-keywords', so we take advantage of the existing
803 ;; mechanism. If font-lock-mode is not activated, we do it by hand in
804 ;; `ada-after-change-function', thanks to `ada-deactivate-properties' and
805 ;; `ada-initialize-properties'.
806 ;;
807 ;; on XEmacs, the `syntax-table' property does not exist and we have to use a
808 ;; slow advice to `parse-partial-sexp' to do the same thing.
809 ;; When executing parse-partial-sexp, we simply modify the strings before and
810 ;; after, so that the special constants '"', '(' and ')' do not interact
811 ;; with parse-partial-sexp.
812 ;; Note: this code is slow and needs to be rewritten as soon as something
813 ;; better is available on XEmacs.
814 ;;-------------------------------------------------------------------------
815
816 (defun ada-create-syntax-table ()
817 "Create the two syntax tables use in the Ada mode.
818 The standard table declares `_' as a symbol constituent, the second one
819 declares it as a word constituent."
820 (interactive)
821 (setq ada-mode-syntax-table (make-syntax-table))
822 (set-syntax-table ada-mode-syntax-table)
823
824 ;; define string brackets (`%' is alternative string bracket, but
825 ;; almost never used as such and throws font-lock and indentation
826 ;; off the track.)
827 (modify-syntax-entry ?% "$" ada-mode-syntax-table)
828 (modify-syntax-entry ?\" "\"" ada-mode-syntax-table)
829
830 (modify-syntax-entry ?: "." ada-mode-syntax-table)
831 (modify-syntax-entry ?\; "." ada-mode-syntax-table)
832 (modify-syntax-entry ?& "." ada-mode-syntax-table)
833 (modify-syntax-entry ?\| "." ada-mode-syntax-table)
834 (modify-syntax-entry ?+ "." ada-mode-syntax-table)
835 (modify-syntax-entry ?* "." ada-mode-syntax-table)
836 (modify-syntax-entry ?/ "." ada-mode-syntax-table)
837 (modify-syntax-entry ?= "." ada-mode-syntax-table)
838 (modify-syntax-entry ?< "." ada-mode-syntax-table)
839 (modify-syntax-entry ?> "." ada-mode-syntax-table)
840 (modify-syntax-entry ?$ "." ada-mode-syntax-table)
841 (modify-syntax-entry ?\[ "." ada-mode-syntax-table)
842 (modify-syntax-entry ?\] "." ada-mode-syntax-table)
843 (modify-syntax-entry ?\{ "." ada-mode-syntax-table)
844 (modify-syntax-entry ?\} "." ada-mode-syntax-table)
845 (modify-syntax-entry ?. "." ada-mode-syntax-table)
846 (modify-syntax-entry ?\\ "." ada-mode-syntax-table)
847 (modify-syntax-entry ?\' "." ada-mode-syntax-table)
848
849 ;; a single hyphen is punctuation, but a double hyphen starts a comment
850 (modify-syntax-entry ?- ". 12" ada-mode-syntax-table)
851
852 ;; See the comment above on grammar related function for the special
853 ;; setup for '#'.
854 (if (featurep 'xemacs)
855 (modify-syntax-entry ?# "<" ada-mode-syntax-table)
856 (modify-syntax-entry ?# "$" ada-mode-syntax-table))
857
858 ;; and \f and \n end a comment
859 (modify-syntax-entry ?\f "> " ada-mode-syntax-table)
860 (modify-syntax-entry ?\n "> " ada-mode-syntax-table)
861
862 ;; define what belongs in Ada symbols
863 (modify-syntax-entry ?_ "_" ada-mode-syntax-table)
864
865 ;; define parentheses to match
866 (modify-syntax-entry ?\( "()" ada-mode-syntax-table)
867 (modify-syntax-entry ?\) ")(" ada-mode-syntax-table)
868
869 (setq ada-mode-symbol-syntax-table (copy-syntax-table ada-mode-syntax-table))
870 (modify-syntax-entry ?_ "w" ada-mode-symbol-syntax-table)
871 )
872
873 ;; Support of special characters in XEmacs (see the comments at the beginning
874 ;; of the section on Grammar related functions).
875
876 (if (featurep 'xemacs)
877 (defadvice parse-partial-sexp (around parse-partial-sexp-protect-constants)
878 "Handles special character constants and gnatprep statements."
879 (let (change)
880 (if (< to from)
881 (let ((tmp from))
882 (setq from to to tmp)))
883 (save-excursion
884 (goto-char from)
885 (while (re-search-forward "'\\([(\")#]\\)'" to t)
886 (setq change (cons (list (match-beginning 1)
887 1
888 (match-string 1))
889 change))
890 (replace-match "'A'"))
891 (goto-char from)
892 (while (re-search-forward "\\(#[0-9a-fA-F]*#\\)" to t)
893 (setq change (cons (list (match-beginning 1)
894 (length (match-string 1))
895 (match-string 1))
896 change))
897 (replace-match (make-string (length (match-string 1)) ?@))))
898 ad-do-it
899 (save-excursion
900 (while change
901 (goto-char (caar change))
902 (delete-char (cadar change))
903 (insert (caddar change))
904 (setq change (cdr change)))))))
905
906 (defun ada-deactivate-properties ()
907 "Deactivate ada-mode's properties handling.
908 This would be a duplicate of font-lock if both are used at the same time."
909 (remove-hook 'after-change-functions 'ada-after-change-function t))
910
911 (defun ada-initialize-properties ()
912 "Initialize some special text properties in the whole buffer.
913 In particular, character constants are said to be strings, #...# are treated
914 as numbers instead of gnatprep comments."
915 (save-excursion
916 (save-restriction
917 (widen)
918 (goto-char (point-min))
919 (while (re-search-forward "'.'" nil t)
920 (add-text-properties (match-beginning 0) (match-end 0)
921 '(syntax-table ("'" . ?\"))))
922 (goto-char (point-min))
923 (while (re-search-forward "^[ \t]*#" nil t)
924 (add-text-properties (match-beginning 0) (match-end 0)
925 '(syntax-table (11 . 10))))
926 (set-buffer-modified-p nil)
927
928 ;; Setting this only if font-lock is not set won't work
929 ;; if the user activates or deactivates font-lock-mode,
930 ;; but will make things faster most of the time
931 (add-hook 'after-change-functions 'ada-after-change-function nil t)
932 )))
933
934 (defun ada-after-change-function (beg end old-len)
935 "Called when the region between BEG and END was changed in the buffer.
936 OLD-LEN indicates what the length of the replaced text was."
937 (let ((inhibit-point-motion-hooks t)
938 (eol (point)))
939 (save-excursion
940 (save-match-data
941 (beginning-of-line)
942 (remove-text-properties (point) eol '(syntax-table nil))
943 (while (re-search-forward "'.'" eol t)
944 (add-text-properties (match-beginning 0) (match-end 0)
945 '(syntax-table ("'" . ?\"))))
946 (beginning-of-line)
947 (if (looking-at "^[ \t]*#")
948 (add-text-properties (match-beginning 0) (match-end 0)
949 '(syntax-table (11 . 10))))))))
950
951 ;;------------------------------------------------------------------
952 ;; Testing the grammatical context
953 ;;------------------------------------------------------------------
954
955 (defsubst ada-in-comment-p (&optional parse-result)
956 "Returns t if inside a comment."
957 (nth 4 (or parse-result
958 (parse-partial-sexp
959 (line-beginning-position) (point)))))
960
961 (defsubst ada-in-string-p (&optional parse-result)
962 "Returns t if point is inside a string.
963 If parse-result is non-nil, use is instead of calling parse-partial-sexp."
964 (nth 3 (or parse-result
965 (parse-partial-sexp
966 (line-beginning-position) (point)))))
967
968 (defsubst ada-in-string-or-comment-p (&optional parse-result)
969 "Returns t if inside a comment or string."
970 (setq parse-result (or parse-result
971 (parse-partial-sexp
972 (line-beginning-position) (point))))
973 (or (ada-in-string-p parse-result) (ada-in-comment-p parse-result)))
974
975
976 ;;------------------------------------------------------------------
977 ;; Contextual menus
978 ;; The Ada-mode comes with contextual menus, bound by default to the right
979 ;; mouse button.
980 ;; Add items to this menu by modifying `ada-contextual-menu'. Note that the
981 ;; variable `ada-contextual-menu-on-identifier' is set automatically to t
982 ;; if the mouse button was pressed on an identifier.
983 ;;------------------------------------------------------------------
984
985 (defun ada-call-from-contextual-menu (function)
986 "Execute FUNCTION when called from the contextual menu.
987 It forces Emacs to change the cursor position."
988 (interactive)
989 (funcall function)
990 (setq ada-contextual-menu-last-point
991 (list (point) (current-buffer))))
992
993 (defun ada-popup-menu (position)
994 "Pops up a contextual menu, depending on where the user clicked.
995 POSITION is the location the mouse was clicked on.
996 Sets `ada-contextual-menu-last-point' to the current position before
997 displaying the menu. When a function from the menu is called, the point is
998 where the mouse button was clicked."
999 (interactive "e")
1000
1001 ;; declare this as a local variable, so that the function called
1002 ;; in the contextual menu does not hide the region in
1003 ;; transient-mark-mode.
1004 (let ((deactivate-mark nil))
1005 (setq ada-contextual-menu-last-point
1006 (list (point) (current-buffer)))
1007 (mouse-set-point last-input-event)
1008
1009 (setq ada-contextual-menu-on-identifier
1010 (and (char-after)
1011 (or (= (char-syntax (char-after)) ?w)
1012 (= (char-after) ?_))
1013 (not (ada-in-string-or-comment-p))
1014 (save-excursion (skip-syntax-forward "w")
1015 (not (ada-after-keyword-p)))
1016 ))
1017 (if (fboundp 'popup-menu)
1018 (funcall (symbol-function 'popup-menu) ada-contextual-menu)
1019 (let (choice)
1020 (setq choice (x-popup-menu position ada-contextual-menu))
1021 (if choice
1022 (funcall (lookup-key ada-contextual-menu (vector (car choice)))))))
1023
1024 (set-buffer (cadr ada-contextual-menu-last-point))
1025 (goto-char (car ada-contextual-menu-last-point))
1026 ))
1027
1028
1029 ;;------------------------------------------------------------------
1030 ;; Misc functions
1031 ;;------------------------------------------------------------------
1032
1033 ;;;###autoload
1034 (defun ada-add-extensions (spec body)
1035 "Define SPEC and BODY as being valid extensions for Ada files.
1036 Going from body to spec with `ff-find-other-file' used these
1037 extensions.
1038 SPEC and BODY are two regular expressions that must match against the file
1039 name"
1040 (let* ((reg (concat (regexp-quote body) "$"))
1041 (tmp (assoc reg ada-other-file-alist)))
1042 (if tmp
1043 (setcdr tmp (list (cons spec (cadr tmp))))
1044 (add-to-list 'ada-other-file-alist (list reg (list spec)))))
1045
1046 (let* ((reg (concat (regexp-quote spec) "$"))
1047 (tmp (assoc reg ada-other-file-alist)))
1048 (if tmp
1049 (setcdr tmp (list (cons body (cadr tmp))))
1050 (add-to-list 'ada-other-file-alist (list reg (list body)))))
1051
1052 (add-to-list 'auto-mode-alist
1053 (cons (concat (regexp-quote spec) "\\'") 'ada-mode))
1054 (add-to-list 'auto-mode-alist
1055 (cons (concat (regexp-quote body) "\\'") 'ada-mode))
1056
1057 (add-to-list 'ada-spec-suffixes spec)
1058 (add-to-list 'ada-body-suffixes body)
1059
1060 ;; Support for speedbar (Specifies that we want to see these files in
1061 ;; speedbar)
1062 (if (fboundp 'speedbar-add-supported-extension)
1063 (progn
1064 (funcall (symbol-function 'speedbar-add-supported-extension)
1065 spec)
1066 (funcall (symbol-function 'speedbar-add-supported-extension)
1067 body)))
1068 )
1069
1070
1071 ;;;###autoload
1072 (defun ada-mode ()
1073 "Ada mode is the major mode for editing Ada code.
1074
1075 Bindings are as follows: (Note: 'LFD' is control-j.)
1076 \\{ada-mode-map}
1077
1078 Indent line '\\[ada-tab]'
1079 Indent line, insert newline and indent the new line. '\\[newline-and-indent]'
1080
1081 Re-format the parameter-list point is in '\\[ada-format-paramlist]'
1082 Indent all lines in region '\\[ada-indent-region]'
1083
1084 Adjust case of identifiers and keywords in region '\\[ada-adjust-case-region]'
1085 Adjust case of identifiers and keywords in buffer '\\[ada-adjust-case-buffer]'
1086
1087 Fill comment paragraph, justify and append postfix '\\[fill-paragraph]'
1088
1089 Next func/proc/task '\\[ada-next-procedure]' Previous func/proc/task '\\[ada-previous-procedure]'
1090 Next package '\\[ada-next-package]' Previous package '\\[ada-previous-package]'
1091
1092 Goto matching start of current 'end ...;' '\\[ada-move-to-start]'
1093 Goto end of current block '\\[ada-move-to-end]'
1094
1095 Comments are handled using standard GNU Emacs conventions, including:
1096 Start a comment '\\[indent-for-comment]'
1097 Comment region '\\[comment-region]'
1098 Uncomment region '\\[ada-uncomment-region]'
1099 Continue comment on next line '\\[indent-new-comment-line]'
1100
1101 If you use imenu.el:
1102 Display index-menu of functions & procedures '\\[imenu]'
1103
1104 If you use find-file.el:
1105 Switch to other file (Body <-> Spec) '\\[ff-find-other-file]'
1106 or '\\[ff-mouse-find-other-file]
1107 Switch to other file in other window '\\[ada-ff-other-window]'
1108 or '\\[ff-mouse-find-other-file-other-window]
1109 If you use this function in a spec and no body is available, it gets created with body stubs.
1110
1111 If you use ada-xref.el:
1112 Goto declaration: '\\[ada-point-and-xref]' on the identifier
1113 or '\\[ada-goto-declaration]' with point on the identifier
1114 Complete identifier: '\\[ada-complete-identifier]'."
1115
1116 (interactive)
1117 (kill-all-local-variables)
1118
1119 (set (make-local-variable 'require-final-newline) mode-require-final-newline)
1120
1121 ;; Set the paragraph delimiters so that one can select a whole block
1122 ;; simply with M-h
1123 (set (make-local-variable 'paragraph-start) "[ \t\n\f]*$")
1124 (set (make-local-variable 'paragraph-separate) "[ \t\n\f]*$")
1125
1126 ;; comment end must be set because it may hold a wrong value if
1127 ;; this buffer had been in another mode before. RE
1128 (set (make-local-variable 'comment-end) "")
1129
1130 ;; used by autofill and indent-new-comment-line
1131 (set (make-local-variable 'comment-start-skip) "---*[ \t]*")
1132
1133 ;; used by autofill to break a comment line and continue it on another line.
1134 ;; The reason we need this one is that the default behavior does not work
1135 ;; correctly with the definition of paragraph-start above when the comment
1136 ;; is right after a multi-line subprogram declaration (the comments are
1137 ;; aligned under the latest parameter, not under the declaration start).
1138 (set (make-local-variable 'comment-line-break-function)
1139 (lambda (&optional soft) (let ((fill-prefix nil))
1140 (indent-new-comment-line soft))))
1141
1142 (set (make-local-variable 'indent-line-function)
1143 'ada-indent-current-function)
1144
1145 (set (make-local-variable 'comment-column) 40)
1146
1147 ;; Emacs 20.3 defines a comment-padding to insert spaces between
1148 ;; the comment and the text. We do not want any, this is already
1149 ;; included in comment-start
1150 (unless (featurep 'xemacs)
1151 (progn
1152 (if (ada-check-emacs-version 20 3)
1153 (progn
1154 (set (make-local-variable 'parse-sexp-ignore-comments) t)
1155 (set (make-local-variable 'comment-padding) 0)))
1156 (set (make-local-variable 'parse-sexp-lookup-properties) t)
1157 ))
1158
1159 (set 'case-fold-search t)
1160 (if (boundp 'imenu-case-fold-search)
1161 (set 'imenu-case-fold-search t))
1162
1163 (set (make-local-variable 'fill-paragraph-function)
1164 'ada-fill-comment-paragraph)
1165
1166 (set (make-local-variable 'imenu-generic-expression)
1167 ada-imenu-generic-expression)
1168
1169 ;; Support for compile.el
1170 ;; We just substitute our own functions to go to the error.
1171 (add-hook 'compilation-mode-hook
1172 (lambda()
1173 (set (make-local-variable 'compile-auto-highlight) 40)
1174 ;; FIXME: This has global impact! -stef
1175 (define-key compilation-minor-mode-map [mouse-2]
1176 'ada-compile-mouse-goto-error)
1177 (define-key compilation-minor-mode-map "\C-c\C-c"
1178 'ada-compile-goto-error)
1179 (define-key compilation-minor-mode-map "\C-m"
1180 'ada-compile-goto-error)))
1181
1182 ;; font-lock support :
1183 ;; We need to set some properties for XEmacs, and define some variables
1184 ;; for Emacs
1185
1186 (if (featurep 'xemacs)
1187 ;; XEmacs
1188 (put 'ada-mode 'font-lock-defaults
1189 '(ada-font-lock-keywords
1190 nil t ((?\_ . "w") (?# . ".")) beginning-of-line))
1191 ;; Emacs
1192 (set (make-local-variable 'font-lock-defaults)
1193 '(ada-font-lock-keywords
1194 nil t
1195 ((?\_ . "w") (?# . "."))
1196 beginning-of-line
1197 (font-lock-syntactic-keywords . ada-font-lock-syntactic-keywords)))
1198 )
1199
1200 ;; Set up support for find-file.el.
1201 (set (make-local-variable 'ff-other-file-alist)
1202 'ada-other-file-alist)
1203 (set (make-local-variable 'ff-search-directories)
1204 'ada-search-directories-internal)
1205 (setq ff-post-load-hook 'ada-set-point-accordingly
1206 ff-file-created-hook 'ada-make-body)
1207 (add-hook 'ff-pre-load-hook 'ada-which-function-are-we-in)
1208
1209 ;; Some special constructs for find-file.el
1210 ;; We do not need to add the construction for 'with', which is in the
1211 ;; standard find-file.el
1212 (make-local-variable 'ff-special-constructs)
1213
1214 ;; Go to the parent package :
1215 (add-to-list 'ff-special-constructs
1216 (cons (eval-when-compile
1217 (concat "^\\(private[ \t]\\)?[ \t]*package[ \t]+"
1218 "\\(body[ \t]+\\)?"
1219 "\\(\\(\\sw\\|[_.]\\)+\\)\\.\\(\\sw\\|_\\)+[ \t\n]+is"))
1220 (lambda ()
1221 (if (fboundp 'ff-get-file)
1222 (if (boundp 'fname)
1223 (set 'fname (ff-get-file
1224 ada-search-directories-internal
1225 (ada-make-filename-from-adaname
1226 (match-string 3))
1227 ada-spec-suffixes)))))))
1228 ;; Another special construct for find-file.el : when in a separate clause,
1229 ;; go to the correct package.
1230 (add-to-list 'ff-special-constructs
1231 (cons "^separate[ \t\n]*(\\(\\(\\sw\\|[_.]\\)+\\))"
1232 (lambda ()
1233 (if (fboundp 'ff-get-file)
1234 (if (boundp 'fname)
1235 (setq fname (ff-get-file
1236 ada-search-directories-internal
1237 (ada-make-filename-from-adaname
1238 (match-string 1))
1239 ada-spec-suffixes)))))))
1240
1241 ;; Another special construct, that redefines the one in find-file.el. The
1242 ;; old one can handle only one possible type of extension for Ada files
1243 ;; remove from the list the standard "with..." that is put by find-file.el,
1244 ;; since it uses the old ada-spec-suffix variable
1245 ;; This one needs to replace the standard one defined in find-file.el (with
1246 ;; Emacs <= 20.4), since that one uses the old variable ada-spec-suffix
1247 (let ((old-construct
1248 (assoc "^with[ \t]+\\([a-zA-Z0-9_\\.]+\\)" ff-special-constructs))
1249 (new-cdr
1250 (lambda ()
1251 (if (fboundp 'ff-get-file)
1252 (if (boundp 'fname)
1253 (set 'fname (ff-get-file
1254 ada-search-directories-internal
1255 (ada-make-filename-from-adaname
1256 (match-string 1))
1257 ada-spec-suffixes)))))))
1258 (if old-construct
1259 (setcdr old-construct new-cdr)
1260 (add-to-list 'ff-special-constructs
1261 (cons "^with[ \t]+\\([a-zA-Z0-9_\\.]+\\)"
1262 new-cdr))))
1263
1264 ;; Support for outline-minor-mode
1265 (set (make-local-variable 'outline-regexp)
1266 "\\([ \t]*\\(procedure\\|function\\|package\\|if\\|while\\|for\\|declare\\|case\\|end\\|begin\\|loop\\)\\|--\\)")
1267 (set (make-local-variable 'outline-level) 'ada-outline-level)
1268
1269 ;; Support for imenu : We want a sorted index
1270 (setq imenu-sort-function 'imenu--sort-by-name)
1271
1272 ;; Support for ispell : Check only comments
1273 (set (make-local-variable 'ispell-check-comments) 'exclusive)
1274
1275 ;; Support for align.el <= 2.2, if present
1276 ;; align.el is distributed with Emacs 21, but not with earlier versions.
1277 (if (boundp 'align-mode-alist)
1278 (add-to-list 'align-mode-alist '(ada-mode . ada-align-list)))
1279
1280 ;; Support for align.el >= 2.8, if present
1281 (if (boundp 'align-dq-string-modes)
1282 (progn
1283 (add-to-list 'align-dq-string-modes 'ada-mode)
1284 (add-to-list 'align-open-comment-modes 'ada-mode)
1285 (set (make-variable-buffer-local 'align-region-separate)
1286 ada-align-region-separate)
1287
1288 ;; Exclude comments alone on line from alignment.
1289 (add-to-list 'align-exclude-rules-list
1290 '(ada-solo-comment
1291 (regexp . "^\\(\\s-*\\)--")
1292 (modes . '(ada-mode))))
1293 (add-to-list 'align-exclude-rules-list
1294 '(ada-solo-use
1295 (regexp . "^\\(\\s-*\\)\\<use\\>")
1296 (modes . '(ada-mode))))
1297
1298 (setq ada-align-modes nil)
1299
1300 (add-to-list 'ada-align-modes
1301 '(ada-declaration-assign
1302 (regexp . "[^:]\\(\\s-*\\):[^:]")
1303 (valid . (lambda() (not (ada-in-comment-p))))
1304 (repeat . t)
1305 (modes . '(ada-mode))))
1306 (add-to-list 'ada-align-modes
1307 '(ada-associate
1308 (regexp . "[^=]\\(\\s-*\\)=>")
1309 (valid . (lambda() (not (ada-in-comment-p))))
1310 (modes . '(ada-mode))))
1311 (add-to-list 'ada-align-modes
1312 '(ada-comment
1313 (regexp . "\\(\\s-*\\)--")
1314 (modes . '(ada-mode))))
1315 (add-to-list 'ada-align-modes
1316 '(ada-use
1317 (regexp . "\\(\\s-*\\)\\<use\\s-")
1318 (valid . (lambda() (not (ada-in-comment-p))))
1319 (modes . '(ada-mode))))
1320 (add-to-list 'ada-align-modes
1321 '(ada-at
1322 (regexp . "\\(\\s-+\\)at\\>")
1323 (modes . '(ada-mode))))
1324
1325
1326 (setq align-mode-rules-list ada-align-modes)
1327 ))
1328
1329 ;; Set up the contextual menu
1330 (if ada-popup-key
1331 (define-key ada-mode-map ada-popup-key 'ada-popup-menu))
1332
1333 ;; Support for Abbreviations (the user still need to "M-x abbrev-mode"
1334 (define-abbrev-table 'ada-mode-abbrev-table ())
1335 (setq local-abbrev-table ada-mode-abbrev-table)
1336
1337 ;; Support for which-function mode
1338 ;; which-function-mode does not work with nested subprograms, since it is
1339 ;; based only on the regexps generated by imenu, and thus can only detect the
1340 ;; beginning of subprograms, not the end.
1341 ;; Fix is: redefine a new function ada-which-function, and call it when the
1342 ;; major-mode is ada-mode.
1343
1344 (make-local-variable 'which-func-functions)
1345 (setq which-func-functions '(ada-which-function))
1346
1347 ;; Support for indent-new-comment-line (Especially for XEmacs)
1348 (setq comment-multi-line nil)
1349
1350 (setq major-mode 'ada-mode
1351 mode-name "Ada")
1352
1353 (use-local-map ada-mode-map)
1354
1355 (easy-menu-add ada-mode-menu ada-mode-map)
1356
1357 (set-syntax-table ada-mode-syntax-table)
1358
1359 (if ada-clean-buffer-before-saving
1360 (progn
1361 ;; remove all spaces at the end of lines in the whole buffer.
1362 (add-hook 'local-write-file-hooks 'delete-trailing-whitespace)
1363 ;; convert all tabs to the correct number of spaces.
1364 (add-hook 'local-write-file-hooks
1365 (lambda () (untabify (point-min) (point-max))))))
1366
1367 (set (make-local-variable 'skeleton-further-elements)
1368 '((< '(backward-delete-char-untabify
1369 (min ada-indent (current-column))))))
1370 (add-hook 'skeleton-end-hook 'ada-adjust-case-skeleton nil t)
1371
1372 (run-mode-hooks 'ada-mode-hook)
1373
1374 ;; To be run after the hook, in case the user modified
1375 ;; ada-fill-comment-prefix
1376 (make-local-variable 'comment-start)
1377 (if ada-fill-comment-prefix
1378 (set 'comment-start ada-fill-comment-prefix)
1379 (set 'comment-start "-- "))
1380
1381 ;; Run this after the hook to give the users a chance to activate
1382 ;; font-lock-mode
1383
1384 (unless (featurep 'xemacs)
1385 (progn
1386 (ada-initialize-properties)
1387 (add-hook 'font-lock-mode-hook 'ada-deactivate-properties nil t)))
1388
1389 ;; the following has to be done after running the ada-mode-hook
1390 ;; because users might want to set the values of these variable
1391 ;; inside the hook (MH)
1392
1393 (cond ((eq ada-language-version 'ada83)
1394 (setq ada-keywords ada-83-keywords))
1395 ((eq ada-language-version 'ada95)
1396 (setq ada-keywords ada-95-keywords)))
1397
1398 (if ada-auto-case
1399 (ada-activate-keys-for-case)))
1400
1401 (defun ada-adjust-case-skeleton ()
1402 "Adjust the case of the text inserted by a skeleton."
1403 (save-excursion
1404 (let ((aa-end (point)))
1405 (ada-adjust-case-region
1406 (progn (goto-char (symbol-value 'beg)) (forward-word -1) (point))
1407 (goto-char aa-end)))))
1408
1409 ;; transient-mark-mode and mark-active are not defined in XEmacs
1410 (defun ada-region-selected ()
1411 "t if a region has been selected by the user and is still active."
1412 (or (and (featurep 'xemacs) (funcall (symbol-function 'region-active-p)))
1413 (and (not (featurep 'xemacs))
1414 (symbol-value 'transient-mark-mode)
1415 (symbol-value 'mark-active))))
1416
1417 \f
1418 ;;-----------------------------------------------------------------
1419 ;; auto-casing
1420 ;; Since Ada is case-insensitive, the Ada-mode provides an extensive set of
1421 ;; functions to auto-case identifiers, keywords, ...
1422 ;; The basic rules for autocasing are defined through the variables
1423 ;; `ada-case-attribute', `ada-case-keyword' and `ada-case-identifier'. These
1424 ;; are references to the functions that will do the actual casing.
1425 ;;
1426 ;; However, in most cases, the user will want to define some exceptions to
1427 ;; these casing rules. This is done through a list of files, that contain
1428 ;; one word per line. These files are stored in `ada-case-exception-file'.
1429 ;; For backward compatibility, this variable can also be a string.
1430 ;;-----------------------------------------------------------------
1431
1432 (defun ada-save-exceptions-to-file (file-name)
1433 "Save the exception lists `ada-case-exception' and
1434 `ada-case-exception-substring' to the file FILE-NAME."
1435
1436 ;; Save the list in the file
1437 (find-file (expand-file-name file-name))
1438 (erase-buffer)
1439 (mapcar (lambda (x) (insert (car x) "\n"))
1440 (sort (copy-sequence ada-case-exception)
1441 (lambda(a b) (string< (car a) (car b)))))
1442 (mapcar (lambda (x) (insert "*" (car x) "\n"))
1443 (sort (copy-sequence ada-case-exception-substring)
1444 (lambda(a b) (string< (car a) (car b)))))
1445 (save-buffer)
1446 (kill-buffer nil)
1447 )
1448
1449 (defun ada-create-case-exception (&optional word)
1450 "Defines WORD as an exception for the casing system.
1451 If WORD is not given, then the current word in the buffer is used instead.
1452 The new words is added to the first file in `ada-case-exception-file'.
1453 The standard casing rules will no longer apply to this word."
1454 (interactive)
1455 (let ((previous-syntax-table (syntax-table))
1456 file-name
1457 )
1458
1459 (cond ((stringp ada-case-exception-file)
1460 (setq file-name ada-case-exception-file))
1461 ((listp ada-case-exception-file)
1462 (setq file-name (car ada-case-exception-file)))
1463 (t
1464 (error (concat "No exception file specified. "
1465 "See variable ada-case-exception-file."))))
1466
1467 (set-syntax-table ada-mode-symbol-syntax-table)
1468 (unless word
1469 (save-excursion
1470 (skip-syntax-backward "w")
1471 (setq word (buffer-substring-no-properties
1472 (point) (save-excursion (forward-word 1) (point))))))
1473 (set-syntax-table previous-syntax-table)
1474
1475 ;; Reread the exceptions file, in case it was modified by some other,
1476 (ada-case-read-exceptions-from-file file-name)
1477
1478 ;; If the word is already in the list, even with a different casing
1479 ;; we simply want to replace it.
1480 (if (and (not (equal ada-case-exception '()))
1481 (assoc-string word ada-case-exception t))
1482 (setcar (assoc-string word ada-case-exception t) word)
1483 (add-to-list 'ada-case-exception (cons word t))
1484 )
1485
1486 (ada-save-exceptions-to-file file-name)
1487 ))
1488
1489 (defun ada-create-case-exception-substring (&optional word)
1490 "Defines the substring WORD as an exception for the casing system.
1491 If WORD is not given, then the current word in the buffer is used instead,
1492 or the selected region if any is active.
1493 The new words is added to the first file in `ada-case-exception-file'.
1494 When auto-casing a word, this substring will be special-cased, unless the
1495 word itself has a special casing."
1496 (interactive)
1497 (let ((file-name
1498 (cond ((stringp ada-case-exception-file)
1499 ada-case-exception-file)
1500 ((listp ada-case-exception-file)
1501 (car ada-case-exception-file))
1502 (t
1503 (error (concat "No exception file specified. "
1504 "See variable ada-case-exception-file."))))))
1505
1506 ;; Find the substring to define as an exception. Order is: the parameter,
1507 ;; if any, or the selected region, or the word under the cursor
1508 (cond
1509 (word nil)
1510
1511 ((ada-region-selected)
1512 (setq word (buffer-substring-no-properties
1513 (region-beginning) (region-end))))
1514
1515 (t
1516 (let ((underscore-syntax (char-syntax ?_)))
1517 (unwind-protect
1518 (progn
1519 (modify-syntax-entry ?_ "." (syntax-table))
1520 (save-excursion
1521 (skip-syntax-backward "w")
1522 (set 'word (buffer-substring-no-properties
1523 (point)
1524 (save-excursion (forward-word 1) (point))))))
1525 (modify-syntax-entry ?_ (make-string 1 underscore-syntax)
1526 (syntax-table))))))
1527
1528 ;; Reread the exceptions file, in case it was modified by some other,
1529 (ada-case-read-exceptions-from-file file-name)
1530
1531 ;; If the word is already in the list, even with a different casing
1532 ;; we simply want to replace it.
1533 (if (and (not (equal ada-case-exception-substring '()))
1534 (assoc-string word ada-case-exception-substring t))
1535 (setcar (assoc-string word ada-case-exception-substring t) word)
1536 (add-to-list 'ada-case-exception-substring (cons word t))
1537 )
1538
1539 (ada-save-exceptions-to-file file-name)
1540
1541 (message (concat "Defining " word " as a casing exception"))))
1542
1543 (defun ada-case-read-exceptions-from-file (file-name)
1544 "Read the content of the casing exception file FILE-NAME."
1545 (if (file-readable-p (expand-file-name file-name))
1546 (let ((buffer (current-buffer)))
1547 (find-file (expand-file-name file-name))
1548 (set-syntax-table ada-mode-symbol-syntax-table)
1549 (widen)
1550 (goto-char (point-min))
1551 (while (not (eobp))
1552
1553 ;; If the item is already in the list, even with an other casing,
1554 ;; do not add it again. This way, the user can easily decide which
1555 ;; priority should be applied to each casing exception
1556 (let ((word (buffer-substring-no-properties
1557 (point) (save-excursion (forward-word 1) (point)))))
1558
1559 ;; Handling a substring ?
1560 (if (char-equal (string-to-char word) ?*)
1561 (progn
1562 (setq word (substring word 1))
1563 (unless (assoc-string word ada-case-exception-substring t)
1564 (add-to-list 'ada-case-exception-substring (cons word t))))
1565 (unless (assoc-string word ada-case-exception t)
1566 (add-to-list 'ada-case-exception (cons word t)))))
1567
1568 (forward-line 1))
1569 (kill-buffer nil)
1570 (set-buffer buffer)))
1571 )
1572
1573 (defun ada-case-read-exceptions ()
1574 "Read all the casing exception files from `ada-case-exception-file'."
1575 (interactive)
1576
1577 ;; Reinitialize the casing exception list
1578 (setq ada-case-exception '()
1579 ada-case-exception-substring '())
1580
1581 (cond ((stringp ada-case-exception-file)
1582 (ada-case-read-exceptions-from-file ada-case-exception-file))
1583
1584 ((listp ada-case-exception-file)
1585 (mapcar 'ada-case-read-exceptions-from-file
1586 ada-case-exception-file))))
1587
1588 (defun ada-adjust-case-substring ()
1589 "Adjust case of substrings in the previous word."
1590 (interactive)
1591 (let ((substrings ada-case-exception-substring)
1592 (max (point))
1593 (case-fold-search t)
1594 (underscore-syntax (char-syntax ?_))
1595 re)
1596
1597 (save-excursion
1598 (forward-word -1)
1599
1600 (unwind-protect
1601 (progn
1602 (modify-syntax-entry ?_ "." (syntax-table))
1603
1604 (while substrings
1605 (setq re (concat "\\b" (regexp-quote (caar substrings)) "\\b"))
1606
1607 (save-excursion
1608 (while (re-search-forward re max t)
1609 (replace-match (caar substrings) t)))
1610 (setq substrings (cdr substrings))
1611 )
1612 )
1613 (modify-syntax-entry ?_ (make-string 1 underscore-syntax) (syntax-table)))
1614 )))
1615
1616 (defun ada-adjust-case-identifier ()
1617 "Adjust case of the previous identifier.
1618 The auto-casing is done according to the value of `ada-case-identifier' and
1619 the exceptions defined in `ada-case-exception-file'."
1620 (interactive)
1621 (if (or (equal ada-case-exception '())
1622 (equal (char-after) ?_))
1623 (progn
1624 (funcall ada-case-identifier -1)
1625 (ada-adjust-case-substring))
1626
1627 (progn
1628 (let ((end (point))
1629 (start (save-excursion (skip-syntax-backward "w")
1630 (point)))
1631 match)
1632 ;; If we have an exception, replace the word by the correct casing
1633 (if (setq match (assoc-string (buffer-substring start end)
1634 ada-case-exception t))
1635
1636 (progn
1637 (delete-region start end)
1638 (insert (car match)))
1639
1640 ;; Else simply re-case the word
1641 (funcall ada-case-identifier -1)
1642 (ada-adjust-case-substring))))))
1643
1644 (defun ada-after-keyword-p ()
1645 "Returns t if cursor is after a keyword that is not an attribute."
1646 (save-excursion
1647 (forward-word -1)
1648 (and (not (and (char-before)
1649 (or (= (char-before) ?_)
1650 (= (char-before) ?'))));; unless we have a _ or '
1651 (looking-at (concat ada-keywords "[^_]")))))
1652
1653 (defun ada-adjust-case (&optional force-identifier)
1654 "Adjust the case of the word before the just typed character.
1655 If FORCE-IDENTIFIER is non-nil then also adjust keyword as identifier."
1656 (if (not (bobp))
1657 (progn
1658 (forward-char -1)
1659 (if (and (not (bobp))
1660 ;; or if at the end of a character constant
1661 (not (and (eq (following-char) ?')
1662 (eq (char-before (1- (point))) ?')))
1663 ;; or if the previous character was not part of a word
1664 (eq (char-syntax (char-before)) ?w)
1665 ;; if in a string or a comment
1666 (not (ada-in-string-or-comment-p))
1667 )
1668 (if (save-excursion
1669 (forward-word -1)
1670 (or (= (point) (point-min))
1671 (backward-char 1))
1672 (= (following-char) ?'))
1673 (funcall ada-case-attribute -1)
1674 (if (and
1675 (not force-identifier) ; (MH)
1676 (ada-after-keyword-p))
1677 (funcall ada-case-keyword -1)
1678 (ada-adjust-case-identifier))))
1679 (forward-char 1)
1680 ))
1681 )
1682
1683 (defun ada-adjust-case-interactive (arg)
1684 "Adjust the case of the previous word, and process the character just typed.
1685 ARG is the prefix the user entered with \C-u."
1686 (interactive "P")
1687
1688 (if ada-auto-case
1689 (let ((lastk last-command-char)
1690 (previous-syntax-table (syntax-table)))
1691
1692 (unwind-protect
1693 (progn
1694 (set-syntax-table ada-mode-symbol-syntax-table)
1695 (cond ((or (eq lastk ?\n)
1696 (eq lastk ?\r))
1697 ;; horrible kludge
1698 (insert " ")
1699 (ada-adjust-case)
1700 ;; horrible dekludge
1701 (delete-backward-char 1)
1702 ;; some special keys and their bindings
1703 (cond
1704 ((eq lastk ?\n)
1705 (funcall ada-lfd-binding))
1706 ((eq lastk ?\r)
1707 (funcall ada-ret-binding))))
1708 ((eq lastk ?\C-i) (ada-tab))
1709 ;; Else just insert the character
1710 ((self-insert-command (prefix-numeric-value arg))))
1711 ;; if there is a keyword in front of the underscore
1712 ;; then it should be part of an identifier (MH)
1713 (if (eq lastk ?_)
1714 (ada-adjust-case t)
1715 (ada-adjust-case))
1716 )
1717 ;; Restore the syntax table
1718 (set-syntax-table previous-syntax-table))
1719 )
1720
1721 ;; Else, no auto-casing
1722 (cond
1723 ((eq last-command-char ?\n)
1724 (funcall ada-lfd-binding))
1725 ((eq last-command-char ?\r)
1726 (funcall ada-ret-binding))
1727 (t
1728 (self-insert-command (prefix-numeric-value arg))))
1729 ))
1730
1731 (defun ada-activate-keys-for-case ()
1732 "Modifies the key bindings for all the keys that should readjust the casing."
1733 (interactive)
1734 ;; Save original key-bindings to allow swapping ret/lfd
1735 ;; when casing is activated.
1736 ;; The 'or ...' is there to be sure that the value will not
1737 ;; be changed again when Ada mode is called more than once
1738 (or ada-ret-binding (setq ada-ret-binding (key-binding "\C-M")))
1739 (or ada-lfd-binding (setq ada-lfd-binding (key-binding "\C-j")))
1740
1741 ;; Call case modifying function after certain keys.
1742 (mapcar (function (lambda(key) (define-key
1743 ada-mode-map
1744 (char-to-string key)
1745 'ada-adjust-case-interactive)))
1746 '( ?` ?_ ?# ?% ?& ?* ?( ?) ?- ?= ?+
1747 ?| ?\; ?: ?' ?\" ?< ?, ?. ?> ?/ ?\n 32 ?\r )))
1748
1749 (defun ada-loose-case-word (&optional arg)
1750 "Upcase first letter and letters following `_' in the following word.
1751 No other letter is modified.
1752 ARG is ignored, and is there for compatibility with `capitalize-word' only."
1753 (interactive)
1754 (save-excursion
1755 (let ((end (save-excursion (skip-syntax-forward "w") (point)))
1756 (first t))
1757 (skip-syntax-backward "w")
1758 (while (and (or first (search-forward "_" end t))
1759 (< (point) end))
1760 (and first
1761 (setq first nil))
1762 (insert-char (upcase (following-char)) 1)
1763 (delete-char 1)))))
1764
1765 (defun ada-no-auto-case (&optional arg)
1766 "Does nothing.
1767 This function can be used for the auto-casing variables in the ada-mode, to
1768 adapt to unusal auto-casing schemes. Since it does nothing, you can for
1769 instance use it for `ada-case-identifier' if you don't want any special
1770 auto-casing for identifiers, whereas keywords have to be lower-cased.
1771 See also `ada-auto-case' to disable auto casing altogether."
1772 )
1773
1774 (defun ada-capitalize-word (&optional arg)
1775 "Upcase first letter and letters following '_', lower case other letters.
1776 ARG is ignored, and is there for compatibility with `capitalize-word' only."
1777 (interactive)
1778 (let ((end (save-excursion (skip-syntax-forward "w") (point)))
1779 (begin (save-excursion (skip-syntax-backward "w") (point))))
1780 (modify-syntax-entry ?_ "_")
1781 (capitalize-region begin end)
1782 (modify-syntax-entry ?_ "w")))
1783
1784 (defun ada-adjust-case-region (from to)
1785 "Adjusts the case of all words in the region between FROM and TO.
1786 Attention: This function might take very long for big regions !"
1787 (interactive "*r")
1788 (let ((begin nil)
1789 (end nil)
1790 (keywordp nil)
1791 (attribp nil)
1792 (previous-syntax-table (syntax-table)))
1793 (message "Adjusting case ...")
1794 (unwind-protect
1795 (save-excursion
1796 (set-syntax-table ada-mode-symbol-syntax-table)
1797 (goto-char to)
1798 ;;
1799 ;; loop: look for all identifiers, keywords, and attributes
1800 ;;
1801 (while (re-search-backward "\\<\\(\\sw+\\)\\>" from t)
1802 (setq end (match-end 1))
1803 (setq attribp
1804 (and (> (point) from)
1805 (save-excursion
1806 (forward-char -1)
1807 (setq attribp (looking-at "'.[^']")))))
1808 (or
1809 ;; do nothing if it is a string or comment
1810 (ada-in-string-or-comment-p)
1811 (progn
1812 ;;
1813 ;; get the identifier or keyword or attribute
1814 ;;
1815 (setq begin (point))
1816 (setq keywordp (looking-at ada-keywords))
1817 (goto-char end)
1818 ;;
1819 ;; casing according to user-option
1820 ;;
1821 (if attribp
1822 (funcall ada-case-attribute -1)
1823 (if keywordp
1824 (funcall ada-case-keyword -1)
1825 (ada-adjust-case-identifier)))
1826 (goto-char begin))))
1827 (message "Adjusting case ... Done"))
1828 (set-syntax-table previous-syntax-table))))
1829
1830 (defun ada-adjust-case-buffer ()
1831 "Adjusts the case of all words in the whole buffer.
1832 ATTENTION: This function might take very long for big buffers !"
1833 (interactive "*")
1834 (ada-adjust-case-region (point-min) (point-max)))
1835
1836 \f
1837 ;;--------------------------------------------------------------
1838 ;; Format Parameter Lists
1839 ;; Some special algorithms are provided to indent the parameter lists in
1840 ;; subprogram declarations. This is done in two steps:
1841 ;; - First parses the parameter list. The returned list has the following
1842 ;; format:
1843 ;; ( (<Param_Name> in? out? access? <Type_Name> <Default_Expression>)
1844 ;; ... )
1845 ;; This is done in `ada-scan-paramlist'.
1846 ;; - Delete and recreate the parameter list in function
1847 ;; `ada-insert-paramlist'.
1848 ;; Both steps are called from `ada-format-paramlist'.
1849 ;; Note: Comments inside the parameter list are lost.
1850 ;; The syntax has to be correct, or the reformating will fail.
1851 ;;--------------------------------------------------------------
1852
1853 (defun ada-format-paramlist ()
1854 "Reformats the parameter list point is in."
1855 (interactive)
1856 (let ((begin nil)
1857 (end nil)
1858 (delend nil)
1859 (paramlist nil)
1860 (previous-syntax-table (syntax-table)))
1861 (unwind-protect
1862 (progn
1863 (set-syntax-table ada-mode-symbol-syntax-table)
1864
1865 ;; check if really inside parameter list
1866 (or (ada-in-paramlist-p)
1867 (error "not in parameter list"))
1868
1869 ;; find start of current parameter-list
1870 (ada-search-ignore-string-comment
1871 (concat ada-subprog-start-re "\\|\\<body\\>" ) t nil)
1872 (down-list 1)
1873 (backward-char 1)
1874 (setq begin (point))
1875
1876 ;; find end of parameter-list
1877 (forward-sexp 1)
1878 (setq delend (point))
1879 (delete-char -1)
1880 (insert "\n")
1881
1882 ;; find end of last parameter-declaration
1883 (forward-comment -1000)
1884 (setq end (point))
1885
1886 ;; build a list of all elements of the parameter-list
1887 (setq paramlist (ada-scan-paramlist (1+ begin) end))
1888
1889 ;; delete the original parameter-list
1890 (delete-region begin delend)
1891
1892 ;; insert the new parameter-list
1893 (goto-char begin)
1894 (ada-insert-paramlist paramlist))
1895
1896 ;; restore syntax-table
1897 (set-syntax-table previous-syntax-table)
1898 )))
1899
1900 (defun ada-scan-paramlist (begin end)
1901 "Scan the parameter list found in between BEGIN and END.
1902 Returns the equivalent internal parameter list."
1903 (let ((paramlist (list))
1904 (param (list))
1905 (notend t)
1906 (apos nil)
1907 (epos nil)
1908 (semipos nil)
1909 (match-cons nil))
1910
1911 (goto-char begin)
1912
1913 ;; loop until end of last parameter
1914 (while notend
1915
1916 ;; find first character of parameter-declaration
1917 (ada-goto-next-non-ws)
1918 (setq apos (point))
1919
1920 ;; find last character of parameter-declaration
1921 (if (setq match-cons
1922 (ada-search-ignore-string-comment "[ \t\n]*;" nil end t))
1923 (progn
1924 (setq epos (car match-cons))
1925 (setq semipos (cdr match-cons)))
1926 (setq epos end))
1927
1928 ;; read name(s) of parameter(s)
1929 (goto-char apos)
1930 (looking-at "\\(\\(\\sw\\|[_, \t\n]\\)*\\(\\sw\\|_\\)\\)[ \t\n]*:[^=]")
1931
1932 (setq param (list (match-string 1)))
1933 (ada-search-ignore-string-comment ":" nil epos t 'search-forward)
1934
1935 ;; look for 'in'
1936 (setq apos (point))
1937 (setq param
1938 (append param
1939 (list
1940 (consp
1941 (ada-search-ignore-string-comment
1942 "in" nil epos t 'word-search-forward)))))
1943
1944 ;; look for 'out'
1945 (goto-char apos)
1946 (setq param
1947 (append param
1948 (list
1949 (consp
1950 (ada-search-ignore-string-comment
1951 "out" nil epos t 'word-search-forward)))))
1952
1953 ;; look for 'access'
1954 (goto-char apos)
1955 (setq param
1956 (append param
1957 (list
1958 (consp
1959 (ada-search-ignore-string-comment
1960 "access" nil epos t 'word-search-forward)))))
1961
1962 ;; skip 'in'/'out'/'access'
1963 (goto-char apos)
1964 (ada-goto-next-non-ws)
1965 (while (looking-at "\\<\\(in\\|out\\|access\\)\\>")
1966 (forward-word 1)
1967 (ada-goto-next-non-ws))
1968
1969 ;; read type of parameter
1970 ;; We accept spaces in the name, since some software like Rose
1971 ;; generates something like: "A : B 'Class"
1972 (looking-at "\\<\\(\\sw\\|[_.' \t]\\)+\\>")
1973 (setq param
1974 (append param
1975 (list (match-string 0))))
1976
1977 ;; read default-expression, if there is one
1978 (goto-char (setq apos (match-end 0)))
1979 (setq param
1980 (append param
1981 (list
1982 (if (setq match-cons
1983 (ada-search-ignore-string-comment
1984 ":=" nil epos t 'search-forward))
1985 (buffer-substring (car match-cons) epos)
1986 nil))))
1987
1988 ;; add this parameter-declaration to the list
1989 (setq paramlist (append paramlist (list param)))
1990
1991 ;; check if it was the last parameter
1992 (if (eq epos end)
1993 (setq notend nil)
1994 (goto-char semipos))
1995 )
1996 (reverse paramlist)))
1997
1998 (defun ada-insert-paramlist (paramlist)
1999 "Inserts a formatted PARAMLIST in the buffer."
2000 (let ((i (length paramlist))
2001 (parlen 0)
2002 (typlen 0)
2003 (inp nil)
2004 (outp nil)
2005 (accessp nil)
2006 (column nil)
2007 (firstcol nil))
2008
2009 ;; loop until last parameter
2010 (while (not (zerop i))
2011 (setq i (1- i))
2012
2013 ;; get max length of parameter-name
2014 (setq parlen (max parlen (length (nth 0 (nth i paramlist)))))
2015
2016 ;; get max length of type-name
2017 (setq typlen (max typlen (length (nth 4 (nth i paramlist)))))
2018
2019 ;; is there any 'in' ?
2020 (setq inp (or inp (nth 1 (nth i paramlist))))
2021
2022 ;; is there any 'out' ?
2023 (setq outp (or outp (nth 2 (nth i paramlist))))
2024
2025 ;; is there any 'access' ?
2026 (setq accessp (or accessp (nth 3 (nth i paramlist))))
2027 )
2028
2029 ;; does paramlist already start on a separate line ?
2030 (if (save-excursion
2031 (re-search-backward "^.\\|[^ \t]" nil t)
2032 (looking-at "^."))
2033 ;; yes => re-indent it
2034 (progn
2035 (ada-indent-current)
2036 (save-excursion
2037 (if (looking-at "\\(is\\|return\\)")
2038 (replace-match " \\1"))))
2039
2040 ;; no => insert it where we are after removing any whitespace
2041 (fixup-whitespace)
2042 (save-excursion
2043 (cond
2044 ((looking-at "[ \t]*\\(\n\\|;\\)")
2045 (replace-match "\\1"))
2046 ((looking-at "[ \t]*\\(is\\|return\\)")
2047 (replace-match " \\1"))))
2048 (insert " "))
2049
2050 (insert "(")
2051 (ada-indent-current)
2052
2053 (setq firstcol (current-column))
2054 (setq i (length paramlist))
2055
2056 ;; loop until last parameter
2057 (while (not (zerop i))
2058 (setq i (1- i))
2059 (setq column firstcol)
2060
2061 ;; insert parameter-name, space and colon
2062 (insert (nth 0 (nth i paramlist)))
2063 (indent-to (+ column parlen 1))
2064 (insert ": ")
2065 (setq column (current-column))
2066
2067 ;; insert 'in' or space
2068 (if (nth 1 (nth i paramlist))
2069 (insert "in ")
2070 (if (and
2071 (or inp
2072 accessp)
2073 (not (nth 3 (nth i paramlist))))
2074 (insert " ")))
2075
2076 ;; insert 'out' or space
2077 (if (nth 2 (nth i paramlist))
2078 (insert "out ")
2079 (if (and
2080 (or outp
2081 accessp)
2082 (not (nth 3 (nth i paramlist))))
2083 (insert " ")))
2084
2085 ;; insert 'access'
2086 (if (nth 3 (nth i paramlist))
2087 (insert "access "))
2088
2089 (setq column (current-column))
2090
2091 ;; insert type-name and, if necessary, space and default-expression
2092 (insert (nth 4 (nth i paramlist)))
2093 (if (nth 5 (nth i paramlist))
2094 (progn
2095 (indent-to (+ column typlen 1))
2096 (insert (nth 5 (nth i paramlist)))))
2097
2098 ;; check if it was the last parameter
2099 (if (zerop i)
2100 (insert ")")
2101 ;; no => insert ';' and newline and indent
2102 (insert ";")
2103 (newline)
2104 (indent-to firstcol))
2105 )
2106
2107 ;; if anything follows, except semicolon, newline, is or return
2108 ;; put it in a new line and indent it
2109 (unless (looking-at "[ \t]*\\(;\\|\n\\|is\\|return\\)")
2110 (ada-indent-newline-indent))
2111 ))
2112
2113
2114 \f
2115 ;;;----------------------------------------------------------------
2116 ;; Indentation Engine
2117 ;; All indentations are indicated as a two-element string:
2118 ;; - position of reference in the buffer
2119 ;; - offset to indent from this position (can also be a symbol or a list
2120 ;; that are evaluated)
2121 ;; Thus the total indentation for a line is the column number of the reference
2122 ;; position plus whatever value the evaluation of the second element provides.
2123 ;; This mechanism is used so that the ada-mode can "explain" how the
2124 ;; indentation was calculated, by showing which variables were used.
2125 ;;
2126 ;; The indentation itself is done in only one pass: first we try to guess in
2127 ;; what context we are by looking at the following keyword or punctuation
2128 ;; sign. If nothing remarkable is found, just try to guess the indentation
2129 ;; based on previous lines.
2130 ;;
2131 ;; The relevant functions for indentation are:
2132 ;; - `ada-indent-region': Re-indent a region of text
2133 ;; - `ada-justified-indent-current': Re-indent the current line and shows the
2134 ;; calculation that were done
2135 ;; - `ada-indent-current': Re-indent the current line
2136 ;; - `ada-get-current-indent': Calculate the indentation for the current line,
2137 ;; based on the context (see above).
2138 ;; - `ada-get-indent-*': Calculate the indentation in a specific context.
2139 ;; For efficiency, these functions do not check they are in the correct
2140 ;; context.
2141 ;;;----------------------------------------------------------------
2142
2143 (defun ada-indent-region (beg end)
2144 "Indent the region between BEG end END."
2145 (interactive "*r")
2146 (goto-char beg)
2147 (let ((block-done 0)
2148 (lines-remaining (count-lines beg end))
2149 (msg (format "%%4d out of %4d lines remaining ..."
2150 (count-lines beg end)))
2151 (endmark (copy-marker end)))
2152 ;; catch errors while indenting
2153 (while (< (point) endmark)
2154 (if (> block-done 39)
2155 (progn
2156 (setq lines-remaining (- lines-remaining block-done)
2157 block-done 0)
2158 (message msg lines-remaining)))
2159 (if (= (char-after) ?\n) nil
2160 (ada-indent-current))
2161 (forward-line 1)
2162 (setq block-done (1+ block-done)))
2163 (message "indenting ... done")))
2164
2165 (defun ada-indent-newline-indent ()
2166 "Indents the current line, inserts a newline and then indents the new line."
2167 (interactive "*")
2168 (ada-indent-current)
2169 (newline)
2170 (ada-indent-current))
2171
2172 (defun ada-indent-newline-indent-conditional ()
2173 "Insert a newline and indent it.
2174 The original line is indented first if `ada-indent-after-return' is non-nil.
2175 This function is intended to be bound to the \C-m and \C-j keys."
2176 (interactive "*")
2177 (if ada-indent-after-return (ada-indent-current))
2178 (newline)
2179 (ada-indent-current))
2180
2181 (defun ada-justified-indent-current ()
2182 "Indent the current line and explains how the calculation was done."
2183 (interactive)
2184
2185 (let ((cur-indent (ada-indent-current)))
2186
2187 (let ((line (save-excursion
2188 (goto-char (car cur-indent))
2189 (count-lines 1 (point)))))
2190
2191 (if (equal (cdr cur-indent) '(0))
2192 (message (concat "same indentation as line " (number-to-string line)))
2193 (message (mapconcat (lambda(x)
2194 (cond
2195 ((symbolp x)
2196 (symbol-name x))
2197 ((numberp x)
2198 (number-to-string x))
2199 ((listp x)
2200 (concat "- " (symbol-name (cadr x))))
2201 ))
2202 (cdr cur-indent)
2203 " + "))))
2204 (save-excursion
2205 (goto-char (car cur-indent))
2206 (sit-for 1))))
2207
2208 (defun ada-batch-reformat ()
2209 "Re-indent and re-case all the files found on the command line.
2210 This function should be used from the Unix/Windows command line, with a
2211 command like:
2212 emacs -batch -l ada-mode -f ada-batch-reformat file1 file2 ..."
2213
2214 (while command-line-args-left
2215 (let ((source (car command-line-args-left)))
2216 (message (concat "formating " source))
2217 (find-file source)
2218 (ada-indent-region (point-min) (point-max))
2219 (ada-adjust-case-buffer)
2220 (write-file source))
2221 (setq command-line-args-left (cdr command-line-args-left)))
2222 (message "Done")
2223 (kill-emacs 0))
2224
2225 (defsubst ada-goto-previous-word ()
2226 "Moves point to the beginning of the previous word of Ada code.
2227 Returns the new position of point or nil if not found."
2228 (ada-goto-next-word t))
2229
2230 (defun ada-indent-current ()
2231 "Indent current line as Ada code.
2232 Returns the calculation that was done, including the reference point and the
2233 offset."
2234 (interactive)
2235 (let ((previous-syntax-table (syntax-table))
2236 (orgpoint (point-marker))
2237 cur-indent tmp-indent
2238 prev-indent)
2239
2240 (unwind-protect
2241 (progn
2242 (set-syntax-table ada-mode-symbol-syntax-table)
2243
2244 ;; This need to be done here so that the advice is not always
2245 ;; activated (this might interact badly with other modes)
2246 (if (featurep 'xemacs)
2247 (ad-activate 'parse-partial-sexp t))
2248
2249 (save-excursion
2250 (setq cur-indent
2251
2252 ;; Not First line in the buffer ?
2253 (if (save-excursion (zerop (forward-line -1)))
2254 (progn
2255 (back-to-indentation)
2256 (ada-get-current-indent))
2257
2258 ;; first line in the buffer
2259 (list (point-min) 0))))
2260
2261 ;; Evaluate the list to get the column to indent to
2262 ;; prev-indent contains the column to indent to
2263 (if cur-indent
2264 (setq prev-indent (save-excursion (goto-char (car cur-indent))
2265 (current-column))
2266 tmp-indent (cdr cur-indent))
2267 (setq prev-indent 0 tmp-indent '()))
2268
2269 (while (not (null tmp-indent))
2270 (cond
2271 ((numberp (car tmp-indent))
2272 (setq prev-indent (+ prev-indent (car tmp-indent))))
2273 (t
2274 (setq prev-indent (+ prev-indent (eval (car tmp-indent)))))
2275 )
2276 (setq tmp-indent (cdr tmp-indent)))
2277
2278 ;; only re-indent if indentation is different then the current
2279 (if (= (save-excursion (back-to-indentation) (current-column)) prev-indent)
2280 nil
2281 (beginning-of-line)
2282 (delete-horizontal-space)
2283 (indent-to prev-indent))
2284 ;;
2285 ;; restore position of point
2286 ;;
2287 (goto-char orgpoint)
2288 (if (< (current-column) (current-indentation))
2289 (back-to-indentation)))
2290
2291 ;; restore syntax-table
2292 (set-syntax-table previous-syntax-table)
2293 (if (featurep 'xemacs)
2294 (ad-deactivate 'parse-partial-sexp))
2295 )
2296
2297 cur-indent
2298 ))
2299
2300 (defun ada-get-current-indent ()
2301 "Return the indentation to use for the current line."
2302 (let (column
2303 pos
2304 match-cons
2305 result
2306 (orgpoint (save-excursion
2307 (beginning-of-line)
2308 (forward-comment -10000)
2309 (forward-line 1)
2310 (point))))
2311
2312 (setq result
2313 (cond
2314
2315 ;;-----------------------------
2316 ;; in open parenthesis, but not in parameter-list
2317 ;;-----------------------------
2318
2319 ((and ada-indent-to-open-paren
2320 (not (ada-in-paramlist-p))
2321 (setq column (ada-in-open-paren-p)))
2322
2323 ;; check if we have something like this (Table_Component_Type =>
2324 ;; Source_File_Record)
2325 (save-excursion
2326
2327 ;; Align the closing parenthesis on the opening one
2328 (if (= (following-char) ?\))
2329 (save-excursion
2330 (goto-char column)
2331 (skip-chars-backward " \t")
2332 (list (1- (point)) 0))
2333
2334 (if (and (skip-chars-backward " \t")
2335 (= (char-before) ?\n)
2336 (not (forward-comment -10000))
2337 (= (char-before) ?>))
2338 ;; ??? Could use a different variable
2339 (list column 'ada-broken-indent)
2340
2341 ;; We want all continuation lines to be indented the same
2342 ;; (ada-broken-line from the opening parenthesis. However, in
2343 ;; parameter list, each new parameter should be indented at the
2344 ;; column as the opening parenthesis.
2345
2346 ;; A special case to handle nested boolean expressions, as in
2347 ;; ((B
2348 ;; and then C) -- indented by ada-broken-indent
2349 ;; or else D) -- indenting this line.
2350 ;; ??? This is really a hack, we should have a proper way to go to
2351 ;; ??? the beginning of the statement
2352
2353 (if (= (char-before) ?\))
2354 (backward-sexp))
2355
2356 (if (memq (char-before) '(?, ?\; ?\( ?\)))
2357 (list column 0)
2358 (list column 'ada-continuation-indent)
2359 )))))
2360
2361 ;;---------------------------
2362 ;; at end of buffer
2363 ;;---------------------------
2364
2365 ((not (char-after))
2366 (ada-indent-on-previous-lines nil orgpoint orgpoint))
2367
2368 ;;---------------------------
2369 ;; starting with e
2370 ;;---------------------------
2371
2372 ((= (downcase (char-after)) ?e)
2373 (cond
2374
2375 ;; ------- end ------
2376
2377 ((looking-at "end\\>")
2378 (let ((label 0)
2379 limit)
2380 (save-excursion
2381 (ada-goto-matching-start 1)
2382
2383 ;;
2384 ;; found 'loop' => skip back to 'while' or 'for'
2385 ;; if 'loop' is not on a separate line
2386 ;; Stop the search for 'while' and 'for' when a ';' is encountered.
2387 ;;
2388 (if (save-excursion
2389 (beginning-of-line)
2390 (looking-at ".+\\<loop\\>"))
2391 (progn
2392 (save-excursion
2393 (setq limit (car (ada-search-ignore-string-comment ";" t))))
2394 (if (save-excursion
2395 (and
2396 (setq match-cons
2397 (ada-search-ignore-string-comment ada-loop-start-re t limit))
2398 (not (looking-at "\\<loop\\>"))))
2399 (progn
2400 (goto-char (car match-cons))
2401 (save-excursion
2402 (beginning-of-line)
2403 (if (looking-at ada-named-block-re)
2404 (setq label (- ada-label-indent))))))))
2405
2406 ;; found 'record' =>
2407 ;; if the keyword is found at the beginning of a line (or just
2408 ;; after limited, we indent on it, otherwise we indent on the
2409 ;; beginning of the type declaration)
2410 ;; type A is (B : Integer;
2411 ;; C : Integer) is record
2412 ;; end record; -- This is badly indented otherwise
2413 (if (looking-at "record")
2414 (if (save-excursion
2415 (beginning-of-line)
2416 (looking-at "^[ \t]*\\(record\\|limited record\\)"))
2417 (list (save-excursion (back-to-indentation) (point)) 0)
2418 (list (save-excursion
2419 (car (ada-search-ignore-string-comment "\\<type\\>" t)))
2420 0))
2421
2422 ;; Else keep the same indentation as the beginning statement
2423 (list (+ (save-excursion (back-to-indentation) (point)) label) 0)))))
2424
2425 ;; ------ exception ----
2426
2427 ((looking-at "exception\\>")
2428 (save-excursion
2429 (ada-goto-matching-start 1)
2430 (list (save-excursion (back-to-indentation) (point)) 0)))
2431
2432 ;; else
2433
2434 ((looking-at "else\\>")
2435 (if (save-excursion (ada-goto-previous-word)
2436 (looking-at "\\<or\\>"))
2437 (ada-indent-on-previous-lines nil orgpoint orgpoint)
2438 (save-excursion
2439 (ada-goto-matching-start 1 nil t)
2440 (list (progn (back-to-indentation) (point)) 0))))
2441
2442 ;; elsif
2443
2444 ((looking-at "elsif\\>")
2445 (save-excursion
2446 (ada-goto-matching-start 1 nil t)
2447 (list (progn (back-to-indentation) (point)) 0)))
2448
2449 ))
2450
2451 ;;---------------------------
2452 ;; starting with w (when)
2453 ;;---------------------------
2454
2455 ((and (= (downcase (char-after)) ?w)
2456 (looking-at "when\\>"))
2457 (save-excursion
2458 (ada-goto-matching-start 1)
2459 (list (save-excursion (back-to-indentation) (point))
2460 'ada-when-indent)))
2461
2462 ;;---------------------------
2463 ;; starting with t (then)
2464 ;;---------------------------
2465
2466 ((and (= (downcase (char-after)) ?t)
2467 (looking-at "then\\>"))
2468 (if (save-excursion (ada-goto-previous-word)
2469 (looking-at "and\\>"))
2470 (ada-indent-on-previous-lines nil orgpoint orgpoint)
2471 (save-excursion
2472 ;; Select has been added for the statement: "select ... then abort"
2473 (ada-search-ignore-string-comment
2474 "\\<\\(elsif\\|if\\|select\\)\\>" t nil)
2475 (list (progn (back-to-indentation) (point))
2476 'ada-stmt-end-indent))))
2477
2478 ;;---------------------------
2479 ;; starting with l (loop)
2480 ;;---------------------------
2481
2482 ((and (= (downcase (char-after)) ?l)
2483 (looking-at "loop\\>"))
2484 (setq pos (point))
2485 (save-excursion
2486 (goto-char (match-end 0))
2487 (ada-goto-stmt-start)
2488 (if (looking-at "\\<\\(loop\\|if\\)\\>")
2489 (ada-indent-on-previous-lines nil orgpoint orgpoint)
2490 (unless (looking-at ada-loop-start-re)
2491 (ada-search-ignore-string-comment ada-loop-start-re
2492 nil pos))
2493 (if (looking-at "\\<loop\\>")
2494 (ada-indent-on-previous-lines nil orgpoint orgpoint)
2495 (list (progn (back-to-indentation) (point)) 'ada-stmt-end-indent)))))
2496
2497 ;;----------------------------
2498 ;; starting with l (limited) or r (record)
2499 ;;----------------------------
2500
2501 ((or (and (= (downcase (char-after)) ?l)
2502 (looking-at "limited\\>"))
2503 (and (= (downcase (char-after)) ?r)
2504 (looking-at "record\\>")))
2505
2506 (save-excursion
2507 (ada-search-ignore-string-comment
2508 "\\<\\(type\\|use\\)\\>" t nil)
2509 (if (looking-at "\\<use\\>")
2510 (ada-search-ignore-string-comment "for" t nil nil
2511 'word-search-backward))
2512 (list (progn (back-to-indentation) (point))
2513 'ada-indent-record-rel-type)))
2514
2515 ;;---------------------------
2516 ;; starting with b (begin)
2517 ;;---------------------------
2518
2519 ((and (= (downcase (char-after)) ?b)
2520 (looking-at "begin\\>"))
2521 (save-excursion
2522 (if (ada-goto-matching-decl-start t)
2523 (list (progn (back-to-indentation) (point)) 0)
2524 (ada-indent-on-previous-lines nil orgpoint orgpoint))))
2525
2526 ;;---------------------------
2527 ;; starting with i (is)
2528 ;;---------------------------
2529
2530 ((and (= (downcase (char-after)) ?i)
2531 (looking-at "is\\>"))
2532
2533 (if (and ada-indent-is-separate
2534 (save-excursion
2535 (goto-char (match-end 0))
2536 (ada-goto-next-non-ws (save-excursion (end-of-line)
2537 (point)))
2538 (looking-at "\\<abstract\\>\\|\\<separate\\>")))
2539 (save-excursion
2540 (ada-goto-stmt-start)
2541 (list (progn (back-to-indentation) (point)) 'ada-indent))
2542 (save-excursion
2543 (ada-goto-stmt-start)
2544 (if (looking-at "\\<package\\|procedure\\|function\\>")
2545 (list (progn (back-to-indentation) (point)) 0)
2546 (list (progn (back-to-indentation) (point)) 'ada-indent)))))
2547
2548 ;;---------------------------
2549 ;; starting with r (return, renames)
2550 ;;---------------------------
2551
2552 ((and (= (downcase (char-after)) ?r)
2553 (looking-at "re\\(turn\\|names\\)\\>"))
2554
2555 (save-excursion
2556 (let ((var 'ada-indent-return))
2557 ;; If looking at a renames, skip the 'return' statement too
2558 (if (looking-at "renames")
2559 (let (pos)
2560 (save-excursion
2561 (set 'pos (ada-search-ignore-string-comment ";\\|return\\>" t)))
2562 (if (and pos
2563 (= (downcase (char-after (car pos))) ?r))
2564 (goto-char (car pos)))
2565 (set 'var 'ada-indent-renames)))
2566
2567 (forward-comment -1000)
2568 (if (= (char-before) ?\))
2569 (forward-sexp -1)
2570 (forward-word -1))
2571
2572 ;; If there is a parameter list, and we have a function declaration
2573 ;; or a access to subprogram declaration
2574 (let ((num-back 1))
2575 (if (and (= (following-char) ?\()
2576 (save-excursion
2577 (or (progn
2578 (backward-word 1)
2579 (looking-at "\\(function\\|procedure\\)\\>"))
2580 (progn
2581 (backward-word 1)
2582 (set 'num-back 2)
2583 (looking-at "\\(function\\|procedure\\)\\>")))))
2584
2585 ;; The indentation depends of the value of ada-indent-return
2586 (if (<= (eval var) 0)
2587 (list (point) (list '- var))
2588 (list (progn (backward-word num-back) (point))
2589 var))
2590
2591 ;; Else there is no parameter list, but we have a function
2592 ;; Only do something special if the user want to indent
2593 ;; relative to the "function" keyword
2594 (if (and (> (eval var) 0)
2595 (save-excursion (forward-word -1)
2596 (looking-at "function\\>")))
2597 (list (progn (forward-word -1) (point)) var)
2598
2599 ;; Else...
2600 (ada-indent-on-previous-lines nil orgpoint orgpoint)))))))
2601
2602 ;;--------------------------------
2603 ;; starting with 'o' or 'p'
2604 ;; 'or' as statement-start
2605 ;; 'private' as statement-start
2606 ;;--------------------------------
2607
2608 ((and (or (= (downcase (char-after)) ?o)
2609 (= (downcase (char-after)) ?p))
2610 (or (ada-looking-at-semi-or)
2611 (ada-looking-at-semi-private)))
2612 (save-excursion
2613 ;; ??? Wasn't this done already in ada-looking-at-semi-or ?
2614 (ada-goto-matching-start 1)
2615 (list (progn (back-to-indentation) (point)) 0)))
2616
2617 ;;--------------------------------
2618 ;; starting with 'd' (do)
2619 ;;--------------------------------
2620
2621 ((and (= (downcase (char-after)) ?d)
2622 (looking-at "do\\>"))
2623 (save-excursion
2624 (ada-goto-stmt-start)
2625 (list (progn (back-to-indentation) (point)) 'ada-stmt-end-indent)))
2626
2627 ;;--------------------------------
2628 ;; starting with '-' (comment)
2629 ;;--------------------------------
2630
2631 ((= (char-after) ?-)
2632 (if ada-indent-comment-as-code
2633
2634 ;; Indent comments on previous line comments if required
2635 ;; We must use a search-forward (even if the code is more complex),
2636 ;; since we want to find the beginning of the comment.
2637 (let (pos)
2638
2639 (if (and ada-indent-align-comments
2640 (save-excursion
2641 (forward-line -1)
2642 (beginning-of-line)
2643 (while (and (not pos)
2644 (search-forward "--"
2645 (save-excursion
2646 (end-of-line) (point))
2647 t))
2648 (unless (ada-in-string-p)
2649 (setq pos (point))))
2650 pos))
2651 (list (- pos 2) 0)
2652
2653 ;; Else always on previous line
2654 (ada-indent-on-previous-lines nil orgpoint orgpoint)))
2655
2656 ;; Else same indentation as the previous line
2657 (list (save-excursion (back-to-indentation) (point)) 0)))
2658
2659 ;;--------------------------------
2660 ;; starting with '#' (preprocessor line)
2661 ;;--------------------------------
2662
2663 ((and (= (char-after) ?#)
2664 (equal ada-which-compiler 'gnat)
2665 (looking-at "#[ \t]*\\(if\\|els\\(e\\|if\\)\\|end[ \t]*if\\)"))
2666 (list (save-excursion (beginning-of-line) (point)) 0))
2667
2668 ;;--------------------------------
2669 ;; starting with ')' (end of a parameter list)
2670 ;;--------------------------------
2671
2672 ((and (not (eobp)) (= (char-after) ?\)))
2673 (save-excursion
2674 (forward-char 1)
2675 (backward-sexp 1)
2676 (list (point) 0)))
2677
2678 ;;---------------------------------
2679 ;; new/abstract/separate
2680 ;;---------------------------------
2681
2682 ((looking-at "\\(new\\|abstract\\|separate\\)\\>")
2683 (ada-indent-on-previous-lines nil orgpoint orgpoint))
2684
2685 ;;---------------------------------
2686 ;; package/function/procedure
2687 ;;---------------------------------
2688
2689 ((and (or (= (downcase (char-after)) ?p) (= (downcase (char-after)) ?f))
2690 (looking-at "\\<\\(package\\|function\\|procedure\\)\\>"))
2691 (save-excursion
2692 ;; Go up until we find either a generic section, or the end of the
2693 ;; previous subprogram/package
2694 (let (found)
2695 (while (and (not found)
2696 (ada-search-ignore-string-comment
2697 "\\<\\(generic\\|end\\|begin\\|package\\|procedure\\|function\\)\\>" t))
2698
2699 ;; avoid "with procedure"... in generic parts
2700 (save-excursion
2701 (forward-word -1)
2702 (setq found (not (looking-at "with"))))))
2703
2704 (if (looking-at "generic")
2705 (list (progn (back-to-indentation) (point)) 0)
2706 (ada-indent-on-previous-lines nil orgpoint orgpoint))))
2707
2708 ;;---------------------------------
2709 ;; label
2710 ;;---------------------------------
2711
2712 ((looking-at "\\(\\sw\\|_\\)+[ \t\n]*:[^=]")
2713 (if (ada-in-decl-p)
2714 (ada-indent-on-previous-lines nil orgpoint orgpoint)
2715 (append (ada-indent-on-previous-lines nil orgpoint orgpoint)
2716 '(ada-label-indent))))
2717
2718 ))
2719
2720 ;;---------------------------------
2721 ;; Other syntaxes
2722 ;;---------------------------------
2723 (or result (ada-indent-on-previous-lines nil orgpoint orgpoint))))
2724
2725 (defun ada-indent-on-previous-lines (&optional nomove orgpoint initial-pos)
2726 "Calculate the indentation for the new line after ORGPOINT.
2727 The result list is based on the previous lines in the buffer.
2728 If NOMOVE is nil, moves point to the beginning of the current statement.
2729 if INITIAL-POS is non-nil, moves point to INITIAL-POS before calculation."
2730 (if initial-pos
2731 (goto-char initial-pos))
2732 (let ((oldpoint (point)))
2733
2734 ;; Is inside a parameter-list ?
2735 (if (ada-in-paramlist-p)
2736 (ada-get-indent-paramlist)
2737
2738 ;; move to beginning of current statement
2739 (unless nomove
2740 (ada-goto-stmt-start))
2741
2742 ;; no beginning found => don't change indentation
2743 (if (and (eq oldpoint (point))
2744 (not nomove))
2745 (ada-get-indent-nochange)
2746
2747 (cond
2748 ;;
2749 ((and
2750 ada-indent-to-open-paren
2751 (ada-in-open-paren-p))
2752 (ada-get-indent-open-paren))
2753 ;;
2754 ((looking-at "end\\>")
2755 (ada-get-indent-end orgpoint))
2756 ;;
2757 ((looking-at ada-loop-start-re)
2758 (ada-get-indent-loop orgpoint))
2759 ;;
2760 ((looking-at ada-subprog-start-re)
2761 (ada-get-indent-subprog orgpoint))
2762 ;;
2763 ((looking-at ada-block-start-re)
2764 (ada-get-indent-block-start orgpoint))
2765 ;;
2766 ((looking-at "\\(sub\\)?type\\>")
2767 (ada-get-indent-type orgpoint))
2768 ;;
2769 ;; "then" has to be included in the case of "select...then abort"
2770 ;; statements, since (goto-stmt-start) at the beginning of
2771 ;; the current function would leave the cursor on that position
2772 ((looking-at "\\(\\(els\\)?if\\>\\)\\|then abort\\\>")
2773 (ada-get-indent-if orgpoint))
2774 ;;
2775 ((looking-at "case\\>")
2776 (ada-get-indent-case orgpoint))
2777 ;;
2778 ((looking-at "when\\>")
2779 (ada-get-indent-when orgpoint))
2780 ;;
2781 ((looking-at "\\(\\sw\\|_\\)+[ \t\n]*:[^=]")
2782 (ada-get-indent-label orgpoint))
2783 ;;
2784 ((looking-at "separate\\>")
2785 (ada-get-indent-nochange))
2786
2787 ;; A label
2788 ((looking-at "<<")
2789 (list (+ (save-excursion (back-to-indentation) (point))
2790 (- ada-label-indent))))
2791
2792 ;;
2793 ((looking-at "with\\>\\|use\\>")
2794 ;; Are we still in that statement, or are we in fact looking at
2795 ;; the previous one ?
2796 (if (save-excursion (search-forward ";" oldpoint t))
2797 (list (progn (back-to-indentation) (point)) 0)
2798 (list (point) (if (looking-at "with")
2799 'ada-with-indent
2800 'ada-use-indent))))
2801 ;;
2802 (t
2803 (ada-get-indent-noindent orgpoint)))))
2804 ))
2805
2806 (defun ada-get-indent-open-paren ()
2807 "Calculates the indentation when point is behind an unclosed parenthesis."
2808 (list (ada-in-open-paren-p) 0))
2809
2810 (defun ada-get-indent-nochange ()
2811 "Return the current indentation of the previous line."
2812 (save-excursion
2813 (forward-line -1)
2814 (back-to-indentation)
2815 (list (point) 0)))
2816
2817 (defun ada-get-indent-paramlist ()
2818 "Calculates the indentation when point is inside a parameter list."
2819 (save-excursion
2820 (ada-search-ignore-string-comment "[^ \t\n]" t nil t)
2821 (cond
2822 ;; in front of the first parameter
2823 ((= (char-after) ?\()
2824 (goto-char (match-end 0))
2825 (list (point) 0))
2826
2827 ;; in front of another parameter
2828 ((= (char-after) ?\;)
2829 (goto-char (cdr (ada-search-ignore-string-comment "(\\|;" t nil t)))
2830 (ada-goto-next-non-ws)
2831 (list (point) 0))
2832
2833 ;; After an affectation (default parameter value in subprogram
2834 ;; declaration)
2835 ((and (= (following-char) ?=) (= (preceding-char) ?:))
2836 (back-to-indentation)
2837 (list (point) 'ada-broken-indent))
2838
2839 ;; inside a parameter declaration
2840 (t
2841 (goto-char (cdr (ada-search-ignore-string-comment "(\\|;" t nil t)))
2842 (ada-goto-next-non-ws)
2843 (list (point) 0)))))
2844
2845 (defun ada-get-indent-end (orgpoint)
2846 "Calculates the indentation when point is just before an end_statement.
2847 ORGPOINT is the limit position used in the calculation."
2848 (let ((defun-name nil)
2849 (indent nil))
2850
2851 ;; is the line already terminated by ';' ?
2852 (if (save-excursion
2853 (ada-search-ignore-string-comment ";" nil orgpoint nil
2854 'search-forward))
2855
2856 ;; yes, look what's following 'end'
2857 (progn
2858 (forward-word 1)
2859 (ada-goto-next-non-ws)
2860 (cond
2861 ((looking-at "\\<\\(loop\\|select\\|if\\|case\\)\\>")
2862 (save-excursion (ada-check-matching-start (match-string 0)))
2863 (list (save-excursion (back-to-indentation) (point)) 0))
2864
2865 ;;
2866 ;; loop/select/if/case/record/select
2867 ;;
2868 ((looking-at "\\<record\\>")
2869 (save-excursion
2870 (ada-check-matching-start (match-string 0))
2871 ;; we are now looking at the matching "record" statement
2872 (forward-word 1)
2873 (ada-goto-stmt-start)
2874 ;; now on the matching type declaration, or use clause
2875 (unless (looking-at "\\(for\\|type\\)\\>")
2876 (ada-search-ignore-string-comment "\\<type\\>" t))
2877 (list (progn (back-to-indentation) (point)) 0)))
2878 ;;
2879 ;; a named block end
2880 ;;
2881 ((looking-at ada-ident-re)
2882 (setq defun-name (match-string 0))
2883 (save-excursion
2884 (ada-goto-matching-start 0)
2885 (ada-check-defun-name defun-name))
2886 (list (progn (back-to-indentation) (point)) 0))
2887 ;;
2888 ;; a block-end without name
2889 ;;
2890 ((= (char-after) ?\;)
2891 (save-excursion
2892 (ada-goto-matching-start 0)
2893 (if (looking-at "\\<begin\\>")
2894 (progn
2895 (setq indent (list (point) 0))
2896 (if (ada-goto-matching-decl-start t)
2897 (list (progn (back-to-indentation) (point)) 0)
2898 indent))
2899 (list (progn (back-to-indentation) (point)) 0)
2900 )))
2901 ;;
2902 ;; anything else - should maybe signal an error ?
2903 ;;
2904 (t
2905 (list (save-excursion (back-to-indentation) (point))
2906 'ada-broken-indent))))
2907
2908 (list (save-excursion (back-to-indentation) (point))
2909 'ada-broken-indent))))
2910
2911 (defun ada-get-indent-case (orgpoint)
2912 "Calculates the indentation when point is just before a case statement.
2913 ORGPOINT is the limit position used in the calculation."
2914 (let ((match-cons nil)
2915 (opos (point)))
2916 (cond
2917 ;;
2918 ;; case..is..when..=>
2919 ;;
2920 ((save-excursion
2921 (setq match-cons (and
2922 ;; the `=>' must be after the keyword `is'.
2923 (ada-search-ignore-string-comment
2924 "is" nil orgpoint nil 'word-search-forward)
2925 (ada-search-ignore-string-comment
2926 "[ \t\n]+=>" nil orgpoint))))
2927 (save-excursion
2928 (goto-char (car match-cons))
2929 (unless (ada-search-ignore-string-comment "when" t opos)
2930 (error "missing 'when' between 'case' and '=>'"))
2931 (list (save-excursion (back-to-indentation) (point)) 'ada-indent)))
2932 ;;
2933 ;; case..is..when
2934 ;;
2935 ((save-excursion
2936 (setq match-cons (ada-search-ignore-string-comment
2937 "when" nil orgpoint nil 'word-search-forward)))
2938 (goto-char (cdr match-cons))
2939 (list (save-excursion (back-to-indentation) (point)) 'ada-broken-indent))
2940 ;;
2941 ;; case..is
2942 ;;
2943 ((save-excursion
2944 (setq match-cons (ada-search-ignore-string-comment
2945 "is" nil orgpoint nil 'word-search-forward)))
2946 (list (save-excursion (back-to-indentation) (point)) 'ada-when-indent))
2947 ;;
2948 ;; incomplete case
2949 ;;
2950 (t
2951 (list (save-excursion (back-to-indentation) (point))
2952 'ada-broken-indent)))))
2953
2954 (defun ada-get-indent-when (orgpoint)
2955 "Calculates the indentation when point is just before a when statement.
2956 ORGPOINT is the limit position used in the calculation."
2957 (let ((cur-indent (save-excursion (back-to-indentation) (point))))
2958 (if (ada-search-ignore-string-comment "[ \t\n]*=>" nil orgpoint)
2959 (list cur-indent 'ada-indent)
2960 (list cur-indent 'ada-broken-indent))))
2961
2962 (defun ada-get-indent-if (orgpoint)
2963 "Calculates the indentation when point is just before an if statement.
2964 ORGPOINT is the limit position used in the calculation."
2965 (let ((cur-indent (save-excursion (back-to-indentation) (point)))
2966 (match-cons nil))
2967 ;;
2968 ;; Move to the correct then (ignore all "and then")
2969 ;;
2970 (while (and (setq match-cons (ada-search-ignore-string-comment
2971 "\\<\\(then\\|and[ \t]*then\\)\\>"
2972 nil orgpoint))
2973 (= (downcase (char-after (car match-cons))) ?a)))
2974 ;; If "then" was found (we are looking at it)
2975 (if match-cons
2976 (progn
2977 ;;
2978 ;; 'then' first in separate line ?
2979 ;; => indent according to 'then',
2980 ;; => else indent according to 'if'
2981 ;;
2982 (if (save-excursion
2983 (back-to-indentation)
2984 (looking-at "\\<then\\>"))
2985 (setq cur-indent (save-excursion (back-to-indentation) (point))))
2986 ;; skip 'then'
2987 (forward-word 1)
2988 (list cur-indent 'ada-indent))
2989
2990 (list cur-indent 'ada-broken-indent))))
2991
2992 (defun ada-get-indent-block-start (orgpoint)
2993 "Calculates the indentation when point is at the start of a block.
2994 ORGPOINT is the limit position used in the calculation."
2995 (let ((pos nil))
2996 (cond
2997 ((save-excursion
2998 (forward-word 1)
2999 (setq pos (ada-goto-next-non-ws orgpoint)))
3000 (goto-char pos)
3001 (save-excursion
3002 (ada-indent-on-previous-lines t orgpoint)))
3003
3004 ;; Special case for record types, for instance for:
3005 ;; type A is (B : Integer;
3006 ;; C : Integer) is record
3007 ;; null; -- This is badly indented otherwise
3008 ((looking-at "record")
3009
3010 ;; If record is at the beginning of the line, indent from there
3011 (if (save-excursion
3012 (beginning-of-line)
3013 (looking-at "^[ \t]*\\(record\\|limited record\\)"))
3014 (list (save-excursion (back-to-indentation) (point)) 'ada-indent)
3015
3016 ;; else indent relative to the type command
3017 (list (save-excursion
3018 (car (ada-search-ignore-string-comment "\\<type\\>" t)))
3019 'ada-indent)))
3020
3021 ;; nothing follows the block-start
3022 (t
3023 (list (save-excursion (back-to-indentation) (point)) 'ada-indent)))))
3024
3025 (defun ada-get-indent-subprog (orgpoint)
3026 "Calculates the indentation when point is just before a subprogram.
3027 ORGPOINT is the limit position used in the calculation."
3028 (let ((match-cons nil)
3029 (cur-indent (save-excursion (back-to-indentation) (point)))
3030 (foundis nil))
3031 ;;
3032 ;; is there an 'is' in front of point ?
3033 ;;
3034 (if (save-excursion
3035 (setq match-cons
3036 (ada-search-ignore-string-comment
3037 "\\<\\(is\\|do\\)\\>" nil orgpoint)))
3038 ;;
3039 ;; yes, then skip to its end
3040 ;;
3041 (progn
3042 (setq foundis t)
3043 (goto-char (cdr match-cons)))
3044 ;;
3045 ;; no, then goto next non-ws, if there is one in front of point
3046 ;;
3047 (progn
3048 (unless (ada-goto-next-non-ws orgpoint)
3049 (goto-char orgpoint))))
3050
3051 (cond
3052 ;;
3053 ;; nothing follows 'is'
3054 ;;
3055 ((and
3056 foundis
3057 (save-excursion
3058 (not (ada-search-ignore-string-comment
3059 "[^ \t\n]" nil orgpoint t))))
3060 (list cur-indent 'ada-indent))
3061 ;;
3062 ;; is abstract/separate/new ...
3063 ;;
3064 ((and
3065 foundis
3066 (save-excursion
3067 (setq match-cons
3068 (ada-search-ignore-string-comment
3069 "\\<\\(separate\\|new\\|abstract\\)\\>"
3070 nil orgpoint))))
3071 (goto-char (car match-cons))
3072 (ada-search-ignore-string-comment ada-subprog-start-re t)
3073 (ada-get-indent-noindent orgpoint))
3074 ;;
3075 ;; something follows 'is'
3076 ;;
3077 ((and
3078 foundis
3079 (save-excursion (setq match-cons (ada-goto-next-non-ws orgpoint)))
3080 (goto-char match-cons)
3081 (ada-indent-on-previous-lines t orgpoint)))
3082 ;;
3083 ;; no 'is' but ';'
3084 ;;
3085 ((save-excursion
3086 (ada-search-ignore-string-comment ";" nil orgpoint nil 'search-forward))
3087 (list cur-indent 0))
3088 ;;
3089 ;; no 'is' or ';'
3090 ;;
3091 (t
3092 (list cur-indent 'ada-broken-indent)))))
3093
3094 (defun ada-get-indent-noindent (orgpoint)
3095 "Calculates the indentation when point is just before a 'noindent stmt'.
3096 ORGPOINT is the limit position used in the calculation."
3097 (let ((label 0))
3098 (save-excursion
3099 (beginning-of-line)
3100
3101 (cond
3102
3103 ;; This one is called when indenting a line preceded by a multi-line
3104 ;; subprogram declaration (in that case, we are at this point inside
3105 ;; the parameter declaration list)
3106 ((ada-in-paramlist-p)
3107 (ada-previous-procedure)
3108 (list (save-excursion (back-to-indentation) (point)) 0))
3109
3110 ;; This one is called when indenting the second line of a multi-line
3111 ;; declaration section, in a declare block or a record declaration
3112 ((looking-at "[ \t]*\\(\\sw\\|_\\)*[ \t]*,[ \t]*$")
3113 (list (save-excursion (back-to-indentation) (point))
3114 'ada-broken-decl-indent))
3115
3116 ;; This one is called in every over case when indenting a line at the
3117 ;; top level
3118 (t
3119 (if (looking-at ada-named-block-re)
3120 (setq label (- ada-label-indent))
3121
3122 (let (p)
3123
3124 ;; "with private" or "null record" cases
3125 (if (or (save-excursion
3126 (and (ada-search-ignore-string-comment "\\<private\\>" nil orgpoint)
3127 (setq p (point))
3128 (save-excursion (forward-char -7);; skip back "private"
3129 (ada-goto-previous-word)
3130 (looking-at "with"))))
3131 (save-excursion
3132 (and (ada-search-ignore-string-comment "\\<record\\>" nil orgpoint)
3133 (setq p (point))
3134 (save-excursion (forward-char -6);; skip back "record"
3135 (ada-goto-previous-word)
3136 (looking-at "null")))))
3137 (progn
3138 (goto-char p)
3139 (re-search-backward "\\<\\(type\\|subtype\\)\\>" nil t)
3140 (list (save-excursion (back-to-indentation) (point)) 0)))))
3141 (if (save-excursion
3142 (ada-search-ignore-string-comment ";" nil orgpoint nil
3143 'search-forward))
3144 (list (+ (save-excursion (back-to-indentation) (point)) label) 0)
3145 (list (+ (save-excursion (back-to-indentation) (point)) label)
3146 'ada-broken-indent)))))))
3147
3148 (defun ada-get-indent-label (orgpoint)
3149 "Calculates the indentation when before a label or variable declaration.
3150 ORGPOINT is the limit position used in the calculation."
3151 (let ((match-cons nil)
3152 (cur-indent (save-excursion (back-to-indentation) (point))))
3153 (ada-search-ignore-string-comment ":" nil)
3154 (cond
3155 ;; loop label
3156 ((save-excursion
3157 (setq match-cons (ada-search-ignore-string-comment
3158 ada-loop-start-re nil orgpoint)))
3159 (goto-char (car match-cons))
3160 (ada-get-indent-loop orgpoint))
3161
3162 ;; declare label
3163 ((save-excursion
3164 (setq match-cons (ada-search-ignore-string-comment
3165 "\\<declare\\|begin\\>" nil orgpoint)))
3166 (goto-char (car match-cons))
3167 (list (save-excursion (back-to-indentation) (point)) 'ada-indent))
3168
3169 ;; variable declaration
3170 ((ada-in-decl-p)
3171 (if (save-excursion
3172 (ada-search-ignore-string-comment ";" nil orgpoint))
3173 (list cur-indent 0)
3174 (list cur-indent 'ada-broken-indent)))
3175
3176 ;; nothing follows colon
3177 (t
3178 (list cur-indent '(- ada-label-indent))))))
3179
3180 (defun ada-get-indent-loop (orgpoint)
3181 "Calculates the indentation when just before a loop or a for ... use.
3182 ORGPOINT is the limit position used in the calculation."
3183 (let ((match-cons nil)
3184 (pos (point))
3185
3186 ;; If looking at a named block, skip the label
3187 (label (save-excursion
3188 (beginning-of-line)
3189 (if (looking-at ada-named-block-re)
3190 (- ada-label-indent)
3191 0))))
3192
3193 (cond
3194
3195 ;;
3196 ;; statement complete
3197 ;;
3198 ((save-excursion
3199 (ada-search-ignore-string-comment ";" nil orgpoint nil
3200 'search-forward))
3201 (list (+ (save-excursion (back-to-indentation) (point)) label) 0))
3202 ;;
3203 ;; simple loop
3204 ;;
3205 ((looking-at "loop\\>")
3206 (setq pos (ada-get-indent-block-start orgpoint))
3207 (if (equal label 0)
3208 pos
3209 (list (+ (car pos) label) (cdr pos))))
3210
3211 ;;
3212 ;; 'for'- loop (or also a for ... use statement)
3213 ;;
3214 ((looking-at "for\\>")
3215 (cond
3216 ;;
3217 ;; for ... use
3218 ;;
3219 ((save-excursion
3220 (and
3221 (goto-char (match-end 0))
3222 (ada-goto-next-non-ws orgpoint)
3223 (forward-word 1)
3224 (if (= (char-after) ?') (forward-word 1) t)
3225 (ada-goto-next-non-ws orgpoint)
3226 (looking-at "\\<use\\>")
3227 ;;
3228 ;; check if there is a 'record' before point
3229 ;;
3230 (progn
3231 (setq match-cons (ada-search-ignore-string-comment
3232 "record" nil orgpoint nil 'word-search-forward))
3233 t)))
3234 (if match-cons
3235 (progn
3236 (goto-char (car match-cons))
3237 (list (save-excursion (back-to-indentation) (point)) 'ada-indent))
3238 (list (save-excursion (back-to-indentation) (point)) 'ada-broken-indent))
3239 )
3240
3241 ;;
3242 ;; for..loop
3243 ;;
3244 ((save-excursion
3245 (setq match-cons (ada-search-ignore-string-comment
3246 "loop" nil orgpoint nil 'word-search-forward)))
3247 (goto-char (car match-cons))
3248 ;;
3249 ;; indent according to 'loop', if it's first in the line;
3250 ;; otherwise to 'for'
3251 ;;
3252 (unless (save-excursion
3253 (back-to-indentation)
3254 (looking-at "\\<loop\\>"))
3255 (goto-char pos))
3256 (list (+ (save-excursion (back-to-indentation) (point)) label)
3257 'ada-indent))
3258 ;;
3259 ;; for-statement is broken
3260 ;;
3261 (t
3262 (list (+ (save-excursion (back-to-indentation) (point)) label)
3263 'ada-broken-indent))))
3264
3265 ;;
3266 ;; 'while'-loop
3267 ;;
3268 ((looking-at "while\\>")
3269 ;;
3270 ;; while..loop ?
3271 ;;
3272 (if (save-excursion
3273 (setq match-cons (ada-search-ignore-string-comment
3274 "loop" nil orgpoint nil 'word-search-forward)))
3275
3276 (progn
3277 (goto-char (car match-cons))
3278 ;;
3279 ;; indent according to 'loop', if it's first in the line;
3280 ;; otherwise to 'while'.
3281 ;;
3282 (unless (save-excursion
3283 (back-to-indentation)
3284 (looking-at "\\<loop\\>"))
3285 (goto-char pos))
3286 (list (+ (save-excursion (back-to-indentation) (point)) label)
3287 'ada-indent))
3288
3289 (list (+ (save-excursion (back-to-indentation) (point)) label)
3290 'ada-broken-indent))))))
3291
3292 (defun ada-get-indent-type (orgpoint)
3293 "Calculates the indentation when before a type statement.
3294 ORGPOINT is the limit position used in the calculation."
3295 (let ((match-dat nil))
3296 (cond
3297 ;;
3298 ;; complete record declaration
3299 ;;
3300 ((save-excursion
3301 (and
3302 (setq match-dat (ada-search-ignore-string-comment
3303 "end" nil orgpoint nil 'word-search-forward))
3304 (ada-goto-next-non-ws)
3305 (looking-at "\\<record\\>")
3306 (forward-word 1)
3307 (ada-goto-next-non-ws)
3308 (= (char-after) ?\;)))
3309 (goto-char (car match-dat))
3310 (list (save-excursion (back-to-indentation) (point)) 0))
3311 ;;
3312 ;; record type
3313 ;;
3314 ((save-excursion
3315 (setq match-dat (ada-search-ignore-string-comment
3316 "record" nil orgpoint nil 'word-search-forward)))
3317 (goto-char (car match-dat))
3318 (list (save-excursion (back-to-indentation) (point)) 'ada-indent))
3319 ;;
3320 ;; complete type declaration
3321 ;;
3322 ((save-excursion
3323 (ada-search-ignore-string-comment ";" nil orgpoint nil
3324 'search-forward))
3325 (list (save-excursion (back-to-indentation) (point)) 0))
3326 ;;
3327 ;; "type ... is", but not "type ... is ...", which is broken
3328 ;;
3329 ((save-excursion
3330 (and
3331 (ada-search-ignore-string-comment "is" nil orgpoint nil
3332 'word-search-forward)
3333 (not (ada-goto-next-non-ws orgpoint))))
3334 (list (save-excursion (back-to-indentation) (point)) 'ada-broken-indent))
3335 ;;
3336 ;; broken statement
3337 ;;
3338 (t
3339 (list (save-excursion (back-to-indentation) (point))
3340 'ada-broken-indent)))))
3341
3342 \f
3343 ;; -----------------------------------------------------------
3344 ;; -- searching and matching
3345 ;; -----------------------------------------------------------
3346
3347 (defun ada-goto-stmt-start ()
3348 "Moves point to the beginning of the statement that point is in or after.
3349 Returns the new position of point.
3350 As a special case, if we are looking at a closing parenthesis, skip to the
3351 open parenthesis."
3352 (let ((match-dat nil)
3353 (orgpoint (point)))
3354
3355 (setq match-dat (ada-search-prev-end-stmt))
3356 (if match-dat
3357
3358 ;;
3359 ;; found a previous end-statement => check if anything follows
3360 ;;
3361 (unless (looking-at "declare")
3362 (progn
3363 (unless (save-excursion
3364 (goto-char (cdr match-dat))
3365 (ada-goto-next-non-ws orgpoint))
3366 ;;
3367 ;; nothing follows => it's the end-statement directly in
3368 ;; front of point => search again
3369 ;;
3370 (setq match-dat (ada-search-prev-end-stmt)))
3371 ;;
3372 ;; if found the correct end-statement => goto next non-ws
3373 ;;
3374 (if match-dat
3375 (goto-char (cdr match-dat)))
3376 (ada-goto-next-non-ws)
3377 ))
3378
3379 ;;
3380 ;; no previous end-statement => we are at the beginning of the
3381 ;; accessible part of the buffer
3382 ;;
3383 (progn
3384 (goto-char (point-min))
3385 ;;
3386 ;; skip to the very first statement, if there is one
3387 ;;
3388 (unless (ada-goto-next-non-ws orgpoint)
3389 (goto-char orgpoint))))
3390 (point)))
3391
3392
3393 (defun ada-search-prev-end-stmt ()
3394 "Moves point to previous end-statement.
3395 Returns a cons cell whose car is the beginning and whose cdr the end of the
3396 match."
3397 (let ((match-dat nil)
3398 (found nil))
3399
3400 ;; search until found or beginning-of-buffer
3401 (while
3402 (and
3403 (not found)
3404 (setq match-dat (ada-search-ignore-string-comment
3405 ada-end-stmt-re t)))
3406
3407 (goto-char (car match-dat))
3408 (unless (ada-in-open-paren-p)
3409 (cond
3410
3411 ((and (looking-at
3412 "\\<\\(record\\|loop\\|select\\|else\\|then\\)\\>")
3413 (save-excursion
3414 (ada-goto-previous-word)
3415 (looking-at "\\<\\(end\\|or\\|and\\)\\>[ \t]*[^;]")))
3416 (forward-word -1))
3417
3418 ((looking-at "is")
3419 (setq found
3420 (and (save-excursion (ada-goto-previous-word)
3421 (ada-goto-previous-word)
3422 (not (looking-at "subtype")))
3423
3424 (save-excursion (goto-char (cdr match-dat))
3425 (ada-goto-next-non-ws)
3426 ;; words that can go after an 'is'
3427 (not (looking-at
3428 (eval-when-compile
3429 (concat "\\<"
3430 (regexp-opt
3431 '("separate" "access" "array"
3432 "abstract" "new") t)
3433 "\\>\\|("))))))))
3434
3435 (t
3436 (setq found t))
3437 )))
3438
3439 (if found
3440 match-dat
3441 nil)))
3442
3443
3444 (defun ada-goto-next-non-ws (&optional limit)
3445 "Skips white spaces, newlines and comments to next non-ws character.
3446 Stop the search at LIMIT.
3447 Do not call this function from within a string."
3448 (unless limit
3449 (setq limit (point-max)))
3450 (while (and (<= (point) limit)
3451 (progn (forward-comment 10000)
3452 (if (and (not (eobp))
3453 (save-excursion (forward-char 1)
3454 (ada-in-string-p)))
3455 (progn (forward-sexp 1) t)))))
3456 (if (< (point) limit)
3457 (point)
3458 nil)
3459 )
3460
3461
3462 (defun ada-goto-stmt-end (&optional limit)
3463 "Moves point to the end of the statement that point is in or before.
3464 Returns the new position of point or nil if not found.
3465 Stop the search at LIMIT."
3466 (if (ada-search-ignore-string-comment ada-end-stmt-re nil limit)
3467 (point)
3468 nil))
3469
3470
3471 (defun ada-goto-next-word (&optional backward)
3472 "Moves point to the beginning of the next word of Ada code.
3473 If BACKWARD is non-nil, jump to the beginning of the previous word.
3474 Returns the new position of point or nil if not found."
3475 (let ((match-cons nil)
3476 (orgpoint (point))
3477 (old-syntax (char-to-string (char-syntax ?_))))
3478 (modify-syntax-entry ?_ "w")
3479 (unless backward
3480 (skip-syntax-forward "w"))
3481 (if (setq match-cons
3482 (if backward
3483 (ada-search-ignore-string-comment "\\w" t nil t)
3484 (ada-search-ignore-string-comment "\\w" nil nil t)))
3485 ;;
3486 ;; move to the beginning of the word found
3487 ;;
3488 (progn
3489 (goto-char (car match-cons))
3490 (skip-syntax-backward "w")
3491 (point))
3492 ;;
3493 ;; if not found, restore old position of point
3494 ;;
3495 (goto-char orgpoint)
3496 'nil)
3497 (modify-syntax-entry ?_ old-syntax))
3498 )
3499
3500
3501 (defun ada-check-matching-start (keyword)
3502 "Signals an error if matching block start is not KEYWORD.
3503 Moves point to the matching block start."
3504 (ada-goto-matching-start 0)
3505 (unless (looking-at (concat "\\<" keyword "\\>"))
3506 (error "matching start is not '%s'" keyword)))
3507
3508
3509 (defun ada-check-defun-name (defun-name)
3510 "Checks if the name of the matching defun really is DEFUN-NAME.
3511 Assumes point to be already positioned by 'ada-goto-matching-start'.
3512 Moves point to the beginning of the declaration."
3513
3514 ;; named block without a `declare'
3515 (if (save-excursion
3516 (ada-goto-previous-word)
3517 (looking-at (concat "\\<" defun-name "\\> *:")))
3518 t ; do nothing
3519 ;;
3520 ;; 'accept' or 'package' ?
3521 ;;
3522 (unless (looking-at ada-subprog-start-re)
3523 (ada-goto-matching-decl-start))
3524 ;;
3525 ;; 'begin' of 'procedure'/'function'/'task' or 'declare'
3526 ;;
3527 (save-excursion
3528 ;;
3529 ;; a named 'declare'-block ?
3530 ;;
3531 (if (looking-at "\\<declare\\>")
3532 (ada-goto-stmt-start)
3533 ;;
3534 ;; no, => 'procedure'/'function'/'task'/'protected'
3535 ;;
3536 (progn
3537 (forward-word 2)
3538 (backward-word 1)
3539 ;;
3540 ;; skip 'body' 'type'
3541 ;;
3542 (if (looking-at "\\<\\(body\\|type\\)\\>")
3543 (forward-word 1))
3544 (forward-sexp 1)
3545 (backward-sexp 1)))
3546 ;;
3547 ;; should be looking-at the correct name
3548 ;;
3549 (unless (looking-at (concat "\\<" defun-name "\\>"))
3550 (error "matching defun has different name: %s"
3551 (buffer-substring (point)
3552 (progn (forward-sexp 1) (point))))))))
3553
3554 (defun ada-goto-matching-decl-start (&optional noerror recursive)
3555 "Moves point to the matching declaration start of the current 'begin'.
3556 If NOERROR is non-nil, it only returns nil if no match was found."
3557 (let ((nest-count 1)
3558
3559 ;; first should be set to t if we should stop at the first
3560 ;; "begin" we encounter.
3561 (first (not recursive))
3562 (count-generic nil)
3563 (stop-at-when nil)
3564 )
3565
3566 ;; Ignore "when" most of the time, except if we are looking at the
3567 ;; beginning of a block (structure: case .. is
3568 ;; when ... =>
3569 ;; begin ...
3570 ;; exception ... )
3571 (if (looking-at "begin")
3572 (setq stop-at-when t))
3573
3574 (if (or
3575 (looking-at "\\<\\(package\\|procedure\\|function\\)\\>")
3576 (save-excursion
3577 (ada-search-ignore-string-comment
3578 "\\<\\(package\\|procedure\\|function\\|generic\\)\\>" t)
3579 (looking-at "generic")))
3580 (setq count-generic t))
3581
3582 ;; search backward for interesting keywords
3583 (while (and
3584 (not (zerop nest-count))
3585 (ada-search-ignore-string-comment ada-matching-decl-start-re t))
3586 ;;
3587 ;; calculate nest-depth
3588 ;;
3589 (cond
3590 ;;
3591 ((looking-at "end")
3592 (ada-goto-matching-start 1 noerror)
3593
3594 ;; In some case, two begin..end block can follow each other closely,
3595 ;; which we have to detect, as in
3596 ;; procedure P is
3597 ;; procedure Q is
3598 ;; begin
3599 ;; end;
3600 ;; begin -- here we should go to procedure, not begin
3601 ;; end
3602
3603 (if (looking-at "begin")
3604 (let ((loop-again t))
3605 (save-excursion
3606 (while loop-again
3607 ;; If begin was just there as the beginning of a block
3608 ;; (with no declare) then do nothing, otherwise just
3609 ;; register that we have to find the statement that
3610 ;; required the begin
3611
3612 (ada-search-ignore-string-comment
3613 "\\<\\(declare\\|begin\\|end\\|procedure\\|function\\|task\\|package\\)\\>"
3614 t)
3615
3616 (if (looking-at "end")
3617 (ada-goto-matching-start 1 noerror t)
3618 ;; (ada-goto-matching-decl-start noerror t)
3619
3620 (setq loop-again nil)
3621 (unless (looking-at "begin")
3622 (setq nest-count (1+ nest-count))))
3623 ))
3624 )))
3625 ;;
3626 ((looking-at "generic")
3627 (if count-generic
3628 (progn
3629 (setq first nil)
3630 (setq nest-count (1- nest-count)))))
3631 ;;
3632 ((looking-at "if")
3633 (save-excursion
3634 (forward-word -1)
3635 (unless (looking-at "\\<end[ \t\n]*if\\>")
3636 (progn
3637 (setq nest-count (1- nest-count))
3638 (setq first nil)))))
3639
3640 ;;
3641 ((looking-at "declare\\|generic")
3642 (setq nest-count (1- nest-count))
3643 (setq first t))
3644 ;;
3645 ((looking-at "is")
3646 ;; check if it is only a type definition, but not a protected
3647 ;; type definition, which should be handled like a procedure.
3648 (if (or (looking-at "is[ \t]+<>")
3649 (save-excursion
3650 (forward-comment -10000)
3651 (forward-char -1)
3652
3653 ;; Detect if we have a closing parenthesis (Could be
3654 ;; either the end of subprogram parameters or (<>)
3655 ;; in a type definition
3656 (if (= (char-after) ?\))
3657 (progn
3658 (forward-char 1)
3659 (backward-sexp 1)
3660 (forward-comment -10000)
3661 ))
3662 (skip-chars-backward "a-zA-Z0-9_.'")
3663 (ada-goto-previous-word)
3664 (and
3665 (looking-at "\\<\\(sub\\)?type\\|case\\>")
3666 (save-match-data
3667 (ada-goto-previous-word)
3668 (not (looking-at "\\<protected\\>"))))
3669 )) ; end of `or'
3670 (goto-char (match-beginning 0))
3671 (progn
3672 (setq nest-count (1- nest-count))
3673 (setq first nil))))
3674
3675 ;;
3676 ((looking-at "new")
3677 (if (save-excursion
3678 (ada-goto-previous-word)
3679 (looking-at "is"))
3680 (goto-char (match-beginning 0))))
3681 ;;
3682 ((and first
3683 (looking-at "begin"))
3684 (setq nest-count 0))
3685 ;;
3686 ((looking-at "when")
3687 (save-excursion
3688 (forward-word -1)
3689 (unless (looking-at "\\<exit[ \t\n]*when\\>")
3690 (progn
3691 (if stop-at-when
3692 (setq nest-count (1- nest-count)))
3693 ))))
3694 ;;
3695 ((looking-at "begin")
3696 (setq first nil))
3697 ;;
3698 (t
3699 (setq nest-count (1+ nest-count))
3700 (setq first nil)))
3701
3702 );; end of loop
3703
3704 ;; check if declaration-start is really found
3705 (if (and
3706 (zerop nest-count)
3707 (if (looking-at "is")
3708 (ada-search-ignore-string-comment ada-subprog-start-re t)
3709 (looking-at "declare\\|generic")))
3710 t
3711 (if noerror nil
3712 (error "no matching proc/func/task/declare/package/protected")))
3713 ))
3714
3715 (defun ada-goto-matching-start (&optional nest-level noerror gotothen)
3716 "Moves point to the beginning of a block-start.
3717 Which block depends on the value of NEST-LEVEL, which defaults to zero. If
3718 NOERROR is non-nil, it only returns nil if no matching start was found.
3719 If GOTOTHEN is non-nil, point moves to the 'then' following 'if'."
3720 (let ((nest-count (if nest-level nest-level 0))
3721 (found nil)
3722 (pos nil))
3723
3724 ;;
3725 ;; search backward for interesting keywords
3726 ;;
3727 (while (and
3728 (not found)
3729 (ada-search-ignore-string-comment ada-matching-start-re t))
3730
3731 (unless (and (looking-at "\\<record\\>")
3732 (save-excursion
3733 (forward-word -1)
3734 (looking-at "\\<null\\>")))
3735 (progn
3736 ;;
3737 ;; calculate nest-depth
3738 ;;
3739 (cond
3740 ;; found block end => increase nest depth
3741 ((looking-at "end")
3742 (setq nest-count (1+ nest-count)))
3743
3744 ;; found loop/select/record/case/if => check if it starts or
3745 ;; ends a block
3746 ((looking-at "loop\\|select\\|record\\|case\\|if")
3747 (setq pos (point))
3748 (save-excursion
3749 ;;
3750 ;; check if keyword follows 'end'
3751 ;;
3752 (ada-goto-previous-word)
3753 (if (looking-at "\\<end\\>[ \t]*[^;]")
3754 ;; it ends a block => increase nest depth
3755 (setq nest-count (1+ nest-count)
3756 pos (point))
3757
3758 ;; it starts a block => decrease nest depth
3759 (setq nest-count (1- nest-count))))
3760 (goto-char pos))
3761
3762 ;; found package start => check if it really is a block
3763 ((looking-at "package")
3764 (save-excursion
3765 ;; ignore if this is just a renames statement
3766 (let ((current (point))
3767 (pos (ada-search-ignore-string-comment
3768 "\\<\\(is\\|renames\\|;\\)\\>" nil)))
3769 (if pos
3770 (goto-char (car pos))
3771 (error (concat
3772 "No matching 'is' or 'renames' for 'package' at"
3773 " line "
3774 (number-to-string (count-lines 1 (1+ current)))))))
3775 (unless (looking-at "renames")
3776 (progn
3777 (forward-word 1)
3778 (ada-goto-next-non-ws)
3779 ;; ignore it if it is only a declaration with 'new'
3780 ;; We could have package Foo is new ....
3781 ;; or package Foo is separate;
3782 ;; or package Foo is begin null; end Foo
3783 ;; for elaboration code (elaboration)
3784 (if (not (looking-at "\\<\\(new\\|separate\\|begin\\)\\>"))
3785 (setq nest-count (1- nest-count)))))))
3786 ;; found task start => check if it has a body
3787 ((looking-at "task")
3788 (save-excursion
3789 (forward-word 1)
3790 (ada-goto-next-non-ws)
3791 (cond
3792 ((looking-at "\\<body\\>"))
3793 ((looking-at "\\<type\\>")
3794 ;; In that case, do nothing if there is a "is"
3795 (forward-word 2);; skip "type"
3796 (ada-goto-next-non-ws);; skip type name
3797
3798 ;; Do nothing if we are simply looking at a simple
3799 ;; "task type name;" statement with no block
3800 (unless (looking-at ";")
3801 (progn
3802 ;; Skip the parameters
3803 (if (looking-at "(")
3804 (ada-search-ignore-string-comment ")" nil))
3805 (let ((tmp (ada-search-ignore-string-comment
3806 "\\<\\(is\\|;\\)\\>" nil)))
3807 (if tmp
3808 (progn
3809 (goto-char (car tmp))
3810 (if (looking-at "is")
3811 (setq nest-count (1- nest-count)))))))))
3812 (t
3813 ;; Check if that task declaration had a block attached to
3814 ;; it (i.e do nothing if we have just "task name;")
3815 (unless (progn (forward-word 1)
3816 (looking-at "[ \t]*;"))
3817 (setq nest-count (1- nest-count)))))))
3818 ;; all the other block starts
3819 (t
3820 (setq nest-count (1- nest-count)))) ; end of 'cond'
3821
3822 ;; match is found, if nest-depth is zero
3823 ;;
3824 (setq found (zerop nest-count))))) ; end of loop
3825
3826 (if (bobp)
3827 (point)
3828 (if found
3829 ;;
3830 ;; match found => is there anything else to do ?
3831 ;;
3832 (progn
3833 (cond
3834 ;;
3835 ;; found 'if' => skip to 'then', if it's on a separate line
3836 ;; and GOTOTHEN is non-nil
3837 ;;
3838 ((and
3839 gotothen
3840 (looking-at "if")
3841 (save-excursion
3842 (ada-search-ignore-string-comment "then" nil nil nil
3843 'word-search-forward)
3844 (back-to-indentation)
3845 (looking-at "\\<then\\>")))
3846 (goto-char (match-beginning 0)))
3847
3848 ;;
3849 ;; found 'do' => skip back to 'accept'
3850 ;;
3851 ((looking-at "do")
3852 (unless (ada-search-ignore-string-comment
3853 "accept" t nil nil
3854 'word-search-backward)
3855 (error "missing 'accept' in front of 'do'"))))
3856 (point))
3857
3858 (if noerror
3859 nil
3860 (error "no matching start"))))))
3861
3862
3863 (defun ada-goto-matching-end (&optional nest-level noerror)
3864 "Moves point to the end of a block.
3865 Which block depends on the value of NEST-LEVEL, which defaults to zero.
3866 If NOERROR is non-nil, it only returns nil if found no matching start."
3867 (let ((nest-count (or nest-level 0))
3868 (regex (eval-when-compile
3869 (concat "\\<"
3870 (regexp-opt '("end" "loop" "select" "begin" "case"
3871 "if" "task" "package" "record" "do"
3872 "procedure" "function") t)
3873 "\\>")))
3874 found
3875 pos
3876
3877 ;; First is used for subprograms: they are generally handled
3878 ;; recursively, but of course we do not want to do that the
3879 ;; first time (see comment below about subprograms)
3880 (first (not (looking-at "declare"))))
3881
3882 ;; If we are already looking at one of the keywords, this shouldn't count
3883 ;; in the nesting loop below, so we just make sure we don't count it.
3884 ;; "declare" is a special case because we need to look after the "begin"
3885 ;; keyword
3886 (if (looking-at "\\<if\\|loop\\|case\\|begin\\>")
3887 (forward-char 1))
3888
3889 ;;
3890 ;; search forward for interesting keywords
3891 ;;
3892 (while (and
3893 (not found)
3894 (ada-search-ignore-string-comment regex nil))
3895
3896 ;;
3897 ;; calculate nest-depth
3898 ;;
3899 (backward-word 1)
3900 (cond
3901 ;; procedures and functions need to be processed recursively, in
3902 ;; case they are defined in a declare/begin block, as in:
3903 ;; declare -- NL 0 (nested level)
3904 ;; A : Boolean;
3905 ;; procedure B (C : D) is
3906 ;; begin -- NL 1
3907 ;; null;
3908 ;; end B; -- NL 0, and we would exit
3909 ;; begin
3910 ;; end; -- we should exit here
3911 ;; processing them recursively avoids the need for any special
3912 ;; handling.
3913 ;; Nothing should be done if we have only the specs or a
3914 ;; generic instantion.
3915
3916 ((and (looking-at "\\<procedure\\|function\\>"))
3917 (if first
3918 (forward-word 1)
3919
3920 (setq pos (point))
3921 (ada-search-ignore-string-comment "is\\|;")
3922 (if (= (char-before) ?s)
3923 (progn
3924 (ada-goto-next-non-ws)
3925 (unless (looking-at "\\<new\\>")
3926 (progn
3927 (goto-char pos)
3928 (ada-goto-matching-end 0 t)))))))
3929
3930 ;; found block end => decrease nest depth
3931 ((looking-at "\\<end\\>")
3932 (setq nest-count (1- nest-count)
3933 found (<= nest-count 0))
3934 ;; skip the following keyword
3935 (if (progn
3936 (skip-chars-forward "end")
3937 (ada-goto-next-non-ws)
3938 (looking-at "\\<\\(loop\\|select\\|record\\|case\\|if\\)\\>"))
3939 (forward-word 1)))
3940
3941 ;; found package start => check if it really starts a block, and is not
3942 ;; in fact a generic instantiation for instance
3943 ((looking-at "\\<package\\>")
3944 (ada-search-ignore-string-comment "is" nil nil nil
3945 'word-search-forward)
3946 (ada-goto-next-non-ws)
3947 ;; ignore and skip it if it is only a 'new' package
3948 (if (looking-at "\\<new\\>")
3949 (goto-char (match-end 0))
3950 (setq nest-count (1+ nest-count)
3951 found (<= nest-count 0))))
3952
3953 ;; all the other block starts
3954 (t
3955 (if (not first)
3956 (setq nest-count (1+ nest-count)))
3957 (setq found (<= nest-count 0))
3958 (forward-word 1))) ; end of 'cond'
3959
3960 (setq first nil))
3961
3962 (if found
3963 t
3964 (if noerror
3965 nil
3966 (error "no matching end")))
3967 ))
3968
3969
3970 (defun ada-search-ignore-string-comment
3971 (search-re &optional backward limit paramlists search-func)
3972 "Regexp-search for SEARCH-RE, ignoring comments, strings.
3973 If PARAMLISTS is nil, ignore parameter lists. Returns a cons cell of
3974 begin and end of match data or nil, if not found.
3975 The search is done using SEARCH-FUNC, which should search backward if
3976 BACKWARD is non-nil, forward otherwise. SEARCH-FUNC can be optimized in case
3977 we are searching for a constant string.
3978 The search stops at pos LIMIT.
3979 Point is moved at the beginning of the search-re."
3980 (let (found
3981 begin
3982 end
3983 parse-result
3984 (previous-syntax-table (syntax-table)))
3985
3986 (unless search-func
3987 (setq search-func (if backward 're-search-backward 're-search-forward)))
3988
3989 ;;
3990 ;; search until found or end-of-buffer
3991 ;; We have to test that we do not look further than limit
3992 ;;
3993 (set-syntax-table ada-mode-symbol-syntax-table)
3994 (while (and (not found)
3995 (or (not limit)
3996 (or (and backward (<= limit (point)))
3997 (>= limit (point))))
3998 (funcall search-func search-re limit 1))
3999 (setq begin (match-beginning 0))
4000 (setq end (match-end 0))
4001
4002 (setq parse-result (parse-partial-sexp
4003 (save-excursion (beginning-of-line) (point))
4004 (point)))
4005
4006 (cond
4007 ;;
4008 ;; If inside a string, skip it (and the following comments)
4009 ;;
4010 ((ada-in-string-p parse-result)
4011 (if (featurep 'xemacs)
4012 (search-backward "\"" nil t)
4013 (goto-char (nth 8 parse-result)))
4014 (unless backward (forward-sexp 1)))
4015 ;;
4016 ;; If inside a comment, skip it (and the following comments)
4017 ;; There is a special code for comments at the end of the file
4018 ;;
4019 ((ada-in-comment-p parse-result)
4020 (if (featurep 'xemacs)
4021 (progn
4022 (forward-line 1)
4023 (beginning-of-line)
4024 (forward-comment -1))
4025 (goto-char (nth 8 parse-result)))
4026 (unless backward
4027 ;; at the end of the file, it is not possible to skip a comment
4028 ;; so we just go at the end of the line
4029 (if (forward-comment 1)
4030 (progn
4031 (forward-comment 1000)
4032 (beginning-of-line))
4033 (end-of-line))))
4034 ;;
4035 ;; directly in front of a comment => skip it, if searching forward
4036 ;;
4037 ((and (= (char-after begin) ?-) (= (char-after (1+ begin)) ?-))
4038 (unless backward (progn (forward-char -1) (forward-comment 1000))))
4039
4040 ;;
4041 ;; found a parameter-list but should ignore it => skip it
4042 ;;
4043 ((and (not paramlists) (ada-in-paramlist-p))
4044 (if backward
4045 (search-backward "(" nil t)
4046 (search-forward ")" nil t)))
4047 ;;
4048 ;; found what we were looking for
4049 ;;
4050 (t
4051 (setq found t)))) ; end of loop
4052
4053 (set-syntax-table previous-syntax-table)
4054
4055 (if found
4056 (cons begin end)
4057 nil)))
4058
4059 ;; -------------------------------------------------------
4060 ;; -- Testing the position of the cursor
4061 ;; -------------------------------------------------------
4062
4063 (defun ada-in-decl-p ()
4064 "Returns t if point is inside a declarative part.
4065 Assumes point to be at the end of a statement."
4066 (or (ada-in-paramlist-p)
4067 (save-excursion
4068 (ada-goto-matching-decl-start t))))
4069
4070
4071 (defun ada-looking-at-semi-or ()
4072 "Returns t if looking-at an 'or' following a semicolon."
4073 (save-excursion
4074 (and (looking-at "\\<or\\>")
4075 (progn
4076 (forward-word 1)
4077 (ada-goto-stmt-start)
4078 (looking-at "\\<or\\>")))))
4079
4080
4081 (defun ada-looking-at-semi-private ()
4082 "Returns t if looking at the start of a private section in a package.
4083 Returns nil if the private is part of the package name, as in
4084 'private package A is...' (this can only happen at top level)."
4085 (save-excursion
4086 (and (looking-at "\\<private\\>")
4087 (not (looking-at "\\<private[ \t]*\\(package\\|generic\\)"))
4088
4089 ;; Make sure this is the start of a private section (ie after
4090 ;; a semicolon or just after the package declaration, but not
4091 ;; after a 'type ... is private' or 'is new ... with private'
4092 ;;
4093 ;; Note that a 'private' statement at the beginning of the buffer
4094 ;; does not indicate a private section, since this is instead a
4095 ;; 'private procedure ...'
4096 (progn (forward-comment -1000)
4097 (and (not (bobp))
4098 (or (= (char-before) ?\;)
4099 (and (forward-word -3)
4100 (looking-at "\\<package\\>"))))))))
4101
4102
4103 (defun ada-in-paramlist-p ()
4104 "Returns t if point is inside a parameter-list."
4105 (save-excursion
4106 (and
4107 (ada-search-ignore-string-comment "(\\|)" t nil t)
4108 ;; inside parentheses ?
4109 (= (char-after) ?\()
4110
4111 ;; We could be looking at two things here:
4112 ;; operator definition: function "." (
4113 ;; subprogram definition: procedure .... (
4114 ;; Let's skip back over the first one
4115 (progn
4116 (skip-chars-backward " \t\n")
4117 (if (= (char-before) ?\")
4118 (backward-char 3)
4119 (backward-word 1))
4120 t)
4121
4122 ;; and now over the second one
4123 (backward-word 1)
4124
4125 ;; We should ignore the case when the reserved keyword is in a
4126 ;; comment (for instance, when we have:
4127 ;; -- .... package
4128 ;; Test (A)
4129 ;; we should return nil
4130
4131 (not (ada-in-string-or-comment-p))
4132
4133 ;; right keyword two words before parenthesis ?
4134 ;; Type is in this list because of discriminants
4135 (looking-at (eval-when-compile
4136 (concat "\\<\\("
4137 "procedure\\|function\\|body\\|"
4138 "task\\|entry\\|accept\\|"
4139 "access[ \t]+procedure\\|"
4140 "access[ \t]+function\\|"
4141 "pragma\\|"
4142 "type\\)\\>"))))))
4143
4144 (defun ada-search-ignore-complex-boolean (regexp backwardp)
4145 "Like `ada-search-ignore-string-comment', except that it also ignores
4146 boolean expressions 'and then' and 'or else'."
4147 (let (result)
4148 (while (and (setq result (ada-search-ignore-string-comment regexp backwardp))
4149 (save-excursion (forward-word -1)
4150 (looking-at "and then\\|or else"))))
4151 result))
4152
4153 (defun ada-in-open-paren-p ()
4154 "Returns the position of the first non-ws behind the last unclosed
4155 parenthesis, or nil."
4156 (save-excursion
4157 (let ((parse (parse-partial-sexp
4158 (point)
4159 (or (car (ada-search-ignore-complex-boolean
4160 "\\<\\(;\\|is\\|then\\|loop\\|begin\\|else\\)\\>"
4161 t))
4162 (point-min)))))
4163
4164 (if (nth 1 parse)
4165 (progn
4166 (goto-char (1+ (nth 1 parse)))
4167
4168 ;; Skip blanks, if they are not followed by a comment
4169 ;; See:
4170 ;; type A is ( Value_0,
4171 ;; Value_1);
4172 ;; type B is ( -- comment
4173 ;; Value_2);
4174
4175 (if (or (not ada-indent-handle-comment-special)
4176 (not (looking-at "[ \t]+--")))
4177 (skip-chars-forward " \t"))
4178
4179 (point))))))
4180
4181 \f
4182 ;; -----------------------------------------------------------
4183 ;; -- Behavior Of TAB Key
4184 ;; -----------------------------------------------------------
4185
4186 (defun ada-tab ()
4187 "Do indenting or tabbing according to `ada-tab-policy'.
4188 In Transient Mark mode, if the mark is active, operate on the contents
4189 of the region. Otherwise, operates only on the current line."
4190 (interactive)
4191 (cond ((eq ada-tab-policy 'indent-rigidly) (ada-tab-hard))
4192 ((eq ada-tab-policy 'indent-auto)
4193 (if (ada-region-selected)
4194 (ada-indent-region (region-beginning) (region-end))
4195 (ada-indent-current)))
4196 ((eq ada-tab-policy 'always-tab) (error "not implemented"))
4197 ))
4198
4199 (defun ada-untab (arg)
4200 "Delete leading indenting according to `ada-tab-policy'."
4201 (interactive "P")
4202 (cond ((eq ada-tab-policy 'indent-rigidly) (ada-untab-hard))
4203 ((eq ada-tab-policy 'indent-auto) (error "not implemented"))
4204 ((eq ada-tab-policy 'always-tab) (error "not implemented"))
4205 ))
4206
4207 (defun ada-indent-current-function ()
4208 "Ada mode version of the indent-line-function."
4209 (interactive "*")
4210 (let ((starting-point (point-marker)))
4211 (beginning-of-line)
4212 (ada-tab)
4213 (if (< (point) starting-point)
4214 (goto-char starting-point))
4215 (set-marker starting-point nil)
4216 ))
4217
4218 (defun ada-tab-hard ()
4219 "Indent current line to next tab stop."
4220 (interactive)
4221 (save-excursion
4222 (beginning-of-line)
4223 (insert-char ? ada-indent))
4224 (if (save-excursion (= (point) (progn (beginning-of-line) (point))))
4225 (forward-char ada-indent)))
4226
4227 (defun ada-untab-hard ()
4228 "indent current line to previous tab stop."
4229 (interactive)
4230 (let ((bol (save-excursion (progn (beginning-of-line) (point))))
4231 (eol (save-excursion (progn (end-of-line) (point)))))
4232 (indent-rigidly bol eol (- 0 ada-indent))))
4233
4234
4235 \f
4236 ;; ------------------------------------------------------------
4237 ;; -- Miscellaneous
4238 ;; ------------------------------------------------------------
4239
4240 ;; Not needed any more for Emacs 21.2, but still needed for backward
4241 ;; compatibility
4242 (defun ada-remove-trailing-spaces ()
4243 "Remove trailing spaces in the whole buffer."
4244 (interactive)
4245 (save-match-data
4246 (save-excursion
4247 (save-restriction
4248 (widen)
4249 (goto-char (point-min))
4250 (while (re-search-forward "[ \t]+$" (point-max) t)
4251 (replace-match "" nil nil))))))
4252
4253 (defun ada-gnat-style ()
4254 "Clean up comments, `(' and `,' for GNAT style checking switch."
4255 (interactive)
4256 (save-excursion
4257
4258 ;; The \n is required, or the line after an empty comment line is
4259 ;; simply ignored.
4260 (goto-char (point-min))
4261 (while (re-search-forward "--[ \t]*\\([^-\n]\\)" nil t)
4262 (replace-match "-- \\1")
4263 (forward-line 1)
4264 (beginning-of-line))
4265
4266 (goto-char (point-min))
4267 (while (re-search-forward "\\>(" nil t)
4268 (if (not (ada-in-string-or-comment-p))
4269 (replace-match " (")))
4270 (goto-char (point-min))
4271 (while (re-search-forward ";--" nil t)
4272 (forward-char -1)
4273 (if (not (ada-in-string-or-comment-p))
4274 (replace-match "; --")))
4275 (goto-char (point-min))
4276 (while (re-search-forward "([ \t]+" nil t)
4277 (if (not (ada-in-string-or-comment-p))
4278 (replace-match "(")))
4279 (goto-char (point-min))
4280 (while (re-search-forward ")[ \t]+)" nil t)
4281 (if (not (ada-in-string-or-comment-p))
4282 (replace-match "))")))
4283 (goto-char (point-min))
4284 (while (re-search-forward "\\>:" nil t)
4285 (if (not (ada-in-string-or-comment-p))
4286 (replace-match " :")))
4287
4288 ;; Make sure there is a space after a ','.
4289 ;; Always go back to the beginning of the match, since otherwise
4290 ;; a statement like ('F','D','E') is incorrectly modified.
4291 (goto-char (point-min))
4292 (while (re-search-forward ",[ \t]*\\(.\\)" nil t)
4293 (if (not (save-excursion
4294 (goto-char (match-beginning 0))
4295 (ada-in-string-or-comment-p)))
4296 (replace-match ", \\1")))
4297
4298 ;; Operators should be surrounded by spaces.
4299 (goto-char (point-min))
4300 (while (re-search-forward
4301 "[ \t]*\\(/=\\|\\*\\*\\|:=\\|\\.\\.\\|[-:+*/]\\)[ \t]*"
4302 nil t)
4303 (goto-char (match-beginning 1))
4304 (if (or (looking-at "--")
4305 (ada-in-string-or-comment-p))
4306 (progn
4307 (forward-line 1)
4308 (beginning-of-line))
4309 (cond
4310 ((string= (match-string 1) "/=")
4311 (replace-match " /= "))
4312 ((string= (match-string 1) "..")
4313 (replace-match " .. "))
4314 ((string= (match-string 1) "**")
4315 (replace-match " ** "))
4316 ((string= (match-string 1) ":=")
4317 (replace-match " := "))
4318 (t
4319 (replace-match " \\1 ")))
4320 (forward-char 1)))
4321 ))
4322
4323
4324 \f
4325 ;; -------------------------------------------------------------
4326 ;; -- Moving To Procedures/Packages/Statements
4327 ;; -------------------------------------------------------------
4328
4329 (defun ada-move-to-start ()
4330 "Moves point to the matching start of the current Ada structure."
4331 (interactive)
4332 (let ((pos (point))
4333 (previous-syntax-table (syntax-table)))
4334 (unwind-protect
4335 (progn
4336 (set-syntax-table ada-mode-symbol-syntax-table)
4337
4338 (save-excursion
4339 ;;
4340 ;; do nothing if in string or comment or not on 'end ...;'
4341 ;; or if an error occurs during processing
4342 ;;
4343 (or
4344 (ada-in-string-or-comment-p)
4345 (and (progn
4346 (or (looking-at "[ \t]*\\<end\\>")
4347 (backward-word 1))
4348 (or (looking-at "[ \t]*\\<end\\>")
4349 (backward-word 1))
4350 (or (looking-at "[ \t]*\\<end\\>")
4351 (error "not on end ...;")))
4352 (ada-goto-matching-start 1)
4353 (setq pos (point))
4354
4355 ;;
4356 ;; on 'begin' => go on, according to user option
4357 ;;
4358 ada-move-to-declaration
4359 (looking-at "\\<begin\\>")
4360 (ada-goto-matching-decl-start)
4361 (setq pos (point))))
4362
4363 ) ; end of save-excursion
4364
4365 ;; now really move to the found position
4366 (goto-char pos))
4367
4368 ;; restore syntax-table
4369 (set-syntax-table previous-syntax-table))))
4370
4371 (defun ada-move-to-end ()
4372 "Moves point to the matching end of the block around point.
4373 Moves to 'begin' if in a declarative part."
4374 (interactive)
4375 (let ((pos (point))
4376 decl-start
4377 (previous-syntax-table (syntax-table)))
4378 (unwind-protect
4379 (progn
4380 (set-syntax-table ada-mode-symbol-syntax-table)
4381
4382 (save-excursion
4383
4384 (cond
4385 ;; Go to the beginning of the current word, and check if we are
4386 ;; directly on 'begin'
4387 ((save-excursion
4388 (skip-syntax-backward "w")
4389 (looking-at "\\<begin\\>"))
4390 (ada-goto-matching-end 1)
4391 )
4392
4393 ;; on first line of subprogram body
4394 ;; Do nothing for specs or generic instantion, since these are
4395 ;; handled as the general case (find the enclosing block)
4396 ;; We also need to make sure that we ignore nested subprograms
4397 ((save-excursion
4398 (and (skip-syntax-backward "w")
4399 (looking-at "\\<function\\>\\|\\<procedure\\>" )
4400 (ada-search-ignore-string-comment "is\\|;")
4401 (not (= (char-before) ?\;))
4402 ))
4403 (skip-syntax-backward "w")
4404 (ada-goto-matching-end 0 t))
4405
4406 ;; on first line of task declaration
4407 ((save-excursion
4408 (and (ada-goto-stmt-start)
4409 (looking-at "\\<task\\>" )
4410 (forward-word 1)
4411 (ada-goto-next-non-ws)
4412 (looking-at "\\<body\\>")))
4413 (ada-search-ignore-string-comment "begin" nil nil nil
4414 'word-search-forward))
4415 ;; accept block start
4416 ((save-excursion
4417 (and (ada-goto-stmt-start)
4418 (looking-at "\\<accept\\>" )))
4419 (ada-goto-matching-end 0))
4420 ;; package start
4421 ((save-excursion
4422 (setq decl-start (and (ada-goto-matching-decl-start t) (point)))
4423 (and decl-start (looking-at "\\<package\\>")))
4424 (ada-goto-matching-end 1))
4425
4426 ;; On a "declare" keyword
4427 ((save-excursion
4428 (skip-syntax-backward "w")
4429 (looking-at "\\<declare\\>"))
4430 (ada-goto-matching-end 0 t))
4431
4432 ;; inside a 'begin' ... 'end' block
4433 (decl-start
4434 (goto-char decl-start)
4435 (ada-goto-matching-end 0 t))
4436
4437 ;; (hopefully ;-) everything else
4438 (t
4439 (ada-goto-matching-end 1)))
4440 (setq pos (point))
4441 )
4442
4443 ;; now really move to the position found
4444 (goto-char pos))
4445
4446 ;; restore syntax-table
4447 (set-syntax-table previous-syntax-table))))
4448
4449 (defun ada-next-procedure ()
4450 "Moves point to next procedure."
4451 (interactive)
4452 (end-of-line)
4453 (if (re-search-forward ada-procedure-start-regexp nil t)
4454 (goto-char (match-beginning 2))
4455 (error "No more functions/procedures/tasks")))
4456
4457 (defun ada-previous-procedure ()
4458 "Moves point to previous procedure."
4459 (interactive)
4460 (beginning-of-line)
4461 (if (re-search-backward ada-procedure-start-regexp nil t)
4462 (goto-char (match-beginning 2))
4463 (error "No more functions/procedures/tasks")))
4464
4465 (defun ada-next-package ()
4466 "Moves point to next package."
4467 (interactive)
4468 (end-of-line)
4469 (if (re-search-forward ada-package-start-regexp nil t)
4470 (goto-char (match-beginning 1))
4471 (error "No more packages")))
4472
4473 (defun ada-previous-package ()
4474 "Moves point to previous package."
4475 (interactive)
4476 (beginning-of-line)
4477 (if (re-search-backward ada-package-start-regexp nil t)
4478 (goto-char (match-beginning 1))
4479 (error "No more packages")))
4480
4481 \f
4482 ;; ------------------------------------------------------------
4483 ;; -- Define keymap and menus for Ada
4484 ;; -------------------------------------------------------------
4485
4486 (defun ada-create-keymap ()
4487 "Create the keymap associated with the Ada mode."
4488
4489 ;; Indentation and Formatting
4490 (define-key ada-mode-map "\C-j" 'ada-indent-newline-indent-conditional)
4491 (define-key ada-mode-map "\C-m" 'ada-indent-newline-indent-conditional)
4492 (define-key ada-mode-map "\t" 'ada-tab)
4493 (define-key ada-mode-map "\C-c\t" 'ada-justified-indent-current)
4494 (define-key ada-mode-map "\C-c\C-l" 'ada-indent-region)
4495 (if (featurep 'xemacs)
4496 (define-key ada-mode-map '(shift tab) 'ada-untab)
4497 (define-key ada-mode-map [(shift tab)] 'ada-untab))
4498 (define-key ada-mode-map "\C-c\C-f" 'ada-format-paramlist)
4499 ;; We don't want to make meta-characters case-specific.
4500
4501 ;; Movement
4502 (define-key ada-mode-map "\M-\C-e" 'ada-next-procedure)
4503 (define-key ada-mode-map "\M-\C-a" 'ada-previous-procedure)
4504 (define-key ada-mode-map "\C-c\C-a" 'ada-move-to-start)
4505 (define-key ada-mode-map "\C-c\C-e" 'ada-move-to-end)
4506
4507 ;; Compilation
4508 (unless (lookup-key ada-mode-map "\C-c\C-c")
4509 (define-key ada-mode-map "\C-c\C-c" 'compile))
4510
4511 ;; Casing
4512 (define-key ada-mode-map "\C-c\C-b" 'ada-adjust-case-buffer)
4513 (define-key ada-mode-map "\C-c\C-t" 'ada-case-read-exceptions)
4514 (define-key ada-mode-map "\C-c\C-y" 'ada-create-case-exception)
4515 (define-key ada-mode-map "\C-c\C-\M-y" 'ada-create-case-exception-substring)
4516
4517 ;; On XEmacs, you can easily specify whether DEL should deletes
4518 ;; one character forward or one character backward. Take this into
4519 ;; account
4520 (if (boundp 'delete-key-deletes-forward)
4521 (define-key ada-mode-map [backspace] 'backward-delete-char-untabify)
4522 (define-key ada-mode-map "\177" 'backward-delete-char-untabify))
4523
4524 ;; Make body
4525 (define-key ada-mode-map "\C-c\C-n" 'ada-make-subprogram-body)
4526
4527 ;; Use predefined function of Emacs19 for comments (RE)
4528 (define-key ada-mode-map "\C-c;" 'comment-region)
4529 (define-key ada-mode-map "\C-c:" 'ada-uncomment-region)
4530
4531 ;; The following keys are bound to functions defined in ada-xref.el or
4532 ;; ada-prj,el., However, RMS rightly thinks that the code should be shared,
4533 ;; and activated only if the right compiler is used
4534 (if (featurep 'xemacs)
4535 (progn
4536 (define-key ada-mode-map '(shift button3) 'ada-point-and-xref)
4537 (define-key ada-mode-map '(control tab) 'ada-complete-identifier))
4538 (define-key ada-mode-map [C-tab] 'ada-complete-identifier)
4539 (define-key ada-mode-map [S-mouse-3] 'ada-point-and-xref))
4540
4541 (define-key ada-mode-map "\C-co" 'ff-find-other-file)
4542 (define-key ada-mode-map "\C-c5\C-d" 'ada-goto-declaration-other-frame)
4543 (define-key ada-mode-map "\C-c\C-d" 'ada-goto-declaration)
4544 (define-key ada-mode-map "\C-c\C-s" 'ada-xref-goto-previous-reference)
4545 (define-key ada-mode-map "\C-c\C-c" 'ada-compile-application)
4546 (define-key ada-mode-map "\C-cc" 'ada-change-prj)
4547 (define-key ada-mode-map "\C-cd" 'ada-set-default-project-file)
4548 (define-key ada-mode-map "\C-cg" 'ada-gdb-application)
4549 (define-key ada-mode-map "\C-cr" 'ada-run-application)
4550 (define-key ada-mode-map "\C-c\C-o" 'ada-goto-parent)
4551 (define-key ada-mode-map "\C-c\C-r" 'ada-find-references)
4552 (define-key ada-mode-map "\C-cl" 'ada-find-local-references)
4553 (define-key ada-mode-map "\C-c\C-v" 'ada-check-current)
4554 (define-key ada-mode-map "\C-cf" 'ada-find-file)
4555
4556 (define-key ada-mode-map "\C-cu" 'ada-prj-edit)
4557
4558 ;; The templates, defined in ada-stmt.el
4559
4560 (let ((map (make-sparse-keymap)))
4561 (define-key map "h" 'ada-header)
4562 (define-key map "\C-a" 'ada-array)
4563 (define-key map "b" 'ada-exception-block)
4564 (define-key map "d" 'ada-declare-block)
4565 (define-key map "c" 'ada-case)
4566 (define-key map "\C-e" 'ada-elsif)
4567 (define-key map "e" 'ada-else)
4568 (define-key map "\C-k" 'ada-package-spec)
4569 (define-key map "k" 'ada-package-body)
4570 (define-key map "\C-p" 'ada-procedure-spec)
4571 (define-key map "p" 'ada-subprogram-body)
4572 (define-key map "\C-f" 'ada-function-spec)
4573 (define-key map "f" 'ada-for-loop)
4574 (define-key map "i" 'ada-if)
4575 (define-key map "l" 'ada-loop)
4576 (define-key map "\C-r" 'ada-record)
4577 (define-key map "\C-s" 'ada-subtype)
4578 (define-key map "S" 'ada-tabsize)
4579 (define-key map "\C-t" 'ada-task-spec)
4580 (define-key map "t" 'ada-task-body)
4581 (define-key map "\C-y" 'ada-type)
4582 (define-key map "\C-v" 'ada-private)
4583 (define-key map "u" 'ada-use)
4584 (define-key map "\C-u" 'ada-with)
4585 (define-key map "\C-w" 'ada-when)
4586 (define-key map "w" 'ada-while-loop)
4587 (define-key map "\C-x" 'ada-exception)
4588 (define-key map "x" 'ada-exit)
4589 (define-key ada-mode-map "\C-ct" map))
4590 )
4591
4592
4593 (defun ada-create-menu ()
4594 "Create the ada menu as shown in the menu bar."
4595 (let ((m '("Ada"
4596 ("Help"
4597 ["Ada Mode" (info "ada-mode") t]
4598 ["GNAT User's Guide" (info "gnat_ugn")
4599 (eq ada-which-compiler 'gnat)]
4600 ["GNAT Reference Manual" (info "gnat_rm")
4601 (eq ada-which-compiler 'gnat)]
4602 ["Gcc Documentation" (info "gcc")
4603 (eq ada-which-compiler 'gnat)]
4604 ["Gdb Documentation" (info "gdb")
4605 (eq ada-which-compiler 'gnat)]
4606 ["Ada95 Reference Manual" (info "arm95")
4607 (eq ada-which-compiler 'gnat)])
4608 ("Options" :included (eq major-mode 'ada-mode)
4609 ["Auto Casing" (setq ada-auto-case (not ada-auto-case))
4610 :style toggle :selected ada-auto-case]
4611 ["Auto Indent After Return"
4612 (setq ada-indent-after-return (not ada-indent-after-return))
4613 :style toggle :selected ada-indent-after-return]
4614 ["Automatically Recompile For Cross-references"
4615 (setq ada-xref-create-ali (not ada-xref-create-ali))
4616 :style toggle :selected ada-xref-create-ali
4617 :included (eq ada-which-compiler 'gnat)]
4618 ["Confirm Commands"
4619 (setq ada-xref-confirm-compile (not ada-xref-confirm-compile))
4620 :style toggle :selected ada-xref-confirm-compile
4621 :included (eq ada-which-compiler 'gnat)]
4622 ["Show Cross-references In Other Buffer"
4623 (setq ada-xref-other-buffer (not ada-xref-other-buffer))
4624 :style toggle :selected ada-xref-other-buffer
4625 :included (eq ada-which-compiler 'gnat)]
4626 ["Tight Integration With GNU Visual Debugger"
4627 (setq ada-tight-gvd-integration (not ada-tight-gvd-integration))
4628 :style toggle :selected ada-tight-gvd-integration
4629 :included (string-match "gvd" ada-prj-default-debugger)])
4630 ["Customize" (customize-group 'ada)
4631 :included (fboundp 'customize-group)]
4632 ["Check file" ada-check-current (eq ada-which-compiler 'gnat)]
4633 ["Compile file" ada-compile-current (eq ada-which-compiler 'gnat)]
4634 ["Build" ada-compile-application
4635 (eq ada-which-compiler 'gnat)]
4636 ["Run" ada-run-application t]
4637 ["Debug" ada-gdb-application (eq ada-which-compiler 'gnat)]
4638 ["------" nil nil]
4639 ("Project"
4640 :included (eq ada-which-compiler 'gnat)
4641 ["Load..." ada-set-default-project-file t]
4642 ["New..." ada-prj-new t]
4643 ["Edit..." ada-prj-edit t])
4644 ("Goto" :included (eq major-mode 'ada-mode)
4645 ["Goto Declaration/Body" ada-goto-declaration
4646 (eq ada-which-compiler 'gnat)]
4647 ["Goto Body" ada-goto-body
4648 (eq ada-which-compiler 'gnat)]
4649 ["Goto Declaration Other Frame"
4650 ada-goto-declaration-other-frame
4651 (eq ada-which-compiler 'gnat)]
4652 ["Goto Previous Reference" ada-xref-goto-previous-reference
4653 (eq ada-which-compiler 'gnat)]
4654 ["List Local References" ada-find-local-references
4655 (eq ada-which-compiler 'gnat)]
4656 ["List References" ada-find-references
4657 (eq ada-which-compiler 'gnat)]
4658 ["Goto Reference To Any Entity" ada-find-any-references
4659 (eq ada-which-compiler 'gnat)]
4660 ["Goto Parent Unit" ada-goto-parent
4661 (eq ada-which-compiler 'gnat)]
4662 ["--" nil nil]
4663 ["Next compilation error" next-error t]
4664 ["Previous Package" ada-previous-package t]
4665 ["Next Package" ada-next-package t]
4666 ["Previous Procedure" ada-previous-procedure t]
4667 ["Next Procedure" ada-next-procedure t]
4668 ["Goto Start Of Statement" ada-move-to-start t]
4669 ["Goto End Of Statement" ada-move-to-end t]
4670 ["-" nil nil]
4671 ["Other File" ff-find-other-file t]
4672 ["Other File Other Window" ada-ff-other-window t])
4673 ("Edit" :included (eq major-mode 'ada-mode)
4674 ["Search File On Source Path" ada-find-file t]
4675 ["------" nil nil]
4676 ["Complete Identifier" ada-complete-identifier t]
4677 ["-----" nil nil]
4678 ["Indent Line" ada-indent-current-function t]
4679 ["Justify Current Indentation" ada-justified-indent-current t]
4680 ["Indent Lines in Selection" ada-indent-region t]
4681 ["Indent Lines in File"
4682 (ada-indent-region (point-min) (point-max)) t]
4683 ["Format Parameter List" ada-format-paramlist t]
4684 ["-" nil nil]
4685 ["Comment Selection" comment-region t]
4686 ["Uncomment Selection" ada-uncomment-region t]
4687 ["--" nil nil]
4688 ["Fill Comment Paragraph" fill-paragraph t]
4689 ["Fill Comment Paragraph Justify"
4690 ada-fill-comment-paragraph-justify t]
4691 ["Fill Comment Paragraph Postfix"
4692 ada-fill-comment-paragraph-postfix t]
4693 ["---" nil nil]
4694 ["Adjust Case Selection" ada-adjust-case-region t]
4695 ["Adjust Case in File" ada-adjust-case-buffer t]
4696 ["Create Case Exception" ada-create-case-exception t]
4697 ["Create Case Exception Substring"
4698 ada-create-case-exception-substring t]
4699 ["Reload Case Exceptions" ada-case-read-exceptions t]
4700 ["----" nil nil]
4701 ["Make body for subprogram" ada-make-subprogram-body t]
4702 ["-----" nil nil]
4703 ["Narrow to subprogram" ada-narrow-to-defun t])
4704 ("Templates"
4705 :included (eq major-mode 'ada-mode)
4706 ["Header" ada-header t]
4707 ["-" nil nil]
4708 ["Package Body" ada-package-body t]
4709 ["Package Spec" ada-package-spec t]
4710 ["Function Spec" ada-function-spec t]
4711 ["Procedure Spec" ada-procedure-spec t]
4712 ["Proc/func Body" ada-subprogram-body t]
4713 ["Task Body" ada-task-body t]
4714 ["Task Spec" ada-task-spec t]
4715 ["Declare Block" ada-declare-block t]
4716 ["Exception Block" ada-exception-block t]
4717 ["--" nil nil]
4718 ["Entry" ada-entry t]
4719 ["Entry family" ada-entry-family t]
4720 ["Select" ada-select t]
4721 ["Accept" ada-accept t]
4722 ["Or accept" ada-or-accep t]
4723 ["Or delay" ada-or-delay t]
4724 ["Or terminate" ada-or-terminate t]
4725 ["---" nil nil]
4726 ["Type" ada-type t]
4727 ["Private" ada-private t]
4728 ["Subtype" ada-subtype t]
4729 ["Record" ada-record t]
4730 ["Array" ada-array t]
4731 ["----" nil nil]
4732 ["If" ada-if t]
4733 ["Else" ada-else t]
4734 ["Elsif" ada-elsif t]
4735 ["Case" ada-case t]
4736 ["-----" nil nil]
4737 ["While Loop" ada-while-loop t]
4738 ["For Loop" ada-for-loop t]
4739 ["Loop" ada-loop t]
4740 ["------" nil nil]
4741 ["Exception" ada-exception t]
4742 ["Exit" ada-exit t]
4743 ["When" ada-when t])
4744 )))
4745
4746 (easy-menu-define ada-mode-menu ada-mode-map "Menu keymap for Ada mode" m)
4747 (if (featurep 'xemacs)
4748 (progn
4749 (define-key ada-mode-map [menu-bar] ada-mode-menu)
4750 (set 'mode-popup-menu (cons "Ada mode" ada-mode-menu))))))
4751
4752 \f
4753 ;; -------------------------------------------------------
4754 ;; Commenting/Uncommenting code
4755 ;; The following two calls are provided to enhance the standard
4756 ;; comment-region function, which only allows uncommenting if the
4757 ;; comment is at the beginning of a line. If the line have been re-indented,
4758 ;; we are unable to use comment-region, which makes no sense.
4759 ;;
4760 ;; In addition, we provide an interface to the standard comment handling
4761 ;; function for justifying the comments.
4762 ;; -------------------------------------------------------
4763
4764 (defadvice comment-region (before ada-uncomment-anywhere disable)
4765 (if (and arg
4766 (listp arg) ;; a prefix with \C-u is of the form '(4), whereas
4767 ;; \C-u 2 sets arg to '2' (fixed by S.Leake)
4768 (string= mode-name "Ada"))
4769 (save-excursion
4770 (let ((cs (concat "^[ \t]*" (regexp-quote comment-start))))
4771 (goto-char beg)
4772 (while (re-search-forward cs end t)
4773 (replace-match comment-start))
4774 ))))
4775
4776 (defun ada-uncomment-region (beg end &optional arg)
4777 "Delete `comment-start' at the beginning of a line in the region."
4778 (interactive "r\nP")
4779
4780 ;; This advice is not needed anymore with Emacs21. However, for older
4781 ;; versions, as well as for XEmacs, we still need to enable it.
4782 (if (or (<= emacs-major-version 20) (featurep 'xemacs))
4783 (progn
4784 (ad-activate 'comment-region)
4785 (comment-region beg end (- (or arg 2)))
4786 (ad-deactivate 'comment-region))
4787 (comment-region beg end (list (- (or arg 2))))
4788 (ada-indent-region beg end)))
4789
4790 (defun ada-fill-comment-paragraph-justify ()
4791 "Fills current comment paragraph and justifies each line as well."
4792 (interactive)
4793 (ada-fill-comment-paragraph 'full))
4794
4795 (defun ada-fill-comment-paragraph-postfix ()
4796 "Fills current comment paragraph and justifies each line as well.
4797 Adds `ada-fill-comment-postfix' at the end of each line."
4798 (interactive)
4799 (ada-fill-comment-paragraph 'full t))
4800
4801 (defun ada-fill-comment-paragraph (&optional justify postfix)
4802 "Fills the current comment paragraph.
4803 If JUSTIFY is non-nil, each line is justified as well.
4804 If POSTFIX and JUSTIFY are non-nil, `ada-fill-comment-postfix' is appended
4805 to each filled and justified line.
4806 The paragraph is indented on the first line."
4807 (interactive "P")
4808
4809 ;; check if inside comment or just in front a comment
4810 (if (and (not (ada-in-comment-p))
4811 (not (looking-at "[ \t]*--")))
4812 (error "not inside comment"))
4813
4814 (let* (indent from to
4815 (opos (point-marker))
4816
4817 ;; Sets this variable to nil, otherwise it prevents
4818 ;; fill-region-as-paragraph to work on Emacs <= 20.2
4819 (parse-sexp-lookup-properties nil)
4820
4821 fill-prefix
4822 (fill-column (current-fill-column)))
4823
4824 ;; Find end of paragraph
4825 (back-to-indentation)
4826 (while (and (not (eobp)) (looking-at ".*--[ \t]*[^ \t\n]"))
4827 (forward-line 1)
4828
4829 ;; If we were at the last line in the buffer, create a dummy empty
4830 ;; line at the end of the buffer.
4831 (if (eobp)
4832 (insert "\n")
4833 (back-to-indentation)))
4834 (beginning-of-line)
4835 (setq to (point-marker))
4836 (goto-char opos)
4837
4838 ;; Find beginning of paragraph
4839 (back-to-indentation)
4840 (while (and (not (bobp)) (looking-at ".*--[ \t]*[^ \t\n]"))
4841 (forward-line -1)
4842 (back-to-indentation))
4843
4844 ;; We want one line above the first one, unless we are at the beginning
4845 ;; of the buffer
4846 (unless (bobp)
4847 (forward-line 1))
4848 (beginning-of-line)
4849 (setq from (point-marker))
4850
4851 ;; Calculate the indentation we will need for the paragraph
4852 (back-to-indentation)
4853 (setq indent (current-column))
4854 ;; unindent the first line of the paragraph
4855 (delete-region from (point))
4856
4857 ;; Remove the old postfixes
4858 (goto-char from)
4859 (while (re-search-forward "--\n" to t)
4860 (replace-match "\n"))
4861
4862 (goto-char (1- to))
4863 (setq to (point-marker))
4864
4865 ;; Indent and justify the paragraph
4866 (setq fill-prefix ada-fill-comment-prefix)
4867 (set-left-margin from to indent)
4868 (if postfix
4869 (setq fill-column (- fill-column (length ada-fill-comment-postfix))))
4870
4871 (fill-region-as-paragraph from to justify)
4872
4873 ;; Add the postfixes if required
4874 (if postfix
4875 (save-restriction
4876 (goto-char from)
4877 (narrow-to-region from to)
4878 (while (not (eobp))
4879 (end-of-line)
4880 (insert-char ? (- fill-column (current-column)))
4881 (insert ada-fill-comment-postfix)
4882 (forward-line))
4883 ))
4884
4885 ;; In Emacs <= 20.2 and XEmacs <=20.4, there is a bug, and a newline is
4886 ;; inserted at the end. Delete it
4887 (if (or (featurep 'xemacs)
4888 (<= emacs-major-version 19)
4889 (and (= emacs-major-version 20)
4890 (<= emacs-minor-version 2)))
4891 (progn
4892 (goto-char to)
4893 (end-of-line)
4894 (delete-char 1)))
4895
4896 (goto-char opos)))
4897
4898
4899 ;; ---------------------------------------------------
4900 ;; support for find-file.el
4901 ;; These functions are used by find-file to guess the file names from
4902 ;; unit names, and to find the other file (spec or body) from the current
4903 ;; file (body or spec).
4904 ;; It is also used to find in which function we are, so as to put the
4905 ;; cursor at the correct position.
4906 ;; Standard Ada does not force any relation between unit names and file names,
4907 ;; so some of these functions can only be a good approximation. However, they
4908 ;; are also overriden in `ada-xref'.el when we know that the user is using
4909 ;; GNAT.
4910 ;; ---------------------------------------------------
4911
4912 ;; Overriden when we work with GNAT, to use gnatkrunch
4913 (defun ada-make-filename-from-adaname (adaname)
4914 "Determine the filename in which ADANAME is found.
4915 This is a generic function, independent from any compiler."
4916 (while (string-match "\\." adaname)
4917 (setq adaname (replace-match "-" t t adaname)))
4918 (downcase adaname)
4919 )
4920
4921 (defun ada-other-file-name ()
4922 "Return the name of the other file.
4923 The name returned is the body if current-buffer is the spec, or the spec
4924 otherwise."
4925
4926 (let ((is-spec nil)
4927 (is-body nil)
4928 (suffixes ada-spec-suffixes)
4929 (name (buffer-file-name)))
4930
4931 ;; Guess whether we have a spec or a body, and get the basename of the
4932 ;; file. Since the extension may not start with '.', we can not use
4933 ;; file-name-extension
4934 (while (and (not is-spec)
4935 suffixes)
4936 (if (string-match (concat "\\(.*\\)" (car suffixes) "$") name)
4937 (setq is-spec t
4938 name (match-string 1 name)))
4939 (setq suffixes (cdr suffixes)))
4940
4941 (if (not is-spec)
4942 (progn
4943 (setq suffixes ada-body-suffixes)
4944 (while (and (not is-body)
4945 suffixes)
4946 (if (string-match (concat "\\(.*\\)" (car suffixes) "$") name)
4947 (setq is-body t
4948 name (match-string 1 name)))
4949 (setq suffixes (cdr suffixes)))))
4950
4951 ;; If this wasn't in either list, return name itself
4952 (if (not (or is-spec is-body))
4953 name
4954
4955 ;; Else find the other possible names
4956 (if is-spec
4957 (setq suffixes ada-body-suffixes)
4958 (setq suffixes ada-spec-suffixes))
4959 (setq is-spec name)
4960
4961 (while suffixes
4962
4963 ;; If we are using project file, search for the other file in all
4964 ;; the possible src directories.
4965
4966 (if (fboundp 'ada-find-src-file-in-dir)
4967 (let ((other
4968 (ada-find-src-file-in-dir
4969 (file-name-nondirectory (concat name (car suffixes))))))
4970 (if other
4971 (set 'is-spec other)))
4972
4973 ;; Else search in the current directory
4974 (if (file-exists-p (concat name (car suffixes)))
4975 (setq is-spec (concat name (car suffixes)))))
4976 (setq suffixes (cdr suffixes)))
4977
4978 is-spec)))
4979
4980 (defun ada-which-function-are-we-in ()
4981 "Return the name of the function whose definition/declaration point is in.
4982 Redefines the function `ff-which-function-are-we-in'."
4983 (setq ff-function-name nil)
4984 (save-excursion
4985 (end-of-line);; make sure we get the complete name
4986 (if (or (re-search-backward ada-procedure-start-regexp nil t)
4987 (re-search-backward ada-package-start-regexp nil t))
4988 (setq ff-function-name (match-string 0)))
4989 ))
4990
4991
4992 (defvar ada-last-which-function-line -1
4993 "Last on which ada-which-function was called")
4994 (defvar ada-last-which-function-subprog 0
4995 "Last subprogram name returned by ada-which-function")
4996 (make-variable-buffer-local 'ada-last-which-function-subprog)
4997 (make-variable-buffer-local 'ada-last-which-function-line)
4998
4999
5000 (defun ada-which-function ()
5001 "Returns the name of the function whose body the point is in.
5002 This function works even in the case of nested subprograms, whereas the
5003 standard Emacs function `which-function' does not.
5004 Since the search can be long, the results are cached."
5005
5006 (let ((line (count-lines 1 (point)))
5007 (pos (point))
5008 end-pos
5009 func-name indent
5010 found)
5011
5012 ;; If this is the same line as before, simply return the same result
5013 (if (= line ada-last-which-function-line)
5014 ada-last-which-function-subprog
5015
5016 (save-excursion
5017 ;; In case the current line is also the beginning of the body
5018 (end-of-line)
5019
5020 ;; Are we looking at "function Foo\n (paramlist)"
5021 (skip-chars-forward " \t\n(")
5022
5023 (condition-case nil
5024 (up-list 1)
5025 (error nil))
5026
5027 (skip-chars-forward " \t\n")
5028 (if (looking-at "return")
5029 (progn
5030 (forward-word 1)
5031 (skip-chars-forward " \t\n")
5032 (skip-chars-forward "a-zA-Z0-9_'")))
5033
5034 ;; Can't simply do forward-word, in case the "is" is not on the
5035 ;; same line as the closing parenthesis
5036 (skip-chars-forward "is \t\n")
5037
5038 ;; No look for the closest subprogram body that has not ended yet.
5039 ;; Not that we expect all the bodies to be finished by "end <name>",
5040 ;; or a simple "end;" indented in the same column as the start of
5041 ;; the subprogram. The goal is to be as efficient as possible.
5042
5043 (while (and (not found)
5044 (re-search-backward ada-imenu-subprogram-menu-re nil t))
5045
5046 ;; Get the function name, but not the properties, or this changes
5047 ;; the face in the modeline on Emacs 21
5048 (setq func-name (match-string-no-properties 2))
5049 (if (and (not (ada-in-comment-p))
5050 (not (save-excursion
5051 (goto-char (match-end 0))
5052 (looking-at "[ \t\n]*new"))))
5053 (save-excursion
5054 (back-to-indentation)
5055 (setq indent (current-column))
5056 (if (ada-search-ignore-string-comment
5057 (concat "end[ \t]+" func-name "[ \t]*;\\|^"
5058 (make-string indent ? ) "end;"))
5059 (setq end-pos (point))
5060 (setq end-pos (point-max)))
5061 (if (>= end-pos pos)
5062 (setq found func-name))))
5063 )
5064 (setq ada-last-which-function-line line
5065 ada-last-which-function-subprog found)
5066 found))))
5067
5068 (defun ada-ff-other-window ()
5069 "Find other file in other window using `ff-find-other-file'."
5070 (interactive)
5071 (and (fboundp 'ff-find-other-file)
5072 (ff-find-other-file t)))
5073
5074 (defun ada-set-point-accordingly ()
5075 "Move to the function declaration that was set by
5076 `ff-which-function-are-we-in'."
5077 (if ff-function-name
5078 (progn
5079 (goto-char (point-min))
5080 (unless (ada-search-ignore-string-comment
5081 (concat ff-function-name "\\b") nil)
5082 (goto-char (point-min))))))
5083
5084 (defun ada-get-body-name (&optional spec-name)
5085 "Returns the file name for the body of SPEC-NAME.
5086 If SPEC-NAME is nil, returns the body for the current package.
5087 Returns nil if no body was found."
5088 (interactive)
5089
5090 (unless spec-name (setq spec-name (buffer-file-name)))
5091
5092 ;; Remove the spec extension. We can not simply remove the file extension,
5093 ;; but we need to take into account the specific non-GNAT extensions that the
5094 ;; user might have specified.
5095
5096 (let ((suffixes ada-spec-suffixes)
5097 end)
5098 (while suffixes
5099 (setq end (- (length spec-name) (length (car suffixes))))
5100 (if (string-equal (car suffixes) (substring spec-name end))
5101 (setq spec-name (substring spec-name 0 end)))
5102 (setq suffixes (cdr suffixes))))
5103
5104 ;; If find-file.el was available, use its functions
5105 (if (fboundp 'ff-get-file-name)
5106 (ff-get-file-name ada-search-directories-internal
5107 (ada-make-filename-from-adaname
5108 (file-name-nondirectory
5109 (file-name-sans-extension spec-name)))
5110 ada-body-suffixes)
5111 ;; Else emulate it very simply
5112 (concat (ada-make-filename-from-adaname
5113 (file-name-nondirectory
5114 (file-name-sans-extension spec-name)))
5115 ".adb")))
5116
5117 \f
5118 ;; ---------------------------------------------------
5119 ;; support for font-lock.el
5120 ;; Strings are a real pain in Ada because a single quote character is
5121 ;; overloaded as a string quote and type/instance delimiter. By default, a
5122 ;; single quote is given punctuation syntax in `ada-mode-syntax-table'.
5123 ;; So, for Font Lock mode purposes, we mark single quotes as having string
5124 ;; syntax when the gods that created Ada determine them to be.
5125 ;;
5126 ;; This only works in Emacs. See the comments before the grammar functions
5127 ;; at the beginning of this file for how this is done with XEmacs.
5128 ;; ----------------------------------------------------
5129
5130 (defconst ada-font-lock-syntactic-keywords
5131 ;; Mark single quotes as having string quote syntax in 'c' instances.
5132 ;; As a special case, ''' will not be highlighted, but if we do not
5133 ;; set this special case, then the rest of the buffer is highlighted as
5134 ;; a string
5135 ;; This sets the properties of the characters, so that ada-in-string-p
5136 ;; correctly handles '"' too...
5137 '(("[^a-zA-Z0-9)]\\('\\)[^'\n]\\('\\)" (1 (7 . ?')) (2 (7 . ?')))
5138 ("^[ \t]*\\(#\\(if\\|else\\|elsif\\|end\\)\\)" (1 (11 . ?\n)))
5139 ))
5140
5141 (defvar ada-font-lock-keywords
5142 (eval-when-compile
5143 (list
5144 ;;
5145 ;; handle "type T is access function return S;"
5146 (list "\\<\\(function[ \t]+return\\)\\>" '(1 font-lock-keyword-face) )
5147
5148 ;; preprocessor line
5149 (list "^[ \t]*\\(#.*\n\\)" '(1 font-lock-type-face t))
5150
5151 ;;
5152 ;; accept, entry, function, package (body), protected (body|type),
5153 ;; pragma, procedure, task (body) plus name.
5154 (list (concat
5155 "\\<\\("
5156 "accept\\|"
5157 "entry\\|"
5158 "function\\|"
5159 "package[ \t]+body\\|"
5160 "package\\|"
5161 "pragma\\|"
5162 "procedure\\|"
5163 "protected[ \t]+body\\|"
5164 "protected[ \t]+type\\|"
5165 "protected\\|"
5166 "task[ \t]+body\\|"
5167 "task[ \t]+type\\|"
5168 "task"
5169 "\\)\\>[ \t]*"
5170 "\\(\\sw+\\(\\.\\sw*\\)*\\)?")
5171 '(1 font-lock-keyword-face) '(2 font-lock-function-name-face nil t))
5172 ;;
5173 ;; Optional keywords followed by a type name.
5174 (list (concat ; ":[ \t]*"
5175 "\\<\\(access[ \t]+all\\|access[ \t]+constant\\|access\\|constant\\|in[ \t]+reverse\\|\\|in[ \t]+out\\|in\\|out\\)\\>"
5176 "[ \t]*"
5177 "\\(\\sw+\\(\\.\\sw*\\)*\\)?")
5178 '(1 font-lock-keyword-face nil t) '(2 font-lock-type-face nil t))
5179
5180 ;;
5181 ;; Main keywords, except those treated specially below.
5182 (concat "\\<"
5183 (regexp-opt
5184 '("abort" "abs" "abstract" "accept" "access" "aliased" "all"
5185 "and" "array" "at" "begin" "case" "declare" "delay" "delta"
5186 "digits" "do" "else" "elsif" "entry" "exception" "exit" "for"
5187 "generic" "if" "in" "is" "limited" "loop" "mod" "not"
5188 "null" "or" "others" "private" "protected" "raise"
5189 "range" "record" "rem" "renames" "requeue" "return" "reverse"
5190 "select" "separate" "tagged" "task" "terminate" "then" "until"
5191 "when" "while" "with" "xor") t)
5192 "\\>")
5193 ;;
5194 ;; Anything following end and not already fontified is a body name.
5195 '("\\<\\(end\\)\\>\\([ \t]+\\)?\\(\\(\\sw\\|[_.]\\)+\\)?"
5196 (1 font-lock-keyword-face) (3 font-lock-function-name-face nil t))
5197 ;;
5198 ;; Keywords followed by a type or function name.
5199 (list (concat "\\<\\("
5200 "new\\|of\\|subtype\\|type"
5201 "\\)\\>[ \t]*\\(\\sw+\\(\\.\\sw*\\)*\\)?[ \t]*\\((\\)?")
5202 '(1 font-lock-keyword-face)
5203 '(2 (if (match-beginning 4)
5204 font-lock-function-name-face
5205 font-lock-type-face) nil t))
5206 ;;
5207 ;; Keywords followed by a (comma separated list of) reference.
5208 ;; Note that font-lock only works on single lines, thus we can not
5209 ;; correctly highlight a with_clause that spans multiple lines.
5210 (list (concat "\\<\\(goto\\|raise\\|use\\|with\\)"
5211 "[ \t]+\\([a-zA-Z0-9_., \t]+\\)\\W")
5212 '(1 font-lock-keyword-face) '(2 font-lock-reference-face nil t))
5213
5214 ;;
5215 ;; Goto tags.
5216 '("<<\\(\\sw+\\)>>" 1 font-lock-reference-face)
5217
5218 ;; Highlight based-numbers (R. Reagan <robin-reply@reagans.org>)
5219 (list "\\([0-9]+#[0-9a-fA-F_]+#\\)" '(1 font-lock-constant-face t))
5220
5221 ;; Ada unnamed numerical constants
5222 (list "\\W\\([-+]?[0-9._]+\\)\\>" '(1 font-lock-constant-face))
5223
5224 ))
5225 "Default expressions to highlight in Ada mode.")
5226
5227
5228 ;; ---------------------------------------------------------
5229 ;; Support for outline.el
5230 ;; ---------------------------------------------------------
5231
5232 (defun ada-outline-level ()
5233 "This is so that `current-column` DTRT in otherwise-hidden text"
5234 ;; patch from Dave Love <fx@gnu.org>
5235 (let (buffer-invisibility-spec)
5236 (save-excursion
5237 (back-to-indentation)
5238 (current-column))))
5239
5240 ;; ---------------------------------------------------------
5241 ;; Support for narrow-to-region
5242 ;; ---------------------------------------------------------
5243
5244 (defun ada-narrow-to-defun (&optional arg)
5245 "make text outside current subprogram invisible.
5246 The subprogram visible is the one that contains or follow point.
5247 Optional ARG is ignored.
5248 Use `M-x widen' to go back to the full visibility for the buffer"
5249
5250 (interactive)
5251 (save-excursion
5252 (let (end)
5253 (widen)
5254 (forward-line 1)
5255 (ada-previous-procedure)
5256
5257 (save-excursion
5258 (beginning-of-line)
5259 (setq end (point)))
5260
5261 (ada-move-to-end)
5262 (end-of-line)
5263 (narrow-to-region end (point))
5264 (message
5265 "Use M-x widen to get back to full visibility in the buffer"))))
5266
5267 ;; ---------------------------------------------------------
5268 ;; Automatic generation of code
5269 ;; The Ada-mode has a set of function to automatically generate a subprogram
5270 ;; or package body from its spec.
5271 ;; These function only use a primary and basic algorithm, this could use a
5272 ;; lot of improvement.
5273 ;; When the user is using GNAT, we rather use gnatstub to generate an accurate
5274 ;; body.
5275 ;; ----------------------------------------------------------
5276
5277 (defun ada-gen-treat-proc (match)
5278 "Make dummy body of a procedure/function specification.
5279 MATCH is a cons cell containing the start and end location of the last search
5280 for ada-procedure-start-regexp."
5281 (goto-char (car match))
5282 (let (func-found procname functype)
5283 (cond
5284 ((or (looking-at "^[ \t]*procedure")
5285 (setq func-found (looking-at "^[ \t]*function")))
5286 ;; treat it as a proc/func
5287 (forward-word 2)
5288 (forward-word -1)
5289 (setq procname (buffer-substring (point) (cdr match))) ; store proc name
5290
5291 ;; goto end of procname
5292 (goto-char (cdr match))
5293
5294 ;; skip over parameterlist
5295 (unless (looking-at "[ \t\n]*\\(;\\|return\\)")
5296 (forward-sexp))
5297
5298 ;; if function, skip over 'return' and result type.
5299 (if func-found
5300 (progn
5301 (forward-word 1)
5302 (skip-chars-forward " \t\n")
5303 (setq functype (buffer-substring (point)
5304 (progn
5305 (skip-chars-forward
5306 "a-zA-Z0-9_\.")
5307 (point))))))
5308 ;; look for next non WS
5309 (cond
5310 ((looking-at "[ \t]*;")
5311 (delete-region (match-beginning 0) (match-end 0));; delete the ';'
5312 (ada-indent-newline-indent)
5313 (insert "is")
5314 (ada-indent-newline-indent)
5315 (if func-found
5316 (progn
5317 (insert "Result : " functype ";")
5318 (ada-indent-newline-indent)))
5319 (insert "begin")
5320 (ada-indent-newline-indent)
5321 (if func-found
5322 (insert "return Result;")
5323 (insert "null;"))
5324 (ada-indent-newline-indent)
5325 (insert "end " procname ";")
5326 (ada-indent-newline-indent)
5327 )
5328 ;; else
5329 ((looking-at "[ \t\n]*is")
5330 ;; do nothing
5331 )
5332 ((looking-at "[ \t\n]*rename")
5333 ;; do nothing
5334 )
5335 (t
5336 (message "unknown syntax"))))
5337 (t
5338 (if (looking-at "^[ \t]*task")
5339 (progn
5340 (message "Task conversion is not yet implemented")
5341 (forward-word 2)
5342 (if (looking-at "[ \t]*;")
5343 (forward-line)
5344 (ada-move-to-end))
5345 ))))))
5346
5347 (defun ada-make-body ()
5348 "Create an Ada package body in the current buffer.
5349 The potential old buffer contents is deleted first, then we copy the
5350 spec buffer in here and modify it to make it a body.
5351 This function typically is to be hooked into `ff-file-created-hooks'."
5352 (interactive)
5353 (delete-region (point-min) (point-max))
5354 (insert-buffer (car (cdr (buffer-list))))
5355 (ada-mode)
5356
5357 (let (found ada-procedure-or-package-start-regexp)
5358 (if (setq found
5359 (ada-search-ignore-string-comment ada-package-start-regexp nil))
5360 (progn (goto-char (cdr found))
5361 (insert " body")
5362 )
5363 (error "No package"))
5364
5365 (setq ada-procedure-or-package-start-regexp
5366 (concat ada-procedure-start-regexp
5367 "\\|"
5368 ada-package-start-regexp))
5369
5370 (while (setq found
5371 (ada-search-ignore-string-comment
5372 ada-procedure-or-package-start-regexp nil))
5373 (progn
5374 (goto-char (car found))
5375 (if (looking-at ada-package-start-regexp)
5376 (progn (goto-char (cdr found))
5377 (insert " body"))
5378 (ada-gen-treat-proc found))))))
5379
5380
5381 (defun ada-make-subprogram-body ()
5382 "Make one dummy subprogram body from spec surrounding point."
5383 (interactive)
5384 (let* ((found (re-search-backward ada-procedure-start-regexp nil t))
5385 (spec (match-beginning 0))
5386 body-file)
5387 (if found
5388 (progn
5389 (goto-char spec)
5390 (if (and (re-search-forward "(\\|;" nil t)
5391 (= (char-before) ?\())
5392 (progn
5393 (ada-search-ignore-string-comment ")" nil)
5394 (ada-search-ignore-string-comment ";" nil)))
5395 (setq spec (buffer-substring spec (point)))
5396
5397 ;; If find-file.el was available, use its functions
5398 (setq body-file (ada-get-body-name))
5399 (if body-file
5400 (find-file body-file)
5401 (error "No body found for the package. Create it first."))
5402
5403 (save-restriction
5404 (widen)
5405 (goto-char (point-max))
5406 (forward-comment -10000)
5407 (re-search-backward "\\<end\\>" nil t)
5408 ;; Move to the beginning of the elaboration part, if any
5409 (re-search-backward "^begin" nil t)
5410 (newline)
5411 (forward-char -1)
5412 (insert spec)
5413 (re-search-backward ada-procedure-start-regexp nil t)
5414 (ada-gen-treat-proc (cons (match-beginning 0) (match-end 0)))
5415 ))
5416 (error "Not in subprogram spec"))))
5417
5418 ;; --------------------------------------------------------
5419 ;; Global initializations
5420 ;; --------------------------------------------------------
5421
5422 ;; Create the keymap once and for all. If we do that in ada-mode,
5423 ;; the keys changed in the user's .emacs have to be modified
5424 ;; every time
5425 (ada-create-keymap)
5426 (ada-create-menu)
5427
5428 ;; Create the syntax tables, but do not activate them
5429 (ada-create-syntax-table)
5430
5431 ;; Add the default extensions (and set up speedbar)
5432 (ada-add-extensions ".ads" ".adb")
5433 ;; This two files are generated by GNAT when running with -gnatD
5434 (if (equal ada-which-compiler 'gnat)
5435 (ada-add-extensions ".ads.dg" ".adb.dg"))
5436
5437 ;; Read the special cases for exceptions
5438 (ada-case-read-exceptions)
5439
5440 ;; Setup auto-loading of the other ada-mode files.
5441 (if (equal ada-which-compiler 'gnat)
5442 (progn
5443 (autoload 'ada-change-prj "ada-xref" nil t)
5444 (autoload 'ada-check-current "ada-xref" nil t)
5445 (autoload 'ada-compile-application "ada-xref" nil t)
5446 (autoload 'ada-compile-current "ada-xref" nil t)
5447 (autoload 'ada-complete-identifier "ada-xref" nil t)
5448 (autoload 'ada-find-file "ada-xref" nil t)
5449 (autoload 'ada-find-any-references "ada-xref" nil t)
5450 (autoload 'ada-find-src-file-in-dir "ada-xref" nil t)
5451 (autoload 'ada-find-local-references "ada-xref" nil t)
5452 (autoload 'ada-find-references "ada-xref" nil t)
5453 (autoload 'ada-gdb-application "ada-xref" nil t)
5454 (autoload 'ada-goto-declaration "ada-xref" nil t)
5455 (autoload 'ada-goto-declaration-other-frame "ada-xref" nil t)
5456 (autoload 'ada-goto-parent "ada-xref" nil t)
5457 (autoload 'ada-make-body-gnatstub "ada-xref" nil t)
5458 (autoload 'ada-point-and-xref "ada-xref" nil t)
5459 (autoload 'ada-reread-prj-file "ada-xref" nil t)
5460 (autoload 'ada-run-application "ada-xref" nil t)
5461 (autoload 'ada-set-default-project-file "ada-xref" nil nil)
5462 (autoload 'ada-set-default-project-file "ada-xref" nil t)
5463 (autoload 'ada-xref-goto-previous-reference "ada-xref" nil t)
5464
5465 (autoload 'ada-customize "ada-prj" nil t)
5466 (autoload 'ada-prj-edit "ada-prj" nil t)
5467 (autoload 'ada-prj-new "ada-prj" nil t)
5468 (autoload 'ada-prj-save "ada-prj" nil t)
5469 ))
5470
5471 (autoload 'ada-array "ada-stmt" nil t)
5472 (autoload 'ada-case "ada-stmt" nil t)
5473 (autoload 'ada-declare-block "ada-stmt" nil t)
5474 (autoload 'ada-else "ada-stmt" nil t)
5475 (autoload 'ada-elsif "ada-stmt" nil t)
5476 (autoload 'ada-exception "ada-stmt" nil t)
5477 (autoload 'ada-exception-block "ada-stmt" nil t)
5478 (autoload 'ada-exit "ada-stmt" nil t)
5479 (autoload 'ada-for-loop "ada-stmt" nil t)
5480 (autoload 'ada-function-spec "ada-stmt" nil t)
5481 (autoload 'ada-header "ada-stmt" nil t)
5482 (autoload 'ada-if "ada-stmt" nil t)
5483 (autoload 'ada-loop "ada-stmt" nil t)
5484 (autoload 'ada-package-body "ada-stmt" nil t)
5485 (autoload 'ada-package-spec "ada-stmt" nil t)
5486 (autoload 'ada-private "ada-stmt" nil t)
5487 (autoload 'ada-procedure-spec "ada-stmt" nil t)
5488 (autoload 'ada-record "ada-stmt" nil t)
5489 (autoload 'ada-subprogram-body "ada-stmt" nil t)
5490 (autoload 'ada-subtype "ada-stmt" nil t)
5491 (autoload 'ada-tabsize "ada-stmt" nil t)
5492 (autoload 'ada-task-body "ada-stmt" nil t)
5493 (autoload 'ada-task-spec "ada-stmt" nil t)
5494 (autoload 'ada-type "ada-stmt" nil t)
5495 (autoload 'ada-use "ada-stmt" nil t)
5496 (autoload 'ada-when "ada-stmt" nil t)
5497 (autoload 'ada-while-loop "ada-stmt" nil t)
5498 (autoload 'ada-with "ada-stmt" nil t)
5499
5500 ;;; provide ourselves
5501 (provide 'ada-mode)
5502
5503 ;;; arch-tag: 1b7d45ec-1698-43b5-8d4a-e479ea023270
5504 ;;; ada-mode.el ends here