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