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