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