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