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