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