1 ;;; ada-mode.el --- major-mode for editing Ada sources
3 ;;; Copyright (C) 1994, 1995, 1997 - 2014 Free Software Foundation, Inc.
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
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
12 ;; (Gnu ELPA requires single digits between dots in versions)
14 ;; This file is part of GNU Emacs.
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.
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.
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/>.
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
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.
41 ;; See the user guide (info "ada-mode"), built from ada-mode.texi.
45 ;; In order to support multiple compilers, we use indirect function
46 ;; calls for all operations that depend on the compiler.
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.
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.
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).
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
69 ;; There are several styles of indirect calls:
71 ;; - scalar global variable set during load
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.
77 ;; - scalar global variable set during project select
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.
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'.
90 ;; - scalar buffer-local variable set during project select or file open
92 ;; Appropriate when choice of implementation is normally
93 ;; per-project, but can be per-buffer.
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.
100 ;; - scalar buffer-local variable set by ada-mode or ada-mode-hook
103 ;; Appropriate when the variable is a non-Ada mode variable, also
104 ;; used by other modes, and choice should not affect those modes.
106 ;; `indent-line-function', `comment-indent-function' use this style
108 ;; - alist global variable indexed by ada-compiler
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.
114 ;; alist entries are set during load by the implementation elisp files.
116 ;; `ada-prj-default-compiler-alist' uses this style.
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.
124 ;; Lynn Slater wrote an extensive Ada mode in 1989. It consisted of
125 ;; several files with support for dired commands and other nice
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
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.
139 ;; A complete rewrite for Emacs-20 / GNAT-3.11 was done by Emmanuel
140 ;; Briot <briot@gnat.com> at Ada Core Technologies.
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>.
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
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.
167 (defun ada-mode-version ()
168 "Return Ada mode version."
170 (let ((version-string "5.1.5"))
175 (if (called-interactively-p 'interactive)
176 (message version-string)
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.")
187 "Major mode for editing Ada source code in Emacs."
190 (defcustom ada-auto-case t
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."
200 (make-variable-buffer-local 'ada-auto-case)
202 (defcustom ada-case-exception-file nil
203 "Default list of special casing exceptions dictionaries for identifiers.
204 Override with 'casing' project variable.
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.
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))
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)
228 (make-variable-buffer-local 'ada-case-keyword)
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))
239 (make-variable-buffer-local 'ada-case-identifier)
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."
249 (make-variable-buffer-local 'ada-case-strict)
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)
261 (make-variable-buffer-local 'ada-language-version)
263 (defcustom ada-fill-comment-prefix "-- "
264 "Comment fill prefix."
267 (make-variable-buffer-local 'ada-language-version)
269 (defcustom ada-fill-comment-postfix " --"
270 "Comment fill postfix."
273 (make-variable-buffer-local 'ada-language-version)
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'."
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."
290 ;;;;; end of user variables
292 (defconst ada-symbol-end
293 ;; we can't just add \> here; that might match _ in a user modified ada-mode-syntax-table
295 "Regexp to add to symbol name in `ada-which-function'.")
297 (defvar ada-compiler nil
298 "Default Ada compiler; can be overridden in project files.
299 Values defined by compiler packages.")
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.")
305 ;;;; keymap and menus
307 (defvar ada-ret-binding nil)
308 (defvar ada-lfd-binding nil)
310 (defun ada-case-activate-keys ()
311 "Modify the key bindings for all the keys that should adjust casing."
313 ;; We can't use post-self-insert-hook for \n, \r, because they are
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")))
327 'ada-case-adjust-interactive)))
328 '( ?_ ?% ?& ?* ?( ?) ?- ?= ?+
329 ?| ?\; ?: ?' ?\" ?< ?, ?. ?> ?/ ?\n 32 ?\r ))
331 (define-key ada-mode-map [return] 'ada-case-adjust-interactive)
335 (let ((map (make-sparse-keymap)))
336 ;; C-c <letter> are reserved for users
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)
371 ) "Local keymap used for Ada mode.")
373 (defvar ada-mode-menu (make-sparse-keymap "Ada"))
374 (easy-menu-define ada-mode-menu ada-mode-map "Menu keymap for Ada mode"
377 ["Ada Mode" (info "ada-mode") t]
378 ["Ada Reference Manual" (info "arm2012") t]
379 ["Key bindings" describe-bindings t]
381 ["Customize" (customize-group 'ada) t]
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]
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]
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]
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]
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]
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]
436 (ada-case-activate-keys)
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)
442 (easy-menu-define ada-context-menu nil
443 "Context menu keymap for Ada mode"
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]
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]))
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."
473 (mouse-set-point last-input-event)
475 (setq ada-context-menu-on-identifier
477 (or (= (char-syntax (char-after)) ?w)
479 (not (ada-in-string-or-comment-p))
480 (save-excursion (skip-syntax-forward "w")
481 (not (ada-after-keyword-p)))
483 (popup-menu ada-context-menu)
486 (defun ada-indent-newline-indent ()
487 "insert a newline, indent the old and new lines."
489 ;; point may be in the middle of a word, so insert newline first,
490 ;; then go back and indent.
493 (funcall indent-line-function)
495 (funcall indent-line-function))
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.")
502 (defun ada-indent-statement ()
503 "Indent current statement."
505 (when ada-indent-statement
506 (funcall ada-indent-statement)))
508 (defvar ada-expand nil
510 "Function to call to expand tokens (ie insert skeletons).")
513 "Expand previous word into a statement skeleton."
516 (funcall ada-expand)))
520 (defvar ada-mode-abbrev-table nil
521 "Local abbrev table for Ada mode.")
523 (defvar ada-align-rules
524 '((ada-declaration-assign
525 (regexp . "[^:]\\(\\s-*\\)\\(:\\)[^:]")
526 (valid . (lambda () (ada-align-valid)))
528 (modes . '(ada-mode)))
530 (regexp . "[^=]\\(\\s-*\\)\\(=>\\)")
531 (valid . (lambda () (ada-align-valid)))
532 (modes . '(ada-mode)))
534 (regexp . "\\(\\s-*\\)--")
535 (valid . (lambda () (ada-align-valid)))
536 (modes . '(ada-mode)))
538 (regexp . "\\(\\s-*\\)\\<\\(use\\s-\\)")
539 (valid . (lambda () (ada-align-valid)))
540 (modes . '(ada-mode)))
542 (regexp . "\\(\\s-+\\)\\(at\\)\\>")
543 (valid . (lambda () (ada-align-valid)))
544 (modes . '(ada-mode))))
545 "Rules to use to align different lines.")
547 (defun ada-align-valid ()
548 "See use in `ada-align-rules'."
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))))
555 (defconst ada-align-region-separate
576 "See the variable `align-region-separate' for more information.")
579 "If region is active, apply 'align'. If not, attempt to align
584 (align (region-beginning) (region-end))
587 ;; else see if we are in a construct we know how to align
589 ((ada-in-paramlist-p)
590 (ada-format-paramlist))
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.")
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)))
606 (defun ada-format-paramlist ()
607 "Reformat the parameter list point is in."
609 (ada-goto-open-paren)
610 (funcall indent-line-function); so new list is indented properly
612 (let* ((inibit-modification-hooks t)
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)))
620 ;; delete the original parameter-list
621 (delete-region begin delend)
623 ;; insert the new parameter-list
626 (ada-insert-paramlist-multi-line paramlist)
627 (ada-insert-paramlist-single-line paramlist)))
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?
640 (defun ada-scan-paramlist (begin end)
641 (when ada-scan-paramlist
642 (funcall ada-scan-paramlist begin end)))
644 (defun ada-insert-paramlist-multi-line (paramlist)
645 "Insert a multi-line formatted PARAMLIST in the buffer."
646 (let ((i (length paramlist))
662 ;; accumulate info across all params
663 (while (not (zerop i))
665 (setq param (nth i paramlist))
670 (mapc (lambda (ident)
672 (setq len (+ len (length ident))))
674 (setq len (+ len (* 2 (1- j)))); space for commas
675 (setq ident-len (max ident-len len))
677 ;; we align the defaults after the types that have defaults, not after all types.
678 ;; "constant", "protected" are treated as part of 'type'
682 (+ (length (nth 7 param))
683 (if (nth 5 param) 10 0); "constant "
684 (if (nth 6 param) 10 0); protected
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)))
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))))))
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 " ")))
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 "
717 (not-null-p 18); ": not null access "
718 (access-p 9); ": access"
719 ((and in-p out-p) 9); ": in out "
724 (setq default-col (+ 1 type-col type-len))
726 (setq i (length paramlist))
727 (while (not (zerop i))
729 (setq param (nth i paramlist))
731 ;; insert identifiers, space and colon
732 (mapc (lambda (ident)
736 (delete-char -2); last ", "
737 (indent-to colon-col)
748 (insert "not null "))
755 (insert "constant "))
757 (insert "protected "))
758 (insert (nth 7 param)); type
760 (when (nth 8 param); default
761 (indent-to default-col)
763 (insert (nth 8 param)))
769 (indent-to ident-col))
773 (defun ada-insert-paramlist-single-line (paramlist)
774 "Insert a single-line formatted PARAMLIST in the buffer."
775 (let ((i (length paramlist))
778 ;; clean up whitespace
779 (skip-syntax-forward " ")
780 (delete-char (- (skip-syntax-backward " ")))
783 (setq i (length paramlist))
784 (while (not (zerop i))
786 (setq param (nth i paramlist))
788 ;; insert identifiers, space and colon
789 (mapc (lambda (ident)
793 (delete-char -2); last ", "
804 (insert "not null "))
810 (insert "constant "))
812 (insert "protected "))
813 (insert (nth 7 param)); type
815 (when (nth 8 param); default
817 (insert (nth 8 param)))
820 (if (= (char-after) ?\;)
827 (defvar ada-reset-parser nil
828 ;; Supplied by indentation engine parser
829 "Function to reset parser, to clear confused state."
832 (defun ada-reset-parser ()
834 (when ada-reset-parser
835 (funcall ada-reset-parser)))
837 (defvar ada-show-parse-error nil
838 ;; Supplied by indentation engine parser
839 "Function to show last error reported by indentation parser."
842 (defun ada-show-parse-error ()
844 (when ada-show-parse-error
845 (funcall ada-show-parse-error)))
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.")
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.")
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)))))
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)
877 (insert-file-contents file-name)
880 (setq word (buffer-substring-no-properties
881 (point) (save-excursion (skip-syntax-forward "w_") (point))))
883 (if (char-equal (string-to-char word) ?*)
884 ;; partial word exception
886 (setq word (substring word 1))
887 (unless (assoc-string word partial-exceptions t)
888 (add-to-list 'partial-exceptions (cons word t))))
890 ;; full word exception
891 (unless (assoc-string word full-exceptions t)
892 (add-to-list 'full-exceptions (cons word t))))
896 (cons full-exceptions partial-exceptions))
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)
904 (defun ada-case-merge-exceptions (result new)
905 "Merge NEW exeptions into RESULT.
906 An item in both lists has the RESULT value."
908 (unless (assoc-string (car item) result t)
909 (add-to-list 'result item)))
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))))
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'."
921 (setq ada-case-full-exceptions '()
922 ada-case-partial-exceptions '())
924 (when (ada-prj-get 'casing)
925 (dolist (file (ada-prj-get 'casing))
926 (ada-case-merge-all-exceptions (ada-case-read-exceptions file))))
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)))
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
943 (let ((casing (ada-prj-get 'casing)))
946 (file-name file-name)
948 ((< 1 (length casing))
949 (completing-read "case exception file: " casing
954 (car casing) ;; default
956 ((= 1 (length casing))
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
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)
969 (error "No exception file specified, and no project active. See variable `ada-case-exception-file'.")))
974 (setq word (buffer-substring-no-properties (region-beginning) (region-end)))
976 (skip-syntax-backward "w_")
978 (buffer-substring-no-properties
980 (progn (skip-syntax-forward "w_") (point))
983 (let* ((exceptions (ada-case-read-exceptions file-name))
984 (full-exceptions (car exceptions))
985 (partial-exceptions (cdr exceptions)))
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)))
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)))
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")
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."
1007 (ada-case-create-exception nil nil t))
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_]+\\)"))
1013 (defvar ada-keywords nil
1014 "List of Ada keywords for current `ada-language-version'.")
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))
1021 (member (downcase word) ada-keywords)))
1023 (defun ada-mixed-case (start end)
1024 "Adjust case of region START END to Mixed_Case."
1028 (downcase-region start end))
1033 (save-excursion (when (search-forward "_" end t) (point-marker)))
1034 (copy-marker (1+ end))))
1036 ;; upcase first char
1037 (insert-char (upcase (following-char)) 1)
1042 (setq start (point))
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'."
1052 (let ((end (point-marker))
1053 (start (progn (skip-syntax-backward "w_") (point)))
1058 (if (setq match (assoc-string (buffer-substring-no-properties start end) ada-case-full-exceptions t))
1059 ;; full word exception
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))
1068 ;; else apply ada-case-identifier
1069 (funcall ada-case-identifier start end)
1071 ;; apply partial-exceptions
1076 (save-excursion (when (search-forward "_" end t) (point-marker)))
1077 (copy-marker (1+ end))))
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)))
1088 (setq start (point))
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."
1098 (when (save-excursion
1099 (forward-char -1); back to last character in word
1101 (eq (char-syntax (char-after)) ?w); it can be capitalized
1103 (not (and (eq typed-char ?')
1104 (eq (char-before (point)) ?'))); character literal
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.
1112 (not (ada-in-numeric-literal-p))
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
1119 (let ((inhibit-modification-hooks t))
1121 ;; Some attributes are also keywords, but captialized as
1122 ;; attributes. So check for attribute first.
1126 (skip-syntax-backward "w_")
1127 (eq (char-before) ?')))
1128 (ada-case-adjust-identifier))
1132 (not (eq typed-char ?_))
1133 (ada-after-keyword-p))
1134 (funcall ada-case-keyword -1))
1136 (t (ada-case-adjust-identifier))
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."
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))
1153 (defun ada-case-adjust-region (begin end)
1154 "Adjust case of all words in region BEGIN END."
1156 (narrow-to-region begin end)
1160 (forward-comment (point-max))
1161 (skip-syntax-forward "^w_")
1162 (skip-syntax-forward "w_")
1166 (defun ada-case-adjust-buffer ()
1167 "Adjust case of current buffer."
1169 (ada-case-adjust-region (point-min) (point-max)))
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]."
1177 ;; character typed has not been inserted yet
1178 (let ((lastk last-command-event))
1183 (ada-case-adjust lastk))
1184 (funcall ada-lfd-binding))
1186 ((memq lastk '(?\r return))
1188 (ada-case-adjust lastk))
1189 (funcall ada-ret-binding))
1193 (ada-case-adjust lastk))
1194 (self-insert-command (prefix-numeric-value arg)))
1199 ;; An Emacs Ada mode project file can specify several things:
1201 ;; - a compiler-specific project file
1203 ;; - compiler-specific environment variables
1205 ;; - other compiler-specific things (see the compiler support elisp code)
1207 ;; - a list of source directories (in addition to those specified in the compiler project file)
1209 ;; - a casing exception file
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).
1217 (defvar ada-prj-alist nil
1218 "Alist holding currently parsed Emacs Ada project files. Indexed by absolute project file name.")
1220 (defvar ada-prj-current-file nil
1221 "Current Emacs Ada project file.")
1223 (defvar ada-prj-current-project nil
1224 "Current Emacs Ada mode project; a plist.")
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)))
1231 (plist-get prj prop)
1233 ;; no project, just use default vars
1234 ;; must match code in ada-prj-default
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)
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))
1255 (defun ada-require-project-file ()
1256 (unless ada-prj-current-file
1257 (error "no Emacs Ada project file specified")))
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.")
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.")
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.")
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'."
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
1300 'xref_tool ada-xref-tool
1303 (cl-dolist (func ada-prj-default-list)
1304 (setq project (funcall func project)))
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)))
1312 (defvar ada-prj-parser-alist
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.")
1323 ;; This autoloaded because it is often used in Makefiles, and thus
1324 ;; will be the first ada-mode function executed.
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))))
1332 (setq prj-file (expand-file-name prj-file))
1334 (unless (file-readable-p prj-file)
1335 (error "Project file '%s' is not readable" prj-file))
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))
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)))
1349 ;; return t for interactive use
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))
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
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
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.")
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.")
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
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))))
1401 (with-current-buffer (find-file-noselect prj-file)
1402 (goto-char (point-min))
1404 ;; process each line
1407 ;; ignore lines that don't have the format "name=value", put
1408 ;; 'name', 'value' in match-string.
1409 (when (looking-at "^\\([^=\n]+\\)=\\(.*\\)")
1411 ;; variable name alphabetical order
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)))))
1419 ((string= (match-string 1) "auto_case")
1420 (setq project (plist-put project 'auto_case (intern (match-string 2)))))
1422 ((string= (match-string 1) "case_keyword")
1423 (setq project (plist-put project 'case_keyword (intern (match-string 2)))))
1425 ((string= (match-string 1) "case_identifier")
1426 (setq project (plist-put project 'case_identifier (intern (match-string 2)))))
1428 ((string= (match-string 1) "case_strict")
1429 (setq project (plist-put project 'case_strict (intern (match-string 2)))))
1431 ((string= (match-string 1) "casing")
1432 (add-to-list 'casing
1434 (substitute-in-file-name (match-string 2)))))
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
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)))))
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)))))
1455 (and parse-one-compiler
1456 (setq tmp-prj (funcall parse-one-compiler (match-string 1) (match-string 2) project)))
1458 (setq tmp-prj (funcall parse-one-xref (match-string 1) (match-string 2) project))))
1460 (setq project tmp-prj)
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
1468 (let ((process-environment (plist-get project 'proc_env)))
1469 (setenv (substring (match-string 1) 1)
1470 (substitute-in-file-name (match-string 2)))
1472 (plist-put project 'proc_env process-environment)))
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)))
1481 );; done reading file
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))))
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))))
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))))
1502 (defvar ada-project-search-path nil
1503 "Search path for finding Ada project files")
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.")
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.")
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.")
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.")
1521 (defun ada-select-prj-file (prj-file)
1522 "Select PRJ-FILE as the current project file."
1524 (setq prj-file (expand-file-name prj-file))
1526 (setq ada-prj-current-project (cdr (assoc prj-file ada-prj-alist)))
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))
1532 (let ((func (cdr (assq (ada-prj-get 'ada_compiler) ada-deselect-prj-compiler))))
1533 (when func (funcall func)))
1535 (let ((func (cdr (assq (ada-prj-get 'xref_tool) ada-deselect-prj-xref-tool))))
1536 (when func (funcall func)))
1538 (setq ada-prj-current-file prj-file)
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)
1546 (when (ada-prj-get 'el_file)
1547 (load-file (ada-prj-get 'el_file)))
1549 (ada-case-read-all-exceptions)
1551 (setq compilation-search-path (ada-prj-get 'src_dir))
1552 (setq ada-project-search-path (ada-prj-get 'prj_dir))
1554 (let ((func (cdr (assq (ada-prj-get 'ada_compiler) ada-select-prj-compiler))))
1555 (when func (funcall func)))
1557 (let ((func (cdr (assq (ada-prj-get 'xref_tool) ada-select-prj-xref-tool))))
1558 (when func (funcall func)))
1560 ;; return 't', for decent display in message buffer when called interactively
1563 (defun ada-prj-select ()
1564 "Select the current project file from the list of currently available project files."
1566 (ada-select-prj-file (completing-read "project: " ada-prj-alist nil t))
1569 (defun ada-prj-show ()
1570 "Show current Emacs Ada mode project file."
1572 (message "current Emacs Ada mode project file: %s" ada-prj-current-file))
1574 (defvar ada-show-xref-tool-buffer nil
1575 ;; Supplied by xref tool
1576 "Function to show process buffer used by xref tool."
1579 (defun ada-show-xref-tool-buffer ()
1581 (when ada-show-xref-tool-buffer
1582 (funcall ada-show-xref-tool-buffer)))
1584 ;;;; syntax properties
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.
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
1596 (modify-syntax-entry ?% "$" table)
1597 (modify-syntax-entry ?\" "\"" table)
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)
1616 ;; and \f and \n end a comment
1617 (modify-syntax-entry ?\f ">" table)
1618 (modify-syntax-entry ?\n ">" table)
1620 (modify-syntax-entry ?_ "_" table); symbol constituents, not word.
1622 (modify-syntax-entry ?\( "()" table)
1623 (modify-syntax-entry ?\) ")(" table)
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)
1633 "Syntax table to be used for editing Ada source code.")
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.")
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")
1647 ;; called from `syntax-propertize', inside save-excursion with-silent-modifications
1648 (let ((inhibit-read-only t)
1649 (inhibit-point-motion-hooks t))
1652 (while (re-search-forward
1654 "[^a-zA-Z0-9)]\\('\\)[^'\n]\\('\\)"; 1, 2: character literal, not attribute
1655 "\\|[^a-zA-Z0-9)]\\('''\\)"; 3: character literal '''
1656 "\\|\\(--\\)"; 4: comment start
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
1664 ((match-beginning 1)
1666 (match-beginning 1) (match-end 1) 'syntax-table '(7 . ?'))
1668 (match-beginning 2) (match-end 2) 'syntax-table '(7 . ?')))
1669 ((match-beginning 3)
1671 (match-beginning 3) (1+ (match-beginning 3)) 'syntax-table '(7 . ?'))
1673 (1- (match-end 3)) (match-end 3) 'syntax-table '(7 . ?')))
1674 ((match-beginning 4)
1676 (match-beginning 4) (match-end 4) 'syntax-table '(11 . nil)))
1678 (run-hook-with-args 'ada-syntax-propertize-hook start end))
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))))
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))))
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)))
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))
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))))))
1708 ;;;; navigation within and between files
1710 (defvar ada-body-suffixes '(".adb")
1711 "List of possible suffixes for Ada body files.
1712 The extensions should include a `.' if needed.")
1714 (defvar ada-spec-suffixes '(".ads")
1715 "List of possible suffixes for Ada spec files.
1716 The extensions should include a `.' if needed.")
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'.")
1724 (defconst ada-name-regexp
1725 "\\(\\(?:\\sw\\|[_.]\\)+\\)")
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.")
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
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))
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.")
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))
1752 (defun ada-ff-special-extract-parent ()
1753 (setq ff-function-name (match-string 1))
1754 (file-name-nondirectory
1757 compilation-search-path
1758 (ada-file-name-from-ada-name ff-function-name)
1760 (error "parent '%s' not found; set project file?" ff-function-name))))
1762 (defun ada-ff-special-extract-separate ()
1763 (let ((package-name (match-string 1)))
1765 (goto-char (match-end 0))
1766 (when (eolp) (forward-char 1))
1767 (skip-syntax-forward " ")
1769 (concat "\\(function\\|package body\\|procedure\\|protected body\\|task body\\)\\s +"
1771 (setq ff-function-name (match-string 0))
1773 (file-name-nondirectory
1776 compilation-search-path
1777 (ada-file-name-from-ada-name package-name)
1779 (error "package '%s' not found; set project file?" package-name)))))
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
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)))
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.
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)
1808 ;; A "separate" clause.
1809 (cons (concat "^separate[ \t\n]*(" ada-name-regexp ")")
1810 'ada-ff-special-extract-separate)
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)
1817 (defvar ada-which-function nil
1818 ;; supplied by indentation engine
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
1829 (defun ada-which-function ()
1830 "See `ada-which-function' variable."
1832 (when ada-which-function
1833 (funcall ada-which-function)))
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'
1843 (ada-which-function)))
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
1851 (goto-char (point-min))
1852 ;; We are looking for an Ada declaration, so don't stop for strings or comments
1854 ;; This will still be confused by multiple references; we need
1855 ;; to use compiler cross reference info for more precision.
1857 (if (search-forward-regexp ff-function-name nil t)
1858 (setq found (match-beginning 0))
1859 ;; not in remainder of buffer
1861 (if (ada-in-string-or-comment-p)
1866 ;; different parsers find different points on the line; normalize here
1867 (back-to-indentation))
1868 (setq ff-function-name nil))))
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
1874 (when (null (car compilation-search-path))
1875 (error "no file search path defined; set project file?"))
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)))
1882 (error "current file not part of current project; wrong project?"))
1884 (setq found-file (file-truename found-file))
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)))))
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."
1898 (ada-find-other-file other-window t))
1900 (defun ada-find-other-file (other-window &optional no-set-point)
1901 "Move to the corresponding declaration in another file.
1903 - If region is active, assume it contains a package name;
1904 position point on that package declaration.
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.
1910 - If point is in the start line of a separate body,
1911 position point on the corresponding separate stub declaration.
1913 - If point is in a context clause line, position point on the
1914 first package declaration that is mentioned.
1916 - If point is in a subprogram body or specification, position point
1917 on the corresponding specification or body.
1919 If OTHER-WINDOW (set by interactive prefix) is non-nil, show the
1920 buffer in another window.
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
1926 ;; ff-get-file, ff-find-other file first process
1927 ;; ff-special-constructs, then run the following hooks:
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
1937 (ada-check-current-project (buffer-file-name))
1941 (setq ff-function-name (buffer-substring-no-properties (point) (mark)))
1943 compilation-search-path
1944 (ada-file-name-from-ada-name ff-function-name)
1949 ;; else use name at point
1950 (ff-find-other-file other-window)))
1952 (defvar ada-operator-re
1953 "\\+\\|-\\|/\\|\\*\\*\\|\\*\\|=\\|&\\|abs\\|mod\\|rem\\|and\\|not\\|or\\|xor\\|<=\\|<\\|>=\\|>"
1954 "Regexp matching Ada operator_symbol.")
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."
1960 (when (ada-in-comment-p)
1961 (error "Inside comment"))
1965 (skip-chars-backward "a-zA-Z0-9_<>=+\\-\\*/&")
1967 ;; Just in front of, or inside, a string => we could have an operator
1972 ((and (= (char-before) ?\")
1975 (looking-at (concat "\"\\(" ada-operator-re "\\)\""))))
1976 (setq identifier (concat "\"" (match-string-no-properties 1) "\"")))
1979 (error "Inside string or character constant"))
1982 ((and (= (char-after) ?\")
1983 (looking-at (concat "\"\\(" ada-operator-re "\\)\"")))
1984 (setq identifier (concat "\"" (match-string-no-properties 1) "\"")))
1986 ((looking-at "[a-zA-Z0-9_]+")
1987 (setq identifier (match-string-no-properties 0)))
1990 (error "No identifier around"))
1993 (defvar ada-goto-pos-ring '()
1994 "List of positions selected by navigation functions. Used
1995 to go back to these positions.")
1997 (defconst ada-goto-pos-ring-max 16
1998 "Number of positions kept in the list `ada-goto-pos-ring'.")
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)))
2006 (defun ada-goto-previous-pos ()
2007 "Go to the first position in `ada-goto-pos-ring', pop `ada-goto-pos-ring'."
2009 (when ada-goto-pos-ring
2010 (let ((pos (pop ada-goto-pos-ring)))
2011 (find-file (cadr pos))
2012 (goto-char (car pos)))))
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'.
2018 If OTHER-WINDOW is non-nil, show the buffer in another window."
2020 (if (file-name-absolute-p file) file
2021 (ff-get-file-name compilation-search-path file))))
2024 (error "File %s not found; installed library, or set project?" file))
2029 (let ((buffer (get-file-buffer file)))
2033 ((null other-window)
2034 (switch-to-buffer buffer))
2036 (t (switch-to-buffer-other-window buffer))
2039 ((file-exists-p file)
2041 ((null other-window)
2045 (find-file-other-window file))
2049 (error "'%s' not found" file))))
2052 ;; move the cursor to the correct position
2054 (goto-char (point-min))
2055 (forward-line (1- line))
2056 (forward-char column)
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.")
2063 (defun ada-xref-refresh ()
2064 "Refresh cross reference information cache, if any."
2067 (when (null ada-xref-refresh-function)
2068 (error "no cross reference information available"))
2070 (funcall ada-xref-refresh-function)
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
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.
2090 If OTHER-WINDOW (set by interactive prefix) is non-nil, show the
2091 buffer in another window."
2093 (ada-check-current-project (buffer-file-name))
2095 (when (null ada-xref-other-function)
2096 (error "no cross reference information available"))
2099 (funcall ada-xref-other-function
2100 (ada-identifier-at-point)
2102 (line-number-at-pos)
2103 (1+ (current-column))
2106 (ada-goto-source (nth 0 target)
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.")
2122 (defun ada-show-declaration-parents ()
2123 "Display the locations of the parent type declarations of the type identifier around point."
2125 (ada-check-current-project (buffer-file-name))
2127 (when (null ada-xref-parent-function)
2128 (error "no cross reference information available"))
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)))
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.")
2148 (defun ada-show-references ()
2149 "Show all references of identifier at point."
2151 (ada-check-current-project (buffer-file-name))
2153 (when (null ada-xref-all-function)
2154 (error "no cross reference information available"))
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)))
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.")
2173 (defun ada-show-overriding ()
2174 "Show all overridings of identifier at point."
2176 (ada-check-current-project (buffer-file-name))
2178 (when (null ada-xref-overriding-function)
2179 (error "no cross reference information available"))
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)))
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'.")
2199 (defun ada-show-overridden (other-window)
2200 "Show the overridden declaration of identifier at point."
2202 (ada-check-current-project (buffer-file-name))
2204 (when (null ada-xref-overridden-function)
2205 (error "'show overridden' not supported, or no cross reference information available"))
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)))))
2214 (ada-goto-source (nth 0 target)
2221 ;; This is autoloaded because it may be used in ~/.emacs
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
2227 (let* ((reg (concat (regexp-quote body) "$"))
2228 (tmp (assoc reg ada-other-file-alist)))
2230 (setcdr tmp (list (cons spec (cadr tmp))))
2231 (add-to-list 'ada-other-file-alist (list reg (list spec)))))
2233 (let* ((reg (concat (regexp-quote spec) "$"))
2234 (tmp (assoc reg ada-other-file-alist)))
2236 (setcdr tmp (list (cons body (cadr tmp))))
2237 (add-to-list 'ada-other-file-alist (list reg (list body)))))
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))
2244 (add-to-list 'ada-spec-suffixes spec)
2245 (add-to-list 'ada-body-suffixes body)
2247 (when (fboundp 'speedbar-add-supported-extension)
2248 (speedbar-add-supported-extension spec)
2249 (speedbar-add-supported-extension body))
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.
2258 If OTHER-WINDOW (set by interactive prefix) is non-nil, show the
2259 buffer in another window."
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))
2267 (set-buffer compilation-last-buffer)
2268 (setq pos (next-single-property-change (point) 'ada-secondary-error))
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)))
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!?
2281 (set-buffer start-buffer);; for windowing history
2286 (nth 2 item); column
2288 (select-window start-window)
2292 (defvar ada-goto-declaration-start nil
2293 ;; Supplied by indentation engine.
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
2302 (defun ada-goto-declaration-start ()
2303 "Call `ada-goto-declaration-start'."
2305 (when ada-goto-declaration-start
2306 (funcall ada-goto-declaration-start)))
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.")
2313 (defun ada-goto-declaration-end ()
2314 "See `ada-goto-declaration-end' variable."
2316 (when ada-goto-declaration-end
2317 (funcall ada-goto-declaration-end)))
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.")
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)))
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.")
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.")
2344 (defun ada-goto-end ()
2345 "Call `ada-goto-end'."
2347 (funcall ada-goto-end)))
2349 (defun ada-next-statement-keyword ()
2350 ;; Supplied by indentation engine
2351 "See `ada-next-statement-keyword' variable."
2353 (when ada-next-statement-keyword
2354 (funcall ada-next-statement-keyword)))
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.")
2363 (defun ada-prev-statement-keyword ()
2364 "See `ada-prev-statement-keyword' variable."
2366 (when ada-prev-statement-keyword
2367 (funcall ada-prev-statement-keyword)))
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.")
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'."
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")))
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.")
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)))
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
2404 (let ((body-file-name (buffer-file-name)))
2405 (ff-find-the-other-file)
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.
2411 ;; back to the body, read in from the disk.
2412 (ff-find-the-other-file)
2413 (revert-buffer t t))
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."
2425 (if (and (not (ada-in-comment-p))
2426 (not (looking-at "[ \t]*--")))
2427 (error "Not inside comment"))
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
2434 (fill-prefix ada-fill-comment-prefix)
2435 (fill-column (current-fill-column)))
2437 ;; Find end of comment paragraph
2438 (back-to-indentation)
2439 (while (and (not (eobp)) (looking-at ".*--[ \t]*[^ \t\n]"))
2442 ;; If we were at the last line in the buffer, create a dummy empty
2443 ;; line at the end of the buffer.
2446 (back-to-indentation)))
2448 (setq to (point-marker))
2451 ;; Find beginning of paragraph
2452 (back-to-indentation)
2453 (while (and (not (bobp)) (looking-at ".*--[ \t]*[^ \t\n]"))
2455 (back-to-indentation))
2460 (setq from (point-marker))
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))
2468 ;; Remove the old postfixes
2470 (while (re-search-forward (concat "\\(" ada-fill-comment-postfix "\\)" "\n") to t)
2471 (delete-region (match-beginning 1) (match-end 1)))
2474 (setq to (point-marker))
2476 ;; Indent and justify the paragraph
2477 (set-left-margin from to indent)
2479 (setq fill-column (- fill-column (length ada-fill-comment-postfix))))
2481 (fill-region-as-paragraph from to justify)
2483 ;; Add the postfixes if required
2487 (narrow-to-region from to)
2490 (insert-char ? (- fill-column (current-column)))
2491 (insert ada-fill-comment-postfix)
2497 ;;;; support for font-lock.el
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.")
2511 (defconst ada-95-keywords
2512 '("abstract" "aliased" "protected" "requeue" "tagged" "until")
2513 "List of keywords new in Ada 95.")
2515 (defconst ada-2005-keywords
2516 '("interface" "overriding" "synchronized")
2517 "List of keywords new in Ada 2005.")
2519 (defconst ada-2012-keywords
2521 "List of keywords new in Ada 2012.")
2523 (defun ada-font-lock-keywords ()
2524 "Return Ada mode value for `font-lock-keywords', depending on `ada-language-version'."
2527 ;; keywords followed by a name that should be in function-name-face.
2536 "package[ \t]+body\\|"
2544 (when (member ada-language-version '(ada95 ada2005 ada2012))
2546 "protected[ \t]+body\\|"
2547 "protected[ \t]+function\\|"
2548 "protected[ \t]+procedure\\|"
2549 "protected[ \t]+type\\|"
2554 ada-name-regexp "?")))
2555 '(1 font-lock-keyword-face) '(2 font-lock-function-name-face nil t))
2557 ;; keywords followed by a name that should be in type-face.
2560 "access[ \t]+all\\|"
2561 "access[ \t]+constant\\|"
2564 "in[ \t]+reverse\\|"; loop iterator
2565 "in[ \t]+not[ \t]+null\\|"
2566 "in[ \t]+out[ \t]+not[ \t]+null\\|"
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\\|"
2577 ada-name-regexp "?")
2578 '(1 font-lock-keyword-face nil t) '(2 font-lock-type-face nil t))
2580 ;; Keywords not treated elsewhere. After above so it doesn't
2581 ;; override fontication of second or third word in those patterns.
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))
2603 '(0 font-lock-keyword-face))
2605 ;; object and parameter declarations; word after ":" should be in
2606 ;; type-face if not already fontified or an exception.
2611 '(1 (if (match-beginning 2)
2613 font-lock-type-face)
2616 ;; keywords followed by a name that should be in function-name-face if not already fontified
2621 ada-name-regexp "?")
2622 '(1 font-lock-keyword-face) '(2 font-lock-function-name-face nil t))
2624 ;; Keywords followed by a name that could be a type or a function (generic instantiation).
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)
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"
2642 ada-name-regexp "?")
2643 '(1 font-lock-keyword-face) '(2 font-lock-type-face nil t))
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.
2651 ;; don't need "limited" "private" here; they are matched separately
2652 "with"; context clause
2654 "\\(\\(?:\\sw\\|[_., \t]\\)+\\>\\)?"; ada-name-regexp, plus ", \t"
2656 '(1 font-lock-keyword-face) '(2 font-lock-constant-face nil t))
2659 '("<<\\(\\sw+\\)>>" 1 font-lock-constant-face)
2661 ;; based numberic literals
2662 (list "\\([0-9]+#[0-9a-fA-F_]+#\\)" '(1 font-lock-constant-face t))
2665 (list "\\W\\([-+]?[0-9._]+\\)\\>" '(1 font-lock-constant-face))
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
2675 ;; autoload required by automatic mode setting
2678 "The major mode for editing Ada code."
2679 ;; the other ada-*.el files add to ada-mode-hook for their setup
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)
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)
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.
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) " ")
2709 (set (make-local-variable 'require-final-newline) t)
2711 (setq font-lock-defaults
2712 '(ada-font-lock-keywords
2714 ((?\_ . "w")))); treat underscore as a word component
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)
2728 (set (make-local-variable 'add-log-current-defun-function)
2729 'ada-add-log-current-function)
2731 (when (boundp 'which-func-functions)
2732 (add-hook 'which-func-functions 'ada-which-function nil t))
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)
2740 ;; Exclude comments alone on line from alignment.
2741 (add-to-list 'align-exclude-rules-list
2743 (regexp . "^\\(\\s-*\\)--")
2744 (modes . '(ada-mode))))
2745 (add-to-list 'align-exclude-rules-list
2747 (regexp . "^\\(\\s-*\\)\\<use\\>")
2748 (modes . '(ada-mode))))
2750 (setq align-mode-rules-list ada-align-rules)
2752 (easy-menu-add ada-mode-menu ada-mode-map)
2754 (run-mode-hooks 'ada-mode-hook)
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
2759 (syntax-ppss-flush-cache (point-min))
2760 (syntax-propertize (point-max))
2762 (add-hook 'hack-local-variables-hook 'ada-mode-post-local-vars nil t)
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).
2772 ;; This means to fully set ada-mode interactively, user must
2773 ;; do M-x ada-mode M-; (hack-local-variables)
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))
2780 (cl-case ada-language-version
2782 (setq ada-keywords ada-83-keywords))
2786 (append ada-83-keywords
2791 (append ada-83-keywords
2793 ada-2005-keywords)))
2796 (append ada-83-keywords
2799 ada-2012-keywords))))
2801 (when ada-goto-declaration-start
2802 (set (make-local-variable 'beginning-of-defun-function) ada-goto-declaration-start))
2804 (when ada-goto-declaration-end
2805 (set (make-local-variable 'end-of-defun-function) ada-goto-declaration-end))
2808 (put 'ada-mode 'custom-mode-group 'ada)
2812 ;;;;; Global initializations
2814 (require 'ada-build)
2816 (unless (featurep 'ada-indent-engine)
2817 (require 'ada-wisi))
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))
2826 (unless (featurep 'ada-compiler)
2827 (require 'ada-gnat-compile))
2829 (unless (featurep 'ada-skeletons)
2830 (require 'ada-skel))
2832 (when (featurep 'imenu)
2833 (require 'ada-imenu))