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