emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals-release/gnat-compiler abad4b333c: Add files to gnat-com


From: Stephen Leake
Subject: [elpa] externals-release/gnat-compiler abad4b333c: Add files to gnat-compiler
Date: Tue, 1 Nov 2022 15:37:06 -0400 (EDT)

branch: externals-release/gnat-compiler
commit abad4b333cf3499baa3285e290f538be4fe0e8de
Author: Stephen Leake <stephen_leake@stephe-leake.org>
Commit: Stephen Leake <stephen_leake@stephe-leake.org>

    Add files to gnat-compiler
    
    * gnat-alire.el: New file.
    
    * gnat-compiler.el: New file.
    
    * gnat-xref.el: New file.
---
 gnat-alire.el    |   91 ++++
 gnat-compiler.el | 1463 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gnat-xref.el     |  328 ++++++++++++
 3 files changed, 1882 insertions(+)

diff --git a/gnat-alire.el b/gnat-alire.el
new file mode 100644
index 0000000000..af37a5f52a
--- /dev/null
+++ b/gnat-alire.el
@@ -0,0 +1,91 @@
+;;; gnat-alire.el --- Support for building with Alire -*- lexical-binding:t -*-
+;;
+;;; Copyright (C) 2012 - 2022  Free Software Foundation, Inc.
+;;
+;; Author: Stephen Leake <stephen_leake@member.fsf.org>
+;; Maintainer: Stephen Leake <stephen_leake@member.fsf.org>
+;; Version: 1.0
+;; package-requires: ((emacs "25.3") (wisi "4.0"))
+;;
+;; This file is part of GNU Emacs.
+;;
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;; See https://alire.ada.dev/
+
+(require 'gnat-compiler)
+
+(defun alire-get-env (project)
+  "Set PROJECT slots from Alire as needed."
+
+  ;; alire inherits GPR_PROJECT_PATH (see
+  ;; https://github.com/alire-project/alire/issues/1147). So empty it
+  ;; here.
+  ;;
+  ;; We need all of the alire settings for "gnat list" and "gpr_query"
+  ;; to properly process complex projects (like Alire).
+  (let ((process-environment (copy-sequence process-environment)))
+    (setenv "GPR_PROJECT_PATH" "")
+
+    (with-temp-buffer
+      (let ((status (call-process "alr" nil (current-buffer) nil "printenv")))
+       (cond
+        ((= 0 status)
+         (goto-char (point-min))
+         (while (not (eobp))
+           (looking-at "export \\(.*\\)$")
+           (setf (wisi-prj-file-env project)
+                 (append (wisi-prj-file-env project) (list 
(match-string-no-properties 1))))
+           (forward-line 1)
+           ))
+
+        (t
+         (user-error "alr printenv failed; bad or missing alire.toml?"))
+        ))
+      )))
+
+;;;###autoload
+(cl-defun create-alire-project (&key name gpr-file compile-env xref-label)
+  ;; We could use "alr exec -P -- echo" to get the project file (also
+  ;; see https://github.com/alire-project/alire/issues/1151), but that
+  ;; doesn't work when there are multiple project files listed in
+  ;; alire.toml. And if there are multiple project files, the user
+  ;; needs to pick one anyway.  So we require it as an argument; must
+  ;; be absolute or relative to Alire root directory.
+  ;;
+  ;; prj-file should _not_ specify the gpr-file or gpr-project-path;
+  ;; it is only used for casing. We get GPR_PROJECT_PATH from the
+  ;; Alire environment.
+  "Return an initial wisi project for the current Alire workspace."
+  (let* ((default-directory (locate-dominating-file default-directory 
"alire.toml"))
+        (abs-gpr-file (expand-file-name gpr-file))
+        (project (make-wisi-prj :name name :compile-env compile-env))
+        )
+
+    (alire-get-env project)
+
+    ;; We need a gnat-compiler to set compilation-search-path.
+    (setf (wisi-prj-compiler project)
+         (create-gnat-compiler
+          :gpr-file abs-gpr-file
+          :run-buffer-name (gnat-run-buffer-name abs-gpr-file)))
+
+    (setf (wisi-prj-xref project)
+         (funcall (intern (format "create-%s-xref" (symbol-name xref-label)))
+                  :gpr-file abs-gpr-file))
+
+    project))
+
+(provide 'gnat-alire)
+;;; gnat-alire.el ends here
diff --git a/gnat-compiler.el b/gnat-compiler.el
new file mode 100644
index 0000000000..a086a369be
--- /dev/null
+++ b/gnat-compiler.el
@@ -0,0 +1,1463 @@
+;; gnat-compiler.el --- Support for running GNAT tools  -*- lexical-binding:t 
-*-
+;;
+;; GNAT is provided by AdaCore; see https://www.adacore.com/community
+;;
+;;; Copyright (C) 2012 - 2022  Free Software Foundation, Inc.
+;;
+;; Author: Stephen Leake <stephen_leake@member.fsf.org>
+;; Maintainer: Stephen Leake <stephen_leake@member.fsf.org>
+;; Version: 1.0.0
+;; package-requires: ((emacs "25.3") (wisi "4.1"))
+;;
+;; This file is part of GNU Emacs.
+;;
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+(require 'cl-lib)
+(require 'wisi-prj)
+
+;;;;; code
+
+(defgroup gnat-compiler nil
+  "Interface to AdaCore gnat compiler via a wisi project."
+  :group 'programming)
+
+(defcustom gnat-debug-run nil
+  "If t or integer > 0, buffers containing a GNAT command will show
+the command.  Otherwise, they will show only the output of the
+command.  Higher integers show more information (environment vars etc)."
+  :type 'integer
+  :safe  #'integerp
+  :group 'gnat-compiler)
+
+(defun gnat-debug-enabled (level)
+  "Return t if gnat-debug-run is t or > LEVEL."
+  (cond
+   ((integerp gnat-debug-run)
+    (> gnat-debug-run level))
+
+   (t gnat-debug-run)))
+
+;;;;; project file handling
+
+(cl-defstruct gnat-compiler
+  "Used with wisi-compiler-* generic functions."
+
+  gpr-file       ;; absolute file name of GNAT project file.
+  run-buffer-name ;; string; some compiler objects have no gpr file
+  project-path    ;; list of directories from GPR_PROJECT_PATH
+  target         ;; gnat --target argument.
+  runtime        ;; gnat --RTS argument.
+  gnat-stub-opts  ;; options for gnat stub
+  gnat-stub-cargs ;; cargs options for gnat stub
+  )
+
+;;;###autoload
+(cl-defun create-gnat-compiler
+    (&key
+     gpr-file
+     run-buffer-name
+     project-path
+     target
+     runtime
+     gnat-stub-opts
+     gnat-stub-cargs)
+  ;; We declare and autoload this because we can't autoload
+  ;; make-gnat-compiler in emacs < 27. We also can't use '(defalias
+  ;; 'create-gnat-compiler 'make-gnat-compiler); then
+  ;; make-gnat-compiler is not defined by autoload.
+  (make-gnat-compiler
+   :gpr-file gpr-file
+   :run-buffer-name run-buffer-name
+   :project-path project-path
+   :target target
+   :runtime runtime
+   :gnat-stub-opts gnat-stub-opts
+   :gnat-stub-cargs gnat-stub-cargs
+   ))
+
+(defun gnat-run-buffer-name (prj-file-name &optional prefix)
+  ;; We don't use (gnat-compiler-gpr-file compiler), because multiple
+  ;; wisi-prj files can use one gpr-file.
+  (concat (or prefix " *gnat-run-")
+         prj-file-name
+         "*"))
+
+(defun gnat-compiler-require-prj ()
+  "Return current `gnat-compiler' object from current project compiler.
+Throw an error if current project does not have a gnat-compiler."
+  (let* ((wisi-prj (wisi-prj-require-prj))
+        (compiler (wisi-prj-compiler wisi-prj)))
+    (if (gnat-compiler-p compiler)
+       compiler
+      (error "no gnat-compiler in current project"))))
+
+(defun gnat-prj-add-prj-dir (project compiler dir)
+  "Add DIR to COMPILER.project_path, and to GPR_PROJECT_PATH in 
PROJECT.file-env"
+  ;; We maintain two project values for this;
+  ;; project-path - a list of directories, for elisp find file
+  ;; GPR_PROJECT_PATH in environment, for gnat-run
+  (when (file-directory-p dir)
+    (let ((process-environment (copy-sequence (wisi-prj-file-env project))))
+      (cl-pushnew dir (gnat-compiler-project-path compiler) :test 
#'string-equal)
+
+      (setenv "GPR_PROJECT_PATH"
+             (mapconcat 'identity
+                        (gnat-compiler-project-path compiler) path-separator))
+      (setf (wisi-prj-file-env project) (copy-sequence process-environment))
+      )))
+
+(cl-defun gnat-get-paths (project &key ignore-prj-paths)
+  "Set source and project paths in PROJECT from \"gnat list\"."
+  (let* ((compiler (wisi-prj-compiler project))
+        (src-dirs (unless ignore-prj-paths (wisi-prj-source-path project)))
+        (prj-dirs nil))
+
+    ;; Don't need project plist obj_dirs if using a project file, so
+    ;; not setting obj-dirs.
+
+    (condition-case-unless-debug nil
+       (with-current-buffer (gnat-run-buffer compiler 
(gnat-compiler-run-buffer-name compiler))
+         ;; gnat list -v -P can return status 0 or 4; always lists compiler 
dirs
+
+         (gnat-run-gnat project "list" (list "-v") '(0 4))
+
+         (goto-char (point-min))
+
+         ;; Source path
+         (search-forward "Source Search Path:")
+         (forward-line 1)
+         (while (not (looking-at "^$")) ;; terminate on blank line
+           (back-to-indentation) ;; skip whitespace forward
+
+           ;; we use 'cl-pushnew here, and nreverse later, to
+           ;; preserve the directory order. Directory order matters
+           ;; for extension projects, which can have duplicate file
+           ;; names, and for project paths, which can contain two
+           ;; compiler libraries (ie Alire and system).
+            (cl-pushnew
+            (if (looking-at "<Current_Directory>")
+                (directory-file-name default-directory)
+              (expand-file-name ; Canonicalize path part.
+               (directory-file-name
+                (buffer-substring-no-properties (point) (line-end-position)))))
+            src-dirs
+            :test
+            #'string-equal)
+           (forward-line 1))
+
+          ;; Project path
+         ;;
+         ;; These are also added to src-dirs, so compilation errors
+         ;; reported in project files are found.
+         (search-forward "Project Search Path:")
+         (forward-line 1)
+         (while (not (looking-at "^$"))
+           (back-to-indentation)
+           (let ((f
+                  (if (looking-at "<Current_Directory>")
+                       (directory-file-name default-directory)
+                    (expand-file-name
+                      (buffer-substring-no-properties (point) 
(line-end-position))))))
+             (cl-pushnew f src-dirs :test 'string-equal)
+             (cl-pushnew f prj-dirs :test 'string-equal))
+           (forward-line 1))
+
+         )
+      (error
+       ;; search-forward failed. Possible causes:
+       ;;
+       ;; missing dirs in GPR_PROJECT_PATH => user error
+       ;; missing Object_Dir => gprbuild not run yet; it will be run soon
+       ;; some files are missing string quotes => user error
+       ;;
+       ;; We used to call gpr_query to get src-dirs, prj-dirs here; it
+       ;; is tolerant of the above errors. But ignoring the errors, to
+       ;; let gprbuild run with GPR_PROJECT_PATH set, is simpler.
+       (pop-to-buffer (gnat-run-buffer compiler (gnat-compiler-run-buffer-name 
compiler)))
+       (message "project search path: %s" prj-dirs)
+       (message "parse gpr failed")
+       ))
+
+    (setf (wisi-prj-source-path project) (nreverse src-dirs))
+    (setf (gnat-compiler-project-path compiler) nil)
+    (mapc (lambda (dir) (gnat-prj-add-prj-dir project compiler dir))
+         (nreverse prj-dirs))
+    ))
+
+(defun gnat-parse-gpr (gpr-file project)
+  "Parse GPR-FILE, append to PROJECT (a `wisi-prj' object).
+GPR-FILE must be absolute file name.
+source-path will include compiler runtime."
+  (let ((compiler (wisi-prj-compiler project)))
+    (if (gnat-compiler-gpr-file compiler)
+       ;; gpr-file previously set; new one must match
+       (when (not (string-equal gpr-file (gnat-compiler-gpr-file compiler)))
+         (error "project file %s defines a different GNAT project file than %s"
+                (gnat-compiler-gpr-file compiler)
+                gpr-file))
+
+      (setf (gnat-compiler-gpr-file compiler) gpr-file)))
+
+  (gnat-get-paths project :ignore-prj-paths t))
+
+(defun gnat-parse-gpr-1 (gpr-file project)
+  "For `wisi-prj-parser-alist'."
+  (let ((compiler (wisi-prj-compiler project)))
+    (setf (gnat-compiler-run-buffer-name compiler) (gnat-run-buffer-name 
gpr-file))
+    (gnat-parse-gpr gpr-file project)))
+
+;;;; command line tool interface
+
+(defun gnat-run-buffer (compiler name)
+  "Return a buffer suitable for running gnat command line tools for COMPILER."
+  (let ((buffer (get-buffer name)))
+
+    (unless (buffer-live-p buffer)
+      (setq buffer (get-buffer-create name))
+      (when (gnat-compiler-gpr-file compiler)
+       ;; Otherwise assume `default-directory' is already correct (or
+       ;; doesn't matter).
+       (with-current-buffer buffer
+         (setq default-directory
+               (file-name-directory
+                (gnat-compiler-gpr-file compiler))))
+       ))
+    buffer))
+
+(defun gnat-run (project exec command &optional err-msg expected-status)
+  "Run a gnat command line tool, as \"EXEC COMMAND\".
+PROJECT  is a `wisi-prj' object.
+EXEC must be an executable found on `exec-path'.
+COMMAND must be a list of strings.
+ERR-MSG must be nil or a string.
+EXPECTED-STATUS must be nil or a list of integers; throws an error if
+process status is not a member.
+
+Return process status.
+Assumes current buffer is (gnat-run-buffer)"
+  (set 'buffer-read-only nil)
+  (erase-buffer)
+
+  (setq command (cl-delete-if 'null command))
+
+  ;; We can't just append file-env and compile-env to
+  ;; process-environment, because they might have values that
+  ;; override what's already in process-environment(for example alire sets 
PATH and
+  ;; GPR_PROJECT_PATH). So we use (setenv ...).
+  (let ((process-environment (copy-sequence process-environment))
+       (process-list
+        (lambda (list)
+          (dolist (var list)
+            (unless (string-match "\\(.*\\)=\\(.*\\)$" var)
+              (error "malformed environment entry: %s" var))
+            (setenv (match-string-no-properties 1 var) 
(match-string-no-properties 2 var)))))
+       status)
+
+    (funcall process-list (wisi-prj-compile-env project))
+    (funcall process-list (wisi-prj-file-env project))
+
+    (when (gnat-debug-enabled 0)
+      (insert (format "GPR_PROJECT_PATH=%s\n%s " (getenv "GPR_PROJECT_PATH") 
exec))
+      (mapc (lambda (str) (insert (concat str " "))) command)
+      (newline))
+
+    (when (gnat-debug-enabled 1)
+      (dolist (item process-environment)
+       (insert item)(insert "\n")))
+
+    (let ((exec-path (split-string (getenv "PATH") path-separator)))
+      (setq status (apply 'call-process exec nil t nil command)))
+    (cond
+     ((memq status (or expected-status '(0))); success
+      nil)
+
+     (t ; failure
+      (pop-to-buffer (current-buffer))
+      (if err-msg
+         (error "%s %s failed; %s" exec (car command) err-msg)
+       (error "%s %s failed" exec (car command))
+       ))
+     )))
+
+(defun gnat-run-gnat (project command &optional switches-args expected-status)
+  "Run the \"gnat\" command line tool, as \"gnat COMMAND -P<prj> 
SWITCHES-ARGS\".
+COMMAND must be a string, SWITCHES-ARGS a list of strings.
+EXPECTED-STATUS must be nil or a list of integers.
+Return process status.
+Assumes current buffer is (gnat-run-buffer)"
+  (let* ((compiler (wisi-prj-compiler project))
+        (gpr-file (gnat-compiler-gpr-file compiler))
+        (project-file-switch
+         (when gpr-file
+           (concat "-P" (file-name-nondirectory gpr-file))))
+         (target-gnat (concat (gnat-compiler-target compiler) "gnat"))
+         ;; gnat list understands --RTS without a fully qualified
+         ;; path, gnat find (in particular) doesn't (but it doesn't
+         ;; need to, it uses the ALI files found via the GPR)
+         (runtime
+          (when (and (gnat-compiler-runtime compiler) (string= command "list"))
+            (list (concat "--RTS=" (gnat-compiler-runtime compiler)))))
+        (cmd (append (list command) (list project-file-switch) runtime 
switches-args)))
+
+    (gnat-run project target-gnat cmd nil expected-status)
+    ))
+
+(defun gnat-run-no-prj (command &optional dir)
+  "Run \"gnat COMMAND\", with DIR as current directory.
+Return process status.  Process output goes to current buffer,
+which is displayed on error."
+  (set 'buffer-read-only nil)
+  (erase-buffer)
+
+  (when gnat-debug-run
+    (setq command (cl-delete-if 'null command))
+    (mapc (lambda (str) (insert (concat str " "))) command)
+    (newline))
+
+  (let ((default-directory (or dir default-directory))
+       status)
+
+    (setq status (apply 'call-process "gnat" nil t nil command))
+    (cond
+     ((= status 0); success
+      nil)
+
+     (t ; failure
+      (pop-to-buffer (current-buffer))
+      (error "gnat %s failed" (car command)))
+     )))
+
+;;;; gnatprep utils
+
+(defun gnatprep-indent ()
+  "If point is on a gnatprep keyword, return indentation column
+for it. Otherwise return nil.  Intended to be added to
+`wisi-indent-calculate-functions' or other indentation function
+list."
+  ;; gnatprep keywords are:
+  ;;
+  ;; #if identifier [then]
+  ;; #elsif identifier [then]
+  ;; #else
+  ;; #end if;
+  ;;
+  ;; they are all indented at column 0.
+  (when (equal (char-after) ?\#) 0))
+
+(defun gnatprep-syntax-propertize (start end)
+  (goto-char start)
+  (save-match-data
+    (while (re-search-forward
+           "^[ \t]*\\(#\\(?:if\\|else\\|elsif\\|end\\)\\)"; gnatprep keywords.
+           end t)
+      (cond
+       ((match-beginning 1)
+       (put-text-property
+        (match-beginning 1) (match-end 1) 'syntax-table '(11 . ?\n)))
+       )
+      )))
+
+(defconst gnatprep-preprocessor-keywords
+   (list (list "^[ \t]*\\(#.*\n\\)"  '(1 font-lock-preprocessor-face t))))
+
+;; We assume that if this file is loaded, any ada buffer may have
+;; gnatprep syntax; even with different compilers; all must run
+;; gnatprep first. If support for another preprocessor is added, we'll
+;; need wisi-prj-preprocessor, along with -compiler and -xref.
+(defun gnatprep-setup ()
+  (add-to-list 'wisi-indent-calculate-functions 'gnatprep-indent)
+  (add-hook 'ada-syntax-propertize-hook #'gnatprep-syntax-propertize)
+  (font-lock-add-keywords 'ada-mode gnatprep-preprocessor-keywords)
+  ;; caller must call font-lock-refresh-defaults after this
+  )
+
+;;;; compiler message handling
+
+(defconst gnat-predefined-package-alist
+  '(
+    ("a-calend" . "Ada.Calendar")
+    ("a-chahan" . "Ada.Characters.Handling")
+    ("a-comlin" . "Ada.Command_Line")
+    ("a-contai" . "Ada.Containers")
+    ("a-direct" . "Ada.Directories")
+    ("a-except" . "Ada.Exceptions")
+    ("a-ioexce" . "Ada.IO_Exceptions")
+    ("a-finali" . "Ada.Finalization")
+    ("a-numeri" . "Ada.Numerics")
+    ("a-nuflra" . "Ada.Numerics.Float_Random")
+    ("a-stream" . "Ada.Streams")
+    ("a-ststio" . "Ada.Streams.Stream_IO")
+    ("a-string" . "Ada.Strings")
+    ("a-strfix" . "Ada.Strings.Fixed")
+    ("a-strmap" . "Ada.Strings.Maps")
+    ("a-strunb" . "Ada.Strings.Unbounded")
+    ("a-stwiun" . "Ada.Strings.Wide_Unbounded")
+    ("a-textio" . "Ada.Text_IO")
+    ("g-comlin" . "GNAT.Command_Line")
+    ("g-dirope" . "GNAT.Directory_Operations")
+    ("g-socket" . "GNAT.Sockets")
+    ("i-c"      . "Interfaces.C")
+    ("i-cstrin" . "Interfaces.C.Strings")
+    ("interfac" . "Interfaces")
+    ("s-stoele" . "System.Storage_Elements")
+    )
+  "Alist (filename . package name) of GNAT file names for predefined Ada 
packages.")
+
+(defun gnat-compilation-filter ()
+  "Filter to add text properties to secondary file references.
+For `compilation-filter-hook'."
+  (save-excursion
+    (goto-char compilation-filter-start)
+
+    ;; primary references are handled by font-lock functions; see
+    ;; `compilation-mode-font-lock-keywords'.
+    ;;
+    ;; compilation-filter might insert partial lines, or it might insert 
multiple lines
+    (goto-char (line-beginning-position))
+    (while (not (eobp))
+      ;; We don't want 'next-error' to always go to secondary
+      ;; references, so we _don't_ set 'compilation-message text
+      ;; property. Instead, we set 'gnat-secondary-error, so
+      ;; `gnat-show-secondary-error' will handle it. We also set
+      ;; fonts, so the user can see the reference.
+
+      ;; typical secondary references look like:
+      ;;
+      ;; trivial_productions_test.adb:57:77:   ==> in call to "Get" at \
+      ;;    opentoken-token-enumerated-analyzer.ads:88, instance at line 41
+      ;;
+      ;; c:/foo/bar/lookahead_test.adb:379:14: found type access to 
"Standard.String" defined at line 379
+      ;;
+      ;; lookahead_test.ads:23:09: "Name" has been inherited from subprogram 
at aunit-simple_test_cases.ads:47
+      ;;
+      ;; lalr.adb:668:37: non-visible declaration at analyzer.ads:60, instance 
at parser.ads:38
+      ;;
+      ;; save the file from the primary reference, look for "*.ad?:nn", "at 
line nnn"
+
+      (let (file)
+       (when (looking-at "^\\(\\(.:\\)?[^ :\n]+\\):")
+         (setq file (match-string-no-properties 1)))
+
+       (skip-syntax-forward "^-"); space following primary reference
+
+       (while (search-forward-regexp 
"\\s-\\(\\([^[:blank:]]+\\.[[:alpha:]]+\\):\\([0-9]+\\):?\\([0-9]+\\)?\\)"
+                                     (line-end-position) t)
+
+         (goto-char (match-end 0))
+         (with-silent-modifications
+           (compilation--put-prop 2 'font-lock-face compilation-info-face); 
file
+           (compilation--put-prop 3 'font-lock-face compilation-line-face); 
line
+           (compilation--put-prop 4 'font-lock-face compilation-line-face); col
+           (put-text-property
+            (match-beginning 0) (match-end 0)
+            'gnat-secondary-error
+            (list
+             (match-string-no-properties 2); file
+             (string-to-number (match-string-no-properties 3)); line
+             (if (match-string 4)
+                 (1- (string-to-number (match-string-no-properties 4)))
+               0); column
+             ))
+           ))
+
+       (when (search-forward-regexp "\\(at line \\)\\([0-9]+\\)" 
(line-end-position) t)
+         (with-silent-modifications
+           (compilation--put-prop 1 'font-lock-face compilation-info-face); 
"at line" instead of file
+           (compilation--put-prop 2 'font-lock-face compilation-line-face); 
line
+           (put-text-property
+            (match-beginning 1) (match-end 1)
+            'gnat-secondary-error
+            (list
+             file
+             (string-to-number (match-string-no-properties 2)); line
+             1)); column
+           ))
+       (forward-line 1))
+      )
+    ))
+
+(defun gnat-show-secondary-error ()
+  "Show the next secondary file reference in the compilation buffer.
+A secondary file reference is defined by text having text
+property `gnat-secondary-error', set by
+`gnat-compilation-filter'."
+  (interactive)
+
+  ;; preserving the current window works only if the frame
+  ;; doesn't change, at least on Windows.
+  (let ((start-buffer (current-buffer))
+       pos item file)
+    (when (eq major-mode 'compilation-mode)
+      (setq next-error-last-buffer (current-buffer)))
+    ;; We use `pop-to-buffer', not `set-buffer', so point is correct
+    ;; for the current window showing compilation-last-buffer, and
+    ;; moving point in that window works. But that might eat an
+    ;; `other-frame-window-mode' prefix, which the user means to apply
+    ;; to ’ada-goto-source’ below; disable that temporarily.
+    (let ((display-buffer-overriding-action nil))
+      (pop-to-buffer next-error-last-buffer nil t)
+      (setq pos (next-single-property-change (point) 'gnat-secondary-error))
+      (unless pos
+       ;; probably at end of compilation-buffer, in new compile
+       (goto-char (point-min))
+       (setq pos (next-single-property-change (point) 'gnat-secondary-error)))
+
+      (when pos
+       (setq item (get-text-property pos 'gnat-secondary-error))
+       ;; file-relative-name handles absolute Windows paths from
+       ;; g++. Do this in compilation buffer to get correct
+       ;; default-directory.
+       (setq file (file-relative-name (nth 0 item)))
+
+       ;; Set point in compilation buffer past this secondary error, so
+       ;; user can easily go to the next one.
+       (goto-char (next-single-property-change (1+ pos) 
'gnat-secondary-error)))
+
+      (pop-to-buffer start-buffer nil t);; for windowing history
+      )
+    (when item
+      (wisi-goto-source
+       file
+       (nth 1 item); line
+       (nth 2 item); column
+       ))
+    ))
+
+(defun gnat-debug-filter ()
+  ;; call gnat-compilation-filter with `compilation-filter-start' bound
+  (interactive)
+  (beginning-of-line)
+  (let ((compilation-filter-start (point)))
+    (gnat-compilation-filter)))
+
+;;;;; auto fix compilation errors
+
+(defconst gnat-name-regexp "\\(\\(?:\\sw\\|[_.]\\)+\\)")
+
+(defconst gnat-file-name-regexp
+  "\\([a-z-_.]+\\)"
+  "regexp to extract a file name")
+
+(defconst gnat-quoted-name-regexp
+  "\"\\([[:alnum:]_.']+\\)\""
+  "regexp to extract the quoted names in error messages")
+
+(defconst gnat-quoted-punctuation-regexp
+  "\"\\([,:;=()|]+\\)\""
+  "regexp to extract quoted punctuation in error messages")
+
+(defun gnat-misspelling ()
+  "Return correct spelling from current compiler error.
+Prompt user if more than one."
+  ;; wisi-output.adb:115:41: no selector "Productions" for type "RHS_Type" 
defined at wisi.ads:77
+  ;; wisi-output.adb:115:41: invalid expression in loop iterator
+  ;; wisi-output.adb:115:42: possible misspelling of "Production"
+  ;; wisi-output.adb:115:42: possible misspelling of "Production"
+  ;;
+  ;; GNAT Community 2021 adds "error: " to the above (a misspelling is never a 
warning):
+  ;; wisi-output.adb:115:41: error: invalid expression in loop iterator
+  ;; wisi-output.adb:115:42: error: possible misspelling of "Production"
+  ;; wisi-output.adb:115:42: error: possible misspelling of "Production"
+  ;;
+  ;; column number can vary, so only check the line number
+  (save-excursion
+    (let* ((start-msg (get-text-property (line-beginning-position) 
'compilation-message))
+          (start-line (nth 1 (compilation--message->loc start-msg)))
+          done choices)
+      (while (not done)
+       (forward-line 1)
+       (let ((msg (get-text-property (line-beginning-position) 
'compilation-message)))
+         (setq done (or (not msg)
+                        (not (equal start-line (nth 1 
(compilation--message->loc msg)))))))
+       (when (and (not done)
+                  (progn
+                    (skip-syntax-forward "^-")
+                    (forward-char 1)
+                    (when (looking-at "error: ")
+                      (goto-char (match-end 0)))
+                    (looking-at (concat "possible misspelling of " 
gnat-quoted-name-regexp))))
+         (push (match-string 1) choices)))
+
+      ;; return correct spelling
+      (cond
+       ((= 0 (length choices))
+       nil)
+
+       ((= 1 (length choices))
+       (car choices))
+
+       (t ;; multiple choices
+       (completing-read "correct spelling: " choices))
+       ))))
+
+(defun gnat-qualified ()
+  "Return qualified name from current compiler error, if there is one offered."
+  (save-excursion
+    (forward-line 1)
+    (skip-syntax-forward "^ ")
+    (when (looking-at " use fully qualified name starting with 
\\([[:alnum:]_]+\\) to make")
+      (match-string 1))
+    ))
+
+(defun gnat-file-name-from-ada-name (compiler ada-name)
+  (let ((result nil))
+
+    (while (string-match "\\." ada-name)
+      (setq ada-name (replace-match "-" t t ada-name)))
+
+    (setq ada-name (downcase ada-name))
+
+    (with-current-buffer (gnat-run-buffer compiler 
(gnat-compiler-run-buffer-name compiler))
+      (gnat-run-no-prj
+       (list
+       "krunch"
+       ada-name
+       ;; "0" means only krunch GNAT library names
+       "0"))
+
+      (goto-char (point-min))
+      (when gnat-debug-run (forward-line 1)); skip  cmd
+      (setq result (buffer-substring-no-properties (line-beginning-position) 
(line-end-position)))
+      )
+    result))
+
+(defun gnat-ada-name-from-file-name (file-name)
+  (let* ((ada-name (file-name-sans-extension (file-name-nondirectory 
file-name)))
+        (predefined (cdr (assoc ada-name gnat-predefined-package-alist))))
+
+    (if predefined
+        predefined
+      (while (string-match "-" ada-name)
+       (setq ada-name (replace-match "." t t ada-name)))
+      ada-name)))
+
+(defun gnat-make-package-body (project body-file-name)
+  ;; gnatstub always creates the body in the current directory (in the
+  ;; process where gnatstub is running); the -o parameter may not
+  ;; contain path info. So we bind default-directory here.
+  (let* ((compiler (wisi-prj-compiler project))
+        (start-file (buffer-file-name))
+       (opts (when (gnat-compiler-gnat-stub-opts compiler)
+               (split-string (gnat-compiler-gnat-stub-opts compiler))))
+       (cargs (when (gnat-compiler-gnat-stub-cargs compiler)
+               (append (list "-cargs") (split-string 
(gnat-compiler-gnat-stub-cargs compiler)))))
+       (process-environment
+        (append
+          (wisi-prj-compile-env project)
+          (wisi-prj-file-env project)
+          (copy-sequence process-environment)))
+       )
+
+    ;; Make sure all relevant files are saved to disk.
+    (save-some-buffers t)
+
+    (with-current-buffer (gnat-run-buffer compiler 
(gnat-compiler-run-buffer-name compiler))
+      (let ((default-directory (file-name-directory body-file-name)))
+       (gnat-run-gnat
+        project
+        "stub"
+        (append opts (list start-file) cargs))
+
+       (find-file body-file-name)
+       (indent-region (point-min) (point-max))
+       (save-buffer)))
+    nil))
+
+(defun gnat-syntax-propertize (start end)
+  (goto-char start)
+  (save-match-data
+    (while (re-search-forward
+           (concat
+            "[^[:alnum:])]\\('\\)\\[[\"a-fA-F0-9]+\"\\]\\('\\)"; 1, 2: 
non-ascii character literal, not attributes
+            "\\|\\(\\[\"[a-fA-F0-9]+\"\\]\\)"; 3: non-ascii character in 
identifier
+            )
+           end t)
+      (cond
+       ((match-beginning 1)
+       (put-text-property
+        (match-beginning 1) (match-end 1) 'syntax-table '(7 . ?'))
+       (put-text-property
+        (match-beginning 2) (match-end 2) 'syntax-table '(7 . ?')))
+
+       ((match-beginning 3)
+       (put-text-property
+        (match-beginning 3) (match-end 3) 'syntax-table '(2 . nil)))
+       )
+      )))
+
+(defun gnat-insert-unit-name (unit-name)
+  "Insert UNIT-NAME at point and capitalize it."
+  ;; unit-name is normally gotten from a file-name, and is thus all lower-case.
+  (let ((start-point (point))
+        search-bound)
+    (insert unit-name)
+    (setq search-bound (point))
+    (insert " ") ; separate from following words, if any, for 
wisi-case-adjust-identifier
+    (goto-char start-point)
+    (while (search-forward "." search-bound t)
+      (forward-char -1)
+      (wisi-case-adjust-identifier)
+      (forward-char 1))
+    (goto-char search-bound)
+    (wisi-case-adjust-identifier)
+    (delete-char 1)))
+
+(defun gnat-context-clause ()
+  (if (fboundp 'ada-fix-context-clause);; in ada-mode
+      (ada-fix-context-clause)
+    (user-error "ada-fix-context-clause not defined; can't find context 
clause")))
+
+(defun gnat-extend-with-clause (partial-parent-name child-name)
+  "Assuming point is in a selected name, just before CHILD-NAME, add or
+extend a with_clause to include CHILD-NAME."
+  ;; In GNAT Community 2020, point is before partial-parent-name; in
+  ;; earlier gnat, it is after.
+  (search-forward partial-parent-name (line-end-position) t)
+  (let ((parent-name-end (point)))
+    ;; Find the full parent name; skip back to whitespace, then match
+    ;; the name forward.
+    (skip-syntax-backward "w_.")
+    (search-forward-regexp gnat-name-regexp parent-name-end t)
+    (let ((parent-name (match-string 0))
+         (context-clause (gnat-context-clause)))
+      (goto-char (car context-clause))
+      (if (search-forward-regexp (concat "^with " parent-name ";") (cdr 
context-clause) t)
+         ;; found exisiting 'with' for parent; extend it
+         (progn
+           (forward-char -1) ; skip back over semicolon
+           (insert "." child-name))
+
+       ;; not found; we are in a package body, with_clause for parent is in 
spec.
+       ;; insert a new one
+       (gnat-add-with-clause (concat parent-name "." child-name)))
+      )))
+
+(defun gnat-add-use (unit-name)
+  (if (fboundp 'ada-fix-add-use);; in ada-mode
+      (ada-fix-add-use unit-name)
+    (user-error "ada-fix-add-use not defined; add use clause manually")))
+
+(defun gnat-add-use-type (type)
+  (if (fboundp 'ada-fix-add-use-type);; in ada-mode
+      (ada-fix-add-use-type type)
+    (user-error "ada-fix-add-use-type not defined; add use type clause 
manually")))
+
+(defun gnat-add-with-clause (unit-name)
+  (if (fboundp 'ada-fix-add-with-clause);; in ada-mode
+      (ada-fix-add-with-clause unit-name)
+    (user-error "ada-fix-add-with-clause not defined; add with clause 
manually")))
+
+(defun gnat-align ()
+  (if (fboundp 'ada-align);; in ada-mode
+      (ada-align)
+    (user-error "ada-align not defined; align manually")))
+
+(defcustom gnat-lsp-server-exec nil
+  "Location of an Ada language server.
+If non-nil, should be an absolute path to an executable for the
+server; this allows specifying a development version. See
+`gnat-find-als' for default behaviour."
+  :group 'gnat-compiler
+  :type 'string)
+
+(defun gnat-find-als (&optional _interactive no-error)
+  ;; in eglot 1.8, eglot--connect calls CONTACT with 1 arg
+  ;; in devel eglot, eglot--connect calls CONTACT with no args
+  "Find the language server executable.
+If `gnat-lsp-server-exec' is set, uses that. Otherwise defaults
+to AdaCore ada_language_server in `exec-path', then in a gnat
+installation found in `exec-path'.  If NO-ERROR, return nil if
+server executable not found; otherwise signal user-error."
+  (if gnat-lsp-server-exec
+      (setq gnat-lsp-server-exec (locate-file gnat-lsp-server-exec exec-path 
exec-suffixes))
+      (if (file-readable-p gnat-lsp-server-exec)
+         gnat-lsp-server-exec
+       (user-error "gnat-lsp-server-exec '%s' not a readable file"
+                   gnat-lsp-server-exec))
+
+    ;; else look for AdaCore ada_language_server
+    ;;
+    ;; ada_language_server is provided by a GNAT compiler installation, in a
+    ;; directory under GNAT/libexec, which is typically not in PATH.
+    (let ((gnat (executable-find "gnat"))
+       (path exec-path))
+    (when gnat
+      (setq path (append
+                 path
+                 (list
+                  (expand-file-name
+                   "../libexec/gnatstudio/als"
+                   (file-name-directory gnat))))))
+    (let ((guess (locate-file "ada_language_server" path exec-suffixes)))
+      (if guess
+         guess
+       (unless no-error
+         (user-error "ada_language_server not found")))))))
+
+;;;;; wisi compiler generic methods
+
+(cl-defmethod wisi-compiler-root-dir ((compiler gnat-compiler))
+  "Return the directory containing the project file."
+  ;; eglot starts the language server in this directory;
+  ;; ada_language_server searches for a project file.
+  (and (gnat-compiler-gpr-file compiler)
+       (file-name-directory (gnat-compiler-gpr-file compiler))))
+
+(cl-defmethod wisi-compiler-parse-one ((compiler gnat-compiler) project name 
value)
+  (cond
+   ((or
+     (string= name "ada_project_path") ;; backward compatibility
+     (string= name "gpr_project_path"))
+    (let ((process-environment
+          (append
+           (wisi-prj-compile-env project)
+           (wisi-prj-file-env project))));; reference, for 
substitute-in-file-name
+      (gnat-prj-add-prj-dir project compiler (expand-file-name 
(substitute-in-file-name value)))))
+
+   ((string= name "gnat-stub-cargs")
+    (setf (gnat-compiler-gnat-stub-cargs compiler) value))
+
+   ((string= name "gnat-stub-opts")
+    (setf (gnat-compiler-gnat-stub-opts compiler) value))
+
+   ((string= name "gpr_file")
+    ;; The gpr file is parsed in `wisi-compiler-parse-final' below, so
+    ;; it sees all file environment vars. We store the absolute gpr
+    ;; file name, so we can get the correct default-directory from
+    ;; it. Note that gprbuild requires the base name be found on
+    ;; GPR_PROJECT_PATH.
+    (let* ((process-environment
+           (append
+            (wisi-prj-compile-env project)
+            (wisi-prj-file-env project)));; reference, for 
substitute-in-file-name
+          (gpr-file (substitute-env-vars value)))
+
+      (if (= (aref gpr-file 0) ?$)
+         ;; An environment variable that was not resolved, possibly
+         ;; because the env var is later defined in the project file;
+         ;; it may be resoved in `wisi-compiler-parse-final'.
+         (setf (gnat-compiler-gpr-file compiler) gpr-file)
+
+       ;; else get the absolute path
+       (setf (gnat-compiler-gpr-file compiler)
+             (or (locate-file gpr-file (gnat-compiler-project-path compiler))
+                 (expand-file-name (substitute-env-vars gpr-file))))))
+    t)
+
+   ((string= name "runtime")
+    (setf (gnat-compiler-runtime compiler) value))
+
+   ((string= name "target")
+    (setf (gnat-compiler-target compiler) value))
+
+   ))
+
+(cl-defmethod wisi-compiler-parse-final ((compiler gnat-compiler) project 
prj-file-name)
+  (setf (gnat-compiler-run-buffer-name compiler) (gnat-run-buffer-name 
prj-file-name))
+
+  (let ((gpr-file (gnat-compiler-gpr-file compiler)))
+    (if gpr-file
+       (progn
+         (when (= (aref gpr-file 0) ?$)
+           ;; An environment variable that was not resolved earlier,
+           ;; because the env var is defined in the project file.
+           (let ((process-environment
+                  (append
+                   (wisi-prj-compile-env project)
+                   (wisi-prj-file-env project))));; reference, for 
substitute-in-file-name
+
+             (setq gpr-file
+                   (or
+                    (locate-file (substitute-env-vars gpr-file)
+                                 (gnat-compiler-project-path compiler))
+                    (expand-file-name (substitute-env-vars gpr-file))))
+
+             (setf (gnat-compiler-gpr-file compiler) gpr-file)))
+
+         (gnat-parse-gpr gpr-file project)
+         )
+
+    ;; else add the compiler libraries to project.source-path
+    (gnat-get-paths project :ignore-prj-paths nil)
+    )))
+
+(defvar ada-syntax-propertize-hook) ;; actually declared in ada-core.el in 
ada-mode package
+
+(cl-defmethod wisi-compiler-select-prj :after ((_compiler gnat-compiler) 
_project)
+  (add-to-list 'completion-ignored-extensions ".ali") ;; gnat library files
+  (setq compilation-error-regexp-alist
+       ;; gnu matches the summary line from make:
+       ;; make: *** [rules.make:143: wisitoken-bnf-generate.exe] Error 4
+       ;; which is just annoying, but should be up to the user.
+       '(gnu)
+       )
+  (add-hook 'compilation-filter-hook 'gnat-compilation-filter)
+  (add-hook 'ada-syntax-propertize-hook #'gnat-syntax-propertize)
+
+  ;; We should call `syntax-ppss-flush-cache' here, to force ppss with
+  ;; the new hook function. But that must be done in all ada-mode
+  ;; buffers, which is tedious. So we're ignoring it until it becomes
+  ;; a problem; normally, the compiler is selected before any Ada
+  ;; files are visited, so it's not an issue.
+  )
+
+(cl-defmethod wisi-compiler-deselect-prj :before ((_compiler gnat-compiler) 
_project)
+  (setq completion-ignored-extensions (delete ".ali" 
completion-ignored-extensions))
+  (setq compilation-error-regexp-alist (mapcar #'car 
compilation-error-regexp-alist-alist))
+  (remove-hook 'ada-syntax-propertize-hook #'gnat-syntax-propertize)
+  (remove-hook 'compilation-filter-hook #'gnat-compilation-filter))
+
+(cl-defmethod wisi-compiler-prj-path ((compiler gnat-compiler))
+    (gnat-compiler-project-path compiler)
+    )
+
+(cl-defmethod wisi-compiler-fix-error ((_compiler gnat-compiler) source-buffer)
+  (let ((start-pos (point))
+       message-column
+       result)
+    ;; Move to start of error message text. GNAT Community 2021 puts
+    ;; warning: | error: after the file:line:column; earlier compilers
+    ;; only put "warning: ".
+    ;;
+    ;; test_incremental.adb:657:20: error: "Checks" not declared in "WisiToken"
+    (skip-syntax-forward "^-") ;; file:line:column
+    (forward-char 1)
+    (when (looking-at "warning: \\|error: ")
+      (goto-char (match-end 0)))
+    (setq message-column (current-column))
+
+    ;; recognize it, handle it
+    (setq
+     result
+     (unwind-protect
+        (cond
+         ;; It is tempting to define an alist of (MATCH . ACTION), but
+         ;; that is too hard to debug
+         ;;
+         ;; This list will get long, so let's impose some order.
+         ;;
+         ;; First expressions that start with a named regexp,
+         ;; alphabetical by variable name and following string.
+         ;;
+         ;; Then expressions that start with a string, alphabetical by string.
+         ;;
+         ;; Then style errors.
+
+         ((looking-at (concat gnat-quoted-name-regexp " is not a component of 
"))
+                  (save-excursion
+            (let ((child-name (match-string 1))
+                  (correct-spelling (gnat-misspelling)))
+              (setq correct-spelling (match-string 1))
+              (pop-to-buffer source-buffer)
+              (search-forward child-name)
+              (replace-match correct-spelling))
+            t))
+
+         ((looking-at (concat gnat-quoted-name-regexp " is not visible"))
+          (let* ((done nil)
+                 (err-msg (get-text-property (line-beginning-position) 
'compilation-message))
+                 (file-line-struct err-msg)
+                 pos choices unit-name)
+            ;; next line may contain a reference to where ident is
+            ;; defined; if present, it will have been marked by
+            ;; gnat-compilation-filter:
+            ;;
+    ;; gnatquery.adb:255:13: error: "Has_Element" is not visible
+    ;; gnatquery.adb:255:13: error: non-visible declaration at 
a-convec.ads:68, instance at gnatcoll-arg_lists.ads:157
+    ;; gnatquery.adb:255:13: error: non-visible declaration at 
a-coorse.ads:62, instance at gnatcoll-xref.ads:912
+    ;; gnatquery.adb:255:13: error: non-visible declaration at 
a-coorse.ads:62, instance at gnatcoll-xref.ads:799
+    ;; gnatquery.adb:255:13: error: non-visible declaration at 
gnatcoll-xref.ads:314
+            ;;
+            ;; or the next line may contain "multiple use clauses cause hiding"
+            ;;
+            ;; the lines after that may contain alternate matches;
+            ;; collect all, let user choose.
+            ;;
+            ;; However, a line that contains 'gnat-secondary-error may be from 
the next error message:
+            ;; parser_no_recover.adb:297:60: no selector "Tree" for type 
"Parser_State" defined at lists.ads:96
+            (forward-line 1)
+            (when (looking-at ".* multiple use clauses cause hiding")
+              (forward-line 1))
+            (while (not done)
+              (let ((limit (1- (line-end-position))))
+                ;; 1- because next compilation error is at next line beginning
+                (setq done (not
+                            (and
+                             (equal file-line-struct err-msg) ;; same error 
message?
+                             (setq pos (next-single-property-change (point) 
'gnat-secondary-error nil limit))
+                             (<= pos limit))))
+                (when (not done)
+                  (let* ((item (get-text-property pos 'gnat-secondary-error))
+                         (unit-file (nth 0 item))
+                         (choice (gnat-ada-name-from-file-name unit-file)))
+                    (unless (member choice choices) (push choice choices))
+                    (goto-char (1+ pos))
+                    (goto-char (1+ (next-single-property-change (point) 
'gnat-secondary-error nil limit)))
+                    (when (eolp)
+                      (forward-line 1)
+                      (setq file-line-struct (get-text-property (point) 
'compilation-message)))
+                    ))
+                ))
+
+            (setq unit-name
+                  (cond
+                   ((= 0 (length choices)) nil)
+                   ((= 1 (length choices)) (car choices))
+                   (t ;; multiple choices
+                    (completing-read "package name: " choices))))
+
+            (when unit-name
+              (pop-to-buffer source-buffer)
+              ;; We either need to add a with_clause for a package, or
+              ;; prepend the package name here (or add a use clause, but I
+              ;; don't want to do that automatically).
+              ;;
+              ;; If we need to add a with_clause, unit-name may be only
+              ;; the prefix of the real package name, but in that case
+              ;; we'll be back after the next compile; no way to get the
+              ;; full package name (without the function/type name) now.
+              ;; Note that we can't use gnat find, because the code
+              ;; doesn't compile.
+              (cond
+               ((looking-at (concat unit-name "\\."))
+                (gnat-add-with-clause unit-name))
+               (t
+                (gnat-insert-unit-name unit-name)
+                (insert ".")))
+              t) ;; success, else nil => fail
+            ))
+
+         ((or (looking-at (concat gnat-quoted-name-regexp " is undefined"))
+              (looking-at (concat gnat-quoted-name-regexp " is not a 
predefined library unit")))
+          ;; We either need to add a with_clause for a package, or
+          ;; something is spelled wrong.
+          (save-excursion
+            (let ((unit-name (match-string 1))
+                  (correct-spelling (gnat-misspelling)))
+              (if correct-spelling
+                  (progn
+                    (pop-to-buffer source-buffer)
+                    (search-forward unit-name)
+                    (replace-match correct-spelling))
+
+                ;; else assume missing with
+                (pop-to-buffer source-buffer)
+                (gnat-add-with-clause unit-name))))
+          t)
+
+         ((looking-at (concat gnat-quoted-name-regexp " not declared in " 
gnat-quoted-name-regexp))
+          (save-excursion
+            (let ((child-name (match-string 1))
+                  (partial-parent-name (match-string 2))
+                  (correct-spelling (gnat-misspelling))
+                  (qualified (gnat-qualified)))
+              (cond
+               (correct-spelling
+                (pop-to-buffer source-buffer)
+                (search-forward child-name)
+                (replace-match correct-spelling))
+
+               (qualified
+                (pop-to-buffer source-buffer)
+                (search-forward child-name)
+                (skip-syntax-backward "w_.")
+                (insert qualified "."))
+
+               (t
+                ;; else guess that "child" is a child package, and extend the 
with_clause
+                (pop-to-buffer source-buffer)
+                (gnat-extend-with-clause partial-parent-name child-name))))
+          t))
+
+         ((looking-at (concat gnat-quoted-punctuation-regexp
+                              " should be "
+                              gnat-quoted-punctuation-regexp))
+          (let ((bad (match-string-no-properties 1))
+                (good (match-string-no-properties 2)))
+            (pop-to-buffer source-buffer)
+            (looking-at bad)
+            (delete-region (match-beginning 0) (match-end 0))
+            (insert good))
+          t)
+
+;;;; strings
+         ((looking-at (concat "aspect \"" gnat-name-regexp "\" requires 
'Class"))
+          (pop-to-buffer source-buffer)
+          (forward-word 1)
+          (insert "'Class")
+          t)
+
+         ((looking-at (concat "\"end " gnat-name-regexp ";\" expected"))
+          (let ((expected-name (match-string 1)))
+            (pop-to-buffer source-buffer)
+            (if (looking-at (concat "end " gnat-name-regexp ";"))
+                (progn
+                  (goto-char (match-end 1))   ; just before ';'
+                  (delete-region (match-beginning 1) (match-end 1)))
+              ;; else we have just 'end;'
+              (forward-word 1)
+              (insert " "))
+            (insert expected-name))
+          t)
+
+         ((looking-at (concat "\"end loop " gnat-name-regexp ";\" expected"))
+          (let ((expected-name (match-string 1)))
+            (pop-to-buffer source-buffer)
+            (if (looking-at (concat "end loop " gnat-name-regexp ";"))
+                (progn
+                  (goto-char (match-end 1))   ; just before ';'
+                  (delete-region (match-beginning 1) (match-end 1)))
+              ;; else we have just 'end loop;'
+              (forward-word 2)
+              (insert " "))
+            (insert expected-name))
+          t)
+
+         ((looking-at "expected an access type")
+          (progn
+            (set-buffer source-buffer)
+            (backward-char 1)
+            (when (looking-at "\\.all")
+              (delete-char 4)
+              t)))
+
+         ((looking-at (concat "expected \\(private \\)?type " 
gnat-quoted-name-regexp))
+          (forward-line 1)
+          (move-to-column message-column)
+          (cond
+           ((looking-at "found procedure name")
+            (pop-to-buffer source-buffer)
+            (forward-word 1)
+            (insert "'Access")
+            t)
+           ((looking-at "found type access")
+            (pop-to-buffer source-buffer)
+            (if (looking-at "'Access")
+                (kill-word 1)
+              (forward-symbol 1)
+              (insert ".all"))
+            t)
+           ((looking-at "found type .*_Access_Type")
+            ;; assume just need '.all'
+            (pop-to-buffer source-buffer)
+            (forward-word 1)
+            (insert ".all")
+            t)
+           ))
+
+         ((looking-at "extra \".\" ignored")
+          (set-buffer source-buffer)
+          (delete-char 1)
+          t)
+
+         ((looking-at (concat "keyword " gnat-quoted-name-regexp " expected 
here"))
+          (let ((expected-keyword (match-string 1)))
+            (pop-to-buffer source-buffer)
+            (insert " " expected-keyword))
+          t)
+
+         ((looking-at "\\(?:possible \\)?missing \"with \\([[:alnum:]_.]+\\);")
+          ;; also 'possible missing "with Ada.Text_IO; use Ada.Text_IO"' - 
ignoring the 'use'
+          (let ((package-name (match-string-no-properties 1)))
+            (pop-to-buffer source-buffer)
+            ;; Could check if prefix is already with'd, extend
+            ;; it. But that's not easy. This message only occurs for
+            ;; compiler-provided Ada and GNAT packages.
+            (gnat-add-with-clause package-name))
+          t)
+
+         ;; must be after above
+         ;;
+         ;; missing "end;" for "begin" at line 234
+         ((looking-at "missing \"\\([^ ]+\\)\"")
+          (let ((stuff (match-string-no-properties 1)))
+            (set-buffer source-buffer)
+            (insert (concat stuff)));; if missing ")", don't need space; 
otherwise do?
+          t)
+
+         ((looking-at (concat "\\(?:possible \\)?misspelling of " 
gnat-quoted-name-regexp))
+          (let ((expected-name (match-string 1)))
+            (pop-to-buffer source-buffer)
+            (looking-at gnat-name-regexp)
+            (delete-region (match-beginning 1) (match-end 1))
+            (insert expected-name))
+          t)
+
+         ((looking-at "No legal interpretation for operator")
+          (forward-line 1)
+          (move-to-column message-column)
+          (looking-at (concat "use clause on " gnat-quoted-name-regexp))
+          (let ((package (match-string 1)))
+            (pop-to-buffer source-buffer)
+            (gnat-add-use package))
+          t)
+
+         ((looking-at (concat "no selector " gnat-quoted-name-regexp))
+          ;; Check next line for spelling error.
+          (save-excursion
+            (let ((unit-name (match-string 1))
+                  (correct-spelling (gnat-misspelling)))
+              (when correct-spelling
+                (pop-to-buffer source-buffer)
+                (search-forward unit-name)
+                (replace-match correct-spelling)
+                t))))
+
+         ((looking-at (concat "operator for \\(?:private \\)?type " 
gnat-quoted-name-regexp
+                              "\\(?: defined at " gnat-file-name-regexp 
"\\)?"))
+          (let ((type (match-string 1))
+                (package-file (match-string 2))
+                ;; IMPROVEME: we'd like to handle ", instance at
+                ;; <file:line:column>", but gnatcoll.xref does not
+                ;; support looking up an entity by location alone; it
+                ;; requires the name, and this error message does not
+                ;; give the name of the instance. When we implement
+                ;; adalang xref, or if the error message improves,
+                ;; try again.
+                )
+            (when package-file
+              (setq type (concat
+                          (gnat-ada-name-from-file-name package-file)
+                          "." type)))
+            (pop-to-buffer source-buffer)
+            (gnat-add-use-type type)
+          t))
+
+         ((looking-at "package \"Ada\" is hidden")
+          (pop-to-buffer source-buffer)
+          (forward-word -1)
+          (insert "Standard.")
+          t)
+
+         ((looking-at "parentheses required for unary minus")
+          (set-buffer source-buffer)
+          (insert "(")
+          (forward-word 1)
+          (insert ")")
+          t)
+
+         ((looking-at "prefix of dereference must be an access type")
+          (pop-to-buffer source-buffer)
+          ;; point is after '.' in '.all'
+          (delete-region (- (point) 1) (+ (point) 3))
+          t)
+
+;;;; warnings
+         ((looking-at (concat gnat-quoted-name-regexp " is already 
use-visible"))
+          ;; just delete the 'use'; assume it's on a line by itself.
+          (pop-to-buffer source-buffer)
+          (beginning-of-line)
+          (delete-region (point) (progn (forward-line 1) (point)))
+          t)
+
+         ((looking-at (concat gnat-quoted-name-regexp " is not modified, could 
be declared constant"))
+          (pop-to-buffer source-buffer)
+          (search-forward ":")
+          (forward-comment (- (point-max) (point)))
+          ;; "aliased" must be before "constant", so check for it
+          (when (looking-at "aliased")
+            (forward-word 1)
+            (forward-char 1))
+          (insert "constant ")
+          t)
+
+         ((looking-at (concat "constant " gnat-quoted-name-regexp " is not 
referenced"))
+          (let ((constant (match-string 1)))
+            (pop-to-buffer source-buffer)
+            (end-of-line)
+            (newline-and-indent)
+            (insert "pragma Unreferenced (" constant ");"))
+          t)
+
+         ((looking-at (concat "formal parameter " gnat-quoted-name-regexp " is 
not referenced"))
+          (let ((param (match-string 1))
+                cache)
+            (pop-to-buffer source-buffer)
+            ;; Point is in a subprogram parameter list;
+            ;; ada-goto-declarative-region-start goes to the package,
+            ;; not the subprogram declarative_part (this is a change
+            ;; from previous wisi versions).
+            (setq cache (wisi-goto-statement-start))
+            (while (not (eq 'IS (wisi-cache-token cache)))
+              (forward-sexp)
+              (setq cache (wisi-get-cache (point))))
+            (forward-word)
+            (newline-and-indent)
+            (insert "pragma Unreferenced (" param ");"))
+          t)
+
+         ((looking-at (concat "formal parameter " gnat-quoted-name-regexp " is 
not modified"))
+          (let ((mode-regexp "\"\\([in out]+\\)\"")
+                new-mode
+                old-mode)
+            (forward-line 1)
+            (search-forward-regexp
+             (concat "mode could be " mode-regexp " instead of " mode-regexp))
+            (setq new-mode (match-string 1))
+            (setq old-mode (match-string 2))
+            (pop-to-buffer source-buffer)
+            (search-forward old-mode)
+            (replace-match new-mode)
+            (gnat-align)
+            )
+          t)
+
+         ((looking-at (concat "variable " gnat-quoted-name-regexp " is not 
referenced"))
+          (let ((param (match-string 1)))
+            (pop-to-buffer source-buffer)
+            (forward-sexp);; end of declaration
+            (forward-char);; skip semicolon
+            (newline-and-indent)
+            (insert "pragma Unreferenced (" param ");"))
+          t)
+
+         ((or
+           (looking-at (concat "no entities of " gnat-quoted-name-regexp " are 
referenced"))
+           (looking-at (concat "unit " gnat-quoted-name-regexp " is never 
instantiated"))
+           (looking-at (concat "renamed constant " gnat-quoted-name-regexp " 
is not referenced"))
+           (looking-at "redundant with clause"))
+          ;; just delete the declaration; assume it's on a line by itself.
+          (pop-to-buffer source-buffer)
+          (beginning-of-line)
+          (delete-region (point) (progn (forward-line 1) (point)))
+          t)
+
+         ((looking-at (concat "variable " gnat-quoted-name-regexp " is 
assigned but never read"))
+          (let ((param (match-string 1)))
+            (pop-to-buffer source-buffer)
+            (wisi-goto-statement-end) ;; leaves point before semicolon
+            (forward-char 1)
+            (newline-and-indent)
+            (insert "pragma Unreferenced (" param ");"))
+          t)
+
+         ((looking-at (concat "unit " gnat-quoted-name-regexp " is not 
referenced"))
+          ;; just delete the 'with'; assume it's on a line by itself.
+          (pop-to-buffer source-buffer)
+          (beginning-of-line)
+          (delete-region (point) (progn (forward-line 1) (point)))
+          t)
+
+         ((looking-at (concat "use clause for \\(package\\|type\\|private 
type\\) " gnat-quoted-name-regexp
+                              " \\(defined at\\|from instance at\\|has no 
effect\\)"))
+          ;; delete the 'use'; assume it's on a line by itself.
+          (pop-to-buffer source-buffer)
+          (beginning-of-line)
+          (delete-region (point) (progn (forward-line 1) (point)))
+          t)
+
+;;;; style errors
+         ((or (looking-at "(style) \".*\" in wrong column")
+              (looking-at "(style) this token should be in column"))
+          (set-buffer source-buffer)
+          (funcall indent-line-function)
+          t)
+
+         ((looking-at "(style) bad capitalization, mixed case required")
+          (set-buffer source-buffer)
+          (forward-word)
+          (wisi-case-adjust-identifier)
+          t)
+
+         ((looking-at (concat "(style) bad casing of " 
gnat-quoted-name-regexp))
+          (let ((correct (match-string-no-properties 1))
+                end)
+            ;; gnat leaves point on first bad character, but we need to 
replace the whole word
+            (set-buffer source-buffer)
+            (skip-syntax-backward "w_")
+            (setq end (point))
+            (skip-syntax-forward "w_")
+            (delete-region (point) end)
+            (insert correct))
+          t)
+
+         ((or
+           (looking-at "(style) bad column")
+           (looking-at "(style) bad indentation")
+           (looking-at "(style) incorrect layout"))
+          (set-buffer source-buffer)
+          (funcall indent-line-function)
+          t)
+
+         ((looking-at "(style) \"exit \\(.*\\)\" required")
+          (let ((name (match-string-no-properties 1)))
+            (set-buffer source-buffer)
+            (forward-word 1)
+            (insert (concat " " name))
+          t))
+
+         ((looking-at "(style) misplaced \"then\"")
+          (set-buffer source-buffer)
+          (delete-indentation)
+          t)
+
+         ((looking-at "(style) missing \"overriding\" indicator")
+          (set-buffer source-buffer)
+          (cond
+           ((looking-at "\\(procedure\\)\\|\\(function\\)")
+            (insert "overriding ")
+           t)
+           (t
+            nil)))
+
+         ((looking-at "(style) reserved words must be all lower case")
+          (set-buffer source-buffer)
+          (downcase-word 1)
+          t)
+
+         ((looking-at "(style) space not allowed")
+          (set-buffer source-buffer)
+          ;; Error places point on space. More than one trailing space
+          ;; should be fixed by delete-trailing-whitespace in
+          ;; before-save-hook, once the file is modified.
+          (delete-char 1)
+          t)
+
+         ((looking-at "(style) space required")
+          (set-buffer source-buffer)
+          (insert " ")
+          t)
+         )));; end of setq unwind-protect cond
+    (if result
+       t
+      (goto-char start-pos)
+      nil)
+    ))
+
+;;;; Initialization
+
+(add-to-list 'wisi-prj-file-extensions  "gpr")
+(add-to-list 'wisi-prj-parser-alist  '("gpr" . gnat-parse-gpr-1))
+
+(add-to-list
+ 'compilation-error-regexp-alist-alist
+ '(gnat
+   ;; typical:
+   ;;   cards_package.adb:45:32: expected private type "System.Address"
+   ;;
+   ;; with full path Source_Reference pragma :
+   ;;   d:/maphds/version_x/1773/sbs-abi-dll_lib.ads.gp:39:06: file 
"interfaces_c.ads" not found
+   ;;
+   ;; gnu cc1: (gnatmake can invoke the C compiler)
+   ;;   foo.c:2: `TRUE' undeclared here (not in a function)
+   ;;   foo.c:2 : `TRUE' undeclared here (not in a function)
+   ;;
+   ;; we can't handle secondary errors here, because a regexp can't 
distinquish "message" from "filename"
+   "^\\(\\(.:\\)?[^ :\n]+\\):\\([0-9]+\\)\\s-?:?\\([0-9]+\\)?" 1 3 4))
+
+(eval-after-load 'ada-mode '(add-hook 'ada-mode-hook #'gnatprep-setup))
+
+(provide 'gnat-compiler)
+;; end of file
diff --git a/gnat-xref.el b/gnat-xref.el
new file mode 100644
index 0000000000..bba675caac
--- /dev/null
+++ b/gnat-xref.el
@@ -0,0 +1,328 @@
+;;; gnat-xref.el --- cross-reference functionality provided by 'gnat xref'  
-*- lexical-binding:t -*-
+;;
+;; These tools are all Ada-specific; see gpr-query for multi-language
+;; GNAT cross-reference tools.
+;;
+;; GNAT is provided by AdaCore; see http://libre.adacore.com/
+;;
+;;; Copyright (C) 2012 - 2022  Free Software Foundation, Inc.
+;;
+;; Author: Stephen Leake <stephen_leake@member.fsf.org>
+;; Maintainer: Stephen Leake <stephen_leake@member.fsf.org>
+;;
+;; This file is part of GNU Emacs.
+;;
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+(require 'compile)
+(require 'gnat-compiler)
+
+;;;;; code
+
+(defconst gnat-xref-buffer-name-prefix "*gnatxref-")
+
+(defconst gnat-file-line-col-regexp "\\(.*\\):\\([0-9]+\\):\\([0-9]+\\)")
+
+(defconst gnat-file-line-col-type-regexp
+  (concat gnat-file-line-col-regexp ": +\\(?:(\\(.*\\))\\)?")
+  "Regexp matching <file>:<line>:<column> (<type>)")
+
+(cl-defstruct (gnat-xref (:include gnat-compiler))
+  "Used with wisi-xref-* generic functions; runs gnat find."
+  ;; no new slots
+  )
+
+;;;###autoload
+(cl-defun create-gnat-xref
+    (&key
+     gpr-file
+     run-buffer-name
+     project-path
+     target
+     runtime
+     gnat-stub-opts
+     gnat-stub-cargs)
+  ;; See note on `create-ada-prj' for why this is not a defalias.
+  (make-gnat-xref
+   :gpr-file gpr-file
+   :run-buffer-name run-buffer-name
+   :project-path project-path
+   :target target
+   :runtime runtime
+   :gnat-stub-opts gnat-stub-opts
+   :gnat-stub-cargs gnat-stub-cargs
+   ))
+
+(cl-defmethod wisi-xref-parse-one ((xref gnat-xref) project name value)
+  (wisi-compiler-parse-one xref project name value))
+
+(cl-defmethod wisi-xref-parse-final ((xref gnat-xref) _project prj-file-name)
+  (setf (gnat-compiler-run-buffer-name xref) (gnat-run-buffer-name 
prj-file-name gnat-xref-buffer-name-prefix)))
+
+(cl-defmethod wisi-xref-completion-table ((_xref gnat-xref) _project)
+  (wisi-names t t))
+
+(cl-defmethod wisi-xref-completion-regexp ((_xref gnat-xref))
+  wisi-names-regexp)
+
+(defun gnat-xref-adj-col (identifier col)
+  "Return COL adjusted for 1-index, quoted operators."
+  (cond
+   ((null col)
+    col)
+
+   ((eq ?\" (aref identifier 0))
+    ;; There are two cases here:
+    ;;
+    ;; In both cases, gnat find wants the operators quoted, and the
+    ;; column on the +. Gnat column is one-indexed; emacs is 0 indexed.
+    ;;
+    ;; In the first case, the front end passes in a column on the leading ", 
so we add one.
+    ;;
+    ;; In the second case, the front end passes in a column on the +
+    (cond
+     ((= ?\" (char-after (point)))
+      ;; test/ada_mode-slices.adb
+      ;; function "+" (Left : in Day; Right : in Integer) return Day;
+      (+ 2 col))
+
+     (t
+      ;; test/ada_mode-slices.adb
+      ;; D1, D2 : Day := +Sun;
+      (+ 1 col))
+     ))
+
+   (t
+    ;; Gnat column is one-indexed; emacs is 0 indexed.
+    (+ 1 col))
+   ))
+
+(defun gnat-xref-common-cmd (project)
+  "Returns the gnatfind command to run to find cross-references."
+  (format "%sgnatfind" (or (gnat-compiler-target (wisi-prj-xref project)) "")))
+
+(defun gnat-xref-common-args (project identifier file line col)
+  "Returns a list of arguments to pass to gnatfind.  Some
+elements of the result may be nil."
+  (list "-a"
+        (when wisi-xref-full-path "-f")
+       ;; 'gnatfind' does not take a gnat project file argument. We
+       ;; assume you are not using gnatxref if you are using a gnat
+       ;; project file; use gpr_query.
+        (when (wisi-prj-source-path project)
+          (concat "-aI" (mapconcat 'identity (wisi-prj-source-path project) " 
-aI")))
+
+       (when (and (fboundp 'ada-prj-plist)
+                  (plist-get (ada-prj-plist project) 'obj_dir))
+          (concat "-aO" (mapconcat 'identity (plist-get (ada-prj-plist 
project) 'obj_dir) " -aO")))
+
+        (format "%s:%s:%s:%s"
+                identifier
+                (file-name-nondirectory file)
+                (or line "")
+                (or (gnat-xref-adj-col identifier col) ""))))
+
+(defun gnat-xref-refs (project item all)
+  ;; WORKAROUND: xref 1.3.2 xref-location changed from defclass to
+  ;; cl-defstruct. If drop emacs 26, use 'with-suppressed-warnings'.
+  (with-no-warnings ;; "unknown slot"
+    (let ((summary (if (functionp 'xref-item-summary) (xref-item-summary item) 
(oref item summary)))
+         (location (if (functionp 'xref-item-location) (xref-item-location 
item) (oref item location))))
+      (let ((file (if (functionp 'xref-file-location-file)
+                     (xref-file-location-file location)
+                   (oref location file)))
+           (line (if (functionp 'xref-file-location-line)
+                     (xref-file-location-line location)
+                   (oref location line)))
+           (column (if (functionp 'xref-file-location-column)
+                       (xref-file-location-column location)
+                     (oref location column))))
+       (let* ((wisi-xref-full-path t)
+              (args (cons "-r" (gnat-xref-common-args project summary file 
line column)))
+              (prj-xref (wisi-prj-xref project))
+              (result nil))
+         (with-current-buffer (gnat-run-buffer prj-xref 
(gnat-compiler-run-buffer-name prj-xref))
+           (gnat-run project (gnat-xref-common-cmd project) args)
+
+           (goto-char (point-min))
+           (when gnat-debug-run (forward-line 2)); skip ADA_PROJECT_PATH, 
command
+           (if (looking-at "WARNING: gnatfind is obsolete.*")
+               ;; Added in gnat pro 23
+               (forward-line 2))
+
+           (while (not (eobp))
+             (cond
+              ((looking-at gnat-file-line-col-type-regexp)
+               ;; process line
+               (let ((found-file (match-string 1))
+                     (found-line (string-to-number (match-string 2)))
+                     (found-col  (string-to-number (match-string 3)))
+                     (found-type (match-string 4)))
+                 (when (or all found-type)
+                   (push (xref-make (if found-type
+                                        (concat summary " " found-type)
+                                      summary)
+                                    (xref-make-file-location found-file 
found-line found-col))
+                         result))
+                 ))
+              (t
+               ;; ignore line
+               ))
+             (forward-line 1)))
+         (nreverse result) ;; specs first.
+         )))))
+
+(cl-defmethod wisi-xref-definitions ((_xref gnat-xref) project item)
+  (gnat-xref-refs project item nil))
+
+(cl-defmethod wisi-xref-references ((_xref gnat-xref) project item)
+  (gnat-xref-refs project item t))
+
+(cl-defmethod wisi-xref-other ((_xref gnat-xref) project &key identifier 
filename line column)
+  (let* ((prj-xref (wisi-prj-xref project))
+         (wisi-xref-full-path t)
+        (cmd (gnat-xref-common-cmd project))
+        (args (gnat-xref-common-args project identifier filename line column))
+        (result nil))
+    (with-current-buffer (gnat-run-buffer prj-xref 
(gnat-compiler-run-buffer-name prj-xref))
+      (gnat-run project cmd args)
+
+      (goto-char (point-min))
+      (when gnat-debug-run (forward-line 2)); skip ADA_PROJECT_PATH, 'gnat 
find'
+
+      ;; gnat find returns two items; the starting point, and the 'other' point
+      (unless (looking-at (concat gnat-file-line-col-regexp ":"))
+       ;; no results
+       (error "'%s' not found in cross-reference files; recompile?" 
identifier))
+
+      (while (not result)
+       (looking-at (concat gnat-file-line-col-regexp "\\(: warning:\\)?"))
+       (if (match-string 4)
+           ;; error in *.gpr; ignore here.
+           (forward-line 1)
+         ;; else process line
+         (let ((found-file (match-string 1))
+               (found-line (string-to-number (match-string 2)))
+               (found-col  (string-to-number (match-string 3))))
+           ;; Sometimes gnatfind does not respect "-f" (test/ada_mode.ads 
Separate_Procedure full body)
+           (unless (file-name-absolute-p found-file)
+             (setq found-file (locate-file found-file 
compilation-search-path)))
+
+           (if (not
+                (and
+                 ;; due to symbolic links, only the non-dir filename is 
comparable.
+                 (equal (file-name-nondirectory filename) 
(file-name-nondirectory found-file))
+                 (= line found-line)
+                 (= (gnat-xref-adj-col identifier column) found-col)))
+               ;; Found other item.
+               (setq result (list found-file found-line (1- found-col)))
+             ;; else keep searching
+             (forward-line 1))
+           ))
+
+       (when (eobp)
+         (error "gnat find did not return other item"))
+       ))
+    result))
+
+(cl-defmethod wisi-xref-parents ((_xref gnat-xref) project &key identifier 
filename line column)
+  (let* ((arg (gnat-xref-common-args project identifier filename line column))
+        (result nil))
+    (with-current-buffer (gnat-run-buffer project 
(gnat-compiler-run-buffer-name (wisi-prj-xref project)))
+      (gnat-run project (gnat-xref-common-cmd project) (cons "-d" arg))
+
+      (goto-char (point-min))
+      (when gnat-debug-run (forward-line 2)); skip GPR_PROJECT_PATH, 'gnat 
find'
+
+      ;; gnat find returns two items; the starting point, and the 'other' point
+      (unless (looking-at (concat gnat-file-line-col-regexp ":"))
+       ;; no results
+       (error "'%s' not found in cross-reference files; recompile?" 
identifier))
+
+      (while (not result)
+       (looking-at (concat gnat-file-line-col-regexp "\\(: warning:\\)?"))
+       (if (match-string 4)
+           ;; error in *.gpr; ignore here.
+           (forward-line 1)
+         ;; else process line
+         (skip-syntax-forward "^ ")
+         (skip-syntax-forward " ")
+         (if (looking-at (concat "derived from .* (" gnat-file-line-col-regexp 
")"))
+             ;; found other item
+             (setq result (list (match-string 1)
+                                (string-to-number (match-string 2))
+                                (1- (string-to-number (match-string 3)))))
+           (forward-line 1))
+         )
+       (when (eobp)
+         (error "gnat find did not return parent types"))
+       ))
+
+    (wisi-goto-source (nth 0 result)
+                     (nth 1 result)
+                     (nth 2 result))
+    ))
+
+(cl-defmethod wisi-xref-all ((_xref gnat-xref) project &key identifier 
filename line column local-only append)
+  ;; we use `compilation-start' to run gnat, not `gnat-run', so it
+  ;; is asynchronous, and automatically runs the compilation error
+  ;; filter.
+
+  (let* ((arg (gnat-xref-common-args project identifier filename line column)))
+    (setq arg (cons "-r" arg))
+    (when local-only (setq arg (append arg (list filename))))
+
+    (with-current-buffer (gnat-run-buffer project 
(gnat-compiler-run-buffer-name (wisi-prj-xref project)))
+      (let ((compilation-buffer-name "*gnatfind*")
+            (compilation-error "reference")
+            (command-and-args (mapconcat (lambda (a) (or a ""))
+                                         (cons (gnat-xref-common-cmd project) 
arg)
+                                         " "))
+           ;; gnat find uses standard gnu format for output, so don't
+           ;; need to set compilation-error-regexp-alist
+           prev-pos
+           prev-content)
+
+       ;; compilation-environment is set in `wisi-prj-select'
+
+       ;; WORKAROUND: the 'compilation' API doesn't let us specify "append", 
so we use this.
+       (with-current-buffer (get-buffer-create compilation-buffer-name)
+         (when append
+           (setq prev-pos (point))
+           (setq prev-content (buffer-substring (point-min) (point-max))))
+
+          (unless gnat-debug-run
+           ;; hide the command and arguments using text properties, show only 
the bare minimum
+           (setq command-and-args
+                 (propertize command-and-args
+                             'display
+                             (format "References to %s at %s:%d:%d" identifier 
filename line column))))
+         (compilation-start command-and-args
+                            'compilation-mode
+                            (lambda (_name) compilation-buffer-name))
+         (when append
+           (let ((inhibit-read-only t))
+               (goto-char (point-min))
+               (insert prev-content)
+               (goto-char prev-pos))))
+       ))))
+
+(cl-defmethod wisi-xref-overriding ((_xref gnat-xref) _project &key 
_identifier _filename _line _column)
+  (error "gnat-xref does not support 'show overriding' - use gpr_query?"))
+
+(cl-defmethod wisi-xref-overridden ((_xref gnat-xref) _project &key 
_identifier _filename _line _column)
+  (error "gnat-xref does not support 'show overridden' - use gpr_query?"))
+
+(provide 'gnat-xref)
+;; end of file



reply via email to

[Prev in Thread] Current Thread [Next in Thread]