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