]> code.delx.au - gnu-emacs-elpa/blob - packages/ada-mode/ada-mode.el
Merge branch 'master' of https://github.com/leoliu/easy-kill
[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.3
9 ;; package-requires: ((wisi "1.0.4") (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.3"))
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-region)
237 (const upcase-region))
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 (if ada-prj-current-file
956 (error "No exception file specified; set `casing' in project file.")
957 ;; IMPROVEME: could prompt, but then need to write to actual project file
958 ;; (let ((temp
959 ;; (read-file-name
960 ;; "No exception file specified; adding to project. file: ")))
961 ;; (message "remember to add %s to project file" temp)
962 ;; (ada-prj-put 'casing temp)
963 ;; temp)
964 (error "No exception file specified, and no project active. See variable `ada-case-exception-file'.")))
965 )))
966
967 (unless word
968 (if (use-region-p)
969 (setq word (buffer-substring-no-properties (region-beginning) (region-end)))
970 (save-excursion
971 (skip-syntax-backward "w_")
972 (setq word
973 (buffer-substring-no-properties
974 (point)
975 (progn (skip-syntax-forward "w_") (point))
976 )))))
977
978 (let* ((exceptions (ada-case-read-exceptions file-name))
979 (full-exceptions (car exceptions))
980 (partial-exceptions (cdr exceptions)))
981
982 (cond
983 ((null partial)
984 (setq ada-case-full-exceptions (ada-case-add-exception word ada-case-full-exceptions))
985 (setq full-exceptions (ada-case-add-exception word full-exceptions)))
986
987 (t
988 (setq ada-case-partial-exceptions (ada-case-add-exception word ada-case-partial-exceptions))
989 (setq partial-exceptions (ada-case-add-exception word partial-exceptions)))
990 )
991 (ada-case-save-exceptions full-exceptions partial-exceptions file-name)
992 (message "created %s case exception '%s' in file '%s'"
993 (if partial "partial" "full")
994 word
995 file-name)
996 ))
997
998 (defun ada-case-create-partial-exception ()
999 "Define active region or word at point as a partial word exception.
1000 User is prompted to choose a file from project variable casing if it is a list."
1001 (interactive)
1002 (ada-case-create-exception nil nil t))
1003
1004 (defun ada-in-numeric-literal-p ()
1005 "Return t if point is after a prefix of a numeric literal."
1006 (looking-back "\\([0-9]+#[0-9a-fA-F_]+\\)"))
1007
1008 (defvar ada-keywords nil
1009 "List of Ada keywords for current `ada-language-version'.")
1010
1011 (defun ada-after-keyword-p ()
1012 "Return non-nil if point is after an element of `ada-keywords'."
1013 (let ((word (buffer-substring-no-properties
1014 (save-excursion (skip-syntax-backward "w_") (point))
1015 (point))))
1016 (member (downcase word) ada-keywords)))
1017
1018 (defun ada-mixed-case (start end)
1019 "Adjust case of region START END to Mixed_Case."
1020 (let ((done nil)
1021 next)
1022 (if ada-case-strict
1023 (downcase-region start end))
1024 (goto-char start)
1025 (while (not done)
1026 (setq next
1027 (or
1028 (save-excursion (when (search-forward "_" end t) (point-marker)))
1029 (copy-marker (1+ end))))
1030
1031 ;; upcase first char
1032 (insert-char (upcase (following-char)) 1)
1033 (delete-char 1)
1034
1035 (goto-char next)
1036 (if (< (point) end)
1037 (setq start (point))
1038 (setq done t))
1039 )))
1040
1041 (defun ada-case-adjust-identifier ()
1042 "Adjust case of the previous word as an identifier.
1043 Uses `ada-case-identifier', with exceptions defined in
1044 `ada-case-full-exceptions', `ada-case-partial-exceptions'."
1045 (interactive)
1046 (save-excursion
1047 (let ((end (point-marker))
1048 (start (progn (skip-syntax-backward "w_") (point)))
1049 match
1050 next
1051 (done nil))
1052
1053 (if (setq match (assoc-string (buffer-substring-no-properties start end) ada-case-full-exceptions t))
1054 ;; full word exception
1055 (progn
1056 ;; 'save-excursion' puts a marker at 'end'; if we do
1057 ;; 'delete-region' first, it moves that marker to 'start',
1058 ;; then 'insert' inserts replacement text after the
1059 ;; marker, defeating 'save-excursion'. So we do 'insert' first.
1060 (insert (car match))
1061 (delete-region (point) end))
1062
1063 ;; else apply ada-case-identifier
1064 (funcall ada-case-identifier start end)
1065
1066 ;; apply partial-exceptions
1067 (goto-char start)
1068 (while (not done)
1069 (setq next
1070 (or
1071 (save-excursion (when (search-forward "_" end t) (point-marker)))
1072 (copy-marker (1+ end))))
1073
1074 (when (setq match (assoc-string (buffer-substring-no-properties start (1- next))
1075 ada-case-partial-exceptions t))
1076 ;; see comment above at 'full word exception' for why
1077 ;; we do insert first.
1078 (insert (car match))
1079 (delete-region (point) (1- next)))
1080
1081 (goto-char next)
1082 (if (< (point) end)
1083 (setq start (point))
1084 (setq done t))
1085 )))))
1086
1087 (defun ada-case-adjust (&optional typed-char in-comment)
1088 "Adjust the case of the word before point.
1089 When invoked interactively, TYPED-CHAR must be
1090 `last-command-event', and it must not have been inserted yet.
1091 If IN-COMMENT is non-nil, adjust case of words in comments."
1092 (when (not (bobp))
1093 (when (save-excursion
1094 (forward-char -1); back to last character in word
1095 (and (not (bobp))
1096 (eq (char-syntax (char-after)) ?w); it can be capitalized
1097
1098 (not (and (eq typed-char ?')
1099 (eq (char-before (point)) ?'))); character literal
1100
1101 (or in-comment
1102 (not (ada-in-string-or-comment-p)))
1103 ;; we sometimes want to capitialize an Ada identifier
1104 ;; referenced in a comment, via
1105 ;; ada-case-adjust-at-point.
1106
1107 (not (ada-in-numeric-literal-p))
1108 ))
1109
1110 ;; The indentation engine may trigger a reparse on
1111 ;; non-whitespace changes, but we know we don't need to reparse
1112 ;; for this change (assuming the user has not abused case
1113 ;; exceptions!).
1114 (let ((inhibit-modification-hooks t))
1115 (cond
1116 ;; Some attributes are also keywords, but captialized as
1117 ;; attributes. So check for attribute first.
1118 ((and
1119 (not in-comment)
1120 (save-excursion
1121 (skip-syntax-backward "w_")
1122 (eq (char-before) ?')))
1123 (ada-case-adjust-identifier))
1124
1125 ((and
1126 (not in-comment)
1127 (not (eq typed-char ?_))
1128 (ada-after-keyword-p))
1129 (funcall ada-case-keyword -1))
1130
1131 (t (ada-case-adjust-identifier))
1132 ))
1133 )))
1134
1135 (defun ada-case-adjust-at-point (&optional in-comment)
1136 "Adjust case of word at point, move to end of word.
1137 With prefix arg, adjust case even if in comment."
1138 (interactive "P")
1139 (when
1140 (and (not (eobp))
1141 ;; we use '(syntax-after (point))' here, not '(char-syntax
1142 ;; (char-after))', because the latter does not respect
1143 ;; ada-syntax-propertize.
1144 (memq (syntax-class (syntax-after (point))) '(2 3)))
1145 (skip-syntax-forward "w_"))
1146 (ada-case-adjust nil in-comment))
1147
1148 (defun ada-case-adjust-region (begin end)
1149 "Adjust case of all words in region BEGIN END."
1150 (interactive "r")
1151 (narrow-to-region begin end)
1152 (save-excursion
1153 (goto-char begin)
1154 (while (not (eobp))
1155 (forward-comment (point-max))
1156 (skip-syntax-forward "^w_")
1157 (skip-syntax-forward "w_")
1158 (ada-case-adjust)))
1159 (widen))
1160
1161 (defun ada-case-adjust-buffer ()
1162 "Adjust case of current buffer."
1163 (interactive)
1164 (ada-case-adjust-region (point-min) (point-max)))
1165
1166 (defun ada-case-adjust-interactive (arg)
1167 "If `ada-auto-case' is non-nil, adjust the case of the previous word, and process the character just typed.
1168 To be bound to keys that should cause auto-casing.
1169 ARG is the prefix the user entered with \\[universal-argument]."
1170 (interactive "P")
1171
1172 ;; character typed has not been inserted yet
1173 (let ((lastk last-command-event))
1174
1175 (cond
1176 ((eq lastk ?\n)
1177 (when ada-auto-case
1178 (ada-case-adjust lastk))
1179 (funcall ada-lfd-binding))
1180
1181 ((memq lastk '(?\r return))
1182 (when ada-auto-case
1183 (ada-case-adjust lastk))
1184 (funcall ada-ret-binding))
1185
1186 (t
1187 (when ada-auto-case
1188 (ada-case-adjust lastk))
1189 (self-insert-command (prefix-numeric-value arg)))
1190 )))
1191
1192 ;;;; project files
1193
1194 ;; An Emacs Ada mode project file can specify several things:
1195 ;;
1196 ;; - a compiler-specific project file
1197 ;;
1198 ;; - compiler-specific environment variables
1199 ;;
1200 ;; - other compiler-specific things (see the compiler support elisp code)
1201 ;;
1202 ;; - a list of source directories (in addition to those specified in the compiler project file)
1203 ;;
1204 ;; - a casing exception file
1205 ;;
1206 ;; All of the data used by Emacs Ada mode functions specified in a
1207 ;; project file is stored in a property list. The property list is
1208 ;; stored in an alist indexed by the project file name, so multiple
1209 ;; project files can be selected without re-parsing them (some
1210 ;; compiler project files can take a long time to parse).
1211
1212 (defvar ada-prj-alist nil
1213 "Alist holding currently parsed Emacs Ada project files. Indexed by absolute project file name.")
1214
1215 (defvar ada-prj-current-file nil
1216 "Current Emacs Ada project file.")
1217
1218 (defvar ada-prj-current-project nil
1219 "Current Emacs Ada mode project; a plist.")
1220
1221 (defun ada-prj-get (prop &optional plist)
1222 "Return value of PROP in PLIST.
1223 Optional PLIST defaults to `ada-prj-current-project'."
1224 (let ((prj (or plist ada-prj-current-project)))
1225 (if prj
1226 (plist-get prj prop)
1227
1228 ;; no project, just use default vars
1229 ;; must match code in ada-prj-default
1230 (cl-case plist
1231 (ada_compiler ada-compiler)
1232 (auto_case ada-auto-case)
1233 (case_keyword ada-case-keyword)
1234 (case_identifier ada-case-identifier)
1235 (case_strict ada-case-strict)
1236 (casing (if (listp ada-case-exception-file)
1237 ada-case-exception-file
1238 (list ada-case-exception-file)))
1239 (path_sep path-separator)
1240 (proc_env process-environment)
1241 (src_dir (list "."))
1242 (xref_tool ada-xref-tool)
1243 ))))
1244
1245 (defun ada-prj-put (prop val &optional plist)
1246 "Set value of PROP in PLIST to VAL.
1247 Optional PLIST defaults to `ada-prj-current-project'."
1248 (plist-put (or plist ada-prj-current-project) prop val))
1249
1250 (defun ada-require-project-file ()
1251 (unless ada-prj-current-file
1252 (error "no Emacs Ada project file specified")))
1253
1254 (defvar ada-prj-default-list nil
1255 ;; project file parse
1256 "List of functions to add default project variables. Called
1257 with one argument; the default project properties list. Function
1258 should add to the properties list and return it.")
1259
1260 (defvar ada-prj-default-compiler-alist nil
1261 ;; project file parse
1262 "Compiler-specific function to set default project variables.
1263 Indexed by ada-compiler. Called with one argument; the default
1264 project properties list. Function should add to the properties
1265 list and return it.")
1266
1267 (defvar ada-prj-default-xref-alist nil
1268 ;; project file parse
1269 "Xref-tool-specific function to set default project variables.
1270 Indexed by ada-xref-tool. Called with one argument; the default
1271 project properties list. Function should add to the properties
1272 list and return it.")
1273
1274 (defun ada-prj-default ()
1275 "Return the default project properties list.
1276 Include properties set via `ada-prj-default-compiler-alist',
1277 `ada-prj-default-xref-alist'."
1278
1279 (let (project func)
1280 (setq
1281 project
1282 (list
1283 ;; variable name alphabetical order
1284 'ada_compiler ada-compiler
1285 'auto_case ada-auto-case
1286 'case_keyword ada-case-keyword
1287 'case_identifier ada-case-identifier
1288 'case_strict ada-case-strict
1289 'casing (if (listp ada-case-exception-file)
1290 ada-case-exception-file
1291 (list ada-case-exception-file))
1292 'path_sep path-separator;; prj variable so users can override it for their compiler
1293 'proc_env process-environment
1294 'src_dir (list ".")
1295 'xref_tool ada-xref-tool
1296 ))
1297
1298 (cl-dolist (func ada-prj-default-list)
1299 (setq project (funcall func project)))
1300
1301 (setq func (cdr (assq ada-compiler ada-prj-default-compiler-alist)))
1302 (when func (setq project (funcall func project)))
1303 (setq func (cdr (assq ada-xref-tool ada-prj-default-xref-alist)))
1304 (when func (setq project (funcall func project)))
1305 project))
1306
1307 (defvar ada-prj-parser-alist
1308 (mapcar
1309 (lambda (ext) (cons ext 'ada-prj-parse-file-1))
1310 ada-prj-file-extensions)
1311 ;; project file parse
1312 "Alist of parsers for project files, indexed by file extension.
1313 Default provides the minimal Ada mode parser; compiler support
1314 code may add other parsers. Parser is called with two arguments;
1315 the project file name and the current project property
1316 list. Parser must modify or add to the property list and return it.")
1317
1318 ;; This autoloaded because it is often used in Makefiles, and thus
1319 ;; will be the first ada-mode function executed.
1320 ;;;###autoload
1321 (defun ada-parse-prj-file (prj-file)
1322 "Read Emacs Ada or compiler-specific project file PRJ-FILE, set project properties in `ada-prj-alist'."
1323 ;; Not called ada-prj-parse-file for Ada mode 4.01 compatibility
1324 (let ((project (ada-prj-default))
1325 (parser (cdr (assoc (file-name-extension prj-file) ada-prj-parser-alist))))
1326
1327 (setq prj-file (expand-file-name prj-file))
1328
1329 (unless (file-readable-p prj-file)
1330 (error "Project file '%s' is not readable" prj-file))
1331
1332 (if parser
1333 ;; parser may reference the "current project", so bind that now.
1334 (let ((ada-prj-current-project project)
1335 (ada-prj-current-file prj-file))
1336 (setq project (funcall parser prj-file project)))
1337 (error "no project file parser defined for '%s'" prj-file))
1338
1339 ;; Store the project properties
1340 (if (assoc prj-file ada-prj-alist)
1341 (setcdr (assoc prj-file ada-prj-alist) project)
1342 (add-to-list 'ada-prj-alist (cons prj-file project)))
1343
1344 ;; return t for interactive use
1345 t))
1346
1347 (defun ada-prj-reparse-select-current ()
1348 "Reparse the current project file, re-select it.
1349 Useful when the project file has been edited."
1350 (ada-parse-prj-file ada-prj-current-file)
1351 (ada-select-prj-file ada-prj-current-file))
1352
1353 (defvar ada-prj-parse-one-compiler nil
1354 ;; project file parse
1355 "Compiler-specific function to process one Ada project property.
1356 Indexed by project variable ada_compiler.
1357 Called with three arguments; the property name, property value,
1358 and project properties list. Function should add to or modify the
1359 properties list and return it, or return nil if the name is not
1360 recognized.")
1361
1362 (defvar ada-prj-parse-one-xref nil
1363 ;; project file parse
1364 "Xref-tool-specific function to process one Ada project property.
1365 Indexed by project variable xref_tool.
1366 Called with three arguments; the property name, property value,
1367 and project properties list. Function should add to or modify the
1368 properties list and return it, or return nil if the name is not
1369 recognized.")
1370
1371 (defvar ada-prj-parse-final-compiler nil
1372 ;; project file parse
1373 "Alist of compiler-specific functions to finish processing Ada project properties.
1374 Indexed by project variable ada_compiler.
1375 Called with one argument; the project properties list. Function
1376 should add to or modify the list and return it.")
1377
1378 (defvar ada-prj-parse-final-xref nil
1379 ;; project file parse
1380 "Alist of xref-tool-specific functions to finish processing Ada project properties.
1381 Indexed by project variable xref_tool.
1382 Called with one argument; the project properties list. Function
1383 should add to or modify the list and return it.")
1384
1385 (defun ada-prj-parse-file-1 (prj-file project)
1386 "Parse the Ada mode project file PRJ-FILE, set project properties in PROJECT.
1387 Return new value of PROJECT."
1388 (let (;; fields that are lists or that otherwise require special processing
1389 casing src_dir
1390 tmp-prj
1391 (parse-one-compiler (cdr (assoc ada-compiler ada-prj-parse-one-compiler)))
1392 (parse-final-compiler (cdr (assoc ada-compiler ada-prj-parse-final-compiler)))
1393 (parse-one-xref (cdr (assoc ada-xref-tool ada-prj-parse-one-xref)))
1394 (parse-final-xref (cdr (assoc ada-xref-tool ada-prj-parse-final-xref))))
1395
1396 (with-current-buffer (find-file-noselect prj-file)
1397 (goto-char (point-min))
1398
1399 ;; process each line
1400 (while (not (eobp))
1401
1402 ;; ignore lines that don't have the format "name=value", put
1403 ;; 'name', 'value' in match-string.
1404 (when (looking-at "^\\([^=\n]+\\)=\\(.*\\)")
1405 (cond
1406 ;; variable name alphabetical order
1407
1408 ((string= (match-string 1) "ada_compiler")
1409 (let ((comp (intern (match-string 2))))
1410 (setq project (plist-put project 'ada_compiler comp))
1411 (setq parse-one-compiler (cdr (assq comp ada-prj-parse-one-compiler)))
1412 (setq parse-final-compiler (cdr (assq comp ada-prj-parse-final-compiler)))))
1413
1414 ((string= (match-string 1) "auto_case")
1415 (setq project (plist-put project 'auto_case (intern (match-string 2)))))
1416
1417 ((string= (match-string 1) "case_keyword")
1418 (setq project (plist-put project 'case_keyword (intern (match-string 2)))))
1419
1420 ((string= (match-string 1) "case_identifier")
1421 (setq project (plist-put project 'case_identifier (intern (match-string 2)))))
1422
1423 ((string= (match-string 1) "case_strict")
1424 (setq project (plist-put project 'case_strict (intern (match-string 2)))))
1425
1426 ((string= (match-string 1) "casing")
1427 (add-to-list 'casing
1428 (expand-file-name
1429 (substitute-in-file-name (match-string 2)))))
1430
1431 ((string= (match-string 1) "el_file")
1432 (let ((file (expand-file-name (substitute-in-file-name (match-string 2)))))
1433 (setq project (plist-put project 'el_file file))
1434 ;; eval now as well as in select, since it might affect parsing
1435 (load-file file)))
1436
1437 ((string= (match-string 1) "src_dir")
1438 (add-to-list 'src_dir
1439 (file-name-as-directory
1440 (expand-file-name (match-string 2)))))
1441
1442 ((string= (match-string 1) "xref_tool")
1443 (let ((xref (intern (match-string 2))))
1444 (setq project (plist-put project 'xref_tool xref))
1445 (setq parse-one-xref (cdr (assq xref ada-prj-parse-one-xref)))
1446 (setq parse-final-xref (cdr (assq xref ada-prj-parse-final-xref)))))
1447
1448 (t
1449 (if (or
1450 (and parse-one-compiler
1451 (setq tmp-prj (funcall parse-one-compiler (match-string 1) (match-string 2) project)))
1452 (and parse-one-xref
1453 (setq tmp-prj (funcall parse-one-xref (match-string 1) (match-string 2) project))))
1454
1455 (setq project tmp-prj)
1456
1457 ;; Any other field in the file is set as an environment
1458 ;; variable or a project file.
1459 (if (= ?$ (elt (match-string 1) 0))
1460 ;; process env var. We don't do expand-file-name
1461 ;; here because the application may be expecting a
1462 ;; simple string.
1463 (let ((process-environment (plist-get project 'proc_env)))
1464 (setenv (substring (match-string 1) 1)
1465 (substitute-in-file-name (match-string 2)))
1466 (setq project
1467 (plist-put project 'proc_env process-environment)))
1468
1469 ;; not recognized; assume it is a user-defined variable like "comp_opt"
1470 (setq project (plist-put project (intern (match-string 1)) (match-string 2)))
1471 )))
1472 ))
1473
1474 (forward-line 1))
1475
1476 );; done reading file
1477
1478 ;; process accumulated lists
1479 (if casing (set 'project (plist-put project 'casing (reverse casing))))
1480 (if src_dir (set 'project (plist-put project 'src_dir (reverse src_dir))))
1481
1482 (when parse-final-compiler
1483 ;; parse-final-compiler may reference the "current project", so
1484 ;; bind that now, to include the properties set above.
1485 (let ((ada-prj-current-project project)
1486 (ada-prj-current-file prj-file))
1487 (setq project (funcall parse-final-compiler project))))
1488
1489 (when parse-final-xref
1490 (let ((ada-prj-current-project project)
1491 (ada-prj-current-file prj-file))
1492 (setq project (funcall parse-final-xref project))))
1493
1494 project
1495 ))
1496
1497 (defvar ada-project-search-path nil
1498 "Search path for finding Ada project files")
1499
1500 (defvar ada-select-prj-compiler nil
1501 "Alist of functions to call for compiler specific project file selection.
1502 Indexed by project variable ada_compiler.")
1503
1504 (defvar ada-deselect-prj-compiler nil
1505 "Alist of functions to call for compiler specific project file deselection.
1506 Indexed by project variable ada_compiler.")
1507
1508 (defvar ada-select-prj-xref-tool nil
1509 "Alist of functions to call for xref-tool specific project file selection.
1510 Indexed by project variable xref_tool.")
1511
1512 (defvar ada-deselect-prj-xref-tool nil
1513 "Alist of functions to call for xref-tool specific project file deselection.
1514 Indexed by project variable xref_tool.")
1515
1516 (defun ada-select-prj-file (prj-file)
1517 "Select PRJ-FILE as the current project file."
1518 (interactive)
1519 (setq prj-file (expand-file-name prj-file))
1520
1521 (setq ada-prj-current-project (cdr (assoc prj-file ada-prj-alist)))
1522
1523 (when (null ada-prj-current-project)
1524 (setq ada-prj-current-file nil)
1525 (error "Project file '%s' was not previously parsed." prj-file))
1526
1527 (let ((func (cdr (assq (ada-prj-get 'ada_compiler) ada-deselect-prj-compiler))))
1528 (when func (funcall func)))
1529
1530 (let ((func (cdr (assq (ada-prj-get 'xref_tool) ada-deselect-prj-xref-tool))))
1531 (when func (funcall func)))
1532
1533 (setq ada-prj-current-file prj-file)
1534
1535 ;; Project file should fully specify what compilers are used,
1536 ;; including what compilation filters they need. There may be more
1537 ;; than just an Ada compiler.
1538 (setq compilation-error-regexp-alist nil)
1539 (setq compilation-filter-hook nil)
1540
1541 (when (ada-prj-get 'el_file)
1542 (load-file (ada-prj-get 'el_file)))
1543
1544 (ada-case-read-all-exceptions)
1545
1546 (setq compilation-search-path (ada-prj-get 'src_dir))
1547 (setq ada-project-search-path (ada-prj-get 'prj_dir))
1548
1549 (let ((func (cdr (assq (ada-prj-get 'ada_compiler) ada-select-prj-compiler))))
1550 (when func (funcall func)))
1551
1552 (let ((func (cdr (assq (ada-prj-get 'xref_tool) ada-select-prj-xref-tool))))
1553 (when func (funcall func)))
1554
1555 ;; return 't', for decent display in message buffer when called interactively
1556 t)
1557
1558 (defun ada-prj-select ()
1559 "Select the current project file from the list of currently available project files."
1560 (interactive)
1561 (ada-select-prj-file (completing-read "project: " ada-prj-alist nil t))
1562 )
1563
1564 (defun ada-prj-show ()
1565 "Show current Emacs Ada mode project file."
1566 (interactive)
1567 (message "current Emacs Ada mode project file: %s" ada-prj-current-file))
1568
1569 ;;;; syntax properties
1570
1571 (defvar ada-mode-syntax-table
1572 (let ((table (make-syntax-table)))
1573 ;; (info "(elisp)Syntax Class Table" "*info syntax class table*")
1574 ;; make-syntax-table sets all alphanumeric to w, etc; so we only
1575 ;; have to add ada-specific things.
1576
1577 ;; string brackets. `%' is the obsolete alternative string
1578 ;; bracket (arm J.2); if we make it syntax class ", it throws
1579 ;; font-lock and indentation off the track, so we use syntax class
1580 ;; $.
1581 (modify-syntax-entry ?% "$" table)
1582 (modify-syntax-entry ?\" "\"" table)
1583
1584 ;; punctuation; operators etc
1585 (modify-syntax-entry ?# "w" table); based number - word syntax, since we don't need the number
1586 (modify-syntax-entry ?& "." table)
1587 (modify-syntax-entry ?* "." table)
1588 (modify-syntax-entry ?+ "." table)
1589 (modify-syntax-entry ?- ". 12" table); operator; see ada-syntax-propertize for double hyphen as comment
1590 (modify-syntax-entry ?. "." table)
1591 (modify-syntax-entry ?/ "." table)
1592 (modify-syntax-entry ?: "." table)
1593 (modify-syntax-entry ?< "." table)
1594 (modify-syntax-entry ?= "." table)
1595 (modify-syntax-entry ?> "." table)
1596 (modify-syntax-entry ?\' "." table); attribute; see ada-syntax-propertize for character literal
1597 (modify-syntax-entry ?\; "." table)
1598 (modify-syntax-entry ?\\ "." table); default is escape; not correct for Ada strings
1599 (modify-syntax-entry ?\| "." table)
1600
1601 ;; and \f and \n end a comment
1602 (modify-syntax-entry ?\f ">" table)
1603 (modify-syntax-entry ?\n ">" table)
1604
1605 (modify-syntax-entry ?_ "_" table); symbol constituents, not word.
1606
1607 (modify-syntax-entry ?\( "()" table)
1608 (modify-syntax-entry ?\) ")(" table)
1609
1610 ;; skeleton placeholder delimiters; see ada-skel.el. We use generic
1611 ;; comment delimiter class, not comment starter/comment ender, so
1612 ;; these can be distinguished from line end.
1613 (modify-syntax-entry ?{ "!" table)
1614 (modify-syntax-entry ?} "!" table)
1615
1616 table
1617 )
1618 "Syntax table to be used for editing Ada source code.")
1619
1620 (defvar ada-syntax-propertize-hook nil
1621 ;; provided by preprocessor, lumped with xref-tool
1622 "Hook run from `ada-syntax-propertize'.
1623 Called by `syntax-propertize', which is called by font-lock in
1624 `after-change-functions'. Therefore, care must be taken to avoid
1625 race conditions with the grammar parser.")
1626
1627 (defun ada-syntax-propertize (start end)
1628 "Assign `syntax-table' properties in accessible part of buffer.
1629 In particular, character constants are set to have string syntax."
1630 ;; (info "(elisp)Syntax Properties")
1631 ;;
1632 ;; called from `syntax-propertize', inside save-excursion with-silent-modifications
1633 (let ((inhibit-read-only t)
1634 (inhibit-point-motion-hooks t))
1635 (goto-char start)
1636 (save-match-data
1637 (while (re-search-forward
1638 (concat
1639 "[^a-zA-Z0-9)]\\('\\)[^'\n]\\('\\)"; 1, 2: character literal, not attribute
1640 "\\|[^a-zA-Z0-9)]\\('''\\)"; 3: character literal '''
1641 "\\|\\(--\\)"; 4: comment start
1642 )
1643 end t)
1644 ;; The help for syntax-propertize-extend-region-functions
1645 ;; implies that 'start end' will always include whole lines, in
1646 ;; which case we don't need
1647 ;; syntax-propertize-extend-region-functions
1648 (cond
1649 ((match-beginning 1)
1650 (put-text-property
1651 (match-beginning 1) (match-end 1) 'syntax-table '(7 . ?'))
1652 (put-text-property
1653 (match-beginning 2) (match-end 2) 'syntax-table '(7 . ?')))
1654 ((match-beginning 3)
1655 (put-text-property
1656 (match-beginning 3) (1+ (match-beginning 3)) 'syntax-table '(7 . ?'))
1657 (put-text-property
1658 (1- (match-end 3)) (match-end 3) 'syntax-table '(7 . ?')))
1659 ((match-beginning 4)
1660 (put-text-property
1661 (match-beginning 4) (match-end 4) 'syntax-table '(11 . nil)))
1662 )))
1663 (run-hook-with-args 'ada-syntax-propertize-hook start end))
1664 )
1665
1666 (defun ada-in-comment-p (&optional parse-result)
1667 "Return t if inside a comment.
1668 If PARSE-RESULT is non-nil, use it instead of calling `syntax-ppss'."
1669 (nth 4 (or parse-result (syntax-ppss))))
1670
1671 (defun ada-in-string-p (&optional parse-result)
1672 "Return t if point is inside a string.
1673 If PARSE-RESULT is non-nil, use it instead of calling `syntax-ppss'."
1674 (nth 3 (or parse-result (syntax-ppss))))
1675
1676 (defun ada-in-string-or-comment-p (&optional parse-result)
1677 "Return t if inside a comment or string.
1678 If PARSE-RESULT is non-nil, use it instead of calling `syntax-ppss'."
1679 (setq parse-result (or parse-result (syntax-ppss)))
1680 (or (ada-in-string-p parse-result) (ada-in-comment-p parse-result)))
1681
1682 (defun ada-in-paren-p (&optional parse-result)
1683 "Return t if point is inside a pair of parentheses.
1684 If PARSE-RESULT is non-nil, use it instead of calling `syntax-ppss'."
1685 (> (nth 0 (or parse-result (syntax-ppss))) 0))
1686
1687 (defun ada-goto-open-paren (&optional offset parse-result)
1688 "Move point to innermost opening paren surrounding current point, plus OFFSET.
1689 Throw error if not in paren. If PARSE-RESULT is non-nil, use it
1690 instead of calling `syntax-ppss'."
1691 (goto-char (+ (or offset 0) (nth 1 (or parse-result (syntax-ppss))))))
1692
1693 ;;;; navigation within and between files
1694
1695 (defvar ada-body-suffixes '(".adb")
1696 "List of possible suffixes for Ada body files.
1697 The extensions should include a `.' if needed.")
1698
1699 (defvar ada-spec-suffixes '(".ads")
1700 "List of possible suffixes for Ada spec files.
1701 The extensions should include a `.' if needed.")
1702
1703 (defvar ada-other-file-alist
1704 '(("\\.ads$" (".adb"))
1705 ("\\.adb$" (".ads")))
1706 "Alist used by `find-file' to find the name of the other package.
1707 See `ff-other-file-alist'.")
1708
1709 (defconst ada-name-regexp
1710 "\\(\\(?:\\sw\\|[_.]\\)+\\)")
1711
1712 (defconst ada-parent-name-regexp
1713 "\\([a-zA-Z0-9_\\.]+\\)\\.[a-zA-Z0-9_]+"
1714 "Regexp for extracting the parent name from fully-qualified name.")
1715
1716 (defvar ada-file-name-from-ada-name nil
1717 ;; determined by ada-xref-tool, set by *-select-prj
1718 "Function called with one parameter ADA-NAME, which is a library
1719 unit name; it should return the filename in which ADA-NAME is
1720 found.")
1721
1722 (defun ada-file-name-from-ada-name (ada-name)
1723 "Return the filename in which ADA-NAME is found."
1724 (funcall ada-file-name-from-ada-name ada-name))
1725
1726 (defvar ada-ada-name-from-file-name nil
1727 ;; depends on ada-compiler, per-project
1728 "Function called with one parameter FILE-NAME, which is a library
1729 unit name; it should return the Ada name that should be found in FILE-NAME.")
1730
1731 (defun ada-ada-name-from-file-name (file-name)
1732 "Return the ada-name that should be found in FILE-NAME."
1733 (funcall ada-ada-name-from-file-name file-name))
1734
1735 (defun ada-ff-special-extract-parent ()
1736 (setq ff-function-name (match-string 1))
1737 (file-name-nondirectory
1738 (or
1739 (ff-get-file-name
1740 compilation-search-path
1741 (ada-file-name-from-ada-name ff-function-name)
1742 ada-spec-suffixes)
1743 (error "parent '%s' not found; set project file?" ff-function-name))))
1744
1745 (defun ada-ff-special-extract-separate ()
1746 (let ((package-name (match-string 1)))
1747 (save-excursion
1748 (goto-char (match-end 0))
1749 (when (eolp) (forward-char 1))
1750 (skip-syntax-forward " ")
1751 (looking-at
1752 (concat "\\(function\\|package body\\|procedure\\|protected body\\|task body\\)\\s +"
1753 ada-name-regexp))
1754 (setq ff-function-name (match-string 0))
1755 )
1756 (file-name-nondirectory
1757 (or
1758 (ff-get-file-name
1759 compilation-search-path
1760 (ada-file-name-from-ada-name package-name)
1761 ada-body-suffixes)
1762 (error "package '%s' not found; set project file?" package-name)))))
1763
1764 (defun ada-ff-special-with ()
1765 (let ((package-name (match-string 1)))
1766 (setq ff-function-name (concat "^package\\s-+" package-name "\\([^_]\\|$\\)"))
1767 (file-name-nondirectory
1768 (or
1769 (ff-get-file-name
1770 compilation-search-path
1771 (ada-file-name-from-ada-name package-name)
1772 (append ada-spec-suffixes ada-body-suffixes))
1773 (error "package '%s' not found; set project file?" package-name)))
1774 ))
1775
1776 (defun ada-set-ff-special-constructs ()
1777 "Add Ada-specific pairs to `ff-special-constructs'."
1778 (set (make-local-variable 'ff-special-constructs) nil)
1779 (mapc (lambda (pair) (add-to-list 'ff-special-constructs pair))
1780 ;; Each car is a regexp; if it matches at point, the cdr is invoked.
1781 ;; Each cdr should set ff-function-name to a string or regexp
1782 ;; for ada-set-point-accordingly, and return the file name
1783 ;; (sans directory, must include suffix) to go to.
1784 (list
1785 ;; Top level child package declaration (not body), or child
1786 ;; subprogram declaration or body; go to the parent package.
1787 (cons (concat "^\\(?:private[ \t]+\\)?\\(?:package\\|procedure\\|function\\)[ \t]+"
1788 ada-parent-name-regexp "\\(?:;\\|[ \t]+\\|$\\)")
1789 'ada-ff-special-extract-parent)
1790
1791 ;; A "separate" clause.
1792 (cons (concat "^separate[ \t\n]*(" ada-name-regexp ")")
1793 'ada-ff-special-extract-separate)
1794
1795 ;; A "with" clause. Note that it may refer to a procedure body, as well as a spec
1796 (cons (concat "^\\(?:limited[ \t]+\\)?\\(?:private[ \t]+\\)?with[ \t]+" ada-name-regexp)
1797 'ada-ff-special-with)
1798 )))
1799
1800 (defvar ada-which-function nil
1801 ;; supplied by indentation engine
1802 ;;
1803 ;; This is run from ff-pre-load-hook, so ff-function-name may have
1804 ;; been set by ff-treat-special; don't reset it.
1805 "Function called with no parameters; it should return the name
1806 of the package, protected type, subprogram, or task type whose
1807 definition/declaration point is in or just after, or nil. In
1808 addition, if ff-function-name is non-nil, store in
1809 ff-function-name a regexp that will find the function in the
1810 other file.")
1811
1812 (defun ada-which-function ()
1813 "See `ada-which-function' variable."
1814 (interactive)
1815 (when ada-which-function
1816 (funcall ada-which-function)))
1817
1818 (defun ada-add-log-current-function ()
1819 "For `add-log-current-defun-function'; uses `ada-which-function'."
1820 ;; add-log-current-defun is typically called with point at the start
1821 ;; of an ediff change section, which is before the start of the
1822 ;; declaration of a new item. So go to the end of the current line
1823 ;; first, then call `ada-which-function'
1824 (save-excursion
1825 (end-of-line 1)
1826 (ada-which-function)))
1827
1828 (defun ada-set-point-accordingly ()
1829 "Move to the string specified in `ff-function-name', which may be a regexp,
1830 previously set by a file navigation command."
1831 (when ff-function-name
1832 (let ((done nil)
1833 (found nil))
1834 (goto-char (point-min))
1835 ;; We are looking for an Ada declaration, so don't stop for strings or comments
1836 ;;
1837 ;; This will still be confused by multiple references; we need
1838 ;; to use compiler cross reference info for more precision.
1839 (while (not done)
1840 (if (search-forward-regexp ff-function-name nil t)
1841 (setq found (match-beginning 0))
1842 ;; not in remainder of buffer
1843 (setq done t))
1844 (if (ada-in-string-or-comment-p)
1845 (setq found nil)
1846 (setq done t)))
1847 (when found
1848 (goto-char found)
1849 ;; different parsers find different points on the line; normalize here
1850 (back-to-indentation))
1851 (setq ff-function-name nil))))
1852
1853 (defun ada-find-other-file-noset (other-window)
1854 "Same as `ada-find-other-file', but preserve point in the other file,
1855 don't move to corresponding declaration."
1856 (interactive "P")
1857 (ada-find-other-file other-window t))
1858
1859 (defun ada-find-other-file (other-window &optional no-set-point)
1860 "Move to the corresponding declaration in another file.
1861
1862 - If region is active, assume it contains a package name;
1863 position point on that package declaration.
1864
1865 - If point is in the start line of a non-nested child package or
1866 subprogram declaration, position point on the corresponding
1867 parent package specification.
1868
1869 - If point is in the start line of a separate body,
1870 position point on the corresponding separate stub declaration.
1871
1872 - If point is in a context clause line, position point on the
1873 first package declaration that is mentioned.
1874
1875 - If point is in a subprogram body or specification, position point
1876 on the corresponding specification or body.
1877
1878 If OTHER-WINDOW (set by interactive prefix) is non-nil, show the
1879 buffer in another window.
1880
1881 If NO-SET-POINT is nil, set point in the other file on the
1882 corresponding declaration. If non-nil, preserve existing point in
1883 the other file."
1884
1885 ;; ff-get-file, ff-find-other file first process
1886 ;; ff-special-constructs, then run the following hooks:
1887 ;;
1888 ;; ff-pre-load-hook set to ada-which-function
1889 ;; ff-file-created-hook set to ada-ff-create-body
1890 ;; ff-post-load-hook set to ada-set-point-accordingly,
1891 ;; or to a compiler-specific function that
1892 ;; uses compiler-generated cross reference
1893 ;; information
1894
1895 (interactive "P")
1896 (when (null (car compilation-search-path))
1897 (error "no file search path defined; set project file?"))
1898
1899 (if mark-active
1900 (progn
1901 (setq ff-function-name (buffer-substring-no-properties (point) (mark)))
1902 (ff-get-file
1903 compilation-search-path
1904 (ada-file-name-from-ada-name ff-function-name)
1905 ada-spec-suffixes
1906 other-window)
1907 (deactivate-mark))
1908
1909 ;; else use name at point
1910 (ff-find-other-file other-window)))
1911
1912 (defvar ada-operator-re
1913 "\\+\\|-\\|/\\|\\*\\*\\|\\*\\|=\\|&\\|abs\\|mod\\|rem\\|and\\|not\\|or\\|xor\\|<=\\|<\\|>=\\|>"
1914 "Regexp matching Ada operator_symbol.")
1915
1916 (defun ada-identifier-at-point ()
1917 "Return the identifier around point, move point to start of
1918 identifier. May be an Ada identifier or operator function name."
1919
1920 (when (ada-in-comment-p)
1921 (error "Inside comment"))
1922
1923 (let (identifier)
1924
1925 (skip-chars-backward "a-zA-Z0-9_<>=+\\-\\*/&")
1926
1927 ;; Just in front of, or inside, a string => we could have an operator
1928 (cond
1929 ((ada-in-string-p)
1930 (cond
1931
1932 ((and (= (char-before) ?\")
1933 (progn
1934 (forward-char -1)
1935 (looking-at (concat "\"\\(" ada-operator-re "\\)\""))))
1936 (setq identifier (concat "\"" (match-string-no-properties 1) "\"")))
1937
1938 (t
1939 (error "Inside string or character constant"))
1940 ))
1941
1942 ((and (= (char-after) ?\")
1943 (looking-at (concat "\"\\(" ada-operator-re "\\)\"")))
1944 (setq identifier (concat "\"" (match-string-no-properties 1) "\"")))
1945
1946 ((looking-at "[a-zA-Z0-9_]+")
1947 (setq identifier (match-string-no-properties 0)))
1948
1949 (t
1950 (error "No identifier around"))
1951 )))
1952
1953 (defun ada-goto-source (file line column other-window)
1954 "Find and select FILE, at LINE and COLUMN.
1955 FILE may be absolute, or on `compilation-search-path'.
1956
1957 If OTHER-WINDOW is non-nil, show the buffer in another window."
1958 (let ((file-1
1959 (if (file-name-absolute-p file) file
1960 (ff-get-file-name compilation-search-path file))))
1961 (if file-1
1962 (setq file file-1)
1963 (error "File %s not found; installed library, or set project?" file))
1964 )
1965
1966 (let ((buffer (get-file-buffer file)))
1967 (cond
1968 ((bufferp buffer)
1969 (cond
1970 ((null other-window)
1971 (switch-to-buffer buffer))
1972
1973 (t (switch-to-buffer-other-window buffer))
1974 ))
1975
1976 ((file-exists-p file)
1977 (cond
1978 ((null other-window)
1979 (find-file file))
1980
1981 (t
1982 (find-file-other-window file))
1983 ))
1984
1985 (t
1986 (error "'%s' not found" file))))
1987
1988
1989 ;; move the cursor to the correct position
1990 (push-mark nil t)
1991 (goto-char (point-min))
1992 (forward-line (1- line))
1993 (forward-char column)
1994 )
1995
1996 (defvar ada-xref-refresh-function nil
1997 ;; determined by xref_tool, set by *-select-prj-xref
1998 "Function that refreshes cross reference information cache.")
1999
2000 (defun ada-xref-refresh ()
2001 "Refresh cross reference information cache, if any."
2002 (interactive)
2003
2004 (when (null ada-xref-refresh-function)
2005 (error "no cross reference information available"))
2006
2007 (funcall ada-xref-refresh-function)
2008 )
2009
2010 (defvar ada-xref-other-function nil
2011 ;; determined by xref_tool, set by *-select-prj-xref
2012 "Function that returns cross reference information.
2013 Function is called with four arguments:
2014 - an Ada identifier or operator_symbol
2015 - filename containing the identifier (full path)
2016 - line number containing the identifier
2017 - column of the start of the identifier
2018 Returns a list '(file line column) giving the corresponding location.
2019 'file' may be absolute, or on `compilation-search-path'. If point is
2020 at the specification, the corresponding location is the body, and vice
2021 versa.")
2022
2023 (defun ada-goto-declaration (other-window)
2024 "Move to the declaration or body of the identifier around point.
2025 If at the declaration, go to the body, and vice versa.
2026
2027 If OTHER-WINDOW (set by interactive prefix) is non-nil, show the
2028 buffer in another window."
2029 (interactive "P")
2030
2031 (when (null ada-xref-other-function)
2032 (error "no cross reference information available"))
2033
2034 (let ((target
2035 (funcall ada-xref-other-function
2036 (ada-identifier-at-point)
2037 (buffer-file-name)
2038 (line-number-at-pos)
2039 (1+ (current-column))
2040 )))
2041
2042 (ada-goto-source (nth 0 target)
2043 (nth 1 target)
2044 (nth 2 target)
2045 other-window)
2046 ))
2047
2048 (defvar ada-xref-parent-function nil
2049 ;; determined by xref_tool, set by *-select-prj-xref
2050 "Function that returns cross reference information.
2051 Function is 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 of the parent type declarations.")
2057
2058 (defun ada-show-declaration-parents ()
2059 "Display the locations of the parent type declarations of the type identifier around point."
2060 (interactive)
2061 (when (null ada-xref-parent-function)
2062 (error "no cross reference information available"))
2063
2064 (funcall ada-xref-parent-function
2065 (ada-identifier-at-point)
2066 (file-name-nondirectory (buffer-file-name))
2067 (line-number-at-pos)
2068 (1+ (current-column)))
2069 )
2070
2071 (defvar ada-xref-all-function nil
2072 ;; determined by xref_tool, set by *-select-prj-xref
2073 "Function that displays cross reference information.
2074 Called with four arguments:
2075 - an Ada identifier or operator_symbol
2076 - filename containing the identifier
2077 - line number containing the identifier
2078 - column of the start of the identifier
2079 Displays a buffer in compilation-mode giving locations where the
2080 identifier is declared or referenced.")
2081
2082 (defun ada-show-references ()
2083 "Show all references of identifier at point."
2084 (interactive)
2085
2086 (when (null ada-xref-all-function)
2087 (error "no cross reference information available"))
2088
2089 (funcall ada-xref-all-function
2090 (ada-identifier-at-point)
2091 (file-name-nondirectory (buffer-file-name))
2092 (line-number-at-pos)
2093 (1+ (current-column)))
2094 )
2095
2096 (defvar ada-xref-overriding-function nil
2097 ;; determined by ada-xref-tool, set by *-select-prj
2098 "Function that displays cross reference information for overriding subprograms.
2099 Called with four arguments:
2100 - an Ada identifier or operator_symbol
2101 - filename containing the identifier
2102 - line number containing the identifier
2103 - column of the start of the identifier
2104 Displays a buffer in compilation-mode giving locations of the overriding declarations.")
2105
2106 (defun ada-show-overriding ()
2107 "Show all overridings of identifier at point."
2108 (interactive)
2109
2110 (when (null ada-xref-overriding-function)
2111 (error "no cross reference information available"))
2112
2113 (funcall ada-xref-overriding-function
2114 (ada-identifier-at-point)
2115 (file-name-nondirectory (buffer-file-name))
2116 (line-number-at-pos)
2117 (1+ (current-column)))
2118 )
2119
2120 (defvar ada-xref-overridden-function nil
2121 ;; determined by ada-xref-tool, set by *-select-prj
2122 "Function that displays cross reference information for overridden subprogram.
2123 Called with four arguments:
2124 - an Ada identifier or operator_symbol
2125 - filename containing the identifier
2126 - line number containing the identifier
2127 - column of the start of the identifier
2128 Returns a list '(file line column) giving the corresponding location.
2129 'file' may be absolute, or on `compilation-search-path'.")
2130
2131 (defun ada-show-overridden (other-window)
2132 "Show the overridden declaration of identifier at point."
2133 (interactive "P")
2134
2135 (when (null ada-xref-overridden-function)
2136 (error "'show overridden' not supported, or no cross reference information available"))
2137
2138 (let ((target
2139 (funcall ada-xref-overridden-function
2140 (ada-identifier-at-point)
2141 (file-name-nondirectory (buffer-file-name))
2142 (line-number-at-pos)
2143 (1+ (current-column)))))
2144
2145 (ada-goto-source (nth 0 target)
2146 (nth 1 target)
2147 (nth 2 target)
2148 other-window)
2149
2150 ))
2151
2152 ;; This is autoloaded because it may be used in ~/.emacs
2153 ;;;###autoload
2154 (defun ada-add-extensions (spec body)
2155 "Define SPEC and BODY as being valid extensions for Ada files.
2156 SPEC and BODY are two regular expressions that must match against
2157 the file name."
2158 (let* ((reg (concat (regexp-quote body) "$"))
2159 (tmp (assoc reg ada-other-file-alist)))
2160 (if tmp
2161 (setcdr tmp (list (cons spec (cadr tmp))))
2162 (add-to-list 'ada-other-file-alist (list reg (list spec)))))
2163
2164 (let* ((reg (concat (regexp-quote spec) "$"))
2165 (tmp (assoc reg ada-other-file-alist)))
2166 (if tmp
2167 (setcdr tmp (list (cons body (cadr tmp))))
2168 (add-to-list 'ada-other-file-alist (list reg (list body)))))
2169
2170 (add-to-list 'auto-mode-alist
2171 (cons (concat (regexp-quote spec) "\\'") 'ada-mode))
2172 (add-to-list 'auto-mode-alist
2173 (cons (concat (regexp-quote body) "\\'") 'ada-mode))
2174
2175 (add-to-list 'ada-spec-suffixes spec)
2176 (add-to-list 'ada-body-suffixes body)
2177
2178 (when (fboundp 'speedbar-add-supported-extension)
2179 (speedbar-add-supported-extension spec)
2180 (speedbar-add-supported-extension body))
2181 )
2182
2183 (defun ada-show-secondary-error (other-window)
2184 "Show the next secondary file reference in the compilation buffer.
2185 A secondary file reference is defined by text having text
2186 property `ada-secondary-error'. These can be set by
2187 compiler-specific compilation filters.
2188
2189 If OTHER-WINDOW (set by interactive prefix) is non-nil, show the
2190 buffer in another window."
2191 (interactive "P")
2192
2193 ;; preserving the current window works only if the frame
2194 ;; doesn't change, at least on Windows.
2195 (let ((start-buffer (current-buffer))
2196 (start-window (selected-window))
2197 pos item file)
2198 (set-buffer compilation-last-buffer)
2199 (setq pos (next-single-property-change (point) 'ada-secondary-error))
2200 (when pos
2201 (setq item (get-text-property pos 'ada-secondary-error))
2202 ;; file-relative-name handles absolute Windows paths from
2203 ;; g++. Do this in compilation buffer to get correct
2204 ;; default-directory.
2205 (setq file (file-relative-name (nth 0 item)))
2206
2207 ;; Set point in compilation buffer past this secondary error, so
2208 ;; user can easily go to the next one. For some reason, this
2209 ;; doesn't change the visible point!?
2210 (forward-line 1))
2211
2212 (set-buffer start-buffer);; for windowing history
2213 (when item
2214 (ada-goto-source
2215 file
2216 (nth 1 item); line
2217 (nth 2 item); column
2218 other-window)
2219 (select-window start-window)
2220 )
2221 ))
2222
2223 (defvar ada-goto-declaration-start nil
2224 ;; Supplied by indentation engine.
2225 ;;
2226 ;; This is run from ff-pre-load-hook, so ff-function-name may have
2227 ;; been set by ff-treat-special; don't reset it.
2228 "Function to move point to start of the generic, package,
2229 protected, subprogram, or task declaration point is currently in
2230 or just after. Called with no parameters.")
2231
2232 (defun ada-goto-declaration-start ()
2233 "Call `ada-goto-declaration-start'."
2234 (when ada-goto-declaration-start
2235 (funcall ada-goto-declaration-start)))
2236
2237 (defvar ada-goto-declarative-region-start nil
2238 ;; Supplied by indentation engine
2239 "Function to move point to start of the declarative region of
2240 the subprogram, package, task, or declare block point
2241 is currently in. Called with no parameters.")
2242
2243 (defun ada-goto-declarative-region-start ()
2244 "Call `ada-goto-declarative-region-start'."
2245 (when ada-goto-declarative-region-start
2246 (funcall ada-goto-declarative-region-start)))
2247
2248 (defvar ada-next-statement-keyword nil
2249 ;; Supplied by indentation engine
2250 "Function called with no parameters; it should move forward to
2251 the next keyword in the statement following the one point is
2252 in (ie from 'if' to 'then'). If not in a keyword, move forward
2253 to the next keyword in the current statement. If at the last keyword,
2254 move forward to the first keyword in the next statement or next
2255 keyword in the containing statement.")
2256
2257 (defvar ada-goto-end nil
2258 ;; Supplied by indentation engine
2259 "Function to move point to end of the declaration or statement point is in or before.
2260 Called with no parameters.")
2261
2262 (defun ada-goto-end ()
2263 "Call `ada-goto-end'."
2264 (when ada-goto-end
2265 (funcall ada-goto-end)))
2266
2267 (defun ada-next-statement-keyword ()
2268 ;; Supplied by indentation engine
2269 "See `ada-next-statement-keyword' variable."
2270 (interactive)
2271 (when ada-next-statement-keyword
2272 (funcall ada-next-statement-keyword)))
2273
2274 (defvar ada-prev-statement-keyword nil
2275 ;; Supplied by indentation engine
2276 "Function called with no parameters; it should move to the previous
2277 keyword in the statement following the one point is in (ie from
2278 'then' to 'if'). If at the first keyword, move to the previous
2279 keyword in the previous statement or containing statement.")
2280
2281 (defun ada-prev-statement-keyword ()
2282 "See `ada-prev-statement-keyword' variable."
2283 (interactive)
2284 (when ada-prev-statement-keyword
2285 (funcall ada-prev-statement-keyword)))
2286
2287 ;;;; code creation
2288
2289 (defvar ada-make-subprogram-body nil
2290 ;; Supplied by indentation engine
2291 "Function to convert subprogram specification after point into a subprogram body stub.
2292 Called with no args, point at declaration start. Leave point in
2293 subprogram body, for user to add code.")
2294
2295 (defun ada-make-subprogram-body ()
2296 "If point is in or after a subprogram specification, convert it
2297 into a subprogram body stub, by calling `ada-make-subprogram-body'."
2298 (interactive)
2299 (ada-goto-declaration-start)
2300 (if ada-make-subprogram-body
2301 (funcall ada-make-subprogram-body)
2302 (error "`ada-make-subprogram-body' not set")))
2303
2304 (defvar ada-make-package-body nil
2305 ;; Supplied by xref tool
2306 "Function to create a package body from a package spec.
2307 Called with one argument; the absolute path to the body
2308 file. Current buffer is the package spec. Should create the
2309 package body file, containing skeleton code that will compile.")
2310
2311 (defun ada-make-package-body (body-file-name)
2312 ;; no error if not set; let ada-skel do its thing.
2313 (when ada-make-package-body
2314 (funcall ada-make-package-body body-file-name)))
2315
2316 (defun ada-ff-create-body ()
2317 ;; no error if not set; let ada-skel do its thing.
2318 (when ada-make-package-body
2319 ;; ff-find-other-file calls us with point in an empty buffer for the
2320 ;; body file; ada-make-package-body expects to be in the spec. So go
2321 ;; back.
2322 (let ((body-file-name (buffer-file-name)))
2323 (ff-find-the-other-file)
2324
2325 (ada-make-package-body body-file-name)
2326 ;; FIXME (later): if 'ada-make-package-body' fails, delete the body buffer
2327 ;; so it doesn't get written to disk, and we can try again.
2328
2329 ;; back to the body, read in from the disk.
2330 (ff-find-the-other-file)
2331 (revert-buffer t t))
2332 ))
2333
2334 ;;;; fill-comment
2335
2336 (defun ada-fill-comment-paragraph (&optional justify postfix)
2337 "Fill the current comment paragraph.
2338 If JUSTIFY is non-nil, each line is justified as well.
2339 If POSTFIX and JUSTIFY are non-nil, `ada-fill-comment-postfix' is appended
2340 to each line filled and justified.
2341 The paragraph is indented on the first line."
2342 (interactive "P")
2343 (if (and (not (ada-in-comment-p))
2344 (not (looking-at "[ \t]*--")))
2345 (error "Not inside comment"))
2346
2347 (let* (indent from to
2348 (opos (point-marker))
2349 ;; we bind `fill-prefix' here rather than in ada-mode because
2350 ;; setting it in ada-mode causes indent-region to use it for
2351 ;; all indentation.
2352 (fill-prefix ada-fill-comment-prefix)
2353 (fill-column (current-fill-column)))
2354
2355 ;; Find end of comment paragraph
2356 (back-to-indentation)
2357 (while (and (not (eobp)) (looking-at ".*--[ \t]*[^ \t\n]"))
2358 (forward-line 1)
2359
2360 ;; If we were at the last line in the buffer, create a dummy empty
2361 ;; line at the end of the buffer.
2362 (if (eobp)
2363 (insert "\n")
2364 (back-to-indentation)))
2365 (beginning-of-line)
2366 (setq to (point-marker))
2367 (goto-char opos)
2368
2369 ;; Find beginning of paragraph
2370 (back-to-indentation)
2371 (while (and (not (bobp)) (looking-at ".*--[ \t]*[^ \t\n]"))
2372 (forward-line -1)
2373 (back-to-indentation))
2374
2375 (unless (bobp)
2376 (forward-line 1))
2377 (beginning-of-line)
2378 (setq from (point-marker))
2379
2380 ;; Calculate the indentation we will need for the paragraph
2381 (back-to-indentation)
2382 (setq indent (current-column))
2383 ;; unindent the first line of the paragraph
2384 (delete-region from (point))
2385
2386 ;; Remove the old postfixes
2387 (goto-char from)
2388 (while (re-search-forward (concat "\\(" ada-fill-comment-postfix "\\)" "\n") to t)
2389 (delete-region (match-beginning 1) (match-end 1)))
2390
2391 (goto-char (1- to))
2392 (setq to (point-marker))
2393
2394 ;; Indent and justify the paragraph
2395 (set-left-margin from to indent)
2396 (if postfix
2397 (setq fill-column (- fill-column (length ada-fill-comment-postfix))))
2398
2399 (fill-region-as-paragraph from to justify)
2400
2401 ;; Add the postfixes if required
2402 (if postfix
2403 (save-restriction
2404 (goto-char from)
2405 (narrow-to-region from to)
2406 (while (not (eobp))
2407 (end-of-line)
2408 (insert-char ? (- fill-column (current-column)))
2409 (insert ada-fill-comment-postfix)
2410 (forward-line))
2411 ))
2412
2413 (goto-char opos)))
2414
2415 ;;;; support for font-lock.el
2416
2417 ;; casing keywords defined here to keep the two lists together
2418 (defconst ada-83-keywords
2419 '("abort" "abs" "accept" "access" "all" "and" "array" "at" "begin"
2420 "body" "case" "constant" "declare" "delay" "delta" "digits" "do"
2421 "else" "elsif" "end" "entry" "exception" "exit" "for" "function"
2422 "generic" "goto" "if" "in" "is" "limited" "loop" "mod" "new"
2423 "not" "null" "of" "or" "others" "out" "package" "pragma" "private"
2424 "procedure" "raise" "range" "record" "rem" "renames" "return"
2425 "reverse" "select" "separate" "subtype" "task" "terminate" "then"
2426 "type" "use" "when" "while" "with" "xor")
2427 "List of Ada 83 keywords.")
2428
2429 (defconst ada-95-keywords
2430 '("abstract" "aliased" "protected" "requeue" "tagged" "until")
2431 "List of keywords new in Ada 95.")
2432
2433 (defconst ada-2005-keywords
2434 '("interface" "overriding" "synchronized")
2435 "List of keywords new in Ada 2005.")
2436
2437 (defconst ada-2012-keywords
2438 '("some")
2439 "List of keywords new in Ada 2012.")
2440
2441 (defun ada-font-lock-keywords ()
2442 "Return Ada mode value for `font-lock-keywords', depending on `ada-language-version'."
2443 (list
2444
2445 ;; keywords followed by a name that should be in function-name-face.
2446 (list
2447 (apply
2448 'concat
2449 (append
2450 '("\\<\\("
2451 "accept\\|"
2452 "entry\\|"
2453 "function\\|"
2454 "package[ \t]+body\\|"
2455 "package\\|"
2456 "pragma\\|"
2457 "procedure\\|"
2458 "task[ \t]+body\\|"
2459 "task[ \t]+type\\|"
2460 "task\\|"
2461 )
2462 (when (member ada-language-version '(ada95 ada2005 ada2012))
2463 '("\\|"
2464 "protected[ \t]+body\\|"
2465 "protected[ \t]+function\\|"
2466 "protected[ \t]+procedure\\|"
2467 "protected[ \t]+type\\|"
2468 "protected"
2469 ))
2470 (list
2471 "\\)\\>[ \t]*"
2472 ada-name-regexp "?")))
2473 '(1 font-lock-keyword-face) '(2 font-lock-function-name-face nil t))
2474
2475 ;; keywords followed by a name that should be in type-face.
2476 (list (concat
2477 "\\<\\("
2478 "access[ \t]+all\\|"
2479 "access[ \t]+constant\\|"
2480 "access\\|"
2481 "constant\\|"
2482 "in[ \t]+reverse\\|"; loop iterator
2483 "in[ \t]+not[ \t]+null\\|"
2484 "in[ \t]+out[ \t]+not[ \t]+null\\|"
2485 "in[ \t]+out\\|"
2486 "in\\|"
2487 ;; "return\\|" can't distinguish between 'function ... return <type>;' and 'return ...;'
2488 ;; An indentation engine can, so a rule for this is added there
2489 "of[ \t]+reverse\\|"
2490 "of\\|"
2491 "out\\|"
2492 "subtype\\|"
2493 "type"
2494 "\\)\\>[ \t]*"
2495 ada-name-regexp "?")
2496 '(1 font-lock-keyword-face nil t) '(2 font-lock-type-face nil t))
2497
2498 ;; Keywords not treated elsewhere. After above so it doesn't
2499 ;; override fontication of second or third word in those patterns.
2500 (list (concat
2501 "\\<"
2502 (regexp-opt
2503 (append
2504 '("abort" "abs" "accept" "all"
2505 "and" "array" "at" "begin" "case" "declare" "delay" "delta"
2506 "digits" "do" "else" "elsif" "entry" "exception" "exit" "for"
2507 "generic" "if" "in" "limited" "loop" "mod" "not"
2508 "null" "or" "others" "private" "raise"
2509 "range" "record" "rem" "renames" "reverse"
2510 "select" "separate" "task" "terminate"
2511 "then" "when" "while" "xor")
2512 (when (member ada-language-version '(ada95 ada2005 ada2012))
2513 '("abstract" "aliased" "requeue" "tagged" "until"))
2514 (when (member ada-language-version '(ada2005 ada2012))
2515 '("interface" "overriding" "synchronized"))
2516 (when (member ada-language-version '(ada2012))
2517 '("some"))
2518 )
2519 t)
2520 "\\>")
2521 '(0 font-lock-keyword-face))
2522
2523 ;; object and parameter declarations; word after ":" should be in
2524 ;; type-face if not already fontified or an exception.
2525 (list (concat
2526 ":[ \t]*"
2527 ada-name-regexp
2528 "[ \t]*\\(=>\\)?")
2529 '(1 (if (match-beginning 2)
2530 'default
2531 font-lock-type-face)
2532 nil t))
2533
2534 ;; keywords followed by a name that should be in function-name-face if not already fontified
2535 (list (concat
2536 "\\<\\("
2537 "end"
2538 "\\)\\>[ \t]*"
2539 ada-name-regexp "?")
2540 '(1 font-lock-keyword-face) '(2 font-lock-function-name-face nil t))
2541
2542 ;; Keywords followed by a name that could be a type or a function (generic instantiation).
2543 (list (concat
2544 "\\<\\("
2545 "new"
2546 "\\)\\>[ \t]*"
2547 ada-name-regexp "?[ \t]*\\((\\)?")
2548 '(1 font-lock-keyword-face)
2549 '(2 (if (match-beginning 3)
2550 font-lock-function-name-face
2551 font-lock-type-face)
2552 nil t))
2553
2554 ;; keywords followed by a name that should be in type-face if not already fontified (for subtypes)
2555 ;; after "new" to handle "is new"
2556 (list (concat
2557 "\\<\\("
2558 "is"
2559 "\\)\\>[ \t]*"
2560 ada-name-regexp "?")
2561 '(1 font-lock-keyword-face) '(2 font-lock-type-face nil t))
2562
2563 ;; Keywords followed by a comma separated list of names which
2564 ;; should be in constant-face, unless already fontified. Ada mode 4.01 used this.
2565 (list (concat
2566 "\\<\\("
2567 "goto\\|"
2568 "use\\|"
2569 ;; don't need "limited" "private" here; they are matched separately
2570 "with"; context clause
2571 "\\)\\>[ \t]*"
2572 "\\(\\(?:\\sw\\|[_., \t]\\)+\\>\\)?"; ada-name-regexp, plus ", \t"
2573 )
2574 '(1 font-lock-keyword-face) '(2 font-lock-constant-face nil t))
2575
2576 ;; statement labels
2577 '("<<\\(\\sw+\\)>>" 1 font-lock-constant-face)
2578
2579 ;; based numberic literals
2580 (list "\\([0-9]+#[0-9a-fA-F_]+#\\)" '(1 font-lock-constant-face t))
2581
2582 ;; numeric literals
2583 (list "\\W\\([-+]?[0-9._]+\\)\\>" '(1 font-lock-constant-face))
2584
2585 ))
2586
2587 ;;;; ada-mode
2588
2589 ;; ada-mode does not derive from prog-mode, because we need to call
2590 ;; ada-mode-post-local-vars, and prog-mode does not provide a way to
2591 ;; do that.
2592 ;;
2593 ;; autoload required by automatic mode setting
2594 ;;;###autoload
2595 (defun ada-mode ()
2596 "The major mode for editing Ada code."
2597 ;; the other ada-*.el files add to ada-mode-hook for their setup
2598
2599 (interactive)
2600 (kill-all-local-variables)
2601 (setq major-mode 'ada-mode)
2602 (setq mode-name "Ada")
2603 (use-local-map ada-mode-map)
2604 (set-syntax-table ada-mode-syntax-table)
2605 (define-abbrev-table 'ada-mode-abbrev-table ())
2606 (setq local-abbrev-table ada-mode-abbrev-table)
2607
2608 (set (make-local-variable 'syntax-propertize-function) 'ada-syntax-propertize)
2609 (set (make-local-variable 'syntax-begin-function) nil)
2610 (set (make-local-variable 'parse-sexp-ignore-comments) t)
2611 (set (make-local-variable 'parse-sexp-lookup-properties) t)
2612 (set 'case-fold-search t); Ada is case insensitive; the syntax parsing requires this setting
2613 (set (make-local-variable 'comment-start) "--")
2614 (set (make-local-variable 'comment-end) "")
2615 (set (make-local-variable 'comment-start-skip) "---*[ \t]*")
2616 (set (make-local-variable 'comment-multi-line) nil)
2617
2618 ;; we _don't_ set `fill-prefix' here because that causes
2619 ;; indent-region to use it for all indentation. See
2620 ;; ada-fill-comment-paragraph.
2621
2622 ;; AdaCore standard style (enforced by -gnaty) requires two spaces
2623 ;; after '--' in comments; this makes it easier to distinguish
2624 ;; special comments that have something else after '--'
2625 (set (make-local-variable 'comment-padding) " ")
2626
2627 (set (make-local-variable 'require-final-newline) t)
2628
2629 (setq font-lock-defaults
2630 '(ada-font-lock-keywords
2631 nil t
2632 ((?\_ . "w")))); treat underscore as a word component
2633
2634 (set (make-local-variable 'ff-other-file-alist)
2635 'ada-other-file-alist)
2636 (setq ff-post-load-hook 'ada-set-point-accordingly
2637 ff-file-created-hook 'ada-ff-create-body)
2638 (add-hook 'ff-pre-load-hook 'ada-which-function)
2639 (setq ff-search-directories 'compilation-search-path)
2640 (when (null (car compilation-search-path))
2641 ;; find-file doesn't handle nil in search path
2642 (setq compilation-search-path (list (file-name-directory (buffer-file-name)))))
2643 (ada-set-ff-special-constructs)
2644
2645 (set (make-local-variable 'add-log-current-defun-function)
2646 'ada-add-log-current-function)
2647
2648 (when (boundp 'which-func-functions)
2649 (add-hook 'which-func-functions 'ada-which-function nil t))
2650
2651 ;; Support for align
2652 (add-to-list 'align-dq-string-modes 'ada-mode)
2653 (add-to-list 'align-open-comment-modes 'ada-mode)
2654 (set (make-local-variable 'align-region-separate) ada-align-region-separate)
2655 (set (make-local-variable 'align-indent-before-aligning) t)
2656
2657 ;; Exclude comments alone on line from alignment.
2658 (add-to-list 'align-exclude-rules-list
2659 '(ada-solo-comment
2660 (regexp . "^\\(\\s-*\\)--")
2661 (modes . '(ada-mode))))
2662 (add-to-list 'align-exclude-rules-list
2663 '(ada-solo-use
2664 (regexp . "^\\(\\s-*\\)\\<use\\>")
2665 (modes . '(ada-mode))))
2666
2667 (setq align-mode-rules-list ada-align-rules)
2668
2669 (easy-menu-add ada-mode-menu ada-mode-map)
2670
2671 (run-mode-hooks 'ada-mode-hook)
2672
2673 ;; If global-font-lock is not enabled, ada-syntax-propertize is
2674 ;; not run when the text is first loaded into the buffer. Recover
2675 ;; from that.
2676 (syntax-ppss-flush-cache (point-min))
2677 (syntax-propertize (point-max))
2678
2679 (add-hook 'hack-local-variables-hook 'ada-mode-post-local-vars nil t)
2680 )
2681
2682 (defun ada-mode-post-local-vars ()
2683 ;; These are run after ada-mode-hook and file local variables
2684 ;; because users or other ada-* files might set the relevant
2685 ;; variable inside the hook or file local variables (file local
2686 ;; variables are processed after the mode is set, and thus after
2687 ;; ada-mode is run).
2688
2689 ;; This means to fully set ada-mode interactively, user must
2690 ;; do M-x ada-mode M-; (hack-local-variables)
2691
2692 (when global-font-lock-mode
2693 ;; This calls ada-font-lock-keywords, which depends on
2694 ;; ada-language-version
2695 (font-lock-refresh-defaults))
2696
2697 (cl-case ada-language-version
2698 (ada83
2699 (setq ada-keywords ada-83-keywords))
2700
2701 (ada95
2702 (setq ada-keywords
2703 (append ada-83-keywords
2704 ada-95-keywords)))
2705
2706 (ada2005
2707 (setq ada-keywords
2708 (append ada-83-keywords
2709 ada-95-keywords
2710 ada-2005-keywords)))
2711 (ada2012
2712 (setq ada-keywords
2713 (append ada-83-keywords
2714 ada-95-keywords
2715 ada-2005-keywords
2716 ada-2012-keywords))))
2717 )
2718
2719 (put 'ada-mode 'custom-mode-group 'ada)
2720
2721 (provide 'ada-mode)
2722
2723 ;;;;; Global initializations
2724
2725 (require 'ada-build)
2726
2727 (unless (featurep 'ada-indent-engine)
2728 (require 'ada-wisi))
2729
2730 (unless (featurep 'ada-xref-tool)
2731 (cl-case ada-xref-tool
2732 ((nil 'gnat) (require 'ada-gnat-xref))
2733 ('gnat_inspect (require 'gnat-inspect))
2734 ('gpr_query (require 'gpr-query))
2735 ))
2736
2737 (unless (featurep 'ada-compiler)
2738 (require 'ada-gnat-compile))
2739
2740 (unless (featurep 'ada-skeletons)
2741 (require 'ada-skel))
2742
2743 (when (featurep 'imenu)
2744 (require 'ada-imenu))
2745
2746 ;;; end of file