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