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