Sync to HEAD
[bpt/emacs.git] / lisp / progmodes / ada-xref.el
CommitLineData
3afbc435 1;;; ada-xref.el --- for lookup and completion in Ada mode
797aab3c 2
c94ca9e0 3;; Copyright (C) 1994, 95, 96, 97, 98, 99, 2000, 2001, 2002, 2003
4884c50b 4;; Free Software Foundation, Inc.
797aab3c
GM
5
6;; Author: Markus Heritsch <Markus.Heritsch@studbox.uni-stuttgart.de>
7;; Rolf Ebert <ebert@inf.enst.fr>
8;; Emmanuel Briot <briot@gnat.com>
9;; Maintainer: Emmanuel Briot <briot@gnat.com>
c94ca9e0 10;; Ada Core Technologies's version: Revision: 1.181
797aab3c
GM
11;; Keywords: languages ada xref
12
874d7995 13;; This file is part of GNU Emacs.
797aab3c 14
2be7dabc 15;; GNU Emacs is free software; you can redistribute it and/or modify
797aab3c
GM
16;; it under the terms of the GNU General Public License as published by
17;; the Free Software Foundation; either version 2, or (at your option)
18;; any later version.
19
2be7dabc 20;; GNU Emacs is distributed in the hope that it will be useful,
797aab3c
GM
21;; but WITHOUT ANY WARRANTY; without even the implied warranty of
22;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23;; GNU General Public License for more details.
24
25;; You should have received a copy of the GNU General Public License
2be7dabc
GM
26;; along with GNU Emacs; see the file COPYING. If not, write to the
27;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
28;; Boston, MA 02111-1307, USA.
797aab3c
GM
29
30;;; Commentary:
31;;; This Package provides a set of functions to use the output of the
32;;; cross reference capabilities of the GNAT Ada compiler
33;;; for lookup and completion in Ada mode.
34;;;
797aab3c
GM
35;;; If a file *.`adp' exists in the ada-file directory, then it is
36;;; read for configuration informations. It is read only the first
37;;; time a cross-reference is asked for, and is not read later.
38
39;;; You need Emacs >= 20.2 to run this package
40
3afbc435
PJ
41;;; Code:
42
797aab3c
GM
43;; ----- Requirements -----------------------------------------------------
44
45(require 'compile)
46(require 'comint)
7abe197c
JB
47(require 'find-file)
48(require 'ada-mode)
797aab3c 49
797aab3c
GM
50;; ------ Use variables
51(defcustom ada-xref-other-buffer t
eec3232e
GM
52 "*If nil, always display the cross-references in the same buffer.
53Otherwise create either a new buffer or a new frame."
797aab3c
GM
54 :type 'boolean :group 'ada)
55
93cdce20 56(defcustom ada-xref-create-ali nil
eec3232e
GM
57 "*If non-nil, run gcc whenever the cross-references are not up-to-date.
58If nil, the cross-reference mode will never run gcc."
797aab3c
GM
59 :type 'boolean :group 'ada)
60
61(defcustom ada-xref-confirm-compile nil
eec3232e
GM
62 "*If non-nil, always ask for user confirmation before compiling or running
63the application."
797aab3c
GM
64 :type 'boolean :group 'ada)
65
66(defcustom ada-krunch-args "0"
eec3232e
GM
67 "*Maximum number of characters for filenames created by gnatkr.
68Set to 0, if you don't use crunched filenames. This should be a string."
797aab3c
GM
69 :type 'string :group 'ada)
70
c94ca9e0
JB
71(defcustom ada-gnatls-args '("-v")
72 "*Arguments to pass to gnatfind when the location of the runtime is searched.
73Typical use is to pass --RTS=soft-floats on some systems that support it.
74
75You can also add -I- if you do not want the current directory to be included.
76Otherwise, going from specs to bodies and back will first look for files in the
77current directory. This only has an impact if you are not using project files,
78but only ADA_INCLUDE_PATH."
79 :type '(repeat string) :group 'ada)
80
4884c50b 81(defcustom ada-prj-default-comp-opt "-gnatq -gnatQ"
15ea3b67
GM
82 "Default compilation options."
83 :type 'string :group 'ada)
84
85(defcustom ada-prj-default-bind-opt ""
86 "Default binder options."
87 :type 'string :group 'ada)
88
89(defcustom ada-prj-default-link-opt ""
90 "Default linker options."
91 :type 'string :group 'ada)
92
93(defcustom ada-prj-default-gnatmake-opt "-g"
94 "Default options for gnatmake."
95 :type 'string :group 'ada)
96
4884c50b
SM
97(defcustom ada-prj-gnatfind-switches "-rf"
98 "Default switches to use for gnatfind.
99You should modify this variable, for instance to add -a, if you are working
100in an environment where most ALI files are write-protected.
101The command gnatfind is used every time you choose the menu
102\"Show all references\"."
103 :type 'string :group 'ada)
104
eec3232e 105(defcustom ada-prj-default-comp-cmd
93cdce20
SM
106 (concat "${cross_prefix}gnatmake -u -c ${gnatmake_opt} ${full_current} -cargs"
107 " ${comp_opt}")
797aab3c 108 "*Default command to be used to compile a single file.
15ea3b67
GM
109Emacs will add the filename at the end of this command. This is the same
110syntax as in the project file."
111 :type 'string :group 'ada)
112
113(defcustom ada-prj-default-debugger "${cross_prefix}gdb"
114 "*Default name of the debugger. We recommend either `gdb',
115`gdb --emacs_gdbtk' or `ddd --tty -fullname'."
797aab3c
GM
116 :type 'string :group 'ada)
117
118(defcustom ada-prj-default-make-cmd
15ea3b67
GM
119 (concat "${cross_prefix}gnatmake -o ${main} ${main_unit} ${gnatmake_opt} "
120 "-cargs ${comp_opt} -bargs ${bind_opt} -largs ${link_opt}")
797aab3c
GM
121 "*Default command to be used to compile the application.
122This is the same syntax as in the project file."
123 :type 'string :group 'ada)
124
125(defcustom ada-prj-default-project-file ""
eec3232e
GM
126 "*Name of the project file to use for every Ada file.
127Emacs will not try to use the standard algorithm to find the project file if
128this string is not empty."
797aab3c
GM
129 :type '(file :must-match t) :group 'ada)
130
131(defcustom ada-gnatstub-opts "-q -I${src_dir}"
eec3232e
GM
132 "*List of the options to pass to gnatsub to generate the body of a package.
133This has the same syntax as in the project file (with variable substitution)."
797aab3c
GM
134 :type 'string :group 'ada)
135
136(defcustom ada-always-ask-project nil
eec3232e 137 "*If nil, use default values when no project file was found.
15ea3b67
GM
138Otherwise, ask the user for the name of the project file to use."
139 :type 'boolean :group 'ada)
797aab3c 140
4884c50b
SM
141(defconst is-windows (memq system-type (quote (windows-nt)))
142 "True if we are running on windows NT or windows 95.")
143
144(defcustom ada-tight-gvd-integration nil
145 "*If non-nil, a new Emacs frame will be swallowed in GVD when debugging.
146If GVD is not the debugger used, nothing happens.")
147
93cdce20
SM
148(defcustom ada-xref-search-with-egrep t
149 "*If non-nil, use egrep to find the possible declarations for an entity.
150This alternate method is used when the exact location was not found in the
151information provided by GNAT. However, it might be expensive if you have a lot
152of sources, since it will search in all the files in your project."
153 :type 'boolean :group 'ada)
154
155(defvar ada-load-project-hook nil
156 "Hook that is run when loading a project file.
157Each function in this hook takes one argument FILENAME, that is the name of
158the project file to load.
159This hook should be used to support new formats for the project files.
160
161If the function can load the file with the given filename, it should create a
162buffer that contains a conversion of the file to the standard format of the
163project files, and return that buffer. (the usual \"src_dir=\" or \"obj_dir=\"
164lines). It should return nil if it doesn't know how to convert that project
165file.")
166
167
797aab3c
GM
168;; ------- Nothing to be modified by the user below this
169(defvar ada-last-prj-file ""
eec3232e 170 "Name of the last project file entered by the user.")
797aab3c 171
15ea3b67 172(defvar ada-check-switch "-gnats"
eec3232e 173 "Switch added to the command line to check the current file.")
797aab3c 174
4884c50b 175(defconst ada-project-file-extension ".adp"
eec3232e 176 "The extension used for project files.")
797aab3c 177
15ea3b67
GM
178(defvar ada-xref-runtime-library-specs-path '()
179 "Directories where the specs for the standard library is found.
180This is used for cross-references.")
181
182(defvar ada-xref-runtime-library-ali-path '()
183 "Directories where the ali for the standard library is found.
184This is used for cross-references.")
185
797aab3c 186(defvar ada-xref-pos-ring '()
eec3232e
GM
187 "List of positions selected by the cross-references functions.
188Used to go back to these positions.")
797aab3c 189
4884c50b
SM
190(defvar ada-cd-command
191 (if (string-match "cmdproxy.exe" shell-file-name)
192 "cd /d"
193 "cd")
194 "Command to use to change to a specific directory. On windows systems
195using cmdproxy.exe as the shell, we need to use /d or the drive is never
196changed.")
197
198(defvar ada-command-separator (if is-windows " && " "\n")
199 "Separator to use when sending multiple commands to `compile' or
200`start-process'.
201cmdproxy.exe doesn't recognize multiple-line commands, so we have to use
202\"&&\" for now.")
203
797aab3c 204(defconst ada-xref-pos-ring-max 16
eec3232e 205 "Number of positions kept in the list ada-xref-pos-ring.")
797aab3c
GM
206
207(defvar ada-operator-re
15ea3b67 208 "\\+\\|-\\|/\\|\\*\\*\\|\\*\\|=\\|&\\|abs\\|mod\\|rem\\|and\\|not\\|or\\|xor\\|<=\\|<\\|>=\\|>"
eec3232e 209 "Regexp to match for operators.")
797aab3c 210
15ea3b67
GM
211(defvar ada-xref-project-files '()
212 "Associative list of project files.
213It has the following format:
fea24571 214\((project_name . value) (project_name . value) ...)
15ea3b67
GM
215As always, the values of the project file are defined through properties.")
216
c94ca9e0
JB
217
218;; ----- Identlist manipulation -------------------------------------------
219;; An identlist is a vector that is used internally to reference an identifier
220;; To facilitate its use, we provide the following macros
221
222(defmacro ada-make-identlist () (make-vector 8 nil))
223(defmacro ada-name-of (identlist) (list 'aref identlist 0))
224(defmacro ada-line-of (identlist) (list 'aref identlist 1))
225(defmacro ada-column-of (identlist) (list 'aref identlist 2))
226(defmacro ada-file-of (identlist) (list 'aref identlist 3))
227(defmacro ada-ali-index-of (identlist) (list 'aref identlist 4))
228(defmacro ada-declare-file-of (identlist) (list 'aref identlist 5))
229(defmacro ada-references-of (identlist) (list 'aref identlist 6))
230(defmacro ada-on-declaration (identlist) (list 'aref identlist 7))
231
232(defmacro ada-set-name (identlist name) (list 'aset identlist 0 name))
233(defmacro ada-set-line (identlist line) (list 'aset identlist 1 line))
234(defmacro ada-set-column (identlist col) (list 'aset identlist 2 col))
235(defmacro ada-set-file (identlist file) (list 'aset identlist 3 file))
236(defmacro ada-set-ali-index (identlist index) (list 'aset identlist 4 index))
237(defmacro ada-set-declare-file (identlist file) (list 'aset identlist 5 file))
238(defmacro ada-set-references (identlist ref) (list 'aset identlist 6 ref))
239(defmacro ada-set-on-declaration (ident value) (list 'aset ident 7 value))
240
241(defsubst ada-get-ali-buffer (file)
242 "Reads the ali file into a new buffer, and returns this buffer's name"
243 (find-file-noselect (ada-get-ali-file-name file)))
244
245
246;; -----------------------------------------------------------------------
247
4884c50b
SM
248(defun ada-quote-cmd (cmd)
249 "Duplicates all \\ characters in CMD so that it can be passed to `compile'"
250 (mapconcat 'identity (split-string cmd "\\\\") "\\\\"))
15ea3b67 251
4884c50b
SM
252(defun ada-initialize-runtime-library (cross-prefix)
253 "Initializes the variables for the runtime library location.
254CROSS-PREFIX is the prefix to use for the gnatls command"
15ea3b67 255 (save-excursion
4884c50b
SM
256 (setq ada-xref-runtime-library-specs-path '()
257 ada-xref-runtime-library-ali-path '())
15ea3b67
GM
258 (set-buffer (get-buffer-create "*gnatls*"))
259 (widen)
260 (erase-buffer)
261 ;; Catch any error in the following form (i.e gnatls was not found)
262 (condition-case nil
263 ;; Even if we get an error, delete the *gnatls* buffer
264 (unwind-protect
265 (progn
c94ca9e0
JB
266 (apply 'call-process (concat cross-prefix "gnatls")
267 (append '(nil t nil) ada-gnatls-args))
15ea3b67
GM
268 (goto-char (point-min))
269
270 ;; Source path
a1506d29 271
15ea3b67
GM
272 (search-forward "Source Search Path:")
273 (forward-line 1)
274 (while (not (looking-at "^$"))
275 (back-to-indentation)
c94ca9e0
JB
276 (if (looking-at "<Current_Directory>")
277 (add-to-list 'ada-xref-runtime-library-specs-path ".")
15ea3b67
GM
278 (add-to-list 'ada-xref-runtime-library-specs-path
279 (buffer-substring-no-properties
280 (point)
281 (save-excursion (end-of-line) (point)))))
282 (forward-line 1))
283
284 ;; Object path
a1506d29 285
15ea3b67
GM
286 (search-forward "Object Search Path:")
287 (forward-line 1)
288 (while (not (looking-at "^$"))
289 (back-to-indentation)
c94ca9e0
JB
290 (if (looking-at "<Current_Directory>")
291 (add-to-list 'ada-xref-runtime-library-ali-path ".")
15ea3b67
GM
292 (add-to-list 'ada-xref-runtime-library-ali-path
293 (buffer-substring-no-properties
294 (point)
295 (save-excursion (end-of-line) (point)))))
296 (forward-line 1))
297 )
298 (kill-buffer nil))
299 (error nil))
300 (set 'ada-xref-runtime-library-specs-path
301 (reverse ada-xref-runtime-library-specs-path))
302 (set 'ada-xref-runtime-library-ali-path
303 (reverse ada-xref-runtime-library-ali-path))
304 ))
305
306
307(defun ada-treat-cmd-string (cmd-string)
308 "Replace meta-sequences like ${...} in CMD-STRING with the appropriate value.
309The project file must have been loaded first.
310As a special case, ${current} is replaced with the name of the currently
4884c50b
SM
311edited file, minus extension but with directory, and ${full_current} is
312replaced by the name including the extension."
15ea3b67
GM
313
314 (while (string-match "\\(-[^-\$IO]*[IO]\\)?\${\\([^}]+\\)}" cmd-string)
4884c50b
SM
315 (let (value
316 (name (match-string 2 cmd-string)))
317 (cond
318 ((string= name "current")
319 (setq value (file-name-sans-extension (buffer-file-name))))
320 ((string= name "full_current")
321 (setq value (buffer-file-name)))
322 (t
15ea3b67 323 (save-match-data
4884c50b
SM
324 (setq value (ada-xref-get-project-field (intern name))))))
325
326 ;; Check if there is an environment variable with the same name
327 (if (null value)
328 (if (not (setq value (getenv name)))
329 (message (concat "No environment variable " name " found"))))
a1506d29 330
15ea3b67
GM
331 (cond
332 ((null value)
4884c50b 333 (setq cmd-string (replace-match "" t t cmd-string)))
15ea3b67 334 ((stringp value)
4884c50b 335 (setq cmd-string (replace-match value t t cmd-string)))
15ea3b67
GM
336 ((listp value)
337 (let ((prefix (match-string 1 cmd-string)))
4884c50b 338 (setq cmd-string (replace-match
15ea3b67
GM
339 (mapconcat (lambda(x) (concat prefix x)) value " ")
340 t t cmd-string)))))
341 ))
342 cmd-string)
343
344(defun ada-xref-set-default-prj-values (symbol ada-buffer)
345 "Reset the properties in SYMBOL to the default values for ADA-BUFFER."
346
347 (let ((file (buffer-file-name ada-buffer))
348 plist)
349 (save-excursion
350 (set-buffer ada-buffer)
a1506d29 351
15ea3b67
GM
352 (set 'plist
353 ;; Try hard to find a default value for filename, so that the user
354 ;; can edit his project file even if the current buffer is not an
355 ;; Ada file or not even associated with a file
4884c50b
SM
356 (list 'filename (expand-file-name
357 (cond
4884c50b
SM
358 (ada-prj-default-project-file
359 ada-prj-default-project-file)
c94ca9e0 360 (file (ada-prj-find-prj-file file t))
4884c50b
SM
361 (t
362 (message (concat "Not editing an Ada file,"
363 "and no default project "
364 "file specified!"))
365 "")))
15ea3b67
GM
366 'build_dir (file-name-as-directory (expand-file-name "."))
367 'src_dir (list ".")
368 'obj_dir (list ".")
369 'casing (if (listp ada-case-exception-file)
370 ada-case-exception-file
371 (list ada-case-exception-file))
372 'comp_opt ada-prj-default-comp-opt
373 'bind_opt ada-prj-default-bind-opt
374 'link_opt ada-prj-default-link-opt
375 'gnatmake_opt ada-prj-default-gnatmake-opt
4884c50b 376 'gnatfind_opt ada-prj-gnatfind-switches
15ea3b67 377 'main (if file
4884c50b
SM
378 (file-name-nondirectory
379 (file-name-sans-extension file))
15ea3b67
GM
380 "")
381 'main_unit (if file
382 (file-name-nondirectory
383 (file-name-sans-extension file))
384 "")
385 'cross_prefix ""
386 'remote_machine ""
4884c50b
SM
387 'comp_cmd (list (concat ada-cd-command " ${build_dir}")
388 ada-prj-default-comp-cmd)
389 'check_cmd (list (concat ada-prj-default-comp-cmd " "
390 ada-check-switch))
391 'make_cmd (list (concat ada-cd-command " ${build_dir}")
392 ada-prj-default-make-cmd)
393 'run_cmd (list (concat ada-cd-command " ${build_dir}")
394 (concat "${main}"
395 (if is-windows ".exe")))
396 'debug_pre_cmd (list (concat ada-cd-command
397 " ${build_dir}"))
15ea3b67
GM
398 'debug_cmd (concat ada-prj-default-debugger
399 (if is-windows " ${main}.exe"
4884c50b
SM
400 " ${main}"))
401 'debug_post_cmd (list nil)))
15ea3b67
GM
402 )
403 (set symbol plist)))
a1506d29 404
15ea3b67 405(defun ada-xref-get-project-field (field)
4884c50b 406 "Extract the value of FIELD from the current project file.
15ea3b67 407The project file must have been loaded first.
4884c50b
SM
408A default value is returned if the file was not found.
409
410Note that for src_dir and obj_dir, you should rather use
411`ada-xref-get-src-dir-field' or `ada-xref-get-obj-dir-field' which will in
412addition return the default paths."
15ea3b67 413
4884c50b 414 (let ((file-name ada-prj-default-project-file)
15ea3b67
GM
415 file value)
416
4884c50b
SM
417 ;; Get the project file (either the current one, or a default one)
418 (setq file (or (assoc file-name ada-xref-project-files)
419 (assoc nil ada-xref-project-files)))
a1506d29 420
15ea3b67
GM
421 ;; If the file was not found, use the default values
422 (if file
423 ;; Get the value from the file
424 (set 'value (plist-get (cdr file) field))
425
426 ;; Create a default nil file that contains the default values
427 (ada-xref-set-default-prj-values 'value (current-buffer))
428 (add-to-list 'ada-xref-project-files (cons nil value))
4884c50b 429 (ada-xref-update-project-menu)
15ea3b67
GM
430 (set 'value (plist-get value field))
431 )
4884c50b
SM
432
433 ;; Substitute the ${...} constructs in all the strings, including
434 ;; inside lists
435 (cond
436 ((stringp value)
437 (ada-treat-cmd-string value))
438 ((null value)
439 nil)
440 ((listp value)
441 (mapcar (lambda(x) (if x (ada-treat-cmd-string x) x)) value))
442 (t
443 value)
444 )
445 ))
446
447
448(defun ada-xref-get-src-dir-field ()
449 "Return the full value for src_dir, including the default directories.
450All the directories are returned as absolute directories."
451
452 (let ((build-dir (ada-xref-get-project-field 'build_dir)))
453 (append
454 ;; Add ${build_dir} in front of the path
455 (list build-dir)
a1506d29 456
4884c50b
SM
457 (ada-get-absolute-dir-list (ada-xref-get-project-field 'src_dir)
458 build-dir)
a1506d29 459
4884c50b
SM
460 ;; Add the standard runtime at the end
461 ada-xref-runtime-library-specs-path)))
462
463(defun ada-xref-get-obj-dir-field ()
464 "Return the full value for obj_dir, including the default directories.
465All the directories are returned as absolute directories."
466
467 (let ((build-dir (ada-xref-get-project-field 'build_dir)))
468 (append
469 ;; Add ${build_dir} in front of the path
470 (list build-dir)
a1506d29 471
4884c50b
SM
472 (ada-get-absolute-dir-list (ada-xref-get-project-field 'obj_dir)
473 build-dir)
a1506d29 474
4884c50b
SM
475 ;; Add the standard runtime at the end
476 ada-xref-runtime-library-ali-path)))
477
478(defun ada-xref-update-project-menu ()
479 "Update the menu Ada->Project, with the list of available project files."
96a483d9
SM
480 ;; Create the standard items.
481 (let ((submenu
482 `("Project"
483 ["Load..." ada-set-default-project-file t]
484 ["New..." ada-prj-new t]
485 ["Edit..." ada-prj-edit t]
486 "---"
487 ;; Add the new items
488 ,@(mapcar
489 (lambda (x)
490 (let ((name (or (car x) "<default>"))
491 (command `(lambda ()
492 "Change the active project file."
493 (interactive)
494 (ada-parse-prj-file ,(car x))
495 (set 'ada-prj-default-project-file ,(car x))
496 (ada-xref-update-project-menu))))
497 (vector
498 (if (string= (file-name-extension name)
499 ada-project-file-extension)
500 (file-name-sans-extension
501 (file-name-nondirectory name))
502 (file-name-nondirectory name))
503 command
504 :button (cons
505 :toggle
506 (equal ada-prj-default-project-file
507 (car x))
508 ))))
509
510 ;; Parses all the known project files, and insert at
511 ;; least the default one (in case
512 ;; ada-xref-project-files is nil)
513 (or ada-xref-project-files '(nil))))))
514
515 (easy-menu-add-item ada-mode-menu '() submenu)))
4884c50b
SM
516
517
518;;-------------------------------------------------------------
519;;-- Searching a file anywhere on the source path.
520;;--
521;;-- The following functions provide support for finding a file anywhere
522;;-- on the source path, without providing an explicit directory.
523;;-- They also provide file name completion in the minibuffer.
524;;--
525;;-- Public subprograms: ada-find-file
526;;--
527;;-------------------------------------------------------------
528
529(defun ada-do-file-completion (string predicate flag)
530 "Completion function when reading a file from the minibuffer.
531Completion is attempted in all the directories in the source path, as
532defined in the project file."
533 (let (list
534 (dirs (ada-xref-get-src-dir-field)))
535
536 (while dirs
537 (if (file-directory-p (car dirs))
538 (set 'list (append list (file-name-all-completions string (car dirs)))))
539 (set 'dirs (cdr dirs)))
540 (cond ((equal flag 'lambda)
541 (assoc string list))
542 (flag
543 list)
544 (t
545 (try-completion string
546 (mapcar (lambda (x) (cons x 1)) list)
547 predicate)))))
548
549;;;###autoload
550(defun ada-find-file (filename)
551 "Open a file anywhere in the source path.
552Completion is available."
553 (interactive
554 (list (completing-read "File: " 'ada-do-file-completion)))
555 (let ((file (ada-find-src-file-in-dir filename)))
556 (if file
557 (find-file file)
558 (error (concat filename " not found in src_dir")))))
559
797aab3c 560
797aab3c
GM
561;; ----- Utilities -------------------------------------------------
562
563(defun ada-require-project-file ()
4884c50b
SM
564 "If no project file is currently active, load a default one."
565 (if (or (not ada-prj-default-project-file)
566 (not ada-xref-project-files)
567 (string= ada-prj-default-project-file ""))
15ea3b67 568 (ada-reread-prj-file)))
a1506d29 569
797aab3c 570(defun ada-xref-push-pos (filename position)
eec3232e 571 "Push (FILENAME, POSITION) on the position ring for cross-references."
797aab3c
GM
572 (setq ada-xref-pos-ring (cons (list position filename) ada-xref-pos-ring))
573 (if (> (length ada-xref-pos-ring) ada-xref-pos-ring-max)
574 (setcdr (nthcdr (1- ada-xref-pos-ring-max) ada-xref-pos-ring) nil)))
575
576(defun ada-xref-goto-previous-reference ()
eec3232e 577 "Go to the previous cross-reference we were on."
797aab3c
GM
578 (interactive)
579 (if ada-xref-pos-ring
eec3232e
GM
580 (let ((pos (car ada-xref-pos-ring)))
581 (setq ada-xref-pos-ring (cdr ada-xref-pos-ring))
582 (find-file (car (cdr pos)))
583 (goto-char (car pos)))))
797aab3c
GM
584
585(defun ada-convert-file-name (name)
eec3232e
GM
586 "Converts from NAME to a name that can be used by the compilation commands.
587This is overriden on VMS to convert from VMS filenames to Unix filenames."
797aab3c
GM
588 name)
589
c94ca9e0
JB
590(defun ada-set-default-project-file (name &optional keep-existing)
591 "Set the file whose name is NAME as the default project file.
592If KEEP-EXISTING is true and a project file has already been loaded, nothing
593is done. This is meant to be used from ada-mode-hook, for instance to force
594a project file unless the user has already loaded one."
eec3232e 595 (interactive "fProject file:")
c94ca9e0
JB
596 (if (or (not keep-existing)
597 (not ada-prj-default-project-file)
598 (equal ada-prj-default-project-file ""))
599 (progn
600 (setq ada-prj-default-project-file name)
601 (ada-reread-prj-file name))))
15ea3b67
GM
602
603;; ------ Handling the project file -----------------------------
797aab3c 604
c94ca9e0
JB
605(defun ada-prj-find-prj-file (&optional file no-user-question)
606 "Find the prj file associated with FILE (or the current buffer if nil).
15ea3b67
GM
607If NO-USER-QUESTION is non-nil, use a default file if not project file was
608found, and do not ask the user.
609If the buffer is not an Ada buffer, associate it with the default project
610file. If none is set, return nil."
797aab3c 611
15ea3b67 612 (let (selected)
797aab3c 613
4884c50b
SM
614 ;; Use the active project file if there is one.
615 ;; This is also valid if we don't currently have an Ada buffer, or if
616 ;; the current buffer is not a real file (for instance an emerge buffer)
a1506d29 617
15ea3b67 618 (if (or (not (string= mode-name "Ada"))
c94ca9e0
JB
619 (not (buffer-file-name)))
620
621 (if (and ada-prj-default-project-file
622 (not (string= ada-prj-default-project-file "")))
623 (setq selected ada-prj-default-project-file)
624 (setq selected nil))
a1506d29 625
4884c50b 626 ;; other cases: use a more complex algorithm
a1506d29 627
c94ca9e0 628 (let* ((current-file (or file (buffer-file-name)))
4884c50b
SM
629 (first-choice (concat
630 (file-name-sans-extension current-file)
631 ada-project-file-extension))
632 (dir (file-name-directory current-file))
a1506d29 633
4884c50b
SM
634 ;; on Emacs 20.2, directory-files does not work if
635 ;; parse-sexp-lookup-properties is set
636 (parse-sexp-lookup-properties nil)
637 (prj-files (directory-files
638 dir t
639 (concat ".*" (regexp-quote
640 ada-project-file-extension) "$")))
641 (choice nil))
a1506d29 642
4884c50b 643 (cond
a1506d29 644
4884c50b
SM
645 ;; Else if there is a project file with the same name as the Ada
646 ;; file, but not the same extension.
647 ((file-exists-p first-choice)
648 (set 'selected first-choice))
a1506d29 649
4884c50b
SM
650 ;; Else if only one project file was found in the current directory
651 ((= (length prj-files) 1)
652 (set 'selected (car prj-files)))
a1506d29 653
4884c50b
SM
654 ;; Else if there are multiple files, ask the user
655 ((and (> (length prj-files) 1) (not no-user-question))
656 (save-window-excursion
657 (with-output-to-temp-buffer "*choice list*"
658 (princ "There are more than one possible project file.\n")
659 (princ "Which one should we use ?\n\n")
660 (princ " no. file name \n")
661 (princ " --- ------------------------\n")
662 (let ((counter 1))
663 (while (<= counter (length prj-files))
664 (princ (format " %2d) %s\n"
665 counter
666 (nth (1- counter) prj-files)))
667 (setq counter (1+ counter))
c94ca9e0 668
4884c50b
SM
669 ))) ; end of with-output-to ...
670 (setq choice nil)
671 (while (or
672 (not choice)
673 (not (integerp choice))
674 (< choice 1)
675 (> choice (length prj-files)))
676 (setq choice (string-to-int
677 (read-from-minibuffer "Enter No. of your choice: "))))
678 (set 'selected (nth (1- choice) prj-files))))
a1506d29 679
4884c50b
SM
680 ;; Else if no project file was found in the directory, ask a name
681 ;; to the user, using as a default value the last one entered by
682 ;; the user
683 ((= (length prj-files) 0)
684 (unless (or no-user-question (not ada-always-ask-project))
685 (setq ada-last-prj-file
686 (read-file-name
687 (concat "project file [" ada-last-prj-file "]:")
688 nil ada-last-prj-file))
689 (unless (string= ada-last-prj-file "")
690 (set 'selected ada-last-prj-file))))
691 )))
c94ca9e0
JB
692
693 (or selected "default.adp")
797aab3c
GM
694 ))
695
696
15ea3b67
GM
697(defun ada-parse-prj-file (prj-file)
698 "Reads and parses the PRJ-FILE file if it was found.
699The current buffer should be the ada-file buffer."
700 (if prj-file
4884c50b
SM
701 (let (project src_dir obj_dir make_cmd comp_cmd check_cmd casing
702 run_cmd debug_pre_cmd debug_post_cmd
15ea3b67 703 (ada-buffer (current-buffer)))
4884c50b 704 (setq prj-file (expand-file-name prj-file))
15ea3b67 705
c94ca9e0
JB
706 ;; Set the project file as the active one.
707 (setq ada-prj-default-project-file prj-file)
708
15ea3b67
GM
709 ;; Initialize the project with the default values
710 (ada-xref-set-default-prj-values 'project (current-buffer))
711
712 ;; Do not use find-file below, since we don't want to show this
713 ;; buffer. If the file is open through speedbar, we can't use
714 ;; find-file anyway, since the speedbar frame is special and does not
715 ;; allow the selection of a file in it.
716
c94ca9e0
JB
717 (if (file-exists-p prj-file)
718 (progn
719 (let* ((buffer (run-hook-with-args-until-success
720 'ada-load-project-hook prj-file)))
721 (unless buffer
7abe197c
JB
722 (setq buffer (find-file-noselect prj-file nil)))
723 (set-buffer buffer))
724
725 (widen)
726 (goto-char (point-min))
727
728 ;; Now overrides these values with the project file
729 (while (not (eobp))
730 (if (looking-at "^\\([^=]+\\)=\\(.*\\)")
731 (cond
732 ((string= (match-string 1) "src_dir")
733 (add-to-list 'src_dir
734 (file-name-as-directory (match-string 2))))
735 ((string= (match-string 1) "obj_dir")
736 (add-to-list 'obj_dir
737 (file-name-as-directory (match-string 2))))
738 ((string= (match-string 1) "casing")
739 (set 'casing (cons (match-string 2) casing)))
740 ((string= (match-string 1) "build_dir")
741 (set 'project
742 (plist-put project 'build_dir
743 (file-name-as-directory (match-string 2)))))
744 ((string= (match-string 1) "make_cmd")
745 (add-to-list 'make_cmd (match-string 2)))
746 ((string= (match-string 1) "comp_cmd")
747 (add-to-list 'comp_cmd (match-string 2)))
748 ((string= (match-string 1) "check_cmd")
749 (add-to-list 'check_cmd (match-string 2)))
750 ((string= (match-string 1) "run_cmd")
751 (add-to-list 'run_cmd (match-string 2)))
752 ((string= (match-string 1) "debug_pre_cmd")
753 (add-to-list 'debug_pre_cmd (match-string 2)))
754 ((string= (match-string 1) "debug_post_cmd")
755 (add-to-list 'debug_post_cmd (match-string 2)))
756 (t
757 (set 'project (plist-put project (intern (match-string 1))
758 (match-string 2))))))
759 (forward-line 1))
760
761 (if src_dir (set 'project (plist-put project 'src_dir
762 (reverse src_dir))))
763 (if obj_dir (set 'project (plist-put project 'obj_dir
764 (reverse obj_dir))))
765 (if casing (set 'project (plist-put project 'casing
766 (reverse casing))))
767 (if make_cmd (set 'project (plist-put project 'make_cmd
768 (reverse make_cmd))))
769 (if comp_cmd (set 'project (plist-put project 'comp_cmd
770 (reverse comp_cmd))))
771 (if check_cmd (set 'project (plist-put project 'check_cmd
772 (reverse check_cmd))))
773 (if run_cmd (set 'project (plist-put project 'run_cmd
774 (reverse run_cmd))))
775 (set 'project (plist-put project 'debug_post_cmd
776 (reverse debug_post_cmd)))
c94ca9e0
JB
777 (set 'project (plist-put project 'debug_pre_cmd
778 (reverse debug_pre_cmd)))
779
780 ;; Kill the project buffer
781 (kill-buffer nil)
782 (set-buffer ada-buffer)
783 )
784
785 ;; Else the file wasn't readable (probably the default project).
786 ;; We initialize it with the current environment variables.
787 ;; We need to add the startup directory in front so that
788 ;; files locally redefined are properly found. We cannot
789 ;; add ".", which varies too much depending on what the
790 ;; current buffer is.
791 (set 'project
792 (plist-put project 'src_dir
793 (append
794 (list command-line-default-directory)
795 (split-string (or (getenv "ADA_INCLUDE_PATH") "") ":")
796 (list "." default-directory))))
797 (set 'project
798 (plist-put project 'obj_dir
799 (append
800 (list command-line-default-directory)
801 (split-string (or (getenv "ADA_OBJECTS_PATH") "") ":")
802 (list "." default-directory))))
803 )
804
4884c50b
SM
805
806 ;; Delete the default project file from the list, if it is there.
807 ;; Note that in that case, this default project is the only one in
808 ;; the list
809 (if (assoc nil ada-xref-project-files)
810 (setq ada-xref-project-files nil))
a1506d29 811
15ea3b67
GM
812 ;; Memorize the newly read project file
813 (if (assoc prj-file ada-xref-project-files)
814 (setcdr (assoc prj-file ada-xref-project-files) project)
815 (add-to-list 'ada-xref-project-files (cons prj-file project)))
4884c50b 816
15ea3b67
GM
817 ;; Sets up the compilation-search-path so that Emacs is able to
818 ;; go to the source of the errors in a compilation buffer
4884c50b
SM
819 (setq compilation-search-path (ada-xref-get-src-dir-field))
820
821 ;; Set the casing exceptions file list
822 (if casing
823 (progn
824 (setq ada-case-exception-file (reverse casing))
825 (ada-case-read-exceptions)))
a1506d29 826
15ea3b67
GM
827 ;; Add the directories to the search path for ff-find-other-file
828 ;; Do not add the '/' or '\' at the end
7abe197c 829 (setq ada-search-directories-internal
15ea3b67
GM
830 (append (mapcar 'directory-file-name compilation-search-path)
831 ada-search-directories))
a1506d29 832
4884c50b 833 (ada-xref-update-project-menu)
15ea3b67 834 )
4884c50b
SM
835
836 ;; No prj file ? => Setup default values
837 ;; Note that nil means that all compilation modes will first look in the
838 ;; current directory, and only then in the current file's directory. This
839 ;; current file is assumed at this point to be in the common source
840 ;; directory.
841 (setq compilation-search-path (list nil default-directory))
15ea3b67 842 ))
a1506d29
JB
843
844
93cdce20 845(defun ada-find-references (&optional pos arg local-only)
eec3232e 846 "Find all references to the entity under POS.
93cdce20
SM
847Calls gnatfind to find the references.
848if ARG is t, the contents of the old *gnatfind* buffer is preserved.
849if LOCAL-ONLY is t, only the declarations in the current file are returned."
850 (interactive "d
851P")
797aab3c
GM
852 (ada-require-project-file)
853
854 (let* ((identlist (ada-read-identifier pos))
15ea3b67
GM
855 (alifile (ada-get-ali-file-name (ada-file-of identlist)))
856 (process-environment (ada-set-environment)))
797aab3c
GM
857
858 (set-buffer (get-file-buffer (ada-file-of identlist)))
859
860 ;; if the file is more recent than the executable
861 (if (or (buffer-modified-p (current-buffer))
862 (file-newer-than-file-p (ada-file-of identlist) alifile))
863 (ada-find-any-references (ada-name-of identlist)
864 (ada-file-of identlist)
93cdce20 865 nil nil local-only arg)
797aab3c
GM
866 (ada-find-any-references (ada-name-of identlist)
867 (ada-file-of identlist)
868 (ada-line-of identlist)
93cdce20 869 (ada-column-of identlist) local-only arg)))
797aab3c
GM
870 )
871
93cdce20
SM
872(defun ada-find-local-references (&optional pos arg)
873 "Find all references to the entity under POS.
874Calls gnatfind to find the references.
875if ARG is t, the contents of the old *gnatfind* buffer is preserved."
876 (interactive "d
877P")
878 (ada-find-references pos arg t))
879
880(defun ada-find-any-references
881 (entity &optional file line column local-only append)
eec3232e 882 "Search for references to any entity whose name is ENTITY.
93cdce20
SM
883ENTITY was first found the location given by FILE, LINE and COLUMN.
884If LOCAL-ONLY is t, then only the references in file will be listed, which
885is much faster.
886If APPEND is t, then the output of the command will be append to the existing
887buffer *gnatfind* if it exists."
797aab3c
GM
888 (interactive "sEntity name: ")
889 (ada-require-project-file)
890
4884c50b
SM
891 ;; Prepare the gnatfind command. Note that we must protect the quotes
892 ;; around operators, so that they are correctly handled and can be
893 ;; processed (gnatfind \"+\":...).
894 (let* ((quote-entity
895 (if (= (aref entity 0) ?\")
896 (if is-windows
897 (concat "\\\"" (substring entity 1 -1) "\\\"")
898 (concat "'\"" (substring entity 1 -1) "\"'"))
899 entity))
900 (switches (ada-xref-get-project-field 'gnatfind_opt))
7abe197c 901 (command (concat "gnat find " switches " "
4884c50b 902 quote-entity
797aab3c
GM
903 (if file (concat ":" (file-name-nondirectory file)))
904 (if line (concat ":" line))
93cdce20
SM
905 (if column (concat ":" column))
906 (if local-only (concat " " (file-name-nondirectory file)))
907 ))
908 old-contents)
797aab3c
GM
909
910 ;; If a project file is defined, use it
4884c50b
SM
911 (if (and ada-prj-default-project-file
912 (not (string= ada-prj-default-project-file "")))
7abe197c
JB
913 (if (string-equal (file-name-extension ada-prj-default-project-file)
914 "gpr")
915 (setq command (concat command " -P" ada-prj-default-project-file))
916 (setq command (concat command " -p" ada-prj-default-project-file))))
797aab3c 917
93cdce20
SM
918 (if (and append (get-buffer "*gnatfind*"))
919 (save-excursion
920 (set-buffer "*gnatfind*")
921 (setq old-contents (buffer-string))))
a1506d29 922
eec3232e 923 (compile-internal command "No more references" "gnatfind")
797aab3c
GM
924
925 ;; Hide the "Compilation" menu
926 (save-excursion
927 (set-buffer "*gnatfind*")
93cdce20
SM
928 (local-unset-key [menu-bar compilation-menu])
929
930 (if old-contents
931 (progn
932 (goto-char 1)
933 (insert old-contents)
934 (goto-char (point-max)))))
797aab3c
GM
935 )
936 )
937
4884c50b 938(defalias 'ada-change-prj (symbol-function 'ada-set-default-project-file))
797aab3c 939
797aab3c
GM
940;; ----- Identifier Completion --------------------------------------------
941(defun ada-complete-identifier (pos)
942 "Tries to complete the identifier around POS.
15ea3b67 943The feature is only available if the files where compiled not using the -gnatx
eec3232e 944option."
797aab3c
GM
945 (interactive "d")
946 (ada-require-project-file)
947
15ea3b67 948 ;; Initialize function-local variables and jump to the .ali buffer
797aab3c
GM
949 ;; Note that for regexp search is case insensitive too
950 (let* ((curbuf (current-buffer))
951 (identlist (ada-read-identifier pos))
952 (sofar (concat "^[0-9]+[a-zA-Z][0-9]+[ *]\\("
953 (regexp-quote (ada-name-of identlist))
954 "[a-zA-Z0-9_]*\\)"))
955 (completed nil)
15ea3b67 956 (symalist nil))
797aab3c 957
15ea3b67
GM
958 ;; Open the .ali file
959 (set-buffer (ada-get-ali-buffer (buffer-file-name)))
797aab3c
GM
960 (goto-char (point-max))
961
962 ;; build an alist of possible completions
963 (while (re-search-backward sofar nil t)
964 (setq symalist (cons (cons (match-string 1) nil) symalist)))
965
966 (setq completed (try-completion "" symalist))
967
968 ;; kills .ali buffer
969 (kill-buffer nil)
970
971 ;; deletes the incomplete identifier in the buffer
972 (set-buffer curbuf)
973 (looking-at "[a-zA-Z0-9_]+")
974 (replace-match "")
975 ;; inserts the completed symbol
976 (insert completed)
977 ))
978
979;; ----- Cross-referencing ----------------------------------------
980
981(defun ada-point-and-xref ()
c94ca9e0 982 "Jump to the declaration of the entity below the cursor."
797aab3c
GM
983 (interactive)
984 (mouse-set-point last-input-event)
985 (ada-goto-declaration (point)))
986
c94ca9e0
JB
987(defun ada-point-and-xref-body ()
988 "Jump to the body of the entity under the cursor."
989 (interactive)
990 (mouse-set-point last-input-event)
991 (ada-goto-body (point)))
992
993(defun ada-goto-body (pos &optional other-frame)
994 "Display the body of the entity around POS.
995If the entity doesn't have a body, display its declaration.
996As a side effect, the buffer for the declaration is also open."
997 (interactive "d")
998 (ada-goto-declaration pos other-frame)
999
1000 ;; Temporarily force the display in the same buffer, since we
1001 ;; already changed previously
1002 (let ((ada-xref-other-buffer nil))
1003 (ada-goto-declaration (point) nil)))
1004
4884c50b 1005(defun ada-goto-declaration (pos &optional other-frame)
eec3232e
GM
1006 "Display the declaration of the identifier around POS.
1007The declaration is shown in another buffer if `ada-xref-other-buffer' is
4884c50b
SM
1008non-nil.
1009If OTHER-FRAME is non-nil, display the cross-reference in another frame."
797aab3c
GM
1010 (interactive "d")
1011 (ada-require-project-file)
1012 (push-mark pos)
1013 (ada-xref-push-pos (buffer-file-name) pos)
797aab3c 1014
4884c50b
SM
1015 ;; First try the standard algorithm by looking into the .ali file, but if
1016 ;; that file was too old or even did not exist, try to look in the whole
1017 ;; object path for a possible location.
1018 (let ((identlist (ada-read-identifier pos)))
1019 (condition-case nil
1020 (ada-find-in-ali identlist other-frame)
93cdce20
SM
1021 (error
1022 (let ((ali-file (ada-get-ali-file-name (ada-file-of identlist))))
1023
1024 ;; If the ALI file was up-to-date, then we probably have a predefined
1025 ;; entity, whose references are not given by GNAT
1026 (if (and (file-exists-p ali-file)
1027 (file-newer-than-file-p ali-file (ada-file-of identlist)))
1028 (message "No cross-reference found. It might be a predefined entity.")
1029
1030 ;; Else, look in every ALI file, except if the user doesn't want that
1031 (if ada-xref-search-with-egrep
1032 (ada-find-in-src-path identlist other-frame)
1033 (message "Cross-referencing information is not up-to-date. Please recompile.")
1034 )))))))
4884c50b 1035
96a483d9 1036(defun ada-goto-declaration-other-frame (pos)
eec3232e
GM
1037 "Display the declaration of the identifier around POS.
1038The declation is shown in another frame if `ada-xref-other-buffer' is non-nil."
797aab3c 1039 (interactive "d")
4884c50b 1040 (ada-goto-declaration pos t))
797aab3c 1041
15ea3b67
GM
1042(defun ada-remote (command)
1043 "Return the remote version of COMMAND, or COMMAND if remote_machine is nil."
1044 (let ((machine (ada-xref-get-project-field 'remote_machine)))
1045 (if (or (not machine) (string= machine ""))
1046 command
1047 (format "%s %s '(%s)'"
1048 remote-shell-program
1049 machine
1050 command))))
1051
15ea3b67
GM
1052(defun ada-get-absolute-dir-list (dir-list root-dir)
1053 "Returns the list of absolute directories found in dir-list.
1054If a directory is a relative directory, the value of ROOT-DIR is added in
1055front."
4884c50b 1056 (mapcar (lambda (x) (expand-file-name x root-dir)) dir-list))
15ea3b67
GM
1057
1058(defun ada-set-environment ()
1059 "Return the new value for process-environment.
1060It modifies the source path and object path with the values found in the
1061project file."
1062 (let ((include (getenv "ADA_INCLUDE_PATH"))
1063 (objects (getenv "ADA_OBJECTS_PATH"))
1064 (build-dir (ada-xref-get-project-field 'build_dir)))
1065 (if include
4884c50b 1066 (set 'include (concat path-separator include)))
15ea3b67 1067 (if objects
4884c50b 1068 (set 'objects (concat path-separator objects)))
15ea3b67
GM
1069 (cons
1070 (concat "ADA_INCLUDE_PATH="
4884c50b 1071 (mapconcat (lambda(x) (expand-file-name x build-dir))
15ea3b67 1072 (ada-xref-get-project-field 'src_dir)
4884c50b
SM
1073 path-separator)
1074 include)
15ea3b67
GM
1075 (cons
1076 (concat "ADA_OBJECTS_PATH="
4884c50b 1077 (mapconcat (lambda(x) (expand-file-name x build-dir))
15ea3b67 1078 (ada-xref-get-project-field 'obj_dir)
4884c50b
SM
1079 path-separator)
1080 objects)
15ea3b67
GM
1081 process-environment))))
1082
1083(defun ada-compile-application (&optional arg)
1084 "Compiles the application, using the command found in the project file.
1085If ARG is not nil, ask for user confirmation."
1086 (interactive "P")
797aab3c 1087 (ada-require-project-file)
15ea3b67
GM
1088 (let ((cmd (ada-xref-get-project-field 'make_cmd))
1089 (process-environment (ada-set-environment))
1090 (compilation-scroll-output t))
1091
4884c50b 1092 (setq compilation-search-path (ada-xref-get-src-dir-field))
15ea3b67
GM
1093
1094 ;; If no project file was found, ask the user
1095 (unless cmd
4884c50b 1096 (setq cmd '("") arg t))
15ea3b67 1097
4884c50b
SM
1098 ;; Make a single command from the list of commands, including the
1099 ;; commands to run it on a remote machine.
1100 (setq cmd (ada-remote (mapconcat 'identity cmd ada-command-separator)))
a1506d29 1101
4884c50b
SM
1102 (if (or ada-xref-confirm-compile arg)
1103 (setq cmd (read-from-minibuffer "enter command to compile: " cmd)))
1104
1105 ;; Insert newlines so as to separate the name of the commands to run
1106 ;; and the output of the commands. this doesn't work with cmdproxy.exe,
1107 ;; which gets confused by newline characters.
c94ca9e0 1108 (if (not (string-match ".exe" shell-file-name))
4884c50b 1109 (setq cmd (concat cmd "\n\n")))
a1506d29 1110
4884c50b 1111 (compile (ada-quote-cmd cmd))))
797aab3c 1112
15ea3b67
GM
1113(defun ada-compile-current (&optional arg prj-field)
1114 "Recompile the current file.
1115If ARG is not nil, ask for user confirmation of the command.
1116PRJ-FIELD is the name of the field to use in the project file to get the
1117command, and should be either comp_cmd (default) or check_cmd."
1118 (interactive "P")
797aab3c 1119 (ada-require-project-file)
15ea3b67
GM
1120 (let* ((field (if prj-field prj-field 'comp_cmd))
1121 (cmd (ada-xref-get-project-field field))
1122 (process-environment (ada-set-environment))
1123 (compilation-scroll-output t))
a1506d29 1124
4884c50b 1125 (setq compilation-search-path (ada-xref-get-src-dir-field))
15ea3b67 1126
4884c50b
SM
1127 (unless cmd
1128 (setq cmd '("") arg t))
a1506d29 1129
4884c50b
SM
1130 ;; Make a single command from the list of commands, including the
1131 ;; commands to run it on a remote machine.
1132 (setq cmd (ada-remote (mapconcat 'identity cmd ada-command-separator)))
a1506d29 1133
15ea3b67 1134 ;; If no project file was found, ask the user
4884c50b
SM
1135 (if (or ada-xref-confirm-compile arg)
1136 (setq cmd (read-from-minibuffer "enter command to compile: " cmd)))
1137
1138 ;; Insert newlines so as to separate the name of the commands to run
1139 ;; and the output of the commands. this doesn't work with cmdproxy.exe,
1140 ;; which gets confused by newline characters.
c94ca9e0 1141 (if (not (string-match ".exe" shell-file-name))
4884c50b 1142 (setq cmd (concat cmd "\n\n")))
a1506d29 1143
4884c50b 1144 (compile (ada-quote-cmd cmd))))
15ea3b67
GM
1145
1146(defun ada-check-current (&optional arg)
1147 "Recompile the current file.
1148If ARG is not nil, ask for user confirmation of the command."
1149 (interactive "P")
1150 (ada-compile-current arg 'check_cmd))
797aab3c 1151
15ea3b67
GM
1152(defun ada-run-application (&optional arg)
1153 "Run the application.
1154if ARG is not-nil, asks for user confirmation."
797aab3c
GM
1155 (interactive)
1156 (ada-require-project-file)
1157
15ea3b67
GM
1158 (let ((machine (ada-xref-get-project-field 'cross_prefix)))
1159 (if (and machine (not (string= machine "")))
1160 (error "This feature is not supported yet for cross environments")))
797aab3c 1161
15ea3b67 1162 (let ((command (ada-xref-get-project-field 'run_cmd)))
797aab3c 1163
15ea3b67 1164 ;; Guess the command if it wasn't specified
4884c50b
SM
1165 (if (not command)
1166 (set 'command (list (file-name-sans-extension (buffer-name)))))
797aab3c 1167
4884c50b
SM
1168 ;; Modify the command to run remotely
1169 (setq command (ada-remote (mapconcat 'identity command
1170 ada-command-separator)))
a1506d29 1171
15ea3b67
GM
1172 ;; Ask for the arguments to the command if required
1173 (if (or ada-xref-confirm-compile arg)
4884c50b
SM
1174 (setq command (read-from-minibuffer "Enter command to execute: "
1175 command)))
797aab3c
GM
1176
1177 ;; Run the command
1178 (save-excursion
1179 (set-buffer (get-buffer-create "*run*"))
15ea3b67 1180 (set 'buffer-read-only nil)
4884c50b 1181
15ea3b67 1182 (erase-buffer)
4884c50b
SM
1183 (start-process "run" (current-buffer) shell-file-name
1184 "-c" command)
1185 (comint-mode)
1186 ;; Set these two variables to their default values, since otherwise
1187 ;; the output buffer is scrolled so that only the last output line
1188 ;; is visible at the top of the buffer.
1189 (set (make-local-variable 'scroll-step) 0)
1190 (set (make-local-variable 'scroll-conservatively) 0)
797aab3c
GM
1191 )
1192 (display-buffer "*run*")
1193
1194 ;; change to buffer *run* for interactive programs
1195 (other-window 1)
1196 (switch-to-buffer "*run*")
15ea3b67 1197 ))
797aab3c 1198
4884c50b 1199(defun ada-gdb-application (&optional arg executable-name)
15ea3b67 1200 "Start the debugger on the application.
4884c50b
SM
1201EXECUTABLE-NAME, if non-nil, is debugged instead of the file specified in the
1202project file.
15ea3b67
GM
1203If ARG is non-nil, ask the user to confirm the command."
1204 (interactive "P")
797aab3c 1205 (let ((buffer (current-buffer))
4884c50b 1206 cmd pre-cmd post-cmd)
797aab3c 1207 (ada-require-project-file)
4884c50b
SM
1208 (setq cmd (if executable-name
1209 (concat ada-prj-default-debugger " " executable-name)
1210 (ada-xref-get-project-field 'debug_cmd))
1211 pre-cmd (ada-xref-get-project-field 'debug_pre_cmd)
1212 post-cmd (ada-xref-get-project-field 'debug_post_cmd))
15ea3b67
GM
1213
1214 ;; If the command was not given in the project file, start a bare gdb
1215 (if (not cmd)
1216 (set 'cmd (concat ada-prj-default-debugger
1217 " "
4884c50b
SM
1218 (or executable-name
1219 (file-name-sans-extension (buffer-file-name))))))
1220
1221 ;; For gvd, add an extra switch so that the Emacs window is completly
1222 ;; swallowed inside the Gvd one
1223 (if (and ada-tight-gvd-integration
1224 (string-match "^[^ \t]*gvd" cmd))
1225 ;; Start a new frame, so that when gvd exists we do not kill Emacs
1226 ;; We make sure that gvd swallows the new frame, not the one the
1227 ;; user has been using until now
1228 ;; The frame is made invisible initially, so that GtkPlug gets a
1229 ;; chance to fully manage it. Then it works fine with Enlightenment
1230 ;; as well
1231 (let ((frame (make-frame '((visibility . nil)))))
1232 (set 'cmd (concat
1233 cmd " --editor-window="
1234 (cdr (assoc 'outer-window-id (frame-parameters frame)))))
1235 (select-frame frame)))
1236
1237 ;; Add a -fullname switch
1238 ;; Use the remote machine
1239 (set 'cmd (ada-remote (concat cmd " -fullname ")))
1240
1241 ;; Ask for confirmation if required
15ea3b67
GM
1242 (if (or arg ada-xref-confirm-compile)
1243 (set 'cmd (read-from-minibuffer "enter command to debug: " cmd)))
1244
96a483d9 1245 (let ((old-comint-exec (symbol-function 'comint-exec)))
4884c50b
SM
1246
1247 ;; Do not add -fullname, since we can have a 'rsh' command in front.
96a483d9 1248 ;; FIXME: This is evil but luckily a nop under Emacs-21.3.50 ! -stef
4884c50b
SM
1249 (fset 'gud-gdb-massage-args (lambda (file args) args))
1250
1251 (set 'pre-cmd (mapconcat 'identity pre-cmd ada-command-separator))
1252 (if (not (equal pre-cmd ""))
1253 (setq pre-cmd (concat pre-cmd ada-command-separator)))
1254
1255 (set 'post-cmd (mapconcat 'identity post-cmd "\n"))
1256 (if post-cmd
96a483d9 1257 (set 'post-cmd (concat post-cmd "\n")))
4884c50b 1258
c94ca9e0 1259
4884c50b
SM
1260 ;; Temporarily replaces the definition of `comint-exec' so that we
1261 ;; can execute commands before running gdb.
96a483d9 1262 ;; FIXME: This is evil and not temporary !!! -stef
a1506d29 1263 (fset 'comint-exec
4884c50b
SM
1264 `(lambda (buffer name command startfile switches)
1265 (let (compilation-buffer-name-function)
1266 (save-excursion
1267 (set 'compilation-buffer-name-function
1268 (lambda(x) (buffer-name buffer)))
1269 (compile (ada-quote-cmd
1270 (concat ,pre-cmd
1271 command " "
1272 (mapconcat 'identity switches " "))))))
1273 ))
1274
1275 ;; Tight integration should force the tty mode
1276 (if (and (string-match "gvd" (comint-arguments cmd 0 0))
1277 ada-tight-gvd-integration
1278 (not (string-match "--tty" cmd)))
1279 (setq cmd (concat cmd "--tty")))
a1506d29 1280
4884c50b
SM
1281 (if (and (string-match "jdb" (comint-arguments cmd 0 0))
1282 (boundp 'jdb))
1283 (funcall (symbol-function 'jdb) cmd)
1284 (gdb cmd))
1285
c94ca9e0
JB
1286 ;; Restore the standard fset command (or for instance C-U M-x shell
1287 ;; wouldn't work anymore
1288
1289 (fset 'comint-exec old-comint-exec)
1290
4884c50b
SM
1291 ;; Send post-commands to the debugger
1292 (process-send-string (get-buffer-process (current-buffer)) post-cmd)
1293
1294 ;; Move to the end of the debugger buffer, so that it is automatically
1295 ;; scrolled from then on.
1296 (end-of-buffer)
1297
1298 ;; Display both the source window and the debugger window (the former
1299 ;; above the latter). No need to show the debugger window unless it
1300 ;; is going to have some relevant information.
1301 (if (or (not (string-match "gvd" (comint-arguments cmd 0 0)))
1302 (string-match "--tty" cmd))
1303 (split-window-vertically))
1304 (switch-to-buffer buffer)
1305 )))
797aab3c
GM
1306
1307
15ea3b67
GM
1308(defun ada-reread-prj-file (&optional filename)
1309 "Forces Emacs to read either FILENAME or the project file associated
1310with the current buffer.
1311Otherwise, this file is only read once, and never read again.
1312Since the information in the project file is shared between all buffers, this
1313automatically modifies the setup for all the Ada buffer that use this file."
797aab3c 1314 (interactive "P")
15ea3b67
GM
1315 (if filename
1316 (ada-parse-prj-file filename)
797aab3c 1317 (ada-parse-prj-file (ada-prj-find-prj-file)))
797aab3c 1318
4884c50b
SM
1319 ;; Reread the location of the standard runtime library
1320 (ada-initialize-runtime-library
c94ca9e0 1321 (or (ada-xref-get-project-field 'cross_prefix) ""))
4884c50b 1322 )
15ea3b67 1323
797aab3c
GM
1324;; ------ Private routines
1325
1326(defun ada-xref-current (file &optional ali-file-name)
eec3232e 1327 "Update the cross-references for FILE.
4884c50b
SM
1328This in fact recompiles FILE to create ALI-FILE-NAME.
1329This function returns the name of the file that was recompiled to generate
1330the cross-reference information. Note that the ali file can then be deduced by
1331replacing the file extension with .ali"
797aab3c
GM
1332 ;; kill old buffer
1333 (if (and ali-file-name
1334 (get-file-buffer ali-file-name))
1335 (kill-buffer (get-file-buffer ali-file-name)))
a1506d29 1336
4884c50b
SM
1337 (let* ((name (ada-convert-file-name file))
1338 (body-name (or (ada-get-body-name name) name)))
15ea3b67 1339
4884c50b
SM
1340 ;; Always recompile the body when we can. We thus temporarily switch to a
1341 ;; buffer than contains the body of the unit
1342 (save-excursion
1343 (let ((body-visible (find-buffer-visiting body-name))
1344 process)
1345 (if body-visible
1346 (set-buffer body-visible)
1347 (find-file body-name))
1348
1349 ;; Execute the compilation. Note that we must wait for the end of the
1350 ;; process, or the ALI file would still not be available.
1351 ;; Unfortunately, the underlying `compile' command that we use is
1352 ;; asynchronous.
1353 (ada-compile-current)
1354 (setq process (get-buffer-process "*compilation*"))
1355
1356 (while (and process
1357 (not (equal (process-status process) 'exit)))
1358 (sit-for 1))
1359
1360 ;; remove the buffer for the body if it wasn't there before
1361 (unless body-visible
1362 (kill-buffer (find-buffer-visiting body-name)))
1363 ))
1364 body-name))
15ea3b67
GM
1365
1366(defun ada-find-file-in-dir (file dir-list)
1367 "Search for FILE in DIR-LIST."
1368 (let (found)
1369 (while (and (not found) dir-list)
1370 (set 'found (concat (file-name-as-directory (car dir-list))
1371 (file-name-nondirectory file)))
a1506d29 1372
15ea3b67
GM
1373 (unless (file-exists-p found)
1374 (set 'found nil))
1375 (set 'dir-list (cdr dir-list)))
1376 found))
797aab3c
GM
1377
1378(defun ada-find-ali-file-in-dir (file)
15ea3b67
GM
1379 "Find an .ali file in obj_dir. The current buffer must be the Ada file.
1380Adds build_dir in front of the search path to conform to gnatmake's behavior,
1381and the standard runtime location at the end."
4884c50b 1382 (ada-find-file-in-dir file (ada-xref-get-obj-dir-field)))
15ea3b67
GM
1383
1384(defun ada-find-src-file-in-dir (file)
1385 "Find a source file in src_dir. The current buffer must be the Ada file.
1386Adds src_dir in front of the search path to conform to gnatmake's behavior,
1387and the standard runtime location at the end."
4884c50b 1388 (ada-find-file-in-dir file (ada-xref-get-src-dir-field)))
797aab3c
GM
1389
1390(defun ada-get-ali-file-name (file)
eec3232e
GM
1391 "Create the ali file name for the ada-file FILE.
1392The file is searched for in every directory shown in the obj_dir lines of
1393the project file."
797aab3c
GM
1394
1395 ;; This function has to handle the special case of non-standard
1396 ;; file names (i.e. not .adb or .ads)
1397 ;; The trick is the following:
1398 ;; 1- replace the extension of the current file with .ali,
1399 ;; and look for this file
1400 ;; 2- If this file is found:
1401 ;; grep the "^U" lines, and make sure we are not reading the
1402 ;; .ali file for a spec file. If we are, go to step 3.
1403 ;; 3- If the file is not found or step 2 failed:
1404 ;; find the name of the "other file", ie the body, and look
1405 ;; for its associated .ali file by subtituing the extension
4884c50b
SM
1406 ;;
1407 ;; We must also handle the case of separate packages and subprograms:
1408 ;; 4- If no ali file was found, we try to modify the file name by removing
1409 ;; everything after the last '-' or '.' character, so as to get the
1410 ;; ali file for the parent unit. If we found an ali file, we check that
1411 ;; it indeed contains the definition for the separate entity by checking
1412 ;; the 'D' lines. This is done repeatedly, in case the direct parent is
1413 ;; also a separate.
797aab3c
GM
1414
1415 (save-excursion
1416 (set-buffer (get-file-buffer file))
1417 (let ((short-ali-file-name
1418 (concat (file-name-sans-extension (file-name-nondirectory file))
1419 ".ali"))
4884c50b
SM
1420 ali-file-name
1421 is-spec)
1422
1423 ;; If we have a non-standard file name, and this is a spec, we first
1424 ;; look for the .ali file of the body, since this is the one that
1425 ;; contains the most complete information. If not found, we will do what
1426 ;; we can with the .ali file for the spec...
1427
1428 (if (not (string= (file-name-extension file) "ads"))
1429 (let ((specs ada-spec-suffixes))
1430 (while specs
1431 (if (string-match (concat (regexp-quote (car specs)) "$")
1432 file)
1433 (set 'is-spec t))
1434 (set 'specs (cdr specs)))))
1435
1436 (if is-spec
1437 (set 'ali-file-name
1438 (ada-find-ali-file-in-dir
1439 (concat (file-name-sans-extension
1440 (file-name-nondirectory
1441 (ada-other-file-name)))
1442 ".ali"))))
a1506d29 1443
4884c50b
SM
1444
1445 (setq ali-file-name
1446 (or ali-file-name
a1506d29 1447
4884c50b
SM
1448 ;; Else we take the .ali file associated with the unit
1449 (ada-find-ali-file-in-dir short-ali-file-name)
a1506d29 1450
4884c50b
SM
1451
1452 ;; else we did not find the .ali file Second chance: in case
1453 ;; the files do not have standard names (such as for instance
1454 ;; file_s.ada and file_b.ada), try to go to the other file
1455 ;; and look for its ali file
1456 (ada-find-ali-file-in-dir
1457 (concat (file-name-sans-extension
1458 (file-name-nondirectory (ada-other-file-name)))
1459 ".ali"))
1460
a1506d29 1461
4884c50b
SM
1462 ;; If we still don't have an ali file, try to get the one
1463 ;; from the parent unit, in case we have a separate entity.
1464 (let ((parent-name (file-name-sans-extension
1465 (file-name-nondirectory file))))
a1506d29 1466
4884c50b
SM
1467 (while (and (not ali-file-name)
1468 (string-match "^\\(.*\\)[.-][^.-]*" parent-name))
a1506d29 1469
4884c50b
SM
1470 (set 'parent-name (match-string 1 parent-name))
1471 (set 'ali-file-name (ada-find-ali-file-in-dir
1472 (concat parent-name ".ali")))
1473 )
1474 ali-file-name)))
a1506d29 1475
4884c50b
SM
1476 ;; If still not found, try to recompile the file
1477 (if (not ali-file-name)
1478 ;; recompile only if the user asked for this. and search the ali
1479 ;; filename again. We avoid a possible infinite recursion by
1480 ;; temporarily disabling the automatic compilation.
a1506d29 1481
4884c50b
SM
1482 (if ada-xref-create-ali
1483 (setq ali-file-name
1484 (concat (file-name-sans-extension (ada-xref-current file))
1485 ".ali"))
797aab3c 1486
4884c50b 1487 (error "Ali file not found. Recompile your file"))
a1506d29
JB
1488
1489
4884c50b
SM
1490 ;; same if the .ali file is too old and we must recompile it
1491 (if (and (file-newer-than-file-p file ali-file-name)
1492 ada-xref-create-ali)
1493 (ada-xref-current file ali-file-name)))
797aab3c 1494
4884c50b 1495 ;; Always return the correct absolute file name
797aab3c 1496 (expand-file-name ali-file-name))
4884c50b 1497 ))
797aab3c
GM
1498
1499(defun ada-get-ada-file-name (file original-file)
eec3232e
GM
1500 "Create the complete file name (+directory) for FILE.
1501The original file (where the user was) is ORIGINAL-FILE. Search in project
1502file for possible paths."
797aab3c
GM
1503
1504 (save-excursion
15ea3b67
GM
1505
1506 ;; If the buffer for original-file, use it to get the values from the
1507 ;; project file, otherwise load the file and its project file
1508 (let ((buffer (get-file-buffer original-file)))
1509 (if buffer
1510 (set-buffer buffer)
1511 (find-file original-file)
1512 (ada-require-project-file)))
a1506d29 1513
797aab3c
GM
1514 ;; we choose the first possible completion and we
1515 ;; return the absolute file name
15ea3b67 1516 (let ((filename (ada-find-src-file-in-dir file)))
797aab3c
GM
1517 (if filename
1518 (expand-file-name filename)
1519 (error (concat
1520 (file-name-nondirectory file)
1521 " not found in src_dir. Please check your project file")))
1522
1523 )))
1524
1525(defun ada-find-file-number-in-ali (file)
eec3232e 1526 "Returns the file number for FILE in the associated ali file."
797aab3c
GM
1527 (set-buffer (ada-get-ali-buffer file))
1528 (goto-char (point-min))
1529
1530 (let ((begin (re-search-forward "^D")))
1531 (beginning-of-line)
1532 (re-search-forward (concat "^D " (file-name-nondirectory file)))
1533 (count-lines begin (point))))
1534
1535(defun ada-read-identifier (pos)
4884c50b
SM
1536 "Returns the identlist around POS and switch to the .ali buffer.
1537The returned list represents the entity, and can be manipulated through the
1538macros `ada-name-of', `ada-line-of', `ada-column-of', `ada-file-of',..."
797aab3c
GM
1539
1540 ;; If at end of buffer (e.g the buffer is empty), error
1541 (if (>= (point) (point-max))
1542 (error "No identifier on point"))
a1506d29 1543
797aab3c
GM
1544 ;; goto first character of the identifier/operator (skip backward < and >
1545 ;; since they are part of multiple character operators
1546 (goto-char pos)
1547 (skip-chars-backward "a-zA-Z0-9_<>")
1548
1549 ;; check if it really is an identifier
1550 (if (ada-in-comment-p)
1551 (error "Inside comment"))
1552
1553 (let (identifier identlist)
1554 ;; Just in front of a string => we could have an operator declaration,
1555 ;; as in "+", "-", ..
1556 (if (= (char-after) ?\")
1557 (forward-char 1))
1558
1559 ;; if looking at an operator
15ea3b67
GM
1560 ;; This is only true if:
1561 ;; - the symbol is +, -, ...
1562 ;; - the symbol is made of letters, and not followed by _ or a letter
1563 (if (and (looking-at ada-operator-re)
1564 (or (not (= (char-syntax (char-after)) ?w))
1565 (not (or (= (char-syntax (char-after (match-end 0))) ?w)
1566 (= (char-after (match-end 0)) ?_)))))
797aab3c
GM
1567 (progn
1568 (if (and (= (char-before) ?\")
1569 (= (char-after (+ (length (match-string 0)) (point))) ?\"))
1570 (forward-char -1))
15ea3b67 1571 (set 'identifier (regexp-quote (concat "\"" (match-string 0) "\""))))
797aab3c
GM
1572
1573 (if (ada-in-string-p)
1574 (error "Inside string or character constant"))
1575 (if (looking-at (concat ada-keywords "[^a-zA-Z_]"))
1576 (error "No cross-reference available for reserved keyword"))
1577 (if (looking-at "[a-zA-Z0-9_]+")
1578 (set 'identifier (match-string 0))
1579 (error "No identifier around")))
a1506d29 1580
797aab3c
GM
1581 ;; Build the identlist
1582 (set 'identlist (ada-make-identlist))
1583 (ada-set-name identlist (downcase identifier))
1584 (ada-set-line identlist
93cdce20 1585 (number-to-string (count-lines 1 (point))))
797aab3c
GM
1586 (ada-set-column identlist
1587 (number-to-string (1+ (current-column))))
1588 (ada-set-file identlist (buffer-file-name))
1589 identlist
1590 ))
1591
1592(defun ada-get-all-references (identlist)
15ea3b67 1593 "Completes and returns IDENTLIST with the information extracted
eec3232e 1594from the ali file (definition file and places where it is referenced)."
a1506d29 1595
797aab3c
GM
1596 (let ((ali-buffer (ada-get-ali-buffer (ada-file-of identlist)))
1597 declaration-found)
1598 (set-buffer ali-buffer)
1599 (goto-char (point-min))
1600 (ada-set-on-declaration identlist nil)
1601
1602 ;; First attempt: we might already be on the declaration of the identifier
1603 ;; We want to look for the declaration only in a definite interval (after
1604 ;; the "^X ..." line for the current file, and before the next "^X" line
a1506d29 1605
797aab3c
GM
1606 (if (re-search-forward
1607 (concat "^X [0-9]+ " (file-name-nondirectory (ada-file-of identlist)))
1608 nil t)
1609 (let ((bound (save-excursion (re-search-forward "^X " nil t))))
1610 (set 'declaration-found
1611 (re-search-forward
1612 (concat "^" (ada-line-of identlist)
1613 "." (ada-column-of identlist)
15ea3b67 1614 "[ *]" (ada-name-of identlist)
93cdce20 1615 "[{\(<= ]?\\(.*\\)$") bound t))
797aab3c
GM
1616 (if declaration-found
1617 (ada-set-on-declaration identlist t))
1618 ))
1619
1620 ;; If declaration is still nil, then we were not on a declaration, and
1621 ;; have to fall back on other algorithms
1622
1623 (unless declaration-found
a1506d29 1624
797aab3c
GM
1625 ;; Since we alread know the number of the file, search for a direct
1626 ;; reference to it
1627 (goto-char (point-min))
1628 (set 'declaration-found t)
1629 (ada-set-ali-index
1630 identlist
1631 (number-to-string (ada-find-file-number-in-ali
1632 (ada-file-of identlist))))
1633 (unless (re-search-forward (concat (ada-ali-index-of identlist)
93cdce20 1634 "|\\([0-9]+[^0-9][0-9]+\\(\n\\.\\)? \\)*"
797aab3c 1635 (ada-line-of identlist)
c94ca9e0 1636 "[^etpzkd<>=^]"
93cdce20 1637 (ada-column-of identlist) "\\>")
797aab3c
GM
1638 nil t)
1639
1640 ;; if we did not find it, it may be because the first reference
1641 ;; is not required to have a 'unit_number|' item included.
1642 ;; Or maybe we are already on the declaration...
4884c50b
SM
1643 (unless (re-search-forward
1644 (concat
93cdce20
SM
1645 "^[0-9]+.[0-9]+[ *]"
1646 (ada-name-of identlist)
1647 "[ <{=\(]\\(.\\|\n\\.\\)*\\<"
4884c50b
SM
1648 (ada-line-of identlist)
1649 "[^0-9]"
93cdce20 1650 (ada-column-of identlist) "\\>")
4884c50b 1651 nil t)
a1506d29 1652
797aab3c
GM
1653 ;; If still not found, then either the declaration is unknown
1654 ;; or the source file has been modified since the ali file was
1655 ;; created
1656 (set 'declaration-found nil)
1657 )
1658 )
1659
1660 ;; Last check to be completly sure we have found the correct line (the
1661 ;; ali might not be up to date for instance)
1662 (if declaration-found
1663 (progn
1664 (beginning-of-line)
1665 ;; while we have a continuation line, go up one line
1666 (while (looking-at "^\\.")
1667 (previous-line 1))
1668 (unless (looking-at (concat "[0-9]+.[0-9]+[ *]"
93cdce20 1669 (ada-name-of identlist) "[ <{=\(]"))
797aab3c
GM
1670 (set 'declaration-found nil))))
1671
1672 ;; Still no success ! The ali file must be too old, and we need to
1673 ;; use a basic algorithm based on guesses. Note that this only happens
1674 ;; if the user does not want us to automatically recompile files
1675 ;; automatically
1676 (unless declaration-found
15ea3b67
GM
1677 (if (ada-xref-find-in-modified-ali identlist)
1678 (set 'declaration-found t)
797aab3c
GM
1679 ;; no more idea to find the declaration. Give up
1680 (progn
1681 (kill-buffer ali-buffer)
1682 (error (concat "No declaration of " (ada-name-of identlist)
1683 " found."))
1684 )))
1685 )
1686
a1506d29 1687
797aab3c
GM
1688 ;; Now that we have found a suitable line in the .ali file, get the
1689 ;; information available
1690 (beginning-of-line)
1691 (if declaration-found
1692 (let ((current-line (buffer-substring
1693 (point) (save-excursion (end-of-line) (point)))))
1694 (save-excursion
1695 (next-line 1)
1696 (beginning-of-line)
1697 (while (looking-at "^\\.\\(.*\\)")
1698 (set 'current-line (concat current-line (match-string 1)))
1699 (next-line 1))
1700 )
1701
1702 (if (re-search-backward "^X [0-9]+ \\([a-zA-Z0-9_.-]+\\)" nil t)
4884c50b
SM
1703
1704 ;; If we can find the file
1705 (condition-case err
1706 (ada-set-declare-file
1707 identlist
1708 (ada-get-ada-file-name (match-string 1)
1709 (ada-file-of identlist)))
a1506d29 1710
4884c50b
SM
1711 ;; Else clean up the ali file
1712 (error
1713 (kill-buffer ali-buffer)
1714 (error (error-message-string err)))
1715 ))
a1506d29 1716
797aab3c
GM
1717 (ada-set-references identlist current-line)
1718 ))
1719 ))
1720
1721(defun ada-xref-find-in-modified-ali (identlist)
1722 "Find the matching position for IDENTLIST in the current ali buffer.
1723This function is only called when the file was not up-to-date, so we need
1724to make some guesses.
eec3232e 1725This function is disabled for operators, and only works for identifiers."
797aab3c
GM
1726
1727 (unless (= (string-to-char (ada-name-of identlist)) ?\")
1728 (progn
1729 (let ((declist '()) ;;; ( (line_in_ali_file line_in_ada) ( ... ))
1730 (my-regexp (concat "[ *]"
1731 (regexp-quote (ada-name-of identlist)) " "))
1732 (line-ada "--")
1733 (col-ada "--")
1734 (line-ali 0)
1735 (len 0)
15ea3b67
GM
1736 (choice 0)
1737 (ali-buffer (current-buffer)))
797aab3c
GM
1738
1739 (goto-char (point-max))
1740 (while (re-search-backward my-regexp nil t)
1741 (save-excursion
c94ca9e0 1742 (set 'line-ali (count-lines 1 (point)))
797aab3c
GM
1743 (beginning-of-line)
1744 ;; have a look at the line and column numbers
1745 (if (looking-at "^\\([0-9]+\\).\\([0-9]+\\)[ *]")
1746 (progn
1747 (setq line-ada (match-string 1))
1748 (setq col-ada (match-string 2)))
1749 (setq line-ada "--")
1750 (setq col-ada "--")
1751 )
1752 ;; construct a list with the file names and the positions within
1753 (if (re-search-backward "^X [0-9]+ \\([a-zA-Z0-9._-]+\\)" nil t)
1754 (add-to-list
1755 'declist (list line-ali (match-string 1) line-ada col-ada))
1756 )
1757 )
1758 )
1759
1760 ;; how many possible declarations have we found ?
1761 (setq len (length declist))
1762 (cond
1763 ;; none => error
1764 ((= len 0)
1765 (kill-buffer (current-buffer))
1766 (error (concat "No declaration of "
1767 (ada-name-of identlist)
1768 " recorded in .ali file")))
a1506d29 1769
797aab3c
GM
1770 ;; one => should be the right one
1771 ((= len 1)
1772 (goto-line (caar declist)))
a1506d29 1773
797aab3c
GM
1774 ;; more than one => display choice list
1775 (t
4884c50b
SM
1776 (save-window-excursion
1777 (with-output-to-temp-buffer "*choice list*"
a1506d29 1778
4884c50b
SM
1779 (princ "Identifier is overloaded and Xref information is not up to date.\n")
1780 (princ "Possible declarations are:\n\n")
1781 (princ " no. in file at line col\n")
1782 (princ " --- --------------------- ---- ----\n")
1783 (let ((counter 0))
1784 (while (< counter len)
1785 (princ (format " %2d) %-21s %4s %4s\n"
1786 (1+ counter)
797aab3c 1787 (ada-get-ada-file-name
4884c50b 1788 (nth 1 (nth counter declist))
797aab3c 1789 (ada-file-of identlist))
4884c50b
SM
1790 (nth 2 (nth counter declist))
1791 (nth 3 (nth counter declist))
797aab3c 1792 ))
4884c50b
SM
1793 (setq counter (1+ counter))
1794 ) ; end of while
1795 ) ; end of let
1796 ) ; end of with-output-to ...
1797 (setq choice nil)
1798 (while (or
1799 (not choice)
1800 (not (integerp choice))
1801 (< choice 1)
1802 (> choice len))
1803 (setq choice
1804 (string-to-int
1805 (read-from-minibuffer "Enter No. of your choice: "))))
1806 )
15ea3b67 1807 (set-buffer ali-buffer)
797aab3c
GM
1808 (goto-line (car (nth (1- choice) declist)))
1809 ))))))
1810
1811
1812(defun ada-find-in-ali (identlist &optional other-frame)
eec3232e
GM
1813 "Look in the .ali file for the definition of the identifier in IDENTLIST.
1814If OTHER-FRAME is non nil, and `ada-xref-other-buffer' is non nil,
1815opens a new window to show the declaration."
797aab3c
GM
1816
1817 (ada-get-all-references identlist)
1818 (let ((ali-line (ada-references-of identlist))
4884c50b
SM
1819 (locations nil)
1820 (start 0)
797aab3c 1821 file line col)
4884c50b
SM
1822
1823 ;; Note: in some cases, an entity can have multiple references to the
1824 ;; bodies (this is for instance the case for a separate subprogram, that
1825 ;; has a reference both to the stub and to the real body).
1826 ;; In that case, we simply go to each one in turn.
1827
1828 ;; Get all the possible locations
1829 (string-match "^\\([0-9]+\\)[a-zA-Z+]\\([0-9]+\\)[ *]" ali-line)
1830 (set 'locations (list (list (match-string 1 ali-line) ;; line
1831 (match-string 2 ali-line) ;; column
1832 (ada-declare-file-of identlist))))
c94ca9e0
JB
1833 (while (string-match "\\([0-9]+\\)[bc]\\(<[^>]+>\\)?\\([0-9]+\\)"
1834 ali-line start)
4884c50b 1835 (setq line (match-string 1 ali-line)
c94ca9e0
JB
1836 col (match-string 3 ali-line)
1837 start (match-end 3))
4884c50b
SM
1838
1839 ;; it there was a file number in the same line
c94ca9e0 1840 (if (string-match (concat "[^{(<]\\([0-9]+\\)|\\([^|bc]+\\)?"
4884c50b
SM
1841 (match-string 0 ali-line))
1842 ali-line)
1843 (let ((file-number (match-string 1 ali-line)))
1844 (goto-char (point-min))
1845 (re-search-forward "^D \\([a-zA-Z0-9_.-]+\\)" nil t
1846 (string-to-number file-number))
1847 (set 'file (match-string 1))
1848 )
1849 ;; Else get the nearest file
1850 (set 'file (ada-declare-file-of identlist)))
a1506d29 1851
4884c50b
SM
1852 (set 'locations (append locations (list (list line col file)))))
1853
1854 ;; Add the specs at the end again, so that from the last body we go to
1855 ;; the specs
1856 (set 'locations (append locations (list (car locations))))
1857
1858 ;; Find the new location we want to go to.
1859 ;; If we are on none of the locations listed, we simply go to the specs.
1860
1861 (setq line (caar locations)
1862 col (nth 1 (car locations))
1863 file (nth 2 (car locations)))
a1506d29 1864
4884c50b
SM
1865 (while locations
1866 (if (and (string= (caar locations) (ada-line-of identlist))
1867 (string= (nth 1 (car locations)) (ada-column-of identlist))
1868 (string= (file-name-nondirectory (nth 2 (car locations)))
1869 (file-name-nondirectory (ada-file-of identlist))))
1870 (setq locations (cadr locations)
1871 line (car locations)
1872 col (nth 1 locations)
1873 file (nth 2 locations)
1874 locations nil)
1875 (set 'locations (cdr locations))))
1876
1877 ;; Find the file in the source path
1878 (set 'file (ada-get-ada-file-name file (ada-file-of identlist)))
1879
1880 ;; Kill the .ali buffer
1881 (kill-buffer (current-buffer))
797aab3c
GM
1882
1883 ;; Now go to the buffer
4884c50b
SM
1884 (ada-xref-change-buffer file
1885 (string-to-number line)
1886 (1- (string-to-number col))
1887 identlist
1888 other-frame)
797aab3c
GM
1889 ))
1890
4884c50b
SM
1891(defun ada-find-in-src-path (identlist &optional other-frame)
1892 "More general function for cross-references.
1893This function should be used when the standard algorithm that parses the
1894.ali file has failed, either because that file was too old or even did not
1895exist.
1896This function attempts to find the possible declarations for the identifier
1897anywhere in the object path.
1898This command requires the external `egrep' program to be available.
1899
1900This works well when one is using an external librarie and wants
1901to find the declaration and documentation of the subprograms one is
1902is using."
a1506d29 1903
4884c50b
SM
1904 (let (list
1905 (dirs (ada-xref-get-obj-dir-field))
1906 (regexp (concat "[ *]" (ada-name-of identlist)))
1907 line column
1908 choice
1909 file)
a1506d29 1910
4884c50b 1911 (save-excursion
a1506d29 1912
4884c50b
SM
1913 ;; Do the grep in all the directories. We do multiple shell
1914 ;; commands instead of one in case there is no .ali file in one
1915 ;; of the directory and the shell stops because of that.
a1506d29 1916
4884c50b
SM
1917 (set-buffer (get-buffer-create "*grep*"))
1918 (while dirs
1919 (insert (shell-command-to-string
1920 (concat "egrep -i -h '^X|" regexp "( |$)' "
1921 (file-name-as-directory (car dirs)) "*.ali")))
1922 (set 'dirs (cdr dirs)))
a1506d29 1923
4884c50b
SM
1924 ;; Now parse the output
1925 (set 'case-fold-search t)
1926 (goto-char (point-min))
1927 (while (re-search-forward regexp nil t)
1928 (save-excursion
1929 (beginning-of-line)
1930 (if (not (= (char-after) ?X))
1931 (progn
1932 (looking-at "\\([0-9]+\\).\\([0-9]+\\)")
1933 (setq line (match-string 1)
1934 column (match-string 2))
1935 (re-search-backward "^X [0-9]+ \\(.*\\)$")
1936 (set 'file (list (match-string 1) line column))
a1506d29 1937
4884c50b
SM
1938 ;; There could be duplicate choices, because of the structure
1939 ;; of the .ali files
1940 (unless (member file list)
1941 (set 'list (append list (list file))))))))
a1506d29 1942
4884c50b
SM
1943 ;; Current buffer is still "*grep*"
1944 (kill-buffer "*grep*")
1945 )
a1506d29 1946
4884c50b
SM
1947 ;; Now display the list of possible matches
1948 (cond
a1506d29 1949
4884c50b
SM
1950 ;; No choice found => Error
1951 ((null list)
1952 (error "No cross-reference found, please recompile your file"))
a1506d29 1953
4884c50b
SM
1954 ;; Only one choice => Do the cross-reference
1955 ((= (length list) 1)
1956 (set 'file (ada-find-src-file-in-dir (caar list)))
1957 (if file
1958 (ada-xref-change-buffer file
1959 (string-to-number (nth 1 (car list)))
1960 (string-to-number (nth 2 (car list)))
1961 identlist
1962 other-frame)
1963 (error (concat (caar list) " not found in src_dir")))
1964 (message "This is only a (good) guess at the cross-reference.")
1965 )
a1506d29 1966
4884c50b
SM
1967 ;; Else, ask the user
1968 (t
1969 (save-window-excursion
1970 (with-output-to-temp-buffer "*choice list*"
a1506d29 1971
4884c50b
SM
1972 (princ "Identifier is overloaded and Xref information is not up to date.\n")
1973 (princ "Possible declarations are:\n\n")
1974 (princ " no. in file at line col\n")
1975 (princ " --- --------------------- ---- ----\n")
1976 (let ((counter 0))
1977 (while (< counter (length list))
1978 (princ (format " %2d) %-21s %4s %4s\n"
1979 (1+ counter)
1980 (nth 0 (nth counter list))
1981 (nth 1 (nth counter list))
1982 (nth 2 (nth counter list))
1983 ))
1984 (setq counter (1+ counter))
1985 )))
1986 (setq choice nil)
1987 (while (or (not choice)
1988 (not (integerp choice))
1989 (< choice 1)
1990 (> choice (length list)))
1991 (setq choice
1992 (string-to-int
1993 (read-from-minibuffer "Enter No. of your choice: "))))
1994 )
1995 (set 'choice (1- choice))
1996 (kill-buffer "*choice list*")
1997
1998 (set 'file (ada-find-src-file-in-dir (car (nth choice list))))
1999 (if file
2000 (ada-xref-change-buffer file
2001 (string-to-number (nth 1 (nth choice list)))
2002 (string-to-number (nth 2 (nth choice list)))
2003 identlist
2004 other-frame)
2005 (error (concat (car (nth choice list)) " not found in src_dir")))
2006 (message "This is only a (good) guess at the cross-reference.")
2007 ))))
2008
797aab3c
GM
2009(defun ada-xref-change-buffer
2010 (file line column identlist &optional other-frame)
4884c50b 2011 "Select and display FILE, at LINE and COLUMN.
797aab3c 2012If we do not end on the same identifier as IDENTLIST, find the closest
eec3232e
GM
2013match. Kills the .ali buffer at the end.
2014If OTHER-FRAME is non-nil, creates a new frame to show the file."
797aab3c 2015
4884c50b 2016 (let (declaration-buffer)
797aab3c
GM
2017
2018 ;; Select and display the destination buffer
2019 (if ada-xref-other-buffer
2020 (if other-frame
2021 (find-file-other-frame file)
2022 (set 'declaration-buffer (find-file-noselect file))
2023 (set-buffer declaration-buffer)
2024 (switch-to-buffer-other-window declaration-buffer)
2025 )
2026 (find-file file)
2027 )
2028
797aab3c
GM
2029 ;; move the cursor to the correct position
2030 (push-mark)
2031 (goto-line line)
2032 (move-to-column column)
2033
2034 ;; If we are not on the identifier, the ali file was not up-to-date.
2035 ;; Try to find the nearest position where the identifier is found,
2036 ;; this is probably the right one.
2037 (unless (looking-at (ada-name-of identlist))
2038 (ada-xref-search-nearest (ada-name-of identlist)))
4884c50b 2039 ))
797aab3c
GM
2040
2041
2042(defun ada-xref-search-nearest (name)
2043 "Searches for NAME nearest to the position recorded in the Xref file.
2044It returns the position of the declaration in the buffer or nil if not found."
2045 (let ((orgpos (point))
2046 (newpos nil)
2047 (diff nil))
2048
2049 (goto-char (point-max))
2050
2051 ;; loop - look for all declarations of name in this file
2052 (while (search-backward name nil t)
2053
2054 ;; check if it really is a complete Ada identifier
2055 (if (and
2056 (not (save-excursion
2057 (goto-char (match-end 0))
2058 (looking-at "_")))
2059 (not (ada-in-string-or-comment-p))
2060 (or
2061 ;; variable declaration ?
2062 (save-excursion
2063 (skip-chars-forward "a-zA-Z_0-9" )
2064 (ada-goto-next-non-ws)
2065 (looking-at ":[^=]"))
2066 ;; procedure, function, task or package declaration ?
2067 (save-excursion
2068 (ada-goto-previous-word)
2069 (looking-at "\\<[pP][rR][oO][cC][eE][dD][uU][rR][eE]\\>\\|\\<[fF][uU][nN][cC][tT][iI][oO][nN]\\>\\|\\<[tT][yY][pP][eE]\\>\\|\\<[tT][aA][sS][kK]\\>\\|\\<[pP][aA][cC][kK][aA][gG][eE]\\>\\|\\<[bB][oO][dD][yY]\\>"))))
2070
2071 ;; check if it is nearer than the ones before if any
2072 (if (or (not diff)
2073 (< (abs (- (point) orgpos)) diff))
2074 (progn
2075 (setq newpos (point)
2076 diff (abs (- newpos orgpos))))))
2077 )
2078
2079 (if newpos
2080 (progn
2081 (message "ATTENTION: this declaration is only a (good) guess ...")
2082 (goto-char newpos))
2083 nil)))
2084
2085
2086;; Find the parent library file of the current file
2087(defun ada-goto-parent ()
eec3232e 2088 "Go to the parent library file."
797aab3c
GM
2089 (interactive)
2090 (ada-require-project-file)
2091
2092 (let ((buffer (ada-get-ali-buffer (buffer-file-name)))
2093 (unit-name nil)
2094 (body-name nil)
2095 (ali-name nil))
2096 (save-excursion
2097 (set-buffer buffer)
2098 (goto-char (point-min))
2099 (re-search-forward "^U \\([^ \t%]+\\)%[bs][ \t]+\\([^ \t]+\\)")
2100 (setq unit-name (match-string 1))
2101 (if (not (string-match "\\(.*\\)\\.[^.]+" unit-name))
2102 (progn
2103 (kill-buffer buffer)
2104 (error "No parent unit !"))
2105 (setq unit-name (match-string 1 unit-name))
2106 )
2107
2108 ;; look for the file name for the parent unit specification
2109 (goto-char (point-min))
2110 (re-search-forward (concat "^W " unit-name
2111 "%s[ \t]+\\([^ \t]+\\)[ \t]+"
2112 "\\([^ \t\n]+\\)"))
2113 (setq body-name (match-string 1))
2114 (setq ali-name (match-string 2))
2115 (kill-buffer buffer)
2116 )
2117
2118 (setq ali-name (ada-find-ali-file-in-dir ali-name))
2119
2120 (save-excursion
2121 ;; Tries to open the new ali file to find the spec file
2122 (if ali-name
2123 (progn
2124 (find-file ali-name)
2125 (goto-char (point-min))
2126 (re-search-forward (concat "^U " unit-name "%s[ \t]+"
2127 "\\([^ \t]+\\)"))
2128 (setq body-name (match-string 1))
2129 (kill-buffer (current-buffer))
2130 )
2131 )
2132 )
2133
2134 (find-file body-name)
2135 ))
2136
2137(defun ada-make-filename-from-adaname (adaname)
eec3232e
GM
2138 "Determine the filename in which ADANAME is found.
2139This is a GNAT specific function that uses gnatkrunch."
797aab3c
GM
2140 (let (krunch-buf)
2141 (setq krunch-buf (generate-new-buffer "*gkrunch*"))
2142 (save-excursion
2143 (set-buffer krunch-buf)
2144 ;; send adaname to external process `gnatkr'.
2145 (call-process "gnatkr" nil krunch-buf nil
2146 adaname ada-krunch-args)
2147 ;; fetch output of that process
2148 (setq adaname (buffer-substring
2149 (point-min)
2150 (progn
2151 (goto-char (point-min))
2152 (end-of-line)
2153 (point))))
2154 (kill-buffer krunch-buf)))
2155 adaname
2156 )
2157
797aab3c
GM
2158(defun ada-make-body-gnatstub ()
2159 "Create an Ada package body in the current buffer.
2160This function uses the `gnatstub' program to create the body.
2161This function typically is to be hooked into `ff-file-created-hooks'."
2162 (interactive)
2163
2164 (save-some-buffers nil nil)
2165
4884c50b
SM
2166 ;; If the current buffer is the body (as is the case when calling this
2167 ;; function from ff-file-created-hooks), then kill this temporary buffer
2168 (unless (interactive-p)
2169 (progn
2170 (set-buffer-modified-p nil)
2171 (kill-buffer (current-buffer))))
a1506d29 2172
797aab3c 2173
4884c50b
SM
2174 ;; Make sure the current buffer is the spec (this might not be the case
2175 ;; if for instance the user was asked for a project file)
2176
2177 (unless (buffer-file-name (car (buffer-list)))
2178 (set-buffer (cadr (buffer-list))))
2179
2180 ;; Make sure we have a project file (for parameters to gnatstub). Note that
2181 ;; this might have already been done if we have been called from the hook,
2182 ;; but this is not an expensive call)
2183 (ada-require-project-file)
797aab3c
GM
2184
2185 ;; Call the external process gnatstub
2186 (let* ((gnatstub-opts (ada-treat-cmd-string ada-gnatstub-opts))
4884c50b 2187 (filename (buffer-file-name (car (buffer-list))))
797aab3c
GM
2188 (output (concat (file-name-sans-extension filename) ".adb"))
2189 (gnatstub-cmd (concat "gnatstub " gnatstub-opts " " filename))
2190 (buffer (get-buffer-create "*gnatstub*")))
2191
2192 (save-excursion
2193 (set-buffer buffer)
2194 (compilation-minor-mode 1)
2195 (erase-buffer)
2196 (insert gnatstub-cmd)
2197 (newline)
2198 )
2199 ;; call gnatstub to create the body file
2200 (call-process shell-file-name nil buffer nil "-c" gnatstub-cmd)
2201
2202 (if (save-excursion
2203 (set-buffer buffer)
2204 (goto-char (point-min))
2205 (search-forward "command not found" nil t))
2206 (progn
2207 (message "gnatstub was not found -- using the basic algorithm")
2208 (sleep-for 2)
2209 (kill-buffer buffer)
2210 (ada-make-body))
2211
2212 ;; Else clean up the output
2213
797aab3c
GM
2214 (if (file-exists-p output)
2215 (progn
2216 (find-file output)
2217 (kill-buffer buffer))
2218
2219 ;; display the error buffer
2220 (display-buffer buffer)
2221 )
2222 )))
2223
797aab3c 2224(defun ada-xref-initialize ()
fea24571
SM
2225 "Function called by `ada-mode-hook' to initialize the ada-xref.el package.
2226For instance, it creates the gnat-specific menus, sets some hooks for
797aab3c 2227find-file...."
fea24571 2228 ;; This should really be an `add-hook'. -stef
7abe197c 2229 (setq ff-file-created-hook 'ada-make-body-gnatstub)
797aab3c 2230
797aab3c
GM
2231 ;; Completion for file names in the mini buffer should ignore .ali files
2232 (add-to-list 'completion-ignored-extensions ".ali")
c94ca9e0
JB
2233
2234 (ada-xref-update-project-menu)
797aab3c
GM
2235 )
2236
2237
2238;; ----- Add to ada-mode-hook ---------------------------------------------
2239
4884c50b
SM
2240;; Use gvd or ddd as the default debugger if it was found
2241;; On windows, do not use the --tty switch for GVD, since this is
2242;; not supported. Actually, we do not use this on Unix either, since otherwise
2243;; there is no console window left in GVD, and people have to use the
2244;; Emacs one.
2245;; This must be done before initializing the Ada menu.
2246(if (ada-find-file-in-dir "gvd" exec-path)
2247 (set 'ada-prj-default-debugger "gvd ")
2248 (if (ada-find-file-in-dir "gvd.exe" exec-path)
2249 (set 'ada-prj-default-debugger "gvd ")
2250 (if (ada-find-file-in-dir "ddd" exec-path)
2251 (set 'ada-prj-default-debugger "ddd --tty -fullname -toolbar"))))
2252
797aab3c
GM
2253(add-hook 'ada-mode-hook 'ada-xref-initialize)
2254
15ea3b67 2255;; Initializes the cross references to the runtime library
4884c50b 2256(ada-initialize-runtime-library "")
15ea3b67
GM
2257
2258;; Add these standard directories to the search path
7abe197c 2259(set 'ada-search-directories-internal
15ea3b67
GM
2260 (append (mapcar 'directory-file-name ada-xref-runtime-library-specs-path)
2261 ada-search-directories))
2262
797aab3c
GM
2263(provide 'ada-xref)
2264
6b61353c 2265;;; arch-tag: 415a39fe-577b-4676-b3b1-6ff6db7ca24e
383d5bbb 2266;;; ada-xref.el ends here