]> code.delx.au - gnu-emacs-elpa/blob - packages/ada-mode/ada-mode.el
8f76749a093ee14d7fb9505891e486d83ccf5594
[gnu-emacs-elpa] / packages / ada-mode / ada-mode.el
1 ;;; ada-mode.el --- major-mode for editing Ada sources
2 ;;
3 ;;; Copyright (C) 1994, 1995, 1997 - 2014 Free Software Foundation, Inc.
4 ;;
5 ;; Author: Stephen Leake <stephen_leake@member.fsf.org>
6 ;; Maintainer: Stephen Leake <stephen_leake@member.fsf.org>
7 ;; Keywords FIXME: languages, ada ELPA broken for multiple keywords
8 ;; Version: 5.1.5
9 ;; package-requires: ((wisi "1.0.5") (cl-lib "0.4") (emacs "24.2"))
10 ;; url: http://stephe-leake.org/emacs/ada-mode/emacs-ada-mode.html
11 ;;
12 ;; (Gnu ELPA requires single digits between dots in versions)
13 ;;
14 ;; This file is part of GNU Emacs.
15 ;;
16 ;; GNU Emacs is free software: you can redistribute it and/or modify
17 ;; it under the terms of the GNU General Public License as published by
18 ;; the Free Software Foundation, either version 3 of the License, or
19 ;; (at your option) any later version.
20 ;;
21 ;; GNU Emacs is distributed in the hope that it will be useful,
22 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
23 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 ;; GNU General Public License for more details.
25 ;;
26 ;; You should have received a copy of the GNU General Public License
27 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
28 ;;
29 ;;; Usage:
30 ;;
31 ;; Emacs should enter Ada mode automatically when you load an Ada
32 ;; file, based on the file extension. The default extensions for Ada
33 ;; files are .ads, .adb; use ada-add-extensions to add other
34 ;; extensions.
35 ;;
36 ;; By default, ada-mode is configured to take full advantage of the
37 ;; GNAT compiler. If you are using another compiler, you
38 ;; should load that compiler's ada-* file first; that will define
39 ;; ada-compiler as a feature, so ada-gnat.el will not be loaded.
40 ;;
41 ;; See the user guide (info "ada-mode"), built from ada-mode.texi.
42
43 ;;; Design:
44 ;;
45 ;; In order to support multiple compilers, we use indirect function
46 ;; calls for all operations that depend on the compiler.
47 ;;
48 ;; We also support a cross reference tool (also called xref tool) that
49 ;; is different from the compiler. For example, you can use a local
50 ;; GNAT compiler to generate and access cross-reference information,
51 ;; while using a cross-compiler for compiling the final executable.
52 ;;
53 ;; Other functions are lumped with the choice of xref tool; mapping
54 ;; Ada names to file names, creating package bodies; any tool function
55 ;; that does not create executable code.
56 ;;
57 ;; The indentation engine and skeleton tools are also called
58 ;; indirectly, to allow parallel development of new versions of these
59 ;; tools (inspired by experience with ada-smie and ada-wisi).
60 ;;
61 ;; We also support using different compilers for different projects;
62 ;; `ada-compiler' can be set in Ada mode project files. Note that
63 ;; there is only one project active at a time; the most recently
64 ;; selected one. All Ada files are assumed to belong to this project
65 ;; (which is not correct, but works well in practice; the user is
66 ;; typically only concerned about files that belong to the current
67 ;; project).
68 ;;
69 ;; There are several styles of indirect calls:
70 ;;
71 ;; - scalar global variable set during load
72 ;;
73 ;; Appropriate when the choice of implementation is fixed at load
74 ;; time; it does not depend on the current Ada project. Used for
75 ;; indentation and skeleton functions.
76 ;;
77 ;; - scalar global variable set during project select
78 ;;
79 ;; Appropriate when the choice of implementation is determined by
80 ;; the choice of compiler or xref tool, which is per-project. The
81 ;; user sets the compiler choice in the project file, but not the
82 ;; lower-level redirect choice.
83 ;;
84 ;; For example, `ada-file-name-from-ada-name' depends on the naming
85 ;; convention used by the compiler. If the project file sets
86 ;; ada_compiler to 'gnat (either directly or by default),
87 ;; ada-gnat-select-prj sets `ada-file-name-from-ada-name' to
88 ;; `ada-gnat-file-name-from-ada-name'.
89 ;;
90 ;; - scalar buffer-local variable set during project select or file open
91 ;;
92 ;; Appropriate when choice of implementation is normally
93 ;; per-project, but can be per-buffer.
94 ;;
95 ;; For example, `ada-case-strict' will normally be set by the
96 ;; project, but some files may deviate from the project standard (if
97 ;; they are generated by -fdumpspec, for example). Those files set
98 ;; `ada-case-strict' in a file local variable comment.
99 ;;
100 ;; - scalar buffer-local variable set by ada-mode or ada-mode-hook
101 ;; function
102 ;;
103 ;; Appropriate when the variable is a non-Ada mode variable, also
104 ;; used by other modes, and choice should not affect those modes.
105 ;;
106 ;; `indent-line-function', `comment-indent-function' use this style
107 ;;
108 ;; - alist global variable indexed by ada-compiler
109 ;;
110 ;; Appropriate when the choice of implementation is determined by
111 ;; the compiler, but the function is invoked during project parse,
112 ;; so we can't depend on a value set by project select.
113 ;;
114 ;; alist entries are set during load by the implementation elisp files.
115 ;;
116 ;; `ada-prj-default-compiler-alist' uses this style.
117
118 ;;; History:
119 ;;
120 ;; The first Ada mode for GNU Emacs was written by V. Broman in
121 ;; 1985. He based his work on the already existing Modula-2 mode.
122 ;; This was distributed as ada.el in versions of Emacs prior to 19.29.
123 ;;
124 ;; Lynn Slater wrote an extensive Ada mode in 1989. It consisted of
125 ;; several files with support for dired commands and other nice
126 ;; things.
127 ;;
128 ;; The probably very first Ada mode (called electric-ada.el) was
129 ;; written by Steven D. Litvintchouk and Steven M. Rosen for the
130 ;; Gosling Emacs. L. Slater based his development on ada.el and
131 ;; electric-ada.el.
132 ;;
133 ;; A complete rewrite by Rolf Ebert <ebert@inf.enst.fr> and Markus
134 ;; Heritsch <Markus.Heritsch@studbox.uni-stuttgart.de> was done at
135 ;; some point. Some ideas from the Ada mode mailing list have been
136 ;; added. Some of the functionality of L. Slater's mode has not (yet)
137 ;; been recoded in this new mode.
138 ;;
139 ;; A complete rewrite for Emacs-20 / GNAT-3.11 was done by Emmanuel
140 ;; Briot <briot@gnat.com> at Ada Core Technologies.
141 ;;
142 ;; A complete rewrite, to restructure the code more orthogonally, and
143 ;; to use wisi for the indentation engine, was done in 2012 - 2013 by
144 ;; Stephen Leake <stephen_leake@stephe-leake.org>.
145
146 ;;; Credits:
147 ;;
148 ;; Many thanks to John McCabe <john@assen.demon.co.uk> for sending so
149 ;; many patches included in this package.
150 ;; Christian Egli <Christian.Egli@hcsd.hac.com>:
151 ;; ada-imenu-generic-expression
152 ;; Many thanks also to the following persons that have contributed
153 ;; to the ada-mode
154 ;; Philippe Waroquiers (PW) <philippe@cfmu.eurocontrol.be> in particular,
155 ;; woodruff@stc.llnl.gov (John Woodruff)
156 ;; jj@ddci.dk (Jesper Joergensen)
157 ;; gse@ocsystems.com (Scott Evans)
158 ;; comar@gnat.com (Cyrille Comar)
159 ;; robin-reply@reagans.org
160 ;; and others for their valuable hints.
161
162 (require 'align)
163 (require 'cl-lib)
164 (require 'compile)
165 (require 'find-file)
166
167 (defun ada-mode-version ()
168 "Return Ada mode version."
169 (interactive)
170 (let ((version-string "5.1.5"))
171 ;; must match:
172 ;; ada-mode.texi
173 ;; README
174 ;; Version: above
175 (if (called-interactively-p 'interactive)
176 (message version-string)
177 version-string)))
178
179 ;;;;; User variables
180
181 (defvar ada-mode-hook nil
182 "List of functions to call when Ada mode is invoked.
183 This hook is executed after `ada-mode' is fully loaded, but
184 before file local variables are processed.")
185
186 (defgroup ada nil
187 "Major mode for editing Ada source code in Emacs."
188 :group 'languages)
189
190 (defcustom ada-auto-case t
191 ;; can be per-buffer
192 "Buffer-local value that may override project variable `auto_case'.
193 Global value is default for project variable `auto_case'.
194 Non-nil means automatically change case of preceding word while typing.
195 Casing of Ada keywords is done according to `ada-case-keyword',
196 identifiers are Mixed_Case."
197 :type 'boolean
198 :group 'ada
199 :safe 'booleanp)
200 (make-variable-buffer-local 'ada-auto-case)
201
202 (defcustom ada-case-exception-file nil
203 "Default list of special casing exceptions dictionaries for identifiers.
204 Override with 'casing' project variable.
205
206 New exceptions may be added interactively via `ada-case-create-exception'.
207 If an exception is defined in multiple files, the first occurence is used.
208
209 The file format is one word per line, that gives the casing to be
210 used for that word in Ada source code. If the line starts with
211 the character *, then the exception will be used for partial
212 words that either start at the beginning of a word or after a _
213 character, and end either at the end of the word or at a _
214 character. Characters after the first word are ignored, and not
215 preserved when the list is written back to the file."
216 :type '(repeat (file))
217 :group 'ada
218 :safe 'listp)
219
220 (defcustom ada-case-keyword 'downcase-word
221 "Buffer-local value that may override project variable `case_keyword'.
222 Global value is default for project variable `case_keyword'.
223 Function to call to adjust the case of Ada keywords."
224 :type '(choice (const downcase-word)
225 (const upcase-word))
226 :group 'ada
227 :safe 'functionp)
228 (make-variable-buffer-local 'ada-case-keyword)
229
230 (defcustom ada-case-identifier 'ada-mixed-case
231 "Buffer-local value that may override project variable `case_keyword'.
232 Global value is default for project variable `case_keyword'.
233 Function to call to adjust the case of Ada keywords."
234 :type '(choice (const ada-mixed-case)
235 (const downcase-region)
236 (const upcase-region))
237 :group 'ada
238 :safe 'functionp)
239 (make-variable-buffer-local 'ada-case-identifier)
240
241 (defcustom ada-case-strict t
242 "Buffer-local value that may override project variable `case_strict'.
243 Global value is default for project variable `case_strict'.
244 If non-nil, force Mixed_Case for identifiers.
245 Otherwise, allow UPPERCASE for identifiers."
246 :type 'boolean
247 :group 'ada
248 :safe 'booleanp)
249 (make-variable-buffer-local 'ada-case-strict)
250
251 (defcustom ada-language-version 'ada2012
252 "Ada language version; one of `ada83', `ada95', `ada2005', `ada2012'.
253 Only affects the keywords to highlight, not which version the
254 indentation parser accepts."
255 :type '(choice (const ada83)
256 (const ada95)
257 (const ada2005)
258 (const ada2012))
259 :group 'ada
260 :safe 'symbolp)
261 (make-variable-buffer-local 'ada-language-version)
262
263 (defcustom ada-fill-comment-prefix "-- "
264 "Comment fill prefix."
265 :type 'string
266 :group 'ada)
267 (make-variable-buffer-local 'ada-language-version)
268
269 (defcustom ada-fill-comment-postfix " --"
270 "Comment fill postfix."
271 :type 'string
272 :group 'ada)
273 (make-variable-buffer-local 'ada-language-version)
274
275 (defcustom ada-prj-file-extensions '("adp" "prj")
276 "List of Emacs Ada mode project file extensions.
277 Used when searching for a project file.
278 Any file with one of these extensions will be parsed by `ada-prj-parse-file-1'."
279 :type 'list
280 :group 'ada)
281
282 (defcustom ada-prj-file-ext-extra nil
283 "List of secondary project file extensions.
284 Used when searching for a project file that can be a primary or
285 secondary project file (referenced from a primary). The user
286 must provide a parser for a file with one of these extensions."
287 :type 'list
288 :group 'ada)
289
290 ;;;;; end of user variables
291
292 (defconst ada-symbol-end
293 ;; we can't just add \> here; that might match _ in a user modified ada-mode-syntax-table
294 "\\([ \t]+\\|$\\)"
295 "Regexp to add to symbol name in `ada-which-function'.")
296
297 (defvar ada-compiler nil
298 "Default Ada compiler; can be overridden in project files.
299 Values defined by compiler packages.")
300
301 (defvar ada-xref-tool nil
302 "Default Ada cross reference tool; can be overridden in project files.
303 Values defined by cross reference packages.")
304
305 ;;;; keymap and menus
306
307 (defvar ada-ret-binding nil)
308 (defvar ada-lfd-binding nil)
309
310 (defun ada-case-activate-keys ()
311 "Modify the key bindings for all the keys that should adjust casing."
312 (interactive)
313 ;; We can't use post-self-insert-hook for \n, \r, because they are
314 ;; not self-insert.
315
316 ;; The 'or ...' is there to be sure that the value will not be
317 ;; changed again when this is called more than once, since we
318 ;; are rebinding the keys.
319 (or ada-ret-binding (setq ada-ret-binding (key-binding "\C-M")))
320 (or ada-lfd-binding (setq ada-lfd-binding (key-binding "\C-j")))
321
322 (mapc (function
323 (lambda(key)
324 (define-key
325 ada-mode-map
326 (char-to-string key)
327 'ada-case-adjust-interactive)))
328 '( ?_ ?% ?& ?* ?( ?) ?- ?= ?+
329 ?| ?\; ?: ?' ?\" ?< ?, ?. ?> ?/ ?\n 32 ?\r ))
330
331 (define-key ada-mode-map [return] 'ada-case-adjust-interactive)
332 )
333
334 (defvar ada-mode-map
335 (let ((map (make-sparse-keymap)))
336 ;; C-c <letter> are reserved for users
337
338 ;; global-map has C-x ` 'next-error
339 (define-key map [return] 'ada-indent-newline-indent)
340 (define-key map "\C-c`" 'ada-show-secondary-error)
341 (define-key map "\C-c;" (lambda () (error "use M-; instead"))) ; comment-dwim
342 (define-key map "\C-c<" 'ada-goto-declaration-start)
343 (define-key map "\C-c>" 'ada-goto-declaration-end)
344 (define-key map "\C-c\M-`" 'ada-fix-compiler-error)
345 (define-key map "\C-c\C-a" 'ada-align)
346 (define-key map "\C-c\C-b" 'ada-make-subprogram-body)
347 (define-key map "\C-c\C-c" 'ada-build-make)
348 (define-key map "\C-c\C-d" 'ada-goto-declaration)
349 (define-key map "\C-c\M-d" 'ada-show-declaration-parents)
350 (define-key map "\C-c\C-e" 'ada-expand)
351 (define-key map "\C-c\C-f" 'ada-show-parse-error)
352 (define-key map "\C-c\C-i" 'ada-indent-statement)
353 (define-key map "\C-c\C-m" 'ada-build-set-make)
354 (define-key map "\C-c\C-n" 'ada-next-statement-keyword)
355 (define-key map "\C-c\C-o" 'ada-find-other-file)
356 (define-key map "\C-c\M-o" 'ada-find-other-file-noset)
357 (define-key map "\C-c\C-p" 'ada-prev-statement-keyword)
358 (define-key map "\C-c\C-q" 'ada-xref-refresh)
359 (define-key map "\C-c\C-r" 'ada-show-references)
360 (define-key map "\C-c\M-r" 'ada-build-run)
361 (define-key map "\C-c\C-s" 'ada-goto-previous-pos)
362 (define-key map "\C-c\C-v" 'ada-build-check)
363 (define-key map "\C-c\C-w" 'ada-case-adjust-at-point)
364 (define-key map "\C-c\C-x" 'ada-show-overriding)
365 (define-key map "\C-c\M-x" 'ada-show-overridden)
366 (define-key map "\C-c\C-y" 'ada-case-create-exception)
367 (define-key map "\C-c\M-y" 'ada-case-create-partial-exception)
368 (define-key map [C-down-mouse-3] 'ada-popup-menu)
369
370 map
371 ) "Local keymap used for Ada mode.")
372
373 (defvar ada-mode-menu (make-sparse-keymap "Ada"))
374 (easy-menu-define ada-mode-menu ada-mode-map "Menu keymap for Ada mode"
375 '("Ada"
376 ("Help"
377 ["Ada Mode" (info "ada-mode") t]
378 ["Ada Reference Manual" (info "arm2012") t]
379 ["Key bindings" describe-bindings t]
380 )
381 ["Customize" (customize-group 'ada) t]
382 ("Project files"
383 ["Find and select project ..." ada-build-prompt-select-prj-file t]
384 ["Select project ..." ada-prj-select t]
385 ["Show project" ada-prj-show t]
386 )
387 ("Build"
388 ["Next compilation error" next-error t]
389 ["Show secondary error" ada-show-secondary-error t]
390 ["Fix compilation error" ada-fix-compiler-error t]
391 ["Show last parse error" ada-show-parse-error t]
392 ["Check syntax" ada-build-check t]
393 ["Show main" ada-build-show-main t]
394 ["Build" ada-build-make t]
395 ["Set main and Build" ada-build-set-make t]
396 ["Run" ada-build-run t]
397 )
398 ("Navigate"
399 ["Other file" ada-find-other-file t]
400 ["Other file don't find decl" ada-find-other-file-noset t]
401 ["Goto declaration/body" ada-goto-declaration t]
402 ["Goto next statement keyword" ada-next-statement-keyword t]
403 ["Goto declaration start" ada-goto-declaration-start t]
404 ["Goto declaration end" ada-goto-declaration-end t]
405 ["Show parent declarations" ada-show-declaration-parents t]
406 ["Show references" ada-show-references t]
407 ["Show overriding" ada-show-overriding t]
408 ["Show overridden" ada-show-overridden t]
409 ["Goto prev position" ada-goto-previous-pos t]
410 )
411 ("Edit"
412 ["Expand skeleton" ada-expand t]
413 ["Indent line or selection" indent-for-tab-command t]
414 ["Indent current statement" ada-indent-statement t]
415 ["Indent lines in file" (indent-region (point-min) (point-max)) t]
416 ["Align" ada-align t]
417 ["Comment/uncomment selection" comment-dwim t]
418 ["Fill comment paragraph" ada-fill-comment-paragraph t]
419 ["Fill comment paragraph justify" (ada-fill-comment-paragraph 'full) t]
420 ["Fill comment paragraph postfix" (ada-fill-comment-paragraph 'full t) t]
421 ["Make body for subprogram" ada-make-subprogram-body t]
422 )
423 ("Casing"
424 ["Create full exception" ada-case-create-exception t]
425 ["Create partial exception" ada-case-create-partial-exception t]
426 ["Adjust case at point" ada-case-adjust-at-point t]
427 ["Adjust case region" ada-case-adjust-region t]
428 ["Adjust case buffer" ada-case-adjust-buffer t]
429 )
430 ("Misc"
431 ["Show last parse error" ada-show-parse-error t]
432 ["Show xref tool buffer" ada-show-xref-tool-buffer t]
433 ["Refresh cross reference cache" ada-xref-refresh t]
434 ["Reset parser" ada-reset-parser t]
435 )))
436 (ada-case-activate-keys)
437
438 ;; This doesn't need to be buffer-local because there can be only one
439 ;; popup menu at a time.
440 (defvar ada-context-menu-on-identifier nil)
441
442 (easy-menu-define ada-context-menu nil
443 "Context menu keymap for Ada mode"
444 '("Ada"
445 ["Make body for subprogram" ada-make-subprogram-body t]
446 ["Goto declaration/body" ada-goto-declaration :included ada-context-menu-on-identifier]
447 ["Show parent declarations" ada-show-declaration-parents :included ada-context-menu-on-identifier]
448 ["Show references" ada-show-references :included ada-context-menu-on-identifier]
449 ["Show overriding" ada-show-overriding :included ada-context-menu-on-identifier]
450 ["Show overridden" ada-show-overridden :included ada-context-menu-on-identifier]
451 ["Expand skeleton" ada-expand t]
452 ["Create full case exception" ada-case-create-exception t]
453 ["Create partial case exception" ada-case-create-partial-exception t]
454
455 ["-" nil nil]
456 ["Align" ada-align t]
457 ["Adjust case at point" ada-case-adjust-at-point (not (use-region-p))]
458 ["Adjust case region" ada-case-adjust-region (use-region-p)]
459 ["Indent current statement" ada-indent-statement t]
460 ["Goto next statement keyword" ada-next-statement-keyword t]
461 ["Goto prev statement keyword" ada-next-statement-keyword t]
462 ["Other File" ada-find-other-file t]
463 ["Other file don't find decl" ada-find-other-file-noset t]))
464
465 (defun ada-popup-menu (position)
466 "Pops up a `ada-context-menu', with `ada-context-menu-on-identifer' set appropriately.
467 POSITION is the location the mouse was clicked on.
468 Sets `ada-context-menu-last-point' to the current position before
469 displaying the menu. When a function from the menu is called,
470 point is where the mouse button was clicked."
471 (interactive "e")
472
473 (mouse-set-point last-input-event)
474
475 (setq ada-context-menu-on-identifier
476 (and (char-after)
477 (or (= (char-syntax (char-after)) ?w)
478 (= (char-after) ?_))
479 (not (ada-in-string-or-comment-p))
480 (save-excursion (skip-syntax-forward "w")
481 (not (ada-after-keyword-p)))
482 ))
483 (popup-menu ada-context-menu)
484 )
485
486 (defun ada-indent-newline-indent ()
487 "insert a newline, indent the old and new lines."
488 (interactive "*")
489 ;; point may be in the middle of a word, so insert newline first,
490 ;; then go back and indent.
491 (newline)
492 (forward-char -1)
493 (funcall indent-line-function)
494 (forward-char 1)
495 (funcall indent-line-function))
496
497 (defvar ada-indent-statement nil
498 ;; indentation function
499 "Function to indent the statement/declaration point is in or after.
500 Function is called with no arguments.")
501
502 (defun ada-indent-statement ()
503 "Indent current statement."
504 (interactive)
505 (when ada-indent-statement
506 (funcall ada-indent-statement)))
507
508 (defvar ada-expand nil
509 ;; skeleton function
510 "Function to call to expand tokens (ie insert skeletons).")
511
512 (defun ada-expand ()
513 "Expand previous word into a statement skeleton."
514 (interactive)
515 (when ada-expand
516 (funcall ada-expand)))
517
518 ;;;; abbrev, align
519
520 (defvar ada-mode-abbrev-table nil
521 "Local abbrev table for Ada mode.")
522
523 (defvar ada-align-rules
524 '((ada-declaration-assign
525 (regexp . "[^:]\\(\\s-*\\)\\(:\\)[^:]")
526 (valid . (lambda () (ada-align-valid)))
527 (repeat . t)
528 (modes . '(ada-mode)))
529 (ada-associate
530 (regexp . "[^=]\\(\\s-*\\)\\(=>\\)")
531 (valid . (lambda () (ada-align-valid)))
532 (modes . '(ada-mode)))
533 (ada-comment
534 (regexp . "\\(\\s-*\\)--")
535 (valid . (lambda () (ada-align-valid)))
536 (modes . '(ada-mode)))
537 (ada-use
538 (regexp . "\\(\\s-*\\)\\<\\(use\\s-\\)")
539 (valid . (lambda () (ada-align-valid)))
540 (modes . '(ada-mode)))
541 (ada-at
542 (regexp . "\\(\\s-+\\)\\(at\\)\\>")
543 (valid . (lambda () (ada-align-valid)))
544 (modes . '(ada-mode))))
545 "Rules to use to align different lines.")
546
547 (defun ada-align-valid ()
548 "See use in `ada-align-rules'."
549 (save-excursion
550 ;; we don't put "when (match-beginning n)" here; missing a match
551 ;; is a bug in the regexp.
552 (goto-char (or (match-beginning 2) (match-beginning 1)))
553 (not (ada-in-string-or-comment-p))))
554
555 (defconst ada-align-region-separate
556 (eval-when-compile
557 (concat
558 "^\\s-*\\($\\|\\("
559 "begin\\|"
560 "declare\\|"
561 "else\\|"
562 "end\\|"
563 "exception\\|"
564 "for\\|"
565 "function\\|"
566 "generic\\|"
567 "if\\|"
568 "is\\|"
569 "procedure\\|"
570 "private\\|"
571 "record\\|"
572 "return\\|"
573 "type\\|"
574 "when"
575 "\\)\\>\\)"))
576 "See the variable `align-region-separate' for more information.")
577
578 (defun ada-align ()
579 "If region is active, apply 'align'. If not, attempt to align
580 current construct."
581 (interactive)
582 (if (use-region-p)
583 (progn
584 (align (region-beginning) (region-end))
585 (deactivate-mark))
586
587 ;; else see if we are in a construct we know how to align
588 (cond
589 ((ada-in-paramlist-p)
590 (ada-format-paramlist))
591
592 (t
593 (align-current))
594 )))
595
596 (defvar ada-in-paramlist-p nil
597 ;; Supplied by indentation engine parser
598 "Function to return t if point is inside the parameter-list of a subprogram declaration.
599 Function is called with no arguments.")
600
601 (defun ada-in-paramlist-p ()
602 "Return t if point is inside the parameter-list of a subprogram declaration."
603 (when ada-in-paramlist-p
604 (funcall ada-in-paramlist-p)))
605
606 (defun ada-format-paramlist ()
607 "Reformat the parameter list point is in."
608 (interactive)
609 (ada-goto-open-paren)
610 (funcall indent-line-function); so new list is indented properly
611
612 (let* ((inibit-modification-hooks t)
613 (begin (point))
614 (delend (progn (forward-sexp) (point))); just after matching closing paren
615 (end (progn (backward-char) (forward-comment (- (point))) (point))); end of last parameter-declaration
616 (multi-line (> end (save-excursion (goto-char begin) (line-end-position))))
617 (paramlist (ada-scan-paramlist (1+ begin) end)))
618
619 (when paramlist
620 ;; delete the original parameter-list
621 (delete-region begin delend)
622
623 ;; insert the new parameter-list
624 (goto-char begin)
625 (if multi-line
626 (ada-insert-paramlist-multi-line paramlist)
627 (ada-insert-paramlist-single-line paramlist)))
628 ))
629
630 (defvar ada-scan-paramlist nil
631 ;; Supplied by indentation engine parser
632 "Function to scan a region, return a list of subprogram parameter declarations (in inverse declaration order).
633 Function is called with two args BEGIN END (the region).
634 Each parameter declaration is represented by a list
635 '((identifier ...) in-p out-p not-null-p access-p constant-p protected-p type default)."
636 ;; mode is 'in | out | in out | [not null] access [constant | protected]'
637 ;; IMPROVEME: handle single-line trailing comments, or longer comments, in paramlist?
638 )
639
640 (defun ada-scan-paramlist (begin end)
641 (when ada-scan-paramlist
642 (funcall ada-scan-paramlist begin end)))
643
644 (defun ada-insert-paramlist-multi-line (paramlist)
645 "Insert a multi-line formatted PARAMLIST in the buffer."
646 (let ((i (length paramlist))
647 param
648 j
649 len
650 (ident-len 0)
651 (type-len 0)
652 (in-p nil)
653 (out-p nil)
654 (not-null-p nil)
655 (access-p nil)
656 ident-col
657 colon-col
658 out-col
659 type-col
660 default-col)
661
662 ;; accumulate info across all params
663 (while (not (zerop i))
664 (setq i (1- i))
665 (setq param (nth i paramlist))
666
667 ;; identifier list
668 (setq len 0
669 j 0)
670 (mapc (lambda (ident)
671 (setq j (1+ j))
672 (setq len (+ len (length ident))))
673 (nth 0 param))
674 (setq len (+ len (* 2 (1- j)))); space for commas
675 (setq ident-len (max ident-len len))
676
677 ;; we align the defaults after the types that have defaults, not after all types.
678 ;; "constant", "protected" are treated as part of 'type'
679 (when (nth 8 param)
680 (setq type-len
681 (max type-len
682 (+ (length (nth 7 param))
683 (if (nth 5 param) 10 0); "constant "
684 (if (nth 6 param) 10 0); protected
685 ))))
686
687 (setq in-p (or in-p (nth 1 param)))
688 (setq out-p (or out-p (nth 2 param)))
689 (setq not-null-p (or not-null-p (nth 3 param)))
690 (setq access-p (or access-p (nth 4 param)))
691 )
692
693 (let ((space-before-p (save-excursion (skip-chars-backward " \t") (not (bolp))))
694 (space-after-p (save-excursion (skip-chars-forward " \t") (not (or (= (char-after) ?\;) (eolp))))))
695 (when space-before-p
696 ;; paramlist starts on same line as subprogram identifier; clean
697 ;; up whitespace. Allow for code on same line as closing paren
698 ;; ('return' or ';').
699 (skip-syntax-forward " ")
700 (delete-char (- (skip-syntax-backward " ")))
701 (if space-after-p
702 (progn
703 (insert " ")
704 (forward-char -1))
705 (insert " "))
706 ))
707
708 (insert "(")
709
710 ;; compute columns.
711 (setq ident-col (current-column))
712 (setq colon-col (+ ident-col ident-len 1))
713 (setq out-col (+ colon-col (if in-p 5 0))); ": in "
714 (setq type-col
715 (+ colon-col
716 (cond
717 (not-null-p 18); ": not null access "
718 (access-p 9); ": access"
719 ((and in-p out-p) 9); ": in out "
720 (out-p 6); ": out "
721 (in-p 5); ": in "
722 (t 2)))); ": "
723
724 (setq default-col (+ 1 type-col type-len))
725
726 (setq i (length paramlist))
727 (while (not (zerop i))
728 (setq i (1- i))
729 (setq param (nth i paramlist))
730
731 ;; insert identifiers, space and colon
732 (mapc (lambda (ident)
733 (insert ident)
734 (insert ", "))
735 (nth 0 param))
736 (delete-char -2); last ", "
737 (indent-to colon-col)
738 (insert ": ")
739
740 (when (nth 1 param)
741 (insert "in "))
742
743 (when (nth 2 param)
744 (indent-to out-col)
745 (insert "out "))
746
747 (when (nth 3 param)
748 (insert "not null "))
749
750 (when (nth 4 param)
751 (insert "access "))
752
753 (indent-to type-col)
754 (when (nth 5 param)
755 (insert "constant "))
756 (when (nth 6 param)
757 (insert "protected "))
758 (insert (nth 7 param)); type
759
760 (when (nth 8 param); default
761 (indent-to default-col)
762 (insert ":= ")
763 (insert (nth 8 param)))
764
765 (if (zerop i)
766 (insert ")")
767 (insert ";")
768 (newline)
769 (indent-to ident-col))
770 )
771 ))
772
773 (defun ada-insert-paramlist-single-line (paramlist)
774 "Insert a single-line formatted PARAMLIST in the buffer."
775 (let ((i (length paramlist))
776 param)
777
778 ;; clean up whitespace
779 (skip-syntax-forward " ")
780 (delete-char (- (skip-syntax-backward " ")))
781 (insert " (")
782
783 (setq i (length paramlist))
784 (while (not (zerop i))
785 (setq i (1- i))
786 (setq param (nth i paramlist))
787
788 ;; insert identifiers, space and colon
789 (mapc (lambda (ident)
790 (insert ident)
791 (insert ", "))
792 (nth 0 param))
793 (delete-char -2); last ", "
794
795 (insert " : ")
796
797 (when (nth 1 param)
798 (insert "in "))
799
800 (when (nth 2 param)
801 (insert "out "))
802
803 (when (nth 3 param)
804 (insert "not null "))
805
806 (when (nth 4 param)
807 (insert "access "))
808
809 (when (nth 5 param)
810 (insert "constant "))
811 (when (nth 6 param)
812 (insert "protected "))
813 (insert (nth 7 param)); type
814
815 (when (nth 8 param); default
816 (insert " := ")
817 (insert (nth 8 param)))
818
819 (if (zerop i)
820 (if (= (char-after) ?\;)
821 (insert ")")
822 (insert ") "))
823 (insert "; "))
824 )
825 ))
826
827 (defvar ada-reset-parser nil
828 ;; Supplied by indentation engine parser
829 "Function to reset parser, to clear confused state."
830 )
831
832 (defun ada-reset-parser ()
833 (interactive)
834 (when ada-reset-parser
835 (funcall ada-reset-parser)))
836
837 (defvar ada-show-parse-error nil
838 ;; Supplied by indentation engine parser
839 "Function to show last error reported by indentation parser."
840 )
841
842 (defun ada-show-parse-error ()
843 (interactive)
844 (when ada-show-parse-error
845 (funcall ada-show-parse-error)))
846
847 ;;;; auto-casing
848
849 (defvar ada-case-full-exceptions '()
850 "Alist of words (entities) that have special casing, built from
851 `ada-case-exception-file' full word exceptions. Indexed by
852 properly cased word; value is t.")
853
854 (defvar ada-case-partial-exceptions '()
855 "Alist of partial words that have special casing, built from
856 `ada-case-exception-file' partial word exceptions. Indexed by
857 properly cased word; value is t.")
858
859 (defun ada-case-save-exceptions (full-exceptions partial-exceptions file-name)
860 "Save FULL-EXCEPTIONS, PARTIAL-EXCEPTIONS to the file FILE-NAME."
861 (with-temp-file (expand-file-name file-name)
862 (mapc (lambda (x) (insert (car x) "\n"))
863 (sort (copy-sequence full-exceptions)
864 (lambda(a b) (string< (car a) (car b)))))
865 (mapc (lambda (x) (insert "*" (car x) "\n"))
866 (sort (copy-sequence partial-exceptions)
867 (lambda(a b) (string< (car a) (car b)))))
868 ))
869
870 (defun ada-case-read-exceptions (file-name)
871 "Read the content of the casing exception file FILE-NAME.
872 Return (cons full-exceptions partial-exceptions)."
873 (setq file-name (expand-file-name (substitute-in-file-name file-name)))
874 (if (file-readable-p file-name)
875 (let (full-exceptions partial-exceptions word)
876 (with-temp-buffer
877 (insert-file-contents file-name)
878 (while (not (eobp))
879
880 (setq word (buffer-substring-no-properties
881 (point) (save-excursion (skip-syntax-forward "w_") (point))))
882
883 (if (char-equal (string-to-char word) ?*)
884 ;; partial word exception
885 (progn
886 (setq word (substring word 1))
887 (unless (assoc-string word partial-exceptions t)
888 (add-to-list 'partial-exceptions (cons word t))))
889
890 ;; full word exception
891 (unless (assoc-string word full-exceptions t)
892 (add-to-list 'full-exceptions (cons word t))))
893
894 (forward-line 1))
895 )
896 (cons full-exceptions partial-exceptions))
897
898 ;; else file not readable; might be a new project with no
899 ;; exceptions yet, so just warn user, return empty pair
900 (message "'%s' is not a readable file." file-name)
901 '(nil . nil)
902 ))
903
904 (defun ada-case-merge-exceptions (result new)
905 "Merge NEW exeptions into RESULT.
906 An item in both lists has the RESULT value."
907 (dolist (item new)
908 (unless (assoc-string (car item) result t)
909 (add-to-list 'result item)))
910 result)
911
912 (defun ada-case-merge-all-exceptions (exceptions)
913 "Merge EXCEPTIONS into `ada-case-full-exceptions', `ada-case-partial-exceptions'."
914 (setq ada-case-full-exceptions (ada-case-merge-exceptions ada-case-full-exceptions (car exceptions)))
915 (setq ada-case-partial-exceptions (ada-case-merge-exceptions ada-case-partial-exceptions (cdr exceptions))))
916
917 (defun ada-case-read-all-exceptions ()
918 "Read case exceptions from all files in `ada-case-exception-file',
919 replacing current values of `ada-case-full-exceptions', `ada-case-partial-exceptions'."
920 (interactive)
921 (setq ada-case-full-exceptions '()
922 ada-case-partial-exceptions '())
923
924 (when (ada-prj-get 'casing)
925 (dolist (file (ada-prj-get 'casing))
926 (ada-case-merge-all-exceptions (ada-case-read-exceptions file))))
927 )
928
929 (defun ada-case-add-exception (word exceptions)
930 "Add case exception WORD to EXCEPTIONS, replacing current entry, if any."
931 (if (assoc-string word exceptions t)
932 (setcar (assoc-string word exceptions t) word)
933 (add-to-list 'exceptions (cons word t)))
934 exceptions)
935
936 (defun ada-case-create-exception (&optional word file-name partial)
937 "Define WORD as an exception for the casing system, save it in FILE-NAME.
938 If PARTIAL is non-nil, create a partial word exception. WORD
939 defaults to the active region, or the word at point. User is
940 prompted to choose a file from project variable casing if it is a
941 list."
942 (interactive)
943 (let ((casing (ada-prj-get 'casing)))
944 (setq file-name
945 (cond
946 (file-name file-name)
947
948 ((< 1 (length casing))
949 (completing-read "case exception file: " casing
950 nil ;; predicate
951 t ;; require-match
952 nil ;; initial-input
953 nil ;; hist
954 (car casing) ;; default
955 ))
956 ((= 1 (length casing))
957 (car casing))
958
959 (t
960 (if ada-prj-current-file
961 (error "No exception file specified; set `casing' in project file.")
962 ;; IMPROVEME: could prompt, but then need to write to actual project file
963 ;; (let ((temp
964 ;; (read-file-name
965 ;; "No exception file specified; adding to project. file: ")))
966 ;; (message "remember to add %s to project file" temp)
967 ;; (ada-prj-put 'casing temp)
968 ;; temp)
969 (error "No exception file specified, and no project active. See variable `ada-case-exception-file'.")))
970 )))
971
972 (unless word
973 (if (use-region-p)
974 (setq word (buffer-substring-no-properties (region-beginning) (region-end)))
975 (save-excursion
976 (skip-syntax-backward "w_")
977 (setq word
978 (buffer-substring-no-properties
979 (point)
980 (progn (skip-syntax-forward "w_") (point))
981 )))))
982
983 (let* ((exceptions (ada-case-read-exceptions file-name))
984 (full-exceptions (car exceptions))
985 (partial-exceptions (cdr exceptions)))
986
987 (cond
988 ((null partial)
989 (setq ada-case-full-exceptions (ada-case-add-exception word ada-case-full-exceptions))
990 (setq full-exceptions (ada-case-add-exception word full-exceptions)))
991
992 (t
993 (setq ada-case-partial-exceptions (ada-case-add-exception word ada-case-partial-exceptions))
994 (setq partial-exceptions (ada-case-add-exception word partial-exceptions)))
995 )
996 (ada-case-save-exceptions full-exceptions partial-exceptions file-name)
997 (message "created %s case exception '%s' in file '%s'"
998 (if partial "partial" "full")
999 word
1000 file-name)
1001 ))
1002
1003 (defun ada-case-create-partial-exception ()
1004 "Define active region or word at point as a partial word exception.
1005 User is prompted to choose a file from project variable casing if it is a list."
1006 (interactive)
1007 (ada-case-create-exception nil nil t))
1008
1009 (defun ada-in-numeric-literal-p ()
1010 "Return t if point is after a prefix of a numeric literal."
1011 (looking-back "\\([0-9]+#[0-9a-fA-F_]+\\)"))
1012
1013 (defvar ada-keywords nil
1014 "List of Ada keywords for current `ada-language-version'.")
1015
1016 (defun ada-after-keyword-p ()
1017 "Return non-nil if point is after an element of `ada-keywords'."
1018 (let ((word (buffer-substring-no-properties
1019 (save-excursion (skip-syntax-backward "w_") (point))
1020 (point))))
1021 (member (downcase word) ada-keywords)))
1022
1023 (defun ada-mixed-case (start end)
1024 "Adjust case of region START END to Mixed_Case."
1025 (let ((done nil)
1026 next)
1027 (if ada-case-strict
1028 (downcase-region start end))
1029 (goto-char start)
1030 (while (not done)
1031 (setq next
1032 (or
1033 (save-excursion (when (search-forward "_" end t) (point-marker)))
1034 (copy-marker (1+ end))))
1035
1036 ;; upcase first char
1037 (insert-char (upcase (following-char)) 1)
1038 (delete-char 1)
1039
1040 (goto-char next)
1041 (if (< (point) end)
1042 (setq start (point))
1043 (setq done t))
1044 )))
1045
1046 (defun ada-case-adjust-identifier ()
1047 "Adjust case of the previous word as an identifier.
1048 Uses `ada-case-identifier', with exceptions defined in
1049 `ada-case-full-exceptions', `ada-case-partial-exceptions'."
1050 (interactive)
1051 (save-excursion
1052 (let ((end (point-marker))
1053 (start (progn (skip-syntax-backward "w_") (point)))
1054 match
1055 next
1056 (done nil))
1057
1058 (if (setq match (assoc-string (buffer-substring-no-properties start end) ada-case-full-exceptions t))
1059 ;; full word exception
1060 (progn
1061 ;; 'save-excursion' puts a marker at 'end'; if we do
1062 ;; 'delete-region' first, it moves that marker to 'start',
1063 ;; then 'insert' inserts replacement text after the
1064 ;; marker, defeating 'save-excursion'. So we do 'insert' first.
1065 (insert (car match))
1066 (delete-region (point) end))
1067
1068 ;; else apply ada-case-identifier
1069 (funcall ada-case-identifier start end)
1070
1071 ;; apply partial-exceptions
1072 (goto-char start)
1073 (while (not done)
1074 (setq next
1075 (or
1076 (save-excursion (when (search-forward "_" end t) (point-marker)))
1077 (copy-marker (1+ end))))
1078
1079 (when (setq match (assoc-string (buffer-substring-no-properties start (1- next))
1080 ada-case-partial-exceptions t))
1081 ;; see comment above at 'full word exception' for why
1082 ;; we do insert first.
1083 (insert (car match))
1084 (delete-region (point) (1- next)))
1085
1086 (goto-char next)
1087 (if (< (point) end)
1088 (setq start (point))
1089 (setq done t))
1090 )))))
1091
1092 (defun ada-case-adjust (&optional typed-char in-comment)
1093 "Adjust the case of the word before point.
1094 When invoked interactively, TYPED-CHAR must be
1095 `last-command-event', and it must not have been inserted yet.
1096 If IN-COMMENT is non-nil, adjust case of words in comments."
1097 (when (not (bobp))
1098 (when (save-excursion
1099 (forward-char -1); back to last character in word
1100 (and (not (bobp))
1101 (eq (char-syntax (char-after)) ?w); it can be capitalized
1102
1103 (not (and (eq typed-char ?')
1104 (eq (char-before (point)) ?'))); character literal
1105
1106 (or in-comment
1107 (not (ada-in-string-or-comment-p)))
1108 ;; we sometimes want to capitialize an Ada identifier
1109 ;; referenced in a comment, via
1110 ;; ada-case-adjust-at-point.
1111
1112 (not (ada-in-numeric-literal-p))
1113 ))
1114
1115 ;; The indentation engine may trigger a reparse on
1116 ;; non-whitespace changes, but we know we don't need to reparse
1117 ;; for this change (assuming the user has not abused case
1118 ;; exceptions!).
1119 (let ((inhibit-modification-hooks t))
1120 (cond
1121 ;; Some attributes are also keywords, but captialized as
1122 ;; attributes. So check for attribute first.
1123 ((and
1124 (not in-comment)
1125 (save-excursion
1126 (skip-syntax-backward "w_")
1127 (eq (char-before) ?')))
1128 (ada-case-adjust-identifier))
1129
1130 ((and
1131 (not in-comment)
1132 (not (eq typed-char ?_))
1133 (ada-after-keyword-p))
1134 (funcall ada-case-keyword -1))
1135
1136 (t (ada-case-adjust-identifier))
1137 ))
1138 )))
1139
1140 (defun ada-case-adjust-at-point (&optional in-comment)
1141 "Adjust case of word at point, move to end of word.
1142 With prefix arg, adjust case even if in comment."
1143 (interactive "P")
1144 (when
1145 (and (not (eobp))
1146 ;; we use '(syntax-after (point))' here, not '(char-syntax
1147 ;; (char-after))', because the latter does not respect
1148 ;; ada-syntax-propertize.
1149 (memq (syntax-class (syntax-after (point))) '(2 3)))
1150 (skip-syntax-forward "w_"))
1151 (ada-case-adjust nil in-comment))
1152
1153 (defun ada-case-adjust-region (begin end)
1154 "Adjust case of all words in region BEGIN END."
1155 (interactive "r")
1156 (narrow-to-region begin end)
1157 (save-excursion
1158 (goto-char begin)
1159 (while (not (eobp))
1160 (forward-comment (point-max))
1161 (skip-syntax-forward "^w_")
1162 (skip-syntax-forward "w_")
1163 (ada-case-adjust)))
1164 (widen))
1165
1166 (defun ada-case-adjust-buffer ()
1167 "Adjust case of current buffer."
1168 (interactive)
1169 (ada-case-adjust-region (point-min) (point-max)))
1170
1171 (defun ada-case-adjust-interactive (arg)
1172 "If `ada-auto-case' is non-nil, adjust the case of the previous word, and process the character just typed.
1173 To be bound to keys that should cause auto-casing.
1174 ARG is the prefix the user entered with \\[universal-argument]."
1175 (interactive "P")
1176
1177 ;; character typed has not been inserted yet
1178 (let ((lastk last-command-event))
1179
1180 (cond
1181 ((eq lastk ?\n)
1182 (when ada-auto-case
1183 (ada-case-adjust lastk))
1184 (funcall ada-lfd-binding))
1185
1186 ((memq lastk '(?\r return))
1187 (when ada-auto-case
1188 (ada-case-adjust lastk))
1189 (funcall ada-ret-binding))
1190
1191 (t
1192 (when ada-auto-case
1193 (ada-case-adjust lastk))
1194 (self-insert-command (prefix-numeric-value arg)))
1195 )))
1196
1197 ;;;; project files
1198
1199 ;; An Emacs Ada mode project file can specify several things:
1200 ;;
1201 ;; - a compiler-specific project file
1202 ;;
1203 ;; - compiler-specific environment variables
1204 ;;
1205 ;; - other compiler-specific things (see the compiler support elisp code)
1206 ;;
1207 ;; - a list of source directories (in addition to those specified in the compiler project file)
1208 ;;
1209 ;; - a casing exception file
1210 ;;
1211 ;; All of the data used by Emacs Ada mode functions specified in a
1212 ;; project file is stored in a property list. The property list is
1213 ;; stored in an alist indexed by the project file name, so multiple
1214 ;; project files can be selected without re-parsing them (some
1215 ;; compiler project files can take a long time to parse).
1216
1217 (defvar ada-prj-alist nil
1218 "Alist holding currently parsed Emacs Ada project files. Indexed by absolute project file name.")
1219
1220 (defvar ada-prj-current-file nil
1221 "Current Emacs Ada project file.")
1222
1223 (defvar ada-prj-current-project nil
1224 "Current Emacs Ada mode project; a plist.")
1225
1226 (defun ada-prj-get (prop &optional plist)
1227 "Return value of PROP in PLIST.
1228 Optional PLIST defaults to `ada-prj-current-project'."
1229 (let ((prj (or plist ada-prj-current-project)))
1230 (if prj
1231 (plist-get prj prop)
1232
1233 ;; no project, just use default vars
1234 ;; must match code in ada-prj-default
1235 (cl-case plist
1236 (ada_compiler ada-compiler)
1237 (auto_case ada-auto-case)
1238 (case_keyword ada-case-keyword)
1239 (case_identifier ada-case-identifier)
1240 (case_strict ada-case-strict)
1241 (casing (if (listp ada-case-exception-file)
1242 ada-case-exception-file
1243 (list ada-case-exception-file)))
1244 (path_sep path-separator)
1245 (proc_env process-environment)
1246 (src_dir (list "."))
1247 (xref_tool ada-xref-tool)
1248 ))))
1249
1250 (defun ada-prj-put (prop val &optional plist)
1251 "Set value of PROP in PLIST to VAL.
1252 Optional PLIST defaults to `ada-prj-current-project'."
1253 (plist-put (or plist ada-prj-current-project) prop val))
1254
1255 (defun ada-require-project-file ()
1256 (unless ada-prj-current-file
1257 (error "no Emacs Ada project file specified")))
1258
1259 (defvar ada-prj-default-list nil
1260 ;; project file parse
1261 "List of functions to add default project variables. Called
1262 with one argument; the default project properties list. Function
1263 should add to the properties list and return it.")
1264
1265 (defvar ada-prj-default-compiler-alist nil
1266 ;; project file parse
1267 "Compiler-specific function to set default project variables.
1268 Indexed by ada-compiler. Called with one argument; the default
1269 project properties list. Function should add to the properties
1270 list and return it.")
1271
1272 (defvar ada-prj-default-xref-alist nil
1273 ;; project file parse
1274 "Xref-tool-specific function to set default project variables.
1275 Indexed by ada-xref-tool. Called with one argument; the default
1276 project properties list. Function should add to the properties
1277 list and return it.")
1278
1279 (defun ada-prj-default ()
1280 "Return the default project properties list.
1281 Include properties set via `ada-prj-default-compiler-alist',
1282 `ada-prj-default-xref-alist'."
1283
1284 (let (project func)
1285 (setq
1286 project
1287 (list
1288 ;; variable name alphabetical order
1289 'ada_compiler ada-compiler
1290 'auto_case ada-auto-case
1291 'case_keyword ada-case-keyword
1292 'case_identifier ada-case-identifier
1293 'case_strict ada-case-strict
1294 'casing (if (listp ada-case-exception-file)
1295 ada-case-exception-file
1296 (list ada-case-exception-file))
1297 'path_sep path-separator;; prj variable so users can override it for their compiler
1298 'proc_env process-environment
1299 'src_dir (list ".")
1300 'xref_tool ada-xref-tool
1301 ))
1302
1303 (cl-dolist (func ada-prj-default-list)
1304 (setq project (funcall func project)))
1305
1306 (setq func (cdr (assq ada-compiler ada-prj-default-compiler-alist)))
1307 (when func (setq project (funcall func project)))
1308 (setq func (cdr (assq ada-xref-tool ada-prj-default-xref-alist)))
1309 (when func (setq project (funcall func project)))
1310 project))
1311
1312 (defvar ada-prj-parser-alist
1313 (mapcar
1314 (lambda (ext) (cons ext 'ada-prj-parse-file-1))
1315 ada-prj-file-extensions)
1316 ;; project file parse
1317 "Alist of parsers for project files, indexed by file extension.
1318 Default provides the minimal Ada mode parser; compiler support
1319 code may add other parsers. Parser is called with two arguments;
1320 the project file name and the current project property
1321 list. Parser must modify or add to the property list and return it.")
1322
1323 ;; This autoloaded because it is often used in Makefiles, and thus
1324 ;; will be the first ada-mode function executed.
1325 ;;;###autoload
1326 (defun ada-parse-prj-file (prj-file)
1327 "Read Emacs Ada or compiler-specific project file PRJ-FILE, set project properties in `ada-prj-alist'."
1328 ;; Not called ada-prj-parse-file for Ada mode 4.01 compatibility
1329 (let ((project (ada-prj-default))
1330 (parser (cdr (assoc (file-name-extension prj-file) ada-prj-parser-alist))))
1331
1332 (setq prj-file (expand-file-name prj-file))
1333
1334 (unless (file-readable-p prj-file)
1335 (error "Project file '%s' is not readable" prj-file))
1336
1337 (if parser
1338 ;; parser may reference the "current project", so bind that now.
1339 (let ((ada-prj-current-project project)
1340 (ada-prj-current-file prj-file))
1341 (setq project (funcall parser prj-file project)))
1342 (error "no project file parser defined for '%s'" prj-file))
1343
1344 ;; Store the project properties
1345 (if (assoc prj-file ada-prj-alist)
1346 (setcdr (assoc prj-file ada-prj-alist) project)
1347 (add-to-list 'ada-prj-alist (cons prj-file project)))
1348
1349 ;; return t for interactive use
1350 t))
1351
1352 (defun ada-prj-reparse-select-current ()
1353 "Reparse the current project file, re-select it.
1354 Useful when the project file has been edited."
1355 (ada-parse-prj-file ada-prj-current-file)
1356 (ada-select-prj-file ada-prj-current-file))
1357
1358 (defvar ada-prj-parse-one-compiler nil
1359 ;; project file parse
1360 "Compiler-specific function to process one Ada project property.
1361 Indexed by project variable ada_compiler.
1362 Called with three arguments; the property name, property value,
1363 and project properties list. Function should add to or modify the
1364 properties list and return it, or return nil if the name is not
1365 recognized.")
1366
1367 (defvar ada-prj-parse-one-xref nil
1368 ;; project file parse
1369 "Xref-tool-specific function to process one Ada project property.
1370 Indexed by project variable xref_tool.
1371 Called with three arguments; the property name, property value,
1372 and project properties list. Function should add to or modify the
1373 properties list and return it, or return nil if the name is not
1374 recognized.")
1375
1376 (defvar ada-prj-parse-final-compiler nil
1377 ;; project file parse
1378 "Alist of compiler-specific functions to finish processing Ada project properties.
1379 Indexed by project variable ada_compiler.
1380 Called with one argument; the project properties list. Function
1381 should add to or modify the list and return it.")
1382
1383 (defvar ada-prj-parse-final-xref nil
1384 ;; project file parse
1385 "Alist of xref-tool-specific functions to finish processing Ada project properties.
1386 Indexed by project variable xref_tool.
1387 Called with one argument; the project properties list. Function
1388 should add to or modify the list and return it.")
1389
1390 (defun ada-prj-parse-file-1 (prj-file project)
1391 "Parse the Ada mode project file PRJ-FILE, set project properties in PROJECT.
1392 Return new value of PROJECT."
1393 (let (;; fields that are lists or that otherwise require special processing
1394 casing src_dir
1395 tmp-prj
1396 (parse-one-compiler (cdr (assoc ada-compiler ada-prj-parse-one-compiler)))
1397 (parse-final-compiler (cdr (assoc ada-compiler ada-prj-parse-final-compiler)))
1398 (parse-one-xref (cdr (assoc ada-xref-tool ada-prj-parse-one-xref)))
1399 (parse-final-xref (cdr (assoc ada-xref-tool ada-prj-parse-final-xref))))
1400
1401 (with-current-buffer (find-file-noselect prj-file)
1402 (goto-char (point-min))
1403
1404 ;; process each line
1405 (while (not (eobp))
1406
1407 ;; ignore lines that don't have the format "name=value", put
1408 ;; 'name', 'value' in match-string.
1409 (when (looking-at "^\\([^=\n]+\\)=\\(.*\\)")
1410 (cond
1411 ;; variable name alphabetical order
1412
1413 ((string= (match-string 1) "ada_compiler")
1414 (let ((comp (intern (match-string 2))))
1415 (setq project (plist-put project 'ada_compiler comp))
1416 (setq parse-one-compiler (cdr (assq comp ada-prj-parse-one-compiler)))
1417 (setq parse-final-compiler (cdr (assq comp ada-prj-parse-final-compiler)))))
1418
1419 ((string= (match-string 1) "auto_case")
1420 (setq project (plist-put project 'auto_case (intern (match-string 2)))))
1421
1422 ((string= (match-string 1) "case_keyword")
1423 (setq project (plist-put project 'case_keyword (intern (match-string 2)))))
1424
1425 ((string= (match-string 1) "case_identifier")
1426 (setq project (plist-put project 'case_identifier (intern (match-string 2)))))
1427
1428 ((string= (match-string 1) "case_strict")
1429 (setq project (plist-put project 'case_strict (intern (match-string 2)))))
1430
1431 ((string= (match-string 1) "casing")
1432 (add-to-list 'casing
1433 (expand-file-name
1434 (substitute-in-file-name (match-string 2)))))
1435
1436 ((string= (match-string 1) "el_file")
1437 (let ((file (expand-file-name (substitute-in-file-name (match-string 2)))))
1438 (setq project (plist-put project 'el_file file))
1439 ;; eval now as well as in select, since it might affect parsing
1440 (load-file file)))
1441
1442 ((string= (match-string 1) "src_dir")
1443 (add-to-list 'src_dir
1444 (file-name-as-directory
1445 (expand-file-name (match-string 2)))))
1446
1447 ((string= (match-string 1) "xref_tool")
1448 (let ((xref (intern (match-string 2))))
1449 (setq project (plist-put project 'xref_tool xref))
1450 (setq parse-one-xref (cdr (assq xref ada-prj-parse-one-xref)))
1451 (setq parse-final-xref (cdr (assq xref ada-prj-parse-final-xref)))))
1452
1453 (t
1454 (if (or
1455 (and parse-one-compiler
1456 (setq tmp-prj (funcall parse-one-compiler (match-string 1) (match-string 2) project)))
1457 (and parse-one-xref
1458 (setq tmp-prj (funcall parse-one-xref (match-string 1) (match-string 2) project))))
1459
1460 (setq project tmp-prj)
1461
1462 ;; Any other field in the file is set as an environment
1463 ;; variable or a project file.
1464 (if (= ?$ (elt (match-string 1) 0))
1465 ;; process env var. We don't do expand-file-name
1466 ;; here because the application may be expecting a
1467 ;; simple string.
1468 (let ((process-environment (plist-get project 'proc_env)))
1469 (setenv (substring (match-string 1) 1)
1470 (substitute-in-file-name (match-string 2)))
1471 (setq project
1472 (plist-put project 'proc_env process-environment)))
1473
1474 ;; not recognized; assume it is a user-defined variable like "comp_opt"
1475 (setq project (plist-put project (intern (match-string 1)) (match-string 2)))
1476 )))
1477 ))
1478
1479 (forward-line 1))
1480
1481 );; done reading file
1482
1483 ;; process accumulated lists
1484 (if casing (set 'project (plist-put project 'casing (reverse casing))))
1485 (if src_dir (set 'project (plist-put project 'src_dir (reverse src_dir))))
1486
1487 (when parse-final-compiler
1488 ;; parse-final-compiler may reference the "current project", so
1489 ;; bind that now, to include the properties set above.
1490 (let ((ada-prj-current-project project)
1491 (ada-prj-current-file prj-file))
1492 (setq project (funcall parse-final-compiler project))))
1493
1494 (when parse-final-xref
1495 (let ((ada-prj-current-project project)
1496 (ada-prj-current-file prj-file))
1497 (setq project (funcall parse-final-xref project))))
1498
1499 project
1500 ))
1501
1502 (defvar ada-project-search-path nil
1503 "Search path for finding Ada project files")
1504
1505 (defvar ada-select-prj-compiler nil
1506 "Alist of functions to call for compiler specific project file selection.
1507 Indexed by project variable ada_compiler.")
1508
1509 (defvar ada-deselect-prj-compiler nil
1510 "Alist of functions to call for compiler specific project file deselection.
1511 Indexed by project variable ada_compiler.")
1512
1513 (defvar ada-select-prj-xref-tool nil
1514 "Alist of functions to call for xref-tool specific project file selection.
1515 Indexed by project variable xref_tool.")
1516
1517 (defvar ada-deselect-prj-xref-tool nil
1518 "Alist of functions to call for xref-tool specific project file deselection.
1519 Indexed by project variable xref_tool.")
1520
1521 (defun ada-select-prj-file (prj-file)
1522 "Select PRJ-FILE as the current project file."
1523 (interactive)
1524 (setq prj-file (expand-file-name prj-file))
1525
1526 (setq ada-prj-current-project (cdr (assoc prj-file ada-prj-alist)))
1527
1528 (when (null ada-prj-current-project)
1529 (setq ada-prj-current-file nil)
1530 (error "Project file '%s' was not previously parsed." prj-file))
1531
1532 (let ((func (cdr (assq (ada-prj-get 'ada_compiler) ada-deselect-prj-compiler))))
1533 (when func (funcall func)))
1534
1535 (let ((func (cdr (assq (ada-prj-get 'xref_tool) ada-deselect-prj-xref-tool))))
1536 (when func (funcall func)))
1537
1538 (setq ada-prj-current-file prj-file)
1539
1540 ;; Project file should fully specify what compilers are used,
1541 ;; including what compilation filters they need. There may be more
1542 ;; than just an Ada compiler.
1543 (setq compilation-error-regexp-alist nil)
1544 (setq compilation-filter-hook nil)
1545
1546 (when (ada-prj-get 'el_file)
1547 (load-file (ada-prj-get 'el_file)))
1548
1549 (ada-case-read-all-exceptions)
1550
1551 (setq compilation-search-path (ada-prj-get 'src_dir))
1552 (setq ada-project-search-path (ada-prj-get 'prj_dir))
1553
1554 (let ((func (cdr (assq (ada-prj-get 'ada_compiler) ada-select-prj-compiler))))
1555 (when func (funcall func)))
1556
1557 (let ((func (cdr (assq (ada-prj-get 'xref_tool) ada-select-prj-xref-tool))))
1558 (when func (funcall func)))
1559
1560 ;; return 't', for decent display in message buffer when called interactively
1561 t)
1562
1563 (defun ada-prj-select ()
1564 "Select the current project file from the list of currently available project files."
1565 (interactive)
1566 (ada-select-prj-file (completing-read "project: " ada-prj-alist nil t))
1567 )
1568
1569 (defun ada-prj-show ()
1570 "Show current Emacs Ada mode project file."
1571 (interactive)
1572 (message "current Emacs Ada mode project file: %s" ada-prj-current-file))
1573
1574 (defvar ada-show-xref-tool-buffer nil
1575 ;; Supplied by xref tool
1576 "Function to show process buffer used by xref tool."
1577 )
1578
1579 (defun ada-show-xref-tool-buffer ()
1580 (interactive)
1581 (when ada-show-xref-tool-buffer
1582 (funcall ada-show-xref-tool-buffer)))
1583
1584 ;;;; syntax properties
1585
1586 (defvar ada-mode-syntax-table
1587 (let ((table (make-syntax-table)))
1588 ;; (info "(elisp)Syntax Class Table" "*info syntax class table*")
1589 ;; make-syntax-table sets all alphanumeric to w, etc; so we only
1590 ;; have to add ada-specific things.
1591
1592 ;; string brackets. `%' is the obsolete alternative string
1593 ;; bracket (arm J.2); if we make it syntax class ", it throws
1594 ;; font-lock and indentation off the track, so we use syntax class
1595 ;; $.
1596 (modify-syntax-entry ?% "$" table)
1597 (modify-syntax-entry ?\" "\"" table)
1598
1599 ;; punctuation; operators etc
1600 (modify-syntax-entry ?# "w" table); based number - word syntax, since we don't need the number
1601 (modify-syntax-entry ?& "." table)
1602 (modify-syntax-entry ?* "." table)
1603 (modify-syntax-entry ?+ "." table)
1604 (modify-syntax-entry ?- ". 12" table); operator; see ada-syntax-propertize for double hyphen as comment
1605 (modify-syntax-entry ?. "." table)
1606 (modify-syntax-entry ?/ "." table)
1607 (modify-syntax-entry ?: "." table)
1608 (modify-syntax-entry ?< "." table)
1609 (modify-syntax-entry ?= "." table)
1610 (modify-syntax-entry ?> "." table)
1611 (modify-syntax-entry ?\' "." table); attribute; see ada-syntax-propertize for character literal
1612 (modify-syntax-entry ?\; "." table)
1613 (modify-syntax-entry ?\\ "." table); default is escape; not correct for Ada strings
1614 (modify-syntax-entry ?\| "." table)
1615
1616 ;; and \f and \n end a comment
1617 (modify-syntax-entry ?\f ">" table)
1618 (modify-syntax-entry ?\n ">" table)
1619
1620 (modify-syntax-entry ?_ "_" table); symbol constituents, not word.
1621
1622 (modify-syntax-entry ?\( "()" table)
1623 (modify-syntax-entry ?\) ")(" table)
1624
1625 ;; skeleton placeholder delimiters; see ada-skel.el. We use generic
1626 ;; comment delimiter class, not comment starter/comment ender, so
1627 ;; these can be distinguished from line end.
1628 (modify-syntax-entry ?{ "!" table)
1629 (modify-syntax-entry ?} "!" table)
1630
1631 table
1632 )
1633 "Syntax table to be used for editing Ada source code.")
1634
1635 (defvar ada-syntax-propertize-hook nil
1636 ;; provided by preprocessor, lumped with xref-tool
1637 "Hook run from `ada-syntax-propertize'.
1638 Called by `syntax-propertize', which is called by font-lock in
1639 `after-change-functions'. Therefore, care must be taken to avoid
1640 race conditions with the grammar parser.")
1641
1642 (defun ada-syntax-propertize (start end)
1643 "Assign `syntax-table' properties in accessible part of buffer.
1644 In particular, character constants are set to have string syntax."
1645 ;; (info "(elisp)Syntax Properties")
1646 ;;
1647 ;; called from `syntax-propertize', inside save-excursion with-silent-modifications
1648 (let ((inhibit-read-only t)
1649 (inhibit-point-motion-hooks t))
1650 (goto-char start)
1651 (save-match-data
1652 (while (re-search-forward
1653 (concat
1654 "[^a-zA-Z0-9)]\\('\\)[^'\n]\\('\\)"; 1, 2: character literal, not attribute
1655 "\\|[^a-zA-Z0-9)]\\('''\\)"; 3: character literal '''
1656 "\\|\\(--\\)"; 4: comment start
1657 )
1658 end t)
1659 ;; The help for syntax-propertize-extend-region-functions
1660 ;; implies that 'start end' will always include whole lines, in
1661 ;; which case we don't need
1662 ;; syntax-propertize-extend-region-functions
1663 (cond
1664 ((match-beginning 1)
1665 (put-text-property
1666 (match-beginning 1) (match-end 1) 'syntax-table '(7 . ?'))
1667 (put-text-property
1668 (match-beginning 2) (match-end 2) 'syntax-table '(7 . ?')))
1669 ((match-beginning 3)
1670 (put-text-property
1671 (match-beginning 3) (1+ (match-beginning 3)) 'syntax-table '(7 . ?'))
1672 (put-text-property
1673 (1- (match-end 3)) (match-end 3) 'syntax-table '(7 . ?')))
1674 ((match-beginning 4)
1675 (put-text-property
1676 (match-beginning 4) (match-end 4) 'syntax-table '(11 . nil)))
1677 )))
1678 (run-hook-with-args 'ada-syntax-propertize-hook start end))
1679 )
1680
1681 (defun ada-in-comment-p (&optional parse-result)
1682 "Return t if inside a comment.
1683 If PARSE-RESULT is non-nil, use it instead of calling `syntax-ppss'."
1684 (nth 4 (or parse-result (syntax-ppss))))
1685
1686 (defun ada-in-string-p (&optional parse-result)
1687 "Return t if point is inside a string.
1688 If PARSE-RESULT is non-nil, use it instead of calling `syntax-ppss'."
1689 (nth 3 (or parse-result (syntax-ppss))))
1690
1691 (defun ada-in-string-or-comment-p (&optional parse-result)
1692 "Return t if inside a comment or string.
1693 If PARSE-RESULT is non-nil, use it instead of calling `syntax-ppss'."
1694 (setq parse-result (or parse-result (syntax-ppss)))
1695 (or (ada-in-string-p parse-result) (ada-in-comment-p parse-result)))
1696
1697 (defun ada-in-paren-p (&optional parse-result)
1698 "Return t if point is inside a pair of parentheses.
1699 If PARSE-RESULT is non-nil, use it instead of calling `syntax-ppss'."
1700 (> (nth 0 (or parse-result (syntax-ppss))) 0))
1701
1702 (defun ada-goto-open-paren (&optional offset parse-result)
1703 "Move point to innermost opening paren surrounding current point, plus OFFSET.
1704 Throw error if not in paren. If PARSE-RESULT is non-nil, use it
1705 instead of calling `syntax-ppss'."
1706 (goto-char (+ (or offset 0) (nth 1 (or parse-result (syntax-ppss))))))
1707
1708 ;;;; navigation within and between files
1709
1710 (defvar ada-body-suffixes '(".adb")
1711 "List of possible suffixes for Ada body files.
1712 The extensions should include a `.' if needed.")
1713
1714 (defvar ada-spec-suffixes '(".ads")
1715 "List of possible suffixes for Ada spec files.
1716 The extensions should include a `.' if needed.")
1717
1718 (defvar ada-other-file-alist
1719 '(("\\.ads$" (".adb"))
1720 ("\\.adb$" (".ads")))
1721 "Alist used by `find-file' to find the name of the other package.
1722 See `ff-other-file-alist'.")
1723
1724 (defconst ada-name-regexp
1725 "\\(\\(?:\\sw\\|[_.]\\)+\\)")
1726
1727 (defconst ada-parent-name-regexp
1728 "\\([a-zA-Z0-9_\\.]+\\)\\.[a-zA-Z0-9_]+"
1729 "Regexp for extracting the parent name from fully-qualified name.")
1730
1731 (defvar ada-file-name-from-ada-name nil
1732 ;; determined by ada-xref-tool, set by *-select-prj
1733 "Function called with one parameter ADA-NAME, which is a library
1734 unit name; it should return the filename in which ADA-NAME is
1735 found.")
1736
1737 (defun ada-file-name-from-ada-name (ada-name)
1738 "Return the filename in which ADA-NAME is found."
1739 (ada-require-project-file)
1740 (funcall ada-file-name-from-ada-name ada-name))
1741
1742 (defvar ada-ada-name-from-file-name nil
1743 ;; depends on ada-compiler, per-project
1744 "Function called with one parameter FILE-NAME, which is a library
1745 unit name; it should return the Ada name that should be found in FILE-NAME.")
1746
1747 (defun ada-ada-name-from-file-name (file-name)
1748 "Return the ada-name that should be found in FILE-NAME."
1749 (ada-require-project-file)
1750 (funcall ada-ada-name-from-file-name file-name))
1751
1752 (defun ada-ff-special-extract-parent ()
1753 (setq ff-function-name (match-string 1))
1754 (file-name-nondirectory
1755 (or
1756 (ff-get-file-name
1757 compilation-search-path
1758 (ada-file-name-from-ada-name ff-function-name)
1759 ada-spec-suffixes)
1760 (error "parent '%s' not found; set project file?" ff-function-name))))
1761
1762 (defun ada-ff-special-extract-separate ()
1763 (let ((package-name (match-string 1)))
1764 (save-excursion
1765 (goto-char (match-end 0))
1766 (when (eolp) (forward-char 1))
1767 (skip-syntax-forward " ")
1768 (looking-at
1769 (concat "\\(function\\|package body\\|procedure\\|protected body\\|task body\\)\\s +"
1770 ada-name-regexp))
1771 (setq ff-function-name (match-string 0))
1772 )
1773 (file-name-nondirectory
1774 (or
1775 (ff-get-file-name
1776 compilation-search-path
1777 (ada-file-name-from-ada-name package-name)
1778 ada-body-suffixes)
1779 (error "package '%s' not found; set project file?" package-name)))))
1780
1781 (defun ada-ff-special-with ()
1782 (let ((package-name (match-string 1)))
1783 (setq ff-function-name (concat "^package\\s-+" package-name "\\([^_]\\|$\\)"))
1784 (file-name-nondirectory
1785 (or
1786 (ff-get-file-name
1787 compilation-search-path
1788 (ada-file-name-from-ada-name package-name)
1789 (append ada-spec-suffixes ada-body-suffixes))
1790 (error "package '%s' not found; set project file?" package-name)))
1791 ))
1792
1793 (defun ada-set-ff-special-constructs ()
1794 "Add Ada-specific pairs to `ff-special-constructs'."
1795 (set (make-local-variable 'ff-special-constructs) nil)
1796 (mapc (lambda (pair) (add-to-list 'ff-special-constructs pair))
1797 ;; Each car is a regexp; if it matches at point, the cdr is invoked.
1798 ;; Each cdr should set ff-function-name to a string or regexp
1799 ;; for ada-set-point-accordingly, and return the file name
1800 ;; (sans directory, must include suffix) to go to.
1801 (list
1802 ;; Top level child package declaration (not body), or child
1803 ;; subprogram declaration or body; go to the parent package.
1804 (cons (concat "^\\(?:private[ \t]+\\)?\\(?:package\\|procedure\\|function\\)[ \t]+"
1805 ada-parent-name-regexp "\\(?:;\\|[ \t]+\\|$\\)")
1806 'ada-ff-special-extract-parent)
1807
1808 ;; A "separate" clause.
1809 (cons (concat "^separate[ \t\n]*(" ada-name-regexp ")")
1810 'ada-ff-special-extract-separate)
1811
1812 ;; A "with" clause. Note that it may refer to a procedure body, as well as a spec
1813 (cons (concat "^\\(?:limited[ \t]+\\)?\\(?:private[ \t]+\\)?with[ \t]+" ada-name-regexp)
1814 'ada-ff-special-with)
1815 )))
1816
1817 (defvar ada-which-function nil
1818 ;; supplied by indentation engine
1819 ;;
1820 ;; This is run from ff-pre-load-hook, so ff-function-name may have
1821 ;; been set by ff-treat-special; don't reset it.
1822 "Function called with no parameters; it should return the name
1823 of the package, protected type, subprogram, or task type whose
1824 definition/declaration point is in or just after, or nil. In
1825 addition, if ff-function-name is non-nil, store in
1826 ff-function-name a regexp that will find the function in the
1827 other file.")
1828
1829 (defun ada-which-function ()
1830 "See `ada-which-function' variable."
1831 (interactive)
1832 (when ada-which-function
1833 (funcall ada-which-function)))
1834
1835 (defun ada-add-log-current-function ()
1836 "For `add-log-current-defun-function'; uses `ada-which-function'."
1837 ;; add-log-current-defun is typically called with point at the start
1838 ;; of an ediff change section, which is before the start of the
1839 ;; declaration of a new item. So go to the end of the current line
1840 ;; first, then call `ada-which-function'
1841 (save-excursion
1842 (end-of-line 1)
1843 (ada-which-function)))
1844
1845 (defun ada-set-point-accordingly ()
1846 "Move to the string specified in `ff-function-name', which may be a regexp,
1847 previously set by a file navigation command."
1848 (when ff-function-name
1849 (let ((done nil)
1850 (found nil))
1851 (goto-char (point-min))
1852 ;; We are looking for an Ada declaration, so don't stop for strings or comments
1853 ;;
1854 ;; This will still be confused by multiple references; we need
1855 ;; to use compiler cross reference info for more precision.
1856 (while (not done)
1857 (if (search-forward-regexp ff-function-name nil t)
1858 (setq found (match-beginning 0))
1859 ;; not in remainder of buffer
1860 (setq done t))
1861 (if (ada-in-string-or-comment-p)
1862 (setq found nil)
1863 (setq done t)))
1864 (when found
1865 (goto-char found)
1866 ;; different parsers find different points on the line; normalize here
1867 (back-to-indentation))
1868 (setq ff-function-name nil))))
1869
1870 (defun ada-check-current-project (file-name)
1871 "Throw error if FILE-NAME (must be absolute) is not found in
1872 the current project source directories, or if no project has been
1873 set."
1874 (when (null (car compilation-search-path))
1875 (error "no file search path defined; set project file?"))
1876
1877 ;; file-truename handles symbolic links
1878 (let* ((visited-file (file-truename file-name))
1879 (found-file (locate-file (file-name-nondirectory visited-file)
1880 compilation-search-path)))
1881 (unless found-file
1882 (error "current file not part of current project; wrong project?"))
1883
1884 (setq found-file (file-truename found-file))
1885
1886 ;; (nth 10 (file-attributes ...)) is the inode; required when hard
1887 ;; links are present.
1888 (let* ((visited-file-inode (nth 10 (file-attributes visited-file)))
1889 (found-file-inode (nth 10 (file-attributes found-file))))
1890 (unless (equal visited-file-inode found-file-inode)
1891 (error "%s (opened) and %s (found in project) are two different files"
1892 file-name found-file)))))
1893
1894 (defun ada-find-other-file-noset (other-window)
1895 "Same as `ada-find-other-file', but preserve point in the other file,
1896 don't move to corresponding declaration."
1897 (interactive "P")
1898 (ada-find-other-file other-window t))
1899
1900 (defun ada-find-other-file (other-window &optional no-set-point)
1901 "Move to the corresponding declaration in another file.
1902
1903 - If region is active, assume it contains a package name;
1904 position point on that package declaration.
1905
1906 - If point is in the start line of a non-nested child package or
1907 subprogram declaration, position point on the corresponding
1908 parent package specification.
1909
1910 - If point is in the start line of a separate body,
1911 position point on the corresponding separate stub declaration.
1912
1913 - If point is in a context clause line, position point on the
1914 first package declaration that is mentioned.
1915
1916 - If point is in a subprogram body or specification, position point
1917 on the corresponding specification or body.
1918
1919 If OTHER-WINDOW (set by interactive prefix) is non-nil, show the
1920 buffer in another window.
1921
1922 If NO-SET-POINT is nil, set point in the other file on the
1923 corresponding declaration. If non-nil, preserve existing point in
1924 the other file."
1925
1926 ;; ff-get-file, ff-find-other file first process
1927 ;; ff-special-constructs, then run the following hooks:
1928 ;;
1929 ;; ff-pre-load-hook set to ada-which-function
1930 ;; ff-file-created-hook set to ada-ff-create-body
1931 ;; ff-post-load-hook set to ada-set-point-accordingly,
1932 ;; or to a compiler-specific function that
1933 ;; uses compiler-generated cross reference
1934 ;; information
1935
1936 (interactive "P")
1937 (ada-check-current-project (buffer-file-name))
1938
1939 (if mark-active
1940 (progn
1941 (setq ff-function-name (buffer-substring-no-properties (point) (mark)))
1942 (ff-get-file
1943 compilation-search-path
1944 (ada-file-name-from-ada-name ff-function-name)
1945 ada-spec-suffixes
1946 other-window)
1947 (deactivate-mark))
1948
1949 ;; else use name at point
1950 (ff-find-other-file other-window)))
1951
1952 (defvar ada-operator-re
1953 "\\+\\|-\\|/\\|\\*\\*\\|\\*\\|=\\|&\\|abs\\|mod\\|rem\\|and\\|not\\|or\\|xor\\|<=\\|<\\|>=\\|>"
1954 "Regexp matching Ada operator_symbol.")
1955
1956 (defun ada-identifier-at-point ()
1957 "Return the identifier around point, move point to start of
1958 identifier. May be an Ada identifier or operator function name."
1959
1960 (when (ada-in-comment-p)
1961 (error "Inside comment"))
1962
1963 (let (identifier)
1964
1965 (skip-chars-backward "a-zA-Z0-9_<>=+\\-\\*/&")
1966
1967 ;; Just in front of, or inside, a string => we could have an operator
1968 (cond
1969 ((ada-in-string-p)
1970 (cond
1971
1972 ((and (= (char-before) ?\")
1973 (progn
1974 (forward-char -1)
1975 (looking-at (concat "\"\\(" ada-operator-re "\\)\""))))
1976 (setq identifier (concat "\"" (match-string-no-properties 1) "\"")))
1977
1978 (t
1979 (error "Inside string or character constant"))
1980 ))
1981
1982 ((and (= (char-after) ?\")
1983 (looking-at (concat "\"\\(" ada-operator-re "\\)\"")))
1984 (setq identifier (concat "\"" (match-string-no-properties 1) "\"")))
1985
1986 ((looking-at "[a-zA-Z0-9_]+")
1987 (setq identifier (match-string-no-properties 0)))
1988
1989 (t
1990 (error "No identifier around"))
1991 )))
1992
1993 (defvar ada-goto-pos-ring '()
1994 "List of positions selected by navigation functions. Used
1995 to go back to these positions.")
1996
1997 (defconst ada-goto-pos-ring-max 16
1998 "Number of positions kept in the list `ada-goto-pos-ring'.")
1999
2000 (defun ada-goto-push-pos ()
2001 "Push current filename, position on `ada-goto-pos-ring'. See `ada-goto-previous-pos'."
2002 (setq ada-goto-pos-ring (cons (list (point) (buffer-file-name)) ada-goto-pos-ring))
2003 (if (> (length ada-goto-pos-ring) ada-goto-pos-ring-max)
2004 (setcdr (nthcdr (1- ada-goto-pos-ring-max) ada-goto-pos-ring) nil)))
2005
2006 (defun ada-goto-previous-pos ()
2007 "Go to the first position in `ada-goto-pos-ring', pop `ada-goto-pos-ring'."
2008 (interactive)
2009 (when ada-goto-pos-ring
2010 (let ((pos (pop ada-goto-pos-ring)))
2011 (find-file (cadr pos))
2012 (goto-char (car pos)))))
2013
2014 (defun ada-goto-source (file line column other-window)
2015 "Find and select FILE, at LINE and COLUMN.
2016 FILE may be absolute, or on `compilation-search-path'.
2017
2018 If OTHER-WINDOW is non-nil, show the buffer in another window."
2019 (let ((file-1
2020 (if (file-name-absolute-p file) file
2021 (ff-get-file-name compilation-search-path file))))
2022 (if file-1
2023 (setq file file-1)
2024 (error "File %s not found; installed library, or set project?" file))
2025 )
2026
2027 (ada-goto-push-pos)
2028
2029 (let ((buffer (get-file-buffer file)))
2030 (cond
2031 ((bufferp buffer)
2032 (cond
2033 ((null other-window)
2034 (switch-to-buffer buffer))
2035
2036 (t (switch-to-buffer-other-window buffer))
2037 ))
2038
2039 ((file-exists-p file)
2040 (cond
2041 ((null other-window)
2042 (find-file file))
2043
2044 (t
2045 (find-file-other-window file))
2046 ))
2047
2048 (t
2049 (error "'%s' not found" file))))
2050
2051
2052 ;; move the cursor to the correct position
2053 (push-mark nil t)
2054 (goto-char (point-min))
2055 (forward-line (1- line))
2056 (forward-char column)
2057 )
2058
2059 (defvar ada-xref-refresh-function nil
2060 ;; determined by xref_tool, set by *-select-prj-xref
2061 "Function that refreshes cross reference information cache.")
2062
2063 (defun ada-xref-refresh ()
2064 "Refresh cross reference information cache, if any."
2065 (interactive)
2066
2067 (when (null ada-xref-refresh-function)
2068 (error "no cross reference information available"))
2069
2070 (funcall ada-xref-refresh-function)
2071 )
2072
2073 (defvar ada-xref-other-function nil
2074 ;; determined by xref_tool, set by *-select-prj-xref
2075 "Function that returns cross reference information.
2076 Function is called with four arguments:
2077 - an Ada identifier or operator_symbol
2078 - filename containing the identifier (full path)
2079 - line number containing the identifier
2080 - column of the start of the identifier
2081 Returns a list '(file line column) giving the corresponding location.
2082 'file' may be absolute, or on `compilation-search-path'. If point is
2083 at the specification, the corresponding location is the body, and vice
2084 versa.")
2085
2086 (defun ada-goto-declaration (other-window)
2087 "Move to the declaration or body of the identifier around point.
2088 If at the declaration, go to the body, and vice versa.
2089
2090 If OTHER-WINDOW (set by interactive prefix) is non-nil, show the
2091 buffer in another window."
2092 (interactive "P")
2093 (ada-check-current-project (buffer-file-name))
2094
2095 (when (null ada-xref-other-function)
2096 (error "no cross reference information available"))
2097
2098 (let ((target
2099 (funcall ada-xref-other-function
2100 (ada-identifier-at-point)
2101 (buffer-file-name)
2102 (line-number-at-pos)
2103 (1+ (current-column))
2104 )))
2105
2106 (ada-goto-source (nth 0 target)
2107 (nth 1 target)
2108 (nth 2 target)
2109 other-window)
2110 ))
2111
2112 (defvar ada-xref-parent-function nil
2113 ;; determined by xref_tool, set by *-select-prj-xref
2114 "Function that returns cross reference information.
2115 Function is called with four arguments:
2116 - an Ada identifier or operator_symbol
2117 - filename containing the identifier
2118 - line number containing the identifier
2119 - column of the start of the identifier
2120 Displays a buffer in compilation-mode giving locations of the parent type declarations.")
2121
2122 (defun ada-show-declaration-parents ()
2123 "Display the locations of the parent type declarations of the type identifier around point."
2124 (interactive)
2125 (ada-check-current-project (buffer-file-name))
2126
2127 (when (null ada-xref-parent-function)
2128 (error "no cross reference information available"))
2129
2130 (funcall ada-xref-parent-function
2131 (ada-identifier-at-point)
2132 (file-name-nondirectory (buffer-file-name))
2133 (line-number-at-pos)
2134 (1+ (current-column)))
2135 )
2136
2137 (defvar ada-xref-all-function nil
2138 ;; determined by xref_tool, set by *-select-prj-xref
2139 "Function that displays cross reference information.
2140 Called with four arguments:
2141 - an Ada identifier or operator_symbol
2142 - filename containing the identifier
2143 - line number containing the identifier
2144 - column of the start of the identifier
2145 Displays a buffer in compilation-mode giving locations where the
2146 identifier is declared or referenced.")
2147
2148 (defun ada-show-references ()
2149 "Show all references of identifier at point."
2150 (interactive)
2151 (ada-check-current-project (buffer-file-name))
2152
2153 (when (null ada-xref-all-function)
2154 (error "no cross reference information available"))
2155
2156 (funcall ada-xref-all-function
2157 (ada-identifier-at-point)
2158 (file-name-nondirectory (buffer-file-name))
2159 (line-number-at-pos)
2160 (1+ (current-column)))
2161 )
2162
2163 (defvar ada-xref-overriding-function nil
2164 ;; determined by ada-xref-tool, set by *-select-prj
2165 "Function that displays cross reference information for overriding subprograms.
2166 Called with four arguments:
2167 - an Ada identifier or operator_symbol
2168 - filename containing the identifier
2169 - line number containing the identifier
2170 - column of the start of the identifier
2171 Displays a buffer in compilation-mode giving locations of the overriding declarations.")
2172
2173 (defun ada-show-overriding ()
2174 "Show all overridings of identifier at point."
2175 (interactive)
2176 (ada-check-current-project (buffer-file-name))
2177
2178 (when (null ada-xref-overriding-function)
2179 (error "no cross reference information available"))
2180
2181 (funcall ada-xref-overriding-function
2182 (ada-identifier-at-point)
2183 (file-name-nondirectory (buffer-file-name))
2184 (line-number-at-pos)
2185 (1+ (current-column)))
2186 )
2187
2188 (defvar ada-xref-overridden-function nil
2189 ;; determined by ada-xref-tool, set by *-select-prj
2190 "Function that displays cross reference information for overridden subprogram.
2191 Called with four arguments:
2192 - an Ada identifier or operator_symbol
2193 - filename containing the identifier
2194 - line number containing the identifier
2195 - column of the start of the identifier
2196 Returns a list '(file line column) giving the corresponding location.
2197 'file' may be absolute, or on `compilation-search-path'.")
2198
2199 (defun ada-show-overridden (other-window)
2200 "Show the overridden declaration of identifier at point."
2201 (interactive "P")
2202 (ada-check-current-project (buffer-file-name))
2203
2204 (when (null ada-xref-overridden-function)
2205 (error "'show overridden' not supported, or no cross reference information available"))
2206
2207 (let ((target
2208 (funcall ada-xref-overridden-function
2209 (ada-identifier-at-point)
2210 (file-name-nondirectory (buffer-file-name))
2211 (line-number-at-pos)
2212 (1+ (current-column)))))
2213
2214 (ada-goto-source (nth 0 target)
2215 (nth 1 target)
2216 (nth 2 target)
2217 other-window)
2218
2219 ))
2220
2221 ;; This is autoloaded because it may be used in ~/.emacs
2222 ;;;###autoload
2223 (defun ada-add-extensions (spec body)
2224 "Define SPEC and BODY as being valid extensions for Ada files.
2225 SPEC and BODY are two regular expressions that must match against
2226 the file name."
2227 (let* ((reg (concat (regexp-quote body) "$"))
2228 (tmp (assoc reg ada-other-file-alist)))
2229 (if tmp
2230 (setcdr tmp (list (cons spec (cadr tmp))))
2231 (add-to-list 'ada-other-file-alist (list reg (list spec)))))
2232
2233 (let* ((reg (concat (regexp-quote spec) "$"))
2234 (tmp (assoc reg ada-other-file-alist)))
2235 (if tmp
2236 (setcdr tmp (list (cons body (cadr tmp))))
2237 (add-to-list 'ada-other-file-alist (list reg (list body)))))
2238
2239 (add-to-list 'auto-mode-alist
2240 (cons (concat (regexp-quote spec) "\\'") 'ada-mode))
2241 (add-to-list 'auto-mode-alist
2242 (cons (concat (regexp-quote body) "\\'") 'ada-mode))
2243
2244 (add-to-list 'ada-spec-suffixes spec)
2245 (add-to-list 'ada-body-suffixes body)
2246
2247 (when (fboundp 'speedbar-add-supported-extension)
2248 (speedbar-add-supported-extension spec)
2249 (speedbar-add-supported-extension body))
2250 )
2251
2252 (defun ada-show-secondary-error (other-window)
2253 "Show the next secondary file reference in the compilation buffer.
2254 A secondary file reference is defined by text having text
2255 property `ada-secondary-error'. These can be set by
2256 compiler-specific compilation filters.
2257
2258 If OTHER-WINDOW (set by interactive prefix) is non-nil, show the
2259 buffer in another window."
2260 (interactive "P")
2261
2262 ;; preserving the current window works only if the frame
2263 ;; doesn't change, at least on Windows.
2264 (let ((start-buffer (current-buffer))
2265 (start-window (selected-window))
2266 pos item file)
2267 (set-buffer compilation-last-buffer)
2268 (setq pos (next-single-property-change (point) 'ada-secondary-error))
2269 (when pos
2270 (setq item (get-text-property pos 'ada-secondary-error))
2271 ;; file-relative-name handles absolute Windows paths from
2272 ;; g++. Do this in compilation buffer to get correct
2273 ;; default-directory.
2274 (setq file (file-relative-name (nth 0 item)))
2275
2276 ;; Set point in compilation buffer past this secondary error, so
2277 ;; user can easily go to the next one. For some reason, this
2278 ;; doesn't change the visible point!?
2279 (forward-line 1))
2280
2281 (set-buffer start-buffer);; for windowing history
2282 (when item
2283 (ada-goto-source
2284 file
2285 (nth 1 item); line
2286 (nth 2 item); column
2287 other-window)
2288 (select-window start-window)
2289 )
2290 ))
2291
2292 (defvar ada-goto-declaration-start nil
2293 ;; Supplied by indentation engine.
2294 ;;
2295 ;; This is run from ff-pre-load-hook, so ff-function-name may have
2296 ;; been set by ff-treat-special; don't reset it.
2297 "For `beginning-of-defun-function'. Function to move point to
2298 start of the generic, package, protected, subprogram, or task
2299 declaration point is currently in or just after. Called with no
2300 parameters.")
2301
2302 (defun ada-goto-declaration-start ()
2303 "Call `ada-goto-declaration-start'."
2304 (interactive)
2305 (when ada-goto-declaration-start
2306 (funcall ada-goto-declaration-start)))
2307
2308 (defvar ada-goto-declaration-end nil
2309 ;; supplied by indentation engine
2310 "For `end-of-defun-function'. Function to move point to end of
2311 current declaration.")
2312
2313 (defun ada-goto-declaration-end ()
2314 "See `ada-goto-declaration-end' variable."
2315 (interactive)
2316 (when ada-goto-declaration-end
2317 (funcall ada-goto-declaration-end)))
2318
2319 (defvar ada-goto-declarative-region-start nil
2320 ;; Supplied by indentation engine
2321 "Function to move point to start of the declarative region of
2322 the subprogram, package, task, or declare block point
2323 is currently in. Called with no parameters.")
2324
2325 (defun ada-goto-declarative-region-start ()
2326 "Call `ada-goto-declarative-region-start'."
2327 (when ada-goto-declarative-region-start
2328 (funcall ada-goto-declarative-region-start)))
2329
2330 (defvar ada-next-statement-keyword nil
2331 ;; Supplied by indentation engine
2332 "Function called with no parameters; it should move forward to
2333 the next keyword in the statement following the one point is
2334 in (ie from 'if' to 'then'). If not in a keyword, move forward
2335 to the next keyword in the current statement. If at the last keyword,
2336 move forward to the first keyword in the next statement or next
2337 keyword in the containing statement.")
2338
2339 (defvar ada-goto-end nil
2340 ;; Supplied by indentation engine
2341 "Function to move point to end of the declaration or statement point is in or before.
2342 Called with no parameters.")
2343
2344 (defun ada-goto-end ()
2345 "Call `ada-goto-end'."
2346 (when ada-goto-end
2347 (funcall ada-goto-end)))
2348
2349 (defun ada-next-statement-keyword ()
2350 ;; Supplied by indentation engine
2351 "See `ada-next-statement-keyword' variable."
2352 (interactive)
2353 (when ada-next-statement-keyword
2354 (funcall ada-next-statement-keyword)))
2355
2356 (defvar ada-prev-statement-keyword nil
2357 ;; Supplied by indentation engine
2358 "Function called with no parameters; it should move to the previous
2359 keyword in the statement following the one point is in (ie from
2360 'then' to 'if'). If at the first keyword, move to the previous
2361 keyword in the previous statement or containing statement.")
2362
2363 (defun ada-prev-statement-keyword ()
2364 "See `ada-prev-statement-keyword' variable."
2365 (interactive)
2366 (when ada-prev-statement-keyword
2367 (funcall ada-prev-statement-keyword)))
2368
2369 ;;;; code creation
2370
2371 (defvar ada-make-subprogram-body nil
2372 ;; Supplied by indentation engine
2373 "Function to convert subprogram specification after point into a subprogram body stub.
2374 Called with no args, point at declaration start. Leave point in
2375 subprogram body, for user to add code.")
2376
2377 (defun ada-make-subprogram-body ()
2378 "If point is in or after a subprogram specification, convert it
2379 into a subprogram body stub, by calling `ada-make-subprogram-body'."
2380 (interactive)
2381 (ada-goto-declaration-start)
2382 (if ada-make-subprogram-body
2383 (funcall ada-make-subprogram-body)
2384 (error "`ada-make-subprogram-body' not set")))
2385
2386 (defvar ada-make-package-body nil
2387 ;; Supplied by xref tool
2388 "Function to create a package body from a package spec.
2389 Called with one argument; the absolute path to the body
2390 file. Current buffer is the package spec. Should create the
2391 package body file, containing skeleton code that will compile.")
2392
2393 (defun ada-make-package-body (body-file-name)
2394 ;; no error if not set; let ada-skel do its thing.
2395 (when ada-make-package-body
2396 (funcall ada-make-package-body body-file-name)))
2397
2398 (defun ada-ff-create-body ()
2399 ;; no error if not set; let ada-skel do its thing.
2400 (when ada-make-package-body
2401 ;; ff-find-other-file calls us with point in an empty buffer for the
2402 ;; body file; ada-make-package-body expects to be in the spec. So go
2403 ;; back.
2404 (let ((body-file-name (buffer-file-name)))
2405 (ff-find-the-other-file)
2406
2407 (ada-make-package-body body-file-name)
2408 ;; FIXME (later): if 'ada-make-package-body' fails, delete the body buffer
2409 ;; so it doesn't get written to disk, and we can try again.
2410
2411 ;; back to the body, read in from the disk.
2412 (ff-find-the-other-file)
2413 (revert-buffer t t))
2414 ))
2415
2416 ;;;; fill-comment
2417
2418 (defun ada-fill-comment-paragraph (&optional justify postfix)
2419 "Fill the current comment paragraph.
2420 If JUSTIFY is non-nil, each line is justified as well.
2421 If POSTFIX and JUSTIFY are non-nil, `ada-fill-comment-postfix' is appended
2422 to each line filled and justified.
2423 The paragraph is indented on the first line."
2424 (interactive "P")
2425 (if (and (not (ada-in-comment-p))
2426 (not (looking-at "[ \t]*--")))
2427 (error "Not inside comment"))
2428
2429 (let* (indent from to
2430 (opos (point-marker))
2431 ;; we bind `fill-prefix' here rather than in ada-mode because
2432 ;; setting it in ada-mode causes indent-region to use it for
2433 ;; all indentation.
2434 (fill-prefix ada-fill-comment-prefix)
2435 (fill-column (current-fill-column)))
2436
2437 ;; Find end of comment paragraph
2438 (back-to-indentation)
2439 (while (and (not (eobp)) (looking-at ".*--[ \t]*[^ \t\n]"))
2440 (forward-line 1)
2441
2442 ;; If we were at the last line in the buffer, create a dummy empty
2443 ;; line at the end of the buffer.
2444 (if (eobp)
2445 (insert "\n")
2446 (back-to-indentation)))
2447 (beginning-of-line)
2448 (setq to (point-marker))
2449 (goto-char opos)
2450
2451 ;; Find beginning of paragraph
2452 (back-to-indentation)
2453 (while (and (not (bobp)) (looking-at ".*--[ \t]*[^ \t\n]"))
2454 (forward-line -1)
2455 (back-to-indentation))
2456
2457 (unless (bobp)
2458 (forward-line 1))
2459 (beginning-of-line)
2460 (setq from (point-marker))
2461
2462 ;; Calculate the indentation we will need for the paragraph
2463 (back-to-indentation)
2464 (setq indent (current-column))
2465 ;; unindent the first line of the paragraph
2466 (delete-region from (point))
2467
2468 ;; Remove the old postfixes
2469 (goto-char from)
2470 (while (re-search-forward (concat "\\(" ada-fill-comment-postfix "\\)" "\n") to t)
2471 (delete-region (match-beginning 1) (match-end 1)))
2472
2473 (goto-char (1- to))
2474 (setq to (point-marker))
2475
2476 ;; Indent and justify the paragraph
2477 (set-left-margin from to indent)
2478 (if postfix
2479 (setq fill-column (- fill-column (length ada-fill-comment-postfix))))
2480
2481 (fill-region-as-paragraph from to justify)
2482
2483 ;; Add the postfixes if required
2484 (if postfix
2485 (save-restriction
2486 (goto-char from)
2487 (narrow-to-region from to)
2488 (while (not (eobp))
2489 (end-of-line)
2490 (insert-char ? (- fill-column (current-column)))
2491 (insert ada-fill-comment-postfix)
2492 (forward-line))
2493 ))
2494
2495 (goto-char opos)))
2496
2497 ;;;; support for font-lock.el
2498
2499 ;; casing keywords defined here to keep the two lists together
2500 (defconst ada-83-keywords
2501 '("abort" "abs" "accept" "access" "all" "and" "array" "at" "begin"
2502 "body" "case" "constant" "declare" "delay" "delta" "digits" "do"
2503 "else" "elsif" "end" "entry" "exception" "exit" "for" "function"
2504 "generic" "goto" "if" "in" "is" "limited" "loop" "mod" "new"
2505 "not" "null" "of" "or" "others" "out" "package" "pragma" "private"
2506 "procedure" "raise" "range" "record" "rem" "renames" "return"
2507 "reverse" "select" "separate" "subtype" "task" "terminate" "then"
2508 "type" "use" "when" "while" "with" "xor")
2509 "List of Ada 83 keywords.")
2510
2511 (defconst ada-95-keywords
2512 '("abstract" "aliased" "protected" "requeue" "tagged" "until")
2513 "List of keywords new in Ada 95.")
2514
2515 (defconst ada-2005-keywords
2516 '("interface" "overriding" "synchronized")
2517 "List of keywords new in Ada 2005.")
2518
2519 (defconst ada-2012-keywords
2520 '("some")
2521 "List of keywords new in Ada 2012.")
2522
2523 (defun ada-font-lock-keywords ()
2524 "Return Ada mode value for `font-lock-keywords', depending on `ada-language-version'."
2525 (list
2526
2527 ;; keywords followed by a name that should be in function-name-face.
2528 (list
2529 (apply
2530 'concat
2531 (append
2532 '("\\<\\("
2533 "accept\\|"
2534 "entry\\|"
2535 "function\\|"
2536 "package[ \t]+body\\|"
2537 "package\\|"
2538 "pragma\\|"
2539 "procedure\\|"
2540 "task[ \t]+body\\|"
2541 "task[ \t]+type\\|"
2542 "task\\|"
2543 )
2544 (when (member ada-language-version '(ada95 ada2005 ada2012))
2545 '("\\|"
2546 "protected[ \t]+body\\|"
2547 "protected[ \t]+function\\|"
2548 "protected[ \t]+procedure\\|"
2549 "protected[ \t]+type\\|"
2550 "protected"
2551 ))
2552 (list
2553 "\\)\\>[ \t]*"
2554 ada-name-regexp "?")))
2555 '(1 font-lock-keyword-face) '(2 font-lock-function-name-face nil t))
2556
2557 ;; keywords followed by a name that should be in type-face.
2558 (list (concat
2559 "\\<\\("
2560 "access[ \t]+all\\|"
2561 "access[ \t]+constant\\|"
2562 "access\\|"
2563 "constant\\|"
2564 "in[ \t]+reverse\\|"; loop iterator
2565 "in[ \t]+not[ \t]+null\\|"
2566 "in[ \t]+out[ \t]+not[ \t]+null\\|"
2567 "in[ \t]+out\\|"
2568 "in\\|"
2569 ;; "return\\|" can't distinguish between 'function ... return <type>;' and 'return ...;'
2570 ;; An indentation engine can, so a rule for this is added there
2571 "of[ \t]+reverse\\|"
2572 "of\\|"
2573 "out\\|"
2574 "subtype\\|"
2575 "type"
2576 "\\)\\>[ \t]*"
2577 ada-name-regexp "?")
2578 '(1 font-lock-keyword-face nil t) '(2 font-lock-type-face nil t))
2579
2580 ;; Keywords not treated elsewhere. After above so it doesn't
2581 ;; override fontication of second or third word in those patterns.
2582 (list (concat
2583 "\\<"
2584 (regexp-opt
2585 (append
2586 '("abort" "abs" "accept" "all"
2587 "and" "array" "at" "begin" "case" "declare" "delay" "delta"
2588 "digits" "do" "else" "elsif" "entry" "exception" "exit" "for"
2589 "generic" "if" "in" "limited" "loop" "mod" "not"
2590 "null" "or" "others" "private" "raise"
2591 "range" "record" "rem" "renames" "reverse"
2592 "select" "separate" "task" "terminate"
2593 "then" "when" "while" "xor")
2594 (when (member ada-language-version '(ada95 ada2005 ada2012))
2595 '("abstract" "aliased" "requeue" "tagged" "until"))
2596 (when (member ada-language-version '(ada2005 ada2012))
2597 '("interface" "overriding" "synchronized"))
2598 (when (member ada-language-version '(ada2012))
2599 '("some"))
2600 )
2601 t)
2602 "\\>")
2603 '(0 font-lock-keyword-face))
2604
2605 ;; object and parameter declarations; word after ":" should be in
2606 ;; type-face if not already fontified or an exception.
2607 (list (concat
2608 ":[ \t]*"
2609 ada-name-regexp
2610 "[ \t]*\\(=>\\)?")
2611 '(1 (if (match-beginning 2)
2612 'default
2613 font-lock-type-face)
2614 nil t))
2615
2616 ;; keywords followed by a name that should be in function-name-face if not already fontified
2617 (list (concat
2618 "\\<\\("
2619 "end"
2620 "\\)\\>[ \t]*"
2621 ada-name-regexp "?")
2622 '(1 font-lock-keyword-face) '(2 font-lock-function-name-face nil t))
2623
2624 ;; Keywords followed by a name that could be a type or a function (generic instantiation).
2625 (list (concat
2626 "\\<\\("
2627 "new"
2628 "\\)\\>[ \t]*"
2629 ada-name-regexp "?[ \t]*\\((\\)?")
2630 '(1 font-lock-keyword-face)
2631 '(2 (if (match-beginning 3)
2632 font-lock-function-name-face
2633 font-lock-type-face)
2634 nil t))
2635
2636 ;; keywords followed by a name that should be in type-face if not already fontified (for subtypes)
2637 ;; after "new" to handle "is new"
2638 (list (concat
2639 "\\<\\("
2640 "is"
2641 "\\)\\>[ \t]*"
2642 ada-name-regexp "?")
2643 '(1 font-lock-keyword-face) '(2 font-lock-type-face nil t))
2644
2645 ;; Keywords followed by a comma separated list of names which
2646 ;; should be in constant-face, unless already fontified. Ada mode 4.01 used this.
2647 (list (concat
2648 "\\<\\("
2649 "goto\\|"
2650 "use\\|"
2651 ;; don't need "limited" "private" here; they are matched separately
2652 "with"; context clause
2653 "\\)\\>[ \t]*"
2654 "\\(\\(?:\\sw\\|[_., \t]\\)+\\>\\)?"; ada-name-regexp, plus ", \t"
2655 )
2656 '(1 font-lock-keyword-face) '(2 font-lock-constant-face nil t))
2657
2658 ;; statement labels
2659 '("<<\\(\\sw+\\)>>" 1 font-lock-constant-face)
2660
2661 ;; based numberic literals
2662 (list "\\([0-9]+#[0-9a-fA-F_]+#\\)" '(1 font-lock-constant-face t))
2663
2664 ;; numeric literals
2665 (list "\\W\\([-+]?[0-9._]+\\)\\>" '(1 font-lock-constant-face))
2666
2667 ))
2668
2669 ;;;; ada-mode
2670
2671 ;; ada-mode does not derive from prog-mode, because we need to call
2672 ;; ada-mode-post-local-vars, and prog-mode does not provide a way to
2673 ;; do that.
2674 ;;
2675 ;; autoload required by automatic mode setting
2676 ;;;###autoload
2677 (defun ada-mode ()
2678 "The major mode for editing Ada code."
2679 ;; the other ada-*.el files add to ada-mode-hook for their setup
2680
2681 (interactive)
2682 (kill-all-local-variables)
2683 (setq major-mode 'ada-mode)
2684 (setq mode-name "Ada")
2685 (use-local-map ada-mode-map)
2686 (set-syntax-table ada-mode-syntax-table)
2687 (define-abbrev-table 'ada-mode-abbrev-table ())
2688 (setq local-abbrev-table ada-mode-abbrev-table)
2689
2690 (set (make-local-variable 'syntax-propertize-function) 'ada-syntax-propertize)
2691 (set (make-local-variable 'syntax-begin-function) nil)
2692 (set (make-local-variable 'parse-sexp-ignore-comments) t)
2693 (set (make-local-variable 'parse-sexp-lookup-properties) t)
2694 (set 'case-fold-search t); Ada is case insensitive; the syntax parsing requires this setting
2695 (set (make-local-variable 'comment-start) "--")
2696 (set (make-local-variable 'comment-end) "")
2697 (set (make-local-variable 'comment-start-skip) "---*[ \t]*")
2698 (set (make-local-variable 'comment-multi-line) nil)
2699
2700 ;; we _don't_ set `fill-prefix' here because that causes
2701 ;; indent-region to use it for all indentation. See
2702 ;; ada-fill-comment-paragraph.
2703
2704 ;; AdaCore standard style (enforced by -gnaty) requires two spaces
2705 ;; after '--' in comments; this makes it easier to distinguish
2706 ;; special comments that have something else after '--'
2707 (set (make-local-variable 'comment-padding) " ")
2708
2709 (set (make-local-variable 'require-final-newline) t)
2710
2711 (setq font-lock-defaults
2712 '(ada-font-lock-keywords
2713 nil t
2714 ((?\_ . "w")))); treat underscore as a word component
2715
2716 (set (make-local-variable 'ff-other-file-alist)
2717 'ada-other-file-alist)
2718 (setq ff-post-load-hook 'ada-set-point-accordingly
2719 ff-file-created-hook 'ada-ff-create-body)
2720 (add-hook 'ff-pre-load-hook 'ada-goto-push-pos)
2721 (add-hook 'ff-pre-load-hook 'ada-which-function)
2722 (setq ff-search-directories 'compilation-search-path)
2723 (when (null (car compilation-search-path))
2724 ;; find-file doesn't handle nil in search path
2725 (setq compilation-search-path (list (file-name-directory (buffer-file-name)))))
2726 (ada-set-ff-special-constructs)
2727
2728 (set (make-local-variable 'add-log-current-defun-function)
2729 'ada-add-log-current-function)
2730
2731 (when (boundp 'which-func-functions)
2732 (add-hook 'which-func-functions 'ada-which-function nil t))
2733
2734 ;; Support for align
2735 (add-to-list 'align-dq-string-modes 'ada-mode)
2736 (add-to-list 'align-open-comment-modes 'ada-mode)
2737 (set (make-local-variable 'align-region-separate) ada-align-region-separate)
2738 (set (make-local-variable 'align-indent-before-aligning) t)
2739
2740 ;; Exclude comments alone on line from alignment.
2741 (add-to-list 'align-exclude-rules-list
2742 '(ada-solo-comment
2743 (regexp . "^\\(\\s-*\\)--")
2744 (modes . '(ada-mode))))
2745 (add-to-list 'align-exclude-rules-list
2746 '(ada-solo-use
2747 (regexp . "^\\(\\s-*\\)\\<use\\>")
2748 (modes . '(ada-mode))))
2749
2750 (setq align-mode-rules-list ada-align-rules)
2751
2752 (easy-menu-add ada-mode-menu ada-mode-map)
2753
2754 (run-mode-hooks 'ada-mode-hook)
2755
2756 ;; If global-font-lock is not enabled, ada-syntax-propertize is
2757 ;; not run when the text is first loaded into the buffer. Recover
2758 ;; from that.
2759 (syntax-ppss-flush-cache (point-min))
2760 (syntax-propertize (point-max))
2761
2762 (add-hook 'hack-local-variables-hook 'ada-mode-post-local-vars nil t)
2763 )
2764
2765 (defun ada-mode-post-local-vars ()
2766 ;; These are run after ada-mode-hook and file local variables
2767 ;; because users or other ada-* files might set the relevant
2768 ;; variable inside the hook or file local variables (file local
2769 ;; variables are processed after the mode is set, and thus after
2770 ;; ada-mode is run).
2771
2772 ;; This means to fully set ada-mode interactively, user must
2773 ;; do M-x ada-mode M-; (hack-local-variables)
2774
2775 (when global-font-lock-mode
2776 ;; This calls ada-font-lock-keywords, which depends on
2777 ;; ada-language-version
2778 (font-lock-refresh-defaults))
2779
2780 (cl-case ada-language-version
2781 (ada83
2782 (setq ada-keywords ada-83-keywords))
2783
2784 (ada95
2785 (setq ada-keywords
2786 (append ada-83-keywords
2787 ada-95-keywords)))
2788
2789 (ada2005
2790 (setq ada-keywords
2791 (append ada-83-keywords
2792 ada-95-keywords
2793 ada-2005-keywords)))
2794 (ada2012
2795 (setq ada-keywords
2796 (append ada-83-keywords
2797 ada-95-keywords
2798 ada-2005-keywords
2799 ada-2012-keywords))))
2800
2801 (when ada-goto-declaration-start
2802 (set (make-local-variable 'beginning-of-defun-function) ada-goto-declaration-start))
2803
2804 (when ada-goto-declaration-end
2805 (set (make-local-variable 'end-of-defun-function) ada-goto-declaration-end))
2806 )
2807
2808 (put 'ada-mode 'custom-mode-group 'ada)
2809
2810 (provide 'ada-mode)
2811
2812 ;;;;; Global initializations
2813
2814 (require 'ada-build)
2815
2816 (unless (featurep 'ada-indent-engine)
2817 (require 'ada-wisi))
2818
2819 (unless (featurep 'ada-xref-tool)
2820 (cl-case ada-xref-tool
2821 ((nil 'gnat) (require 'ada-gnat-xref))
2822 ('gnat_inspect (require 'gnat-inspect))
2823 ('gpr_query (require 'gpr-query))
2824 ))
2825
2826 (unless (featurep 'ada-compiler)
2827 (require 'ada-gnat-compile))
2828
2829 (unless (featurep 'ada-skeletons)
2830 (require 'ada-skel))
2831
2832 (when (featurep 'imenu)
2833 (require 'ada-imenu))
2834
2835 ;;; end of file