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