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