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