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