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