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