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