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