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