From 21754206dd68262f3cd03d0ff1b033dadb04f833 Mon Sep 17 00:00:00 2001 From: Camden Dixie O'Brien Date: Fri, 1 Jan 2021 00:00:37 +0000 Subject: [PATCH] Add Ada config --- ada-mode/ada-mode.el | 5493 ++++++++++++++++++++++++++++++++++ ada-mode/ada-prj.el | 682 +++++ ada-mode/ada-stmt.el | 486 +++ ada-mode/ada-xref.el | 2359 +++++++++++++++ ada-mode/doc/ada-mode.html | 2288 ++++++++++++++ ada-mode/doc/ada-mode.info | 1983 ++++++++++++ ada-mode/doc/ada-mode.pdf | Bin 0 -> 303898 bytes ada-mode/doc/ada-mode.texi | 1526 ++++++++++ ada-mode/doc/build.sh | 3 + ada-mode/doc/clean.sh | 2 + ada-mode/doc/doclicense.texi | 505 ++++ ada-mode/doc/docstyle.texi | 19 + config.org | 58 + 13 files changed, 15404 insertions(+) create mode 100644 ada-mode/ada-mode.el create mode 100644 ada-mode/ada-prj.el create mode 100644 ada-mode/ada-stmt.el create mode 100644 ada-mode/ada-xref.el create mode 100644 ada-mode/doc/ada-mode.html create mode 100644 ada-mode/doc/ada-mode.info create mode 100644 ada-mode/doc/ada-mode.pdf create mode 100644 ada-mode/doc/ada-mode.texi create mode 100755 ada-mode/doc/build.sh create mode 100755 ada-mode/doc/clean.sh create mode 100644 ada-mode/doc/doclicense.texi create mode 100644 ada-mode/doc/docstyle.texi diff --git a/ada-mode/ada-mode.el b/ada-mode/ada-mode.el new file mode 100644 index 0000000..4a4e1a7 --- /dev/null +++ b/ada-mode/ada-mode.el @@ -0,0 +1,5493 @@ +;;; ada-mode.el --- major-mode for editing Ada sources + +;; Copyright (C) 1994-1995, 1997-2019 Free Software Foundation, Inc. + +;; Author: Rolf Ebert +;; Markus Heritsch +;; Emmanuel Briot +;; Maintainer: Stephen Leake +;; Keywords: languages ada +;; Version: 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 . + +;;; Commentary: +;; This mode is a major mode for editing Ada code. This is a major +;; rewrite of the file packaged with Emacs-20. The Ada mode is +;; composed of four Lisp files: ada-mode.el, ada-xref.el, ada-prj.el +;; and ada-stmt.el. Only this file (ada-mode.el) is completely +;; independent from the GNU Ada compiler GNAT, distributed by Ada +;; Core Technologies. All the other files rely heavily on features +;; provided only by GNAT. + +;;; Usage: +;; Emacs should enter Ada mode automatically when you load an Ada file. +;; By default, the valid extensions for Ada files are .ads, .adb or .ada +;; If the ada-mode does not start automatically, then simply type the +;; following command : +;; M-x ada-mode +;; +;; By default, ada-mode is configured to take full advantage of the GNAT +;; compiler (the menus will include the cross-referencing features,...). +;; If you are using another compiler, you might want to set the following +;; variable in your .emacs (Note: do not set this in the ada-mode-hook, it +;; won't work) : +;; (setq ada-which-compiler 'generic) +;; +;; This mode requires find-file.el to be present on your system. + +;;; History: +;; The first Ada mode for GNU Emacs was written by V. Broman in +;; 1985. He based his work on the already existing Modula-2 mode. +;; This was distributed as ada.el in versions of Emacs prior to 19.29. +;; +;; Lynn Slater wrote an extensive Ada mode in 1989. It consisted of +;; several files with support for dired commands and other nice +;; things. It is currently available from the PAL +;; (wuarchive.wustl.edu:/languages/ada) as ada-mode-1.06a.tar.Z. +;; +;; The probably very first Ada mode (called electric-ada.el) was +;; written by Steven D. Litvintchouk and Steven M. Rosen for the +;; Gosling Emacs. L. Slater based his development on ada.el and +;; electric-ada.el. +;; +;; A complete rewrite by M. Heritsch and R. Ebert has been done. +;; Some ideas from the Ada mode mailing list have been +;; added. Some of the functionality of L. Slater's mode has not +;; (yet) been recoded in this new mode. Perhaps you prefer sticking +;; to his version. +;; +;; A complete rewrite for Emacs-20 / GNAT-3.11 has been done by Ada Core +;; Technologies. + +;;; Credits: +;; Many thanks to John McCabe for sending so +;; many patches included in this package. +;; Christian Egli : +;; ada-imenu-generic-expression +;; Many thanks also to the following persons that have contributed +;; to the ada-mode +;; Philippe Waroquiers (PW) in particular, +;; woodruff@stc.llnl.gov (John Woodruff) +;; jj@ddci.dk (Jesper Joergensen) +;; gse@ocsystems.com (Scott Evans) +;; comar@gnat.com (Cyrille Comar) +;; stephen.leake@gsfc.nasa.gov (Stephen Leake) +;; robin-reply@reagans.org +;; and others for their valuable hints. + +;;; Code: +;; Note: Every function in this package is compiler-independent. +;; The names start with ada- +;; The variables that the user can edit can all be modified through +;; the customize mode. They are sorted in alphabetical order in this +;; file. + +;; Supported packages. +;; This package supports a number of other Emacs modes. These other modes +;; should be loaded before the ada-mode, which will then setup some variables +;; to improve the support for Ada code. +;; Here is the list of these modes: +;; `which-function-mode': Display in the mode line the name of the subprogram +;; the cursor is in. +;; `outline-mode': Provides the capability to collapse or expand the code +;; for specific language constructs, for instance if you want to hide the +;; code corresponding to a subprogram +;; `align': This mode is now provided with Emacs 21, but can also be +;; installed manually for older versions of Emacs. It provides the +;; capability to automatically realign the selected region (for instance +;; all ':=', ':' and '--' will be aligned on top of each other. +;; `imenu': Provides a menu with the list of entities defined in the current +;; buffer, and an easy way to jump to any of them +;; `speedbar': Provides a separate file browser, and the capability for each +;; file to see the list of entities defined in it and to jump to them +;; easily +;; `abbrev-mode': Provides the capability to define abbreviations, which +;; are automatically expanded when you type them. See the Emacs manual. + +(require 'find-file nil t) +(require 'align nil t) +(require 'which-func nil t) +(require 'compile nil t) + +(defvar ispell-check-comments) +(defvar skeleton-further-elements) + +(define-error 'ada-mode-errors nil) + +(defun ada-mode-version () + "Return Ada mode version." + (interactive) + (let ((version-string "4.00")) + (if (called-interactively-p 'interactive) + (message version-string) + version-string))) + +(defvar ada-mode-hook nil + "List of functions to call when Ada mode is invoked. +This hook is automatically executed after the `ada-mode' is +fully loaded. +This is a good place to add Ada environment specific bindings.") + +(defgroup ada nil + "Major mode for editing and compiling Ada source in Emacs." + :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces) + :link '(custom-manual "(ada-mode) Top") + :link '(emacs-commentary-link :tag "Commentary" "ada-mode.el") + :group 'languages) + +(defcustom ada-auto-case t + "Non-nil means automatically change case of preceding word while typing. +Casing is done according to `ada-case-keyword', `ada-case-identifier' +and `ada-case-attribute'." + :type 'boolean :group 'ada) + +(defcustom ada-broken-decl-indent 0 + "Number of columns to indent a broken declaration. + +An example is : + declare + A, + >>>>>B : Integer;" + :type 'integer :group 'ada) + +(defcustom ada-broken-indent 2 + "Number of columns to indent the continuation of a broken line. + +An example is : + My_Var : My_Type := (Field1 => + >>>>>>>>>Value);" + :type 'integer :group 'ada) + +(defcustom ada-continuation-indent ada-broken-indent + "Number of columns to indent the continuation of broken lines in parenthesis. + +An example is : + Func (Param1, + >>>>>Param2);" + :type 'integer :group 'ada) + +(defcustom ada-case-attribute 'ada-capitalize-word + "Function to call to adjust the case of Ada attributes. +It may be `downcase-word', `upcase-word', `ada-loose-case-word', +`ada-capitalize-word' or `ada-no-auto-case'." + :type '(choice (const downcase-word) + (const upcase-word) + (const ada-capitalize-word) + (const ada-loose-case-word) + (const ada-no-auto-case)) + :group 'ada) + +(defcustom ada-case-exception-file + (list (convert-standard-filename' "~/.emacs_case_exceptions")) + "List of special casing exceptions dictionaries for identifiers. +The first file is the one where new exceptions will be saved by Emacs +when you call `ada-create-case-exception'. + +These files should contain one word per line, that gives the casing +to be used for that word in Ada files. If the line starts with the +character *, then the exception will be used for substrings that either +start at the beginning of a word or after a _ character, and end either +at the end of the word or at a _ character. Each line can be terminated +by a comment." + :type '(repeat (file)) + :group 'ada) + +(defcustom ada-case-keyword 'downcase-word + "Function to call to adjust the case of an Ada keywords. +It may be `downcase-word', `upcase-word', `ada-loose-case-word' or +`ada-capitalize-word'." + :type '(choice (const downcase-word) + (const upcase-word) + (const ada-capitalize-word) + (const ada-loose-case-word) + (const ada-no-auto-case)) + :group 'ada) + +(defcustom ada-case-identifier 'ada-loose-case-word + "Function to call to adjust the case of an Ada identifier. +It may be `downcase-word', `upcase-word', `ada-loose-case-word' or +`ada-capitalize-word'." + :type '(choice (const downcase-word) + (const upcase-word) + (const ada-capitalize-word) + (const ada-loose-case-word) + (const ada-no-auto-case)) + :group 'ada) + +(defcustom ada-clean-buffer-before-saving t + "Non-nil means remove trailing spaces and untabify the buffer before saving." + :type 'boolean :group 'ada) +(make-obsolete-variable 'ada-clean-buffer-before-saving + "it has no effect - use `write-file-functions' hook." + "23.2") + + +(defcustom ada-indent 3 + "Size of Ada indentation. + +An example is : +procedure Foo is +begin +>>>>>>>>>>null;" + :type 'integer :group 'ada) + +(defcustom ada-indent-after-return t + "Non-nil means automatically indent after RET or LFD." + :type 'boolean :group 'ada) + +(defcustom ada-indent-align-comments t + "Non-nil means align comments on previous line comments, if any. +If nil, indentation is calculated as usual. +Note that indentation is calculated only if `ada-indent-comment-as-code' is t. + +For instance: + A := 1; -- A multi-line comment + -- aligned if `ada-indent-align-comments' is t" + :type 'boolean :group 'ada) + +(defcustom ada-indent-comment-as-code t + "Non-nil means indent comment lines as code. +A nil value means do not auto-indent comments." + :type 'boolean :group 'ada) + +(defcustom ada-indent-handle-comment-special nil + "Non-nil if comment lines should be handled specially inside parenthesis. +By default, if the line that contains the open parenthesis has some +text following it, then the following lines will be indented in the +same column as this text. This will not be true if the first line is +a comment and `ada-indent-handle-comment-special' is t. + +type A is + ( Value_1, -- common behavior, when not a comment + Value_2); + +type A is + ( -- `ada-indent-handle-comment-special' is nil + Value_1, + Value_2); + +type A is + ( -- `ada-indent-handle-comment-special' is non-nil + Value_1, + Value_2);" + :type 'boolean :group 'ada) + +(defcustom ada-indent-is-separate t + "Non-nil means indent `is separate' or `is abstract' if on a single line." + :type 'boolean :group 'ada) + +(defcustom ada-indent-record-rel-type 3 + "Indentation for `record' relative to `type' or `use'. + +An example is: + type A is + >>>>>>>>>>>record" + :type 'integer :group 'ada) + +(defcustom ada-indent-renames ada-broken-indent + "Indentation for renames relative to the matching function statement. +If `ada-indent-return' is null or negative, the indentation is done relative to +the open parenthesis (if there is no parenthesis, `ada-broken-indent' is used). + +An example is: + function A (B : Integer) + return C; + >>>renames Foo;" + :type 'integer :group 'ada) + +(defcustom ada-indent-return 0 + "Indentation for `return' relative to the matching `function' statement. +If `ada-indent-return' is null or negative, the indentation is done relative to +the open parenthesis (if there is no parenthesis, `ada-broken-indent' is used). + +An example is: + function A (B : Integer) + >>>>>return C;" + :type 'integer :group 'ada) + +(defcustom ada-indent-to-open-paren t + "Non-nil means indent according to the innermost open parenthesis." + :type 'boolean :group 'ada) + +(defcustom ada-fill-comment-prefix "-- " + "Text inserted in the first columns when filling a comment paragraph. +Note: if you modify this variable, you will have to invoke `ada-mode' +again to take account of the new value." + :type 'string :group 'ada) + +(defcustom ada-fill-comment-postfix " --" + "Text inserted at the end of each line when filling a comment paragraph. +Used by `ada-fill-comment-paragraph-postfix'." + :type 'string :group 'ada) + +(defcustom ada-label-indent -4 + "Number of columns to indent a label. + +An example is: +procedure Foo is +begin +>>>>Label: + +This is also used for <<..>> labels" + :type 'integer :group 'ada) + +(defcustom ada-language-version 'ada95 + "Ada language version; one of `ada83', `ada95', `ada2005'." + :type '(choice (const ada83) (const ada95) (const ada2005)) :group 'ada) + +(defcustom ada-move-to-declaration nil + "Non-nil means `ada-move-to-start' moves to the subprogram declaration, not to `begin'." + :type 'boolean :group 'ada) + +(defcustom ada-popup-key '[down-mouse-3] + "Key used for binding the contextual menu. +If nil, no contextual menu is available." + :type '(restricted-sexp :match-alternatives (stringp vectorp)) + :group 'ada) + +(defcustom ada-search-directories + (append '(".") + (split-string (or (getenv "ADA_INCLUDE_PATH") "") ":") + '("/usr/adainclude" "/usr/local/adainclude" + "/opt/gnu/adainclude")) + "Default list of directories to search for Ada files. +See the description for the `ff-search-directories' variable. This variable +is the initial value of `ada-search-directories-internal'." + :type '(repeat (choice :tag "Directory" + (const :tag "default" nil) + (directory :format "%v"))) + :group 'ada) + +(defvar ada-search-directories-internal ada-search-directories + "Internal version of `ada-search-directories'. +Its value is the concatenation of the search path as read in the project file +and the standard runtime location, and the value of the user-defined +`ada-search-directories'.") + +(defcustom ada-stmt-end-indent 0 + "Number of columns to indent the end of a statement on a separate line. + +An example is: + if A = B + >>>>then" + :type 'integer :group 'ada) + +(defcustom ada-tab-policy 'indent-auto + "Control the behavior of the TAB key. +Must be one of : +`indent-rigidly' : always adds `ada-indent' blanks at the beginning of the line. +`indent-auto' : use indentation functions in this file. +`always-tab' : do `indent-relative'." + :type '(choice (const indent-auto) + (const indent-rigidly) + (const always-tab)) + :group 'ada) + +(defcustom ada-use-indent ada-broken-indent + "Indentation for the lines in a `use' statement. + +An example is: + use Ada.Text_IO, + >>>>Ada.Numerics;" + :type 'integer :group 'ada) + +(defcustom ada-when-indent 3 + "Indentation for `when' relative to `exception' or `case'. + +An example is: + case A is + >>>>when B =>" + :type 'integer :group 'ada) + +(defcustom ada-with-indent ada-broken-indent + "Indentation for the lines in a `with' statement. + +An example is: + with Ada.Text_IO, + >>>>Ada.Numerics;" + :type 'integer :group 'ada) + +(defcustom ada-which-compiler 'gnat + "Name of the compiler to use. +This will determine what features are made available through the Ada mode. +The possible choices are: +`gnat': Use Ada Core Technologies' GNAT compiler. Add some cross-referencing + features. +`generic': Use a generic compiler." + :type '(choice (const gnat) + (const generic)) + :group 'ada) + + +;;; ---- end of user configurable variables + + +(defvar ada-body-suffixes '(".adb") + "List of possible suffixes for Ada body files. +The extensions should include a `.' if needed.") + +(defvar ada-spec-suffixes '(".ads") + "List of possible suffixes for Ada spec files. +The extensions should include a `.' if needed.") + +(defvar ada-mode-menu (make-sparse-keymap "Ada") + "Menu for Ada mode.") + +(defvar ada-mode-map (make-sparse-keymap) + "Local keymap used for Ada mode.") + +(defvar ada-mode-extra-map (make-sparse-keymap) + "Keymap used for non-standard keybindings.") + +;; default is C-c C-q because it's free in ada-mode-map +(defvar ada-mode-extra-prefix "\C-c\C-q" + "Prefix key to access `ada-mode-extra-map' functions.") + +(define-abbrev-table 'ada-mode-abbrev-table () + "Local abbrev table for Ada mode.") + +(eval-when-compile + ;; These values are used in eval-when-compile expressions. + (defconst ada-83-string-keywords + '("abort" "abs" "accept" "access" "all" "and" "array" "at" "begin" + "body" "case" "constant" "declare" "delay" "delta" "digits" "do" + "else" "elsif" "end" "entry" "exception" "exit" "for" "function" + "generic" "goto" "if" "in" "is" "limited" "loop" "mod" "new" + "not" "null" "of" "or" "others" "out" "package" "pragma" "private" + "procedure" "raise" "range" "record" "rem" "renames" "return" + "reverse" "select" "separate" "subtype" "task" "terminate" "then" + "type" "use" "when" "while" "with" "xor") + "List of Ada 83 keywords. +Used to define `ada-*-keywords'.") + + (defconst ada-95-string-keywords + '("abstract" "aliased" "protected" "requeue" "tagged" "until") + "List of keywords new in Ada 95. +Used to define `ada-*-keywords'.") + + (defconst ada-2005-string-keywords + '("interface" "overriding" "synchronized") + "List of keywords new in Ada 2005. +Used to define `ada-*-keywords.'")) + +(defvar ada-ret-binding nil + "Variable to save key binding of RET when casing is activated.") + +(defvar ada-case-exception '() + "Alist of words (entities) that have special casing.") + +(defvar ada-case-exception-substring '() + "Alist of substrings (entities) that have special casing. +The substrings are detected for word constituent when the word +is not itself in `ada-case-exception', and only for substrings that +either are at the beginning or end of the word, or start after `_'.") + +(defvar ada-lfd-binding nil + "Variable to save key binding of LFD when casing is activated.") + +(defvar ada-other-file-alist nil + "Variable used by `find-file' to find the name of the other package. +See `ff-other-file-alist'.") + +(defvar ada-align-list + '(("[^:]\\(\\s-*\\):[^:]" 1 t) + ("[^=]\\(\\s-+\\)=[^=]" 1 t) + ("\\(\\s-*\\)use\\s-" 1) + ("\\(\\s-*\\)--" 1)) + "Ada support for align.el <= 2.2. +This variable provides regular expressions on which to align different lines. +See `align-mode-alist' for more information.") + +(defvar ada-align-modes + '((ada-declaration + (regexp . "[^:]\\(\\s-*\\):[^:]") + (valid . (lambda() (not (ada-in-comment-p)))) + (modes . '(ada-mode))) + (ada-assignment + (regexp . "[^=]\\(\\s-+\\)=[^=]") + (valid . (lambda() (not (ada-in-comment-p)))) + (modes . '(ada-mode))) + (ada-comment + (regexp . "\\(\\s-*\\)--") + (modes . '(ada-mode))) + (ada-use + (regexp . "\\(\\s-*\\)use\\s-") + (valid . (lambda() (not (ada-in-comment-p)))) + (modes . '(ada-mode))) + ) + "Ada support for align.el >= 2.8. +This variable defines several rules to use to align different lines.") + +(defconst ada-align-region-separate + (eval-when-compile + (concat + "^\\s-*\\($\\|\\(" + "begin\\|" + "declare\\|" + "else\\|" + "end\\|" + "exception\\|" + "for\\|" + "function\\|" + "generic\\|" + "if\\|" + "is\\|" + "procedure\\|" + "record\\|" + "return\\|" + "type\\|" + "when" + "\\)\\>\\)")) + "See the variable `align-region-separate' for more information.") + +;;; ---- Below are the regexp used in this package for parsing + +(defconst ada-83-keywords + (eval-when-compile + (concat "\\<" (regexp-opt ada-83-string-keywords t) "\\>")) + "Regular expression matching Ada83 keywords.") + +(defconst ada-95-keywords + (eval-when-compile + (concat "\\<" (regexp-opt + (append + ada-95-string-keywords + ada-83-string-keywords) t) "\\>")) + "Regular expression matching Ada95 keywords.") + +(defconst ada-2005-keywords + (eval-when-compile + (concat "\\<" (regexp-opt + (append + ada-2005-string-keywords + ada-83-string-keywords + ada-95-string-keywords) t) "\\>")) + "Regular expression matching Ada2005 keywords.") + +(defvar ada-keywords ada-2005-keywords + "Regular expression matching Ada keywords.") +;; FIXME: make this customizable + +(defconst ada-ident-re + "[[:alpha:]]\\(?:[_[:alnum:]]\\)*" + ;; [:alnum:] matches any multibyte word constituent, as well as + ;; Latin-1 letters and numbers. This allows __ and trailing _; + ;; someone (emacs bug#1919) proposed [^\W_] to fix that, but \W does + ;; _not_ mean "not word constituent" inside a character alternative. + "Regexp matching an Ada identifier.") + +(defconst ada-goto-label-re + (concat "<<" ada-ident-re ">>") + "Regexp matching a goto label.") + +(defconst ada-block-label-re + (concat ada-ident-re "[ \t\n]*:[^=]") + "Regexp matching a block label. +Note that this also matches a variable declaration.") + +(defconst ada-label-re + (concat "\\(?:" ada-block-label-re "\\)\\|\\(?:" ada-goto-label-re "\\)") + "Regexp matching a goto or block label.") + +;; "with" needs to be included in the regexp, to match generic subprogram parameters +;; Similarly, we put '[not] overriding' on the same line with 'procedure' etc. +(defvar ada-procedure-start-regexp + (concat + "^[ \t]*\\(with[ \t]+\\)?\\(\\(not[ \t]+\\)?overriding[ \t]+\\)?\\(procedure\\|function\\|task\\)[ \t\n]+" + + ;; subprogram name: operator ("[+/=*]") + "\\(" + "\\(\"[^\"]+\"\\)" + + ;; subprogram name: name + "\\|" + "\\(\\(\\sw\\|[_.]\\)+\\)" + "\\)") + "Regexp matching Ada subprogram start. +The actual start is at (match-beginning 4). The name is in (match-string 5).") + +(defconst ada-name-regexp + "\\([a-zA-Z][a-zA-Z0-9_.']*[a-zA-Z0-9]\\)" + "Regexp matching a fully qualified name (including attribute).") + +(defconst ada-package-start-regexp + (concat "^[ \t]*\\(private[ \t]+\\)?\\(package\\)[ \t\n]+\\(body[ \t]*\\)?" ada-name-regexp) + "Regexp matching start of package. +The package name is in (match-string 4).") + +(defconst ada-compile-goto-error-file-linenr-re + "\\([-_.a-zA-Z0-9]+\\):\\([0-9]+\\)\\(:\\([0-9]+\\)\\)?" + "Regexp matching filename:linenr[:column].") + + +;;; ---- regexps for indentation functions + +(defvar ada-block-start-re + (eval-when-compile + (concat "\\<\\(" (regexp-opt '("begin" "declare" "else" + "exception" "generic" "loop" "or" + "private" "select" )) + "\\|\\(\\(limited\\|abstract\\|tagged\\)[ \t\n]+\\)*record\\)\\>")) + "Regexp for keywords starting Ada blocks.") + +(defvar ada-end-stmt-re + (eval-when-compile + (concat "\\(" + ";" "\\|" + "=>[ \t]*$" "\\|" + "=>[ \t]*--.*$" "\\|" + "^[ \t]*separate[ \t]*(\\(\\sw\\|[_.]\\)+)" "\\|" + "\\<" (regexp-opt '("begin" "declare" "is" "do" "else" "generic" + "loop" "private" "record" "select" + "then abort" "then") t) "\\>" "\\|" + "^[ \t]*" (regexp-opt '("function" "package" "procedure") + t) "\\>\\(\\sw\\|[ \t_.]\\)+\\" "\\|" + "^[ \t]*exception\\>" + "\\)") ) + "Regexp of possible ends for a non-broken statement. +A new statement starts after these.") + +(defvar ada-matching-start-re + (eval-when-compile + (concat "\\<" + (regexp-opt + '("end" "loop" "select" "begin" "case" "do" "declare" + "if" "task" "package" "procedure" "function" "record" "protected") t) + "\\>")) + "Regexp used in `ada-goto-matching-start'.") + +(defvar ada-loop-start-re + "\\<\\(for\\|while\\|loop\\)\\>" + "Regexp for the start of a loop.") + +(defvar ada-subprog-start-re + (eval-when-compile + (concat "\\<" (regexp-opt '("accept" "entry" "function" "overriding" "package" "procedure" + "protected" "task") t) "\\>")) + "Regexp for the start of a subprogram.") + +(defvar ada-contextual-menu-on-identifier nil + "Set to true when the right mouse button was clicked on an identifier.") + +(defvar ada-contextual-menu-last-point nil + "Position of point just before displaying the menu. +This is a list (point buffer). +Since `ada-popup-menu' moves the point where the user clicked, the region +is modified. Therefore no command from the menu knows what the user selected +before displaying the contextual menu. +To get the original region, restore the point to this position before +calling `region-end' and `region-beginning'. +Modify this variable if you want to restore the point to another position.") + +(easy-menu-define ada-contextual-menu nil + "Menu to use when the user presses the right mouse button. +The variable `ada-contextual-menu-on-identifier' will be set to t before +displaying the menu if point was on an identifier." + '("Ada" + ["Goto Declaration/Body" ada-point-and-xref + :included ada-contextual-menu-on-identifier] + ["Goto Body" ada-point-and-xref-body + :included ada-contextual-menu-on-identifier] + ["Goto Previous Reference" ada-xref-goto-previous-reference] + ["List References" ada-find-references + :included ada-contextual-menu-on-identifier] + ["List Local References" ada-find-local-references + :included ada-contextual-menu-on-identifier] + ["-" nil nil] + ["Other File" ff-find-other-file] + ["Goto Parent Unit" ada-goto-parent])) + + +;;------------------------------------------------------------------ +;; Support for imenu (see imenu.el) +;;------------------------------------------------------------------ + +(defconst ada-imenu-comment-re "\\([ \t]*--.*\\)?") + +(defconst ada-imenu-subprogram-menu-re + (concat "^[ \t]*\\(overriding[ \t]*\\)?\\(procedure\\|function\\)[ \t\n]+" + "\\(\\(\\sw\\|_\\)+\\)[ \t\n]*\\([ \t\n]\\|([^)]+)" + ada-imenu-comment-re + "\\)[ \t\n]*" + "\\(return[ \t\n]+\\(\\sw\\|[_.]\\)+[ \t\n]*\\)?is[ \t\n]")) + +(defvar ada-imenu-generic-expression + (list + (list nil ada-imenu-subprogram-menu-re 3) + (list "*Specs*" + (concat + "^[ \t]*\\(procedure\\|function\\)[ \t\n]+\\(\\(\\sw\\|_\\)+\\)" + "\\(" + "\\(" ada-imenu-comment-re "[ \t\n]+\\|[ \t\n]*([^)]+)" + ada-imenu-comment-re "\\)";; parameter list or simple space + "\\([ \t\n]*return[ \t\n]+\\(\\sw\\|[_.]\\)+[ \t\n]*\\)?" + "\\)?;") 2) + '("*Tasks*" "^[ \t]*task[ \t]+\\(type[ \t]+\\)?\\(\\(body[ \t]+\\)?\\(\\sw\\|_\\)+\\)" 2) + '("*Type Defs*" "^[ \t]*\\(sub\\)?type[ \t]+\\(\\(\\sw\\|_\\)+\\)" 2) + '("*Protected*" + "^[ \t]*protected[ \t]+\\(type[ \t]+\\)?\\(\\(body[ \t]+\\)?\\(\\sw\\|_\\)+\\)" 2) + '("*Packages*" "^[ \t]*package[ \t]+\\(\\(body[ \t]+\\)?\\(\\sw\\|[_.]\\)+\\)" 1)) + "Imenu generic expression for Ada mode. +See `imenu-generic-expression'. This variable will create several submenus for +each type of entity that can be found in an Ada file.") + + +;;------------------------------------------------------------ +;; Support for compile.el +;;------------------------------------------------------------ + +(defun ada-compile-mouse-goto-error () + "Mouse interface for `ada-compile-goto-error'." + (interactive) + (mouse-set-point last-input-event) + (ada-compile-goto-error (point)) + ) + +(defun ada-compile-goto-error (pos) + "Replace `compile-goto-error' from compile.el. +If POS is on a file and line location, go to this position. It adds +to compile.el the capacity to go to a reference in an error message. +For instance, on these lines: + foo.adb:61:11: [...] in call to size declared at foo.ads:11 + foo.adb:61:11: [...] in call to local declared at line 20 +the 4 file locations can be clicked on and jumped to." + (interactive "d") + (goto-char pos) + + (skip-chars-backward "-a-zA-Z0-9_:./\\\\") + (cond + ;; special case: looking at a filename:line not at the beginning of a line + ;; or a simple line reference "at line ..." + ((and (not (bolp)) + (or (looking-at ada-compile-goto-error-file-linenr-re) + (and + (save-excursion + (beginning-of-line) + (looking-at ada-compile-goto-error-file-linenr-re)) + (save-excursion + (if (looking-at "\\([0-9]+\\)") (backward-word-strictly 1)) + (looking-at "line \\([0-9]+\\)")))) + ) + (let ((line (if (match-beginning 2) (match-string 2) (match-string 1))) + (file (if (match-beginning 2) (match-string 1) + (save-excursion (beginning-of-line) + (looking-at ada-compile-goto-error-file-linenr-re) + (match-string 1)))) + (error-pos (point-marker)) + source) + + ;; set source marker + (save-excursion + (compilation-find-file (point-marker) (match-string 1) "./") + (set-buffer file) + + (when (stringp line) + (goto-char (point-min)) + (forward-line (1- (string-to-number line)))) + + (setq source (point-marker))) + + (compilation-goto-locus error-pos source nil) + + )) + + ;; otherwise, default behavior + (t + (compile-goto-error)) + ) + (recenter)) + + +;;------------------------------------------------------------------------- +;; Grammar related function +;; The functions below work with the syntax class of the characters in an Ada +;; buffer. Two syntax tables are created, depending on whether we want '_' +;; to be considered as part of a word or not. +;; Some characters may have multiple meanings depending on the context: +;; - ' is either the beginning of a constant character or an attribute +;; - # is either part of a based literal or a gnatprep statement. +;; - " starts a string, but not if inside a constant character. +;; - ( and ) should be ignored if inside a constant character. +;; Thus their syntax property is changed automatically, and we can still use +;; the standard Emacs functions for sexp (see `ada-in-string-p') +;; +;; On Emacs, this is done through the `syntax-table' text property. The +;; corresponding action is applied automatically each time the buffer +;; changes via syntax-propertize-function. +;; +;; on XEmacs, the `syntax-table' property does not exist and we have to use a +;; slow advice to `parse-partial-sexp' to do the same thing. +;; When executing parse-partial-sexp, we simply modify the strings before and +;; after, so that the special constants '"', '(' and ')' do not interact +;; with parse-partial-sexp. +;; Note: this code is slow and needs to be rewritten as soon as something +;; better is available on XEmacs. +;;------------------------------------------------------------------------- + +(defvar ada-mode-syntax-table + (let ((st (make-syntax-table))) + ;; Define string brackets (`%' is alternative string bracket, but + ;; almost never used as such and throws font-lock and indentation + ;; off the track.) + (modify-syntax-entry ?% "$" st) + (modify-syntax-entry ?\" "\"" st) + + (modify-syntax-entry ?: "." st) + (modify-syntax-entry ?\; "." st) + (modify-syntax-entry ?& "." st) + (modify-syntax-entry ?\| "." st) + (modify-syntax-entry ?+ "." st) + (modify-syntax-entry ?* "." st) + (modify-syntax-entry ?/ "." st) + (modify-syntax-entry ?= "." st) + (modify-syntax-entry ?< "." st) + (modify-syntax-entry ?> "." st) + (modify-syntax-entry ?$ "." st) + (modify-syntax-entry ?\[ "." st) + (modify-syntax-entry ?\] "." st) + (modify-syntax-entry ?\{ "." st) + (modify-syntax-entry ?\} "." st) + (modify-syntax-entry ?. "." st) + (modify-syntax-entry ?\\ "." st) + (modify-syntax-entry ?\' "." st) + + ;; A single hyphen is punctuation, but a double hyphen starts a comment. + (modify-syntax-entry ?- ". 12" st) + + ;; See the comment above on grammar related function for the special + ;; setup for '#'. + (modify-syntax-entry ?# (if (featurep 'xemacs) "<" "$") st) + + ;; And \f and \n end a comment. + (modify-syntax-entry ?\f "> " st) + (modify-syntax-entry ?\n "> " st) + + ;; Define what belongs in Ada symbols. + (modify-syntax-entry ?_ "_" st) + + ;; Define parentheses to match. + (modify-syntax-entry ?\( "()" st) + (modify-syntax-entry ?\) ")(" st) + st) + "Syntax table to be used for editing Ada source code.") + +(defvar ada-mode-symbol-syntax-table + (let ((st (make-syntax-table ada-mode-syntax-table))) + (modify-syntax-entry ?_ "w" st) + st) + "Syntax table for Ada, where `_' is a word constituent.") + +;; Support of special characters in XEmacs (see the comments at the beginning +;; of the section on Grammar related functions). + +(if (featurep 'xemacs) + (defadvice parse-partial-sexp (around parse-partial-sexp-protect-constants) + "Handles special character constants and gnatprep statements." + (let (change) + (if (< to from) + (let ((tmp from)) + (setq from to to tmp))) + (save-excursion + (goto-char from) + (while (re-search-forward "'\\([(\")#]\\)'" to t) + (setq change (cons (list (match-beginning 1) + 1 + (match-string 1)) + change)) + (replace-match "'A'")) + (goto-char from) + (while (re-search-forward "\\(#[[:xdigit:]]*#\\)" to t) + (setq change (cons (list (match-beginning 1) + (length (match-string 1)) + (match-string 1)) + change)) + (replace-match (make-string (length (match-string 1)) ?@)))) + ad-do-it + (save-excursion + (while change + (goto-char (caar change)) + (delete-char (cadar change)) + (insert (caddar change)) + (setq change (cdr change))))))) + +(unless (eval-when-compile (fboundp 'syntax-propertize-via-font-lock)) + ;; Before `syntax-propertize', we had to use font-lock to apply syntax-table + ;; properties, and in some cases we even had to do it manually (in + ;; `ada-after-change-function'). `ada-handle-syntax-table-properties' + ;; decides which method to use. + +(defun ada-set-syntax-table-properties () + "Assign `syntax-table' properties in accessible part of buffer. +In particular, character constants are said to be strings, #...# +are treated as numbers instead of gnatprep comments." + (let ((modified (buffer-modified-p)) + (buffer-undo-list t) + (inhibit-read-only t) + (inhibit-point-motion-hooks t) + (inhibit-modification-hooks t)) + (remove-text-properties (point-min) (point-max) '(syntax-table nil)) + (goto-char (point-min)) + (while (re-search-forward + ;; The following regexp was adapted from + ;; `ada-font-lock-syntactic-keywords'. + "^[ \t]*\\(#\\(?:if\\|else\\|elsif\\|end\\)\\)\\|[^a-zA-Z0-9)]\\('\\)[^'\n]\\('\\)" + nil t) + (if (match-beginning 1) + (put-text-property + (match-beginning 1) (match-end 1) 'syntax-table '(11 . ?\n)) + (put-text-property + (match-beginning 2) (match-end 2) 'syntax-table '(7 . ?')) + (put-text-property + (match-beginning 3) (match-end 3) 'syntax-table '(7 . ?')))) + (unless modified + (restore-buffer-modified-p nil)))) + +(defun ada-after-change-function (beg end _old-len) + "Called when the region between BEG and END was changed in the buffer. +OLD-LEN indicates what the length of the replaced text was." + (save-excursion + (save-restriction + (let ((from (progn (goto-char beg) (line-beginning-position))) + (to (progn (goto-char end) (line-end-position)))) + (narrow-to-region from to) + (save-match-data + (ada-set-syntax-table-properties)))))) + +(defun ada-initialize-syntax-table-properties () + "Assign `syntax-table' properties in current buffer." + (save-excursion + (save-restriction + (widen) + (save-match-data + (ada-set-syntax-table-properties)))) + (add-hook 'after-change-functions 'ada-after-change-function nil t)) + +(defun ada-handle-syntax-table-properties () + "Handle `syntax-table' properties." + (if font-lock-mode + ;; `font-lock-mode' will take care of `syntax-table' properties. + (remove-hook 'after-change-functions 'ada-after-change-function t) + ;; Take care of `syntax-table' properties manually. + (ada-initialize-syntax-table-properties))) + +) ;;(not (fboundp 'syntax-propertize)) + +;;------------------------------------------------------------------ +;; Testing the grammatical context +;;------------------------------------------------------------------ + +(defsubst ada-in-comment-p (&optional parse-result) + "Return t if inside a comment. +If PARSE-RESULT is non-nil, use it instead of calling `parse-partial-sexp'." + (nth 4 (or parse-result + (parse-partial-sexp + (line-beginning-position) (point))))) + +(defsubst ada-in-string-p (&optional parse-result) + "Return t if point is inside a string. +If PARSE-RESULT is non-nil, use it instead of calling `parse-partial-sexp'." + (nth 3 (or parse-result + (parse-partial-sexp + (line-beginning-position) (point))))) + +(defsubst ada-in-string-or-comment-p (&optional parse-result) + "Return t if inside a comment or string. +If PARSE-RESULT is non-nil, use it instead of calling `parse-partial-sexp'." + (setq parse-result (or parse-result + (parse-partial-sexp + (line-beginning-position) (point)))) + (or (ada-in-string-p parse-result) (ada-in-comment-p parse-result))) + +(defsubst ada-in-numeric-literal-p () + "Return t if point is after a prefix of a numeric literal." + (looking-back "\\([0-9]+#[[:xdigit:]_]+\\)" (line-beginning-position))) + +;;------------------------------------------------------------------ +;; Contextual menus +;; The Ada mode comes with contextual menus, bound by default to the right +;; mouse button. +;; Add items to this menu by modifying `ada-contextual-menu'. Note that the +;; variable `ada-contextual-menu-on-identifier' is set automatically to t +;; if the mouse button was pressed on an identifier. +;;------------------------------------------------------------------ + +(defun ada-call-from-contextual-menu (function) + "Execute FUNCTION when called from the contextual menu. +It forces Emacs to change the cursor position." + (interactive) + (funcall function) + (setq ada-contextual-menu-last-point + (list (point) (current-buffer)))) + +(defun ada-popup-menu (position) + "Pops up a contextual menu, depending on where the user clicked. +POSITION is the location the mouse was clicked on. +Sets `ada-contextual-menu-last-point' to the current position before +displaying the menu. When a function from the menu is called, the +point is where the mouse button was clicked." + (interactive "e") + + ;; declare this as a local variable, so that the function called + ;; in the contextual menu does not hide the region in + ;; transient-mark-mode. + (let ((deactivate-mark nil)) + (setq ada-contextual-menu-last-point + (list (point) (current-buffer))) + (mouse-set-point last-input-event) + + (setq ada-contextual-menu-on-identifier + (and (char-after) + (or (= (char-syntax (char-after)) ?w) + (= (char-after) ?_)) + (not (ada-in-string-or-comment-p)) + (save-excursion (skip-syntax-forward "w") + (not (ada-after-keyword-p))) + )) + (if (fboundp 'popup-menu) + (funcall (symbol-function 'popup-menu) ada-contextual-menu) + (let (choice) + (setq choice (x-popup-menu position ada-contextual-menu)) + (if choice + (funcall (lookup-key ada-contextual-menu (vector (car choice))))))) + + (set-buffer (cadr ada-contextual-menu-last-point)) + (goto-char (car ada-contextual-menu-last-point)) + )) + + +;;------------------------------------------------------------------ +;; Misc functions +;;------------------------------------------------------------------ + +;;;###autoload +(defun ada-add-extensions (spec body) + "Define SPEC and BODY as being valid extensions for Ada files. +Going from body to spec with `ff-find-other-file' used these +extensions. +SPEC and BODY are two regular expressions that must match against +the file name." + (let* ((reg (concat (regexp-quote body) "$")) + (tmp (assoc reg ada-other-file-alist))) + (if tmp + (setcdr tmp (list (cons spec (cadr tmp)))) + (add-to-list 'ada-other-file-alist (list reg (list spec))))) + + (let* ((reg (concat (regexp-quote spec) "$")) + (tmp (assoc reg ada-other-file-alist))) + (if tmp + (setcdr tmp (list (cons body (cadr tmp)))) + (add-to-list 'ada-other-file-alist (list reg (list body))))) + + (add-to-list 'auto-mode-alist + (cons (concat (regexp-quote spec) "\\'") 'ada-mode)) + (add-to-list 'auto-mode-alist + (cons (concat (regexp-quote body) "\\'") 'ada-mode)) + + (add-to-list 'ada-spec-suffixes spec) + (add-to-list 'ada-body-suffixes body) + + ;; Support for speedbar (Specifies that we want to see these files in + ;; speedbar) + (if (fboundp 'speedbar-add-supported-extension) + (progn + (funcall (symbol-function 'speedbar-add-supported-extension) + spec) + (funcall (symbol-function 'speedbar-add-supported-extension) + body)))) + +(defvar ada-font-lock-syntactic-keywords) ; defined below + +;;;###autoload +(define-derived-mode ada-mode prog-mode "Ada" + "Ada mode is the major mode for editing Ada code." + + ;; Set the paragraph delimiters so that one can select a whole block + ;; simply with M-h + (set (make-local-variable 'paragraph-start) "[ \t\n\f]*$") + (set (make-local-variable 'paragraph-separate) "[ \t\n\f]*$") + + ;; comment end must be set because it may hold a wrong value if + ;; this buffer had been in another mode before. RE + (set (make-local-variable 'comment-end) "") + + ;; used by autofill and indent-new-comment-line + (set (make-local-variable 'comment-start-skip) "---*[ \t]*") + + ;; used by autofill to break a comment line and continue it on another line. + ;; The reason we need this one is that the default behavior does not work + ;; correctly with the definition of paragraph-start above when the comment + ;; is right after a multi-line subprogram declaration (the comments are + ;; aligned under the latest parameter, not under the declaration start). + (set (make-local-variable 'comment-line-break-function) + (lambda (&optional soft) (let ((fill-prefix nil)) + (indent-new-comment-line soft)))) + + (set (make-local-variable 'indent-line-function) + 'ada-indent-current-function) + + (set (make-local-variable 'comment-column) 40) + + ;; Emacs 20.3 defines a comment-padding to insert spaces between + ;; the comment and the text. We do not want any, this is already + ;; included in comment-start + (unless (featurep 'xemacs) + (set (make-local-variable 'parse-sexp-ignore-comments) t) + (set (make-local-variable 'comment-padding) 0) + (set (make-local-variable 'parse-sexp-lookup-properties) t)) + + (setq case-fold-search t) + (if (boundp 'imenu-case-fold-search) + (setq imenu-case-fold-search t)) + + (set (make-local-variable 'fill-paragraph-function) + 'ada-fill-comment-paragraph) + + ;; Support for compile.el + ;; We just substitute our own functions to go to the error. + (add-hook 'compilation-mode-hook + (lambda() + ;; FIXME: This has global impact! -stef + (define-key compilation-minor-mode-map [mouse-2] + 'ada-compile-mouse-goto-error) + (define-key compilation-minor-mode-map "\C-c\C-c" + 'ada-compile-goto-error) + (define-key compilation-minor-mode-map "\C-m" + 'ada-compile-goto-error))) + + ;; font-lock support : + + (set (make-local-variable 'font-lock-defaults) + '(ada-font-lock-keywords + nil t + ((?\_ . "w") (?# . ".")) + beginning-of-line)) + + (if (eval-when-compile (fboundp 'syntax-propertize-via-font-lock)) + (set (make-local-variable 'syntax-propertize-function) + (syntax-propertize-via-font-lock ada-font-lock-syntactic-keywords)) + (set (make-local-variable 'font-lock-syntactic-keywords) + ada-font-lock-syntactic-keywords)) + + ;; Set up support for find-file.el. + (set (make-local-variable 'ff-other-file-alist) + 'ada-other-file-alist) + (set (make-local-variable 'ff-search-directories) + 'ada-search-directories-internal) + (setq ff-post-load-hook 'ada-set-point-accordingly + ff-file-created-hook 'ada-make-body) + (add-hook 'ff-pre-load-hook 'ada-which-function-are-we-in) + + (make-local-variable 'ff-special-constructs) + (mapc (lambda (pair) (add-to-list 'ff-special-constructs pair)) + (list + ;; Top level child package declaration; go to the parent package. + (cons (eval-when-compile + (concat "^\\(private[ \t]\\)?[ \t]*package[ \t]+" + "\\(body[ \t]+\\)?" + "\\(\\(\\sw\\|[_.]\\)+\\)\\.\\(\\sw\\|_\\)+[ \t\n]+is")) + (lambda () + (ff-get-file + ada-search-directories-internal + (ada-make-filename-from-adaname (match-string 3)) + ada-spec-suffixes))) + + ;; A "separate" clause. + (cons "^separate[ \t\n]*(\\(\\(\\sw\\|[_.]\\)+\\))" + (lambda () + (ff-get-file + ada-search-directories-internal + (ada-make-filename-from-adaname (match-string 1)) + ada-spec-suffixes))) + + ;; A "with" clause. + (cons "^with[ \t]+\\([a-zA-Z0-9_\\.]+\\)" + (lambda () + (ff-get-file + ada-search-directories-internal + (ada-make-filename-from-adaname (match-string 1)) + ada-spec-suffixes))) + )) + + ;; Support for outline-minor-mode + (set (make-local-variable 'outline-regexp) + "\\([ \t]*\\(procedure\\|function\\|package\\|if\\|while\\|for\\|declare\\|case\\|end\\|begin\\|loop\\)\\|--\\)") + (set (make-local-variable 'outline-level) 'ada-outline-level) + + ;; Support for imenu : We want a sorted index + (setq imenu-generic-expression ada-imenu-generic-expression) + + (setq imenu-sort-function 'imenu--sort-by-name) + + ;; Support for ispell : Check only comments + (set (make-local-variable 'ispell-check-comments) 'exclusive) + + ;; Support for align + (add-to-list 'align-dq-string-modes 'ada-mode) + (add-to-list 'align-open-comment-modes 'ada-mode) + (set (make-local-variable 'align-region-separate) ada-align-region-separate) + + ;; Exclude comments alone on line from alignment. + (add-to-list 'align-exclude-rules-list + '(ada-solo-comment + (regexp . "^\\(\\s-*\\)--") + (modes . '(ada-mode)))) + (add-to-list 'align-exclude-rules-list + '(ada-solo-use + (regexp . "^\\(\\s-*\\)\\") + (modes . '(ada-mode)))) + + (setq ada-align-modes nil) + + (add-to-list 'ada-align-modes + '(ada-declaration-assign + (regexp . "[^:]\\(\\s-*\\):[^:]") + (valid . (lambda() (not (ada-in-comment-p)))) + (repeat . t) + (modes . '(ada-mode)))) + (add-to-list 'ada-align-modes + '(ada-associate + (regexp . "[^=]\\(\\s-*\\)=>") + (valid . (lambda() (not (ada-in-comment-p)))) + (modes . '(ada-mode)))) + (add-to-list 'ada-align-modes + '(ada-comment + (regexp . "\\(\\s-*\\)--") + (modes . '(ada-mode)))) + (add-to-list 'ada-align-modes + '(ada-use + (regexp . "\\(\\s-*\\)\\") + (modes . '(ada-mode)))) + + (setq align-mode-rules-list ada-align-modes) + + ;; Set up the contextual menu + (if ada-popup-key + (define-key ada-mode-map ada-popup-key 'ada-popup-menu)) + + ;; Support for Abbreviations (the user still needs to "M-x abbrev-mode"). + (setq local-abbrev-table ada-mode-abbrev-table) + + ;; Support for which-function mode + (set (make-local-variable 'which-func-functions) '(ada-which-function)) + + ;; Support for indent-new-comment-line (Especially for XEmacs) + (set (make-local-variable 'comment-multi-line) nil) + + ;; Support for add-log + (set (make-local-variable 'add-log-current-defun-function) + 'ada-which-function) + + (easy-menu-add ada-mode-menu ada-mode-map) + + (set (make-local-variable 'skeleton-further-elements) + '((< '(backward-delete-char-untabify + (min ada-indent (current-column)))))) + (add-hook 'skeleton-end-hook 'ada-adjust-case-skeleton nil t) + + ;; To be run after the hook, in case the user modified + ;; ada-fill-comment-prefix + (add-hook 'hack-local-variables-hook + (lambda () + (set (make-local-variable 'comment-start) + (or ada-fill-comment-prefix "-- ")) + + ;; Run this after the hook to give the users a chance + ;; to activate font-lock-mode. + + (unless (or (eval-when-compile (fboundp 'syntax-propertize-via-font-lock)) + (featurep 'xemacs)) + (ada-initialize-syntax-table-properties) + (add-hook 'font-lock-mode-hook + 'ada-handle-syntax-table-properties nil t)) + + ;; FIXME: ada-language-version might be set in the mode + ;; hook or it might even be set later on via file-local + ;; vars, so ada-keywords should be set lazily. + (cond ((eq ada-language-version 'ada83) + (setq ada-keywords ada-83-keywords)) + ((eq ada-language-version 'ada95) + (setq ada-keywords ada-95-keywords)) + ((eq ada-language-version 'ada2005) + (setq ada-keywords ada-2005-keywords))) + + (if ada-auto-case + (ada-activate-keys-for-case))) + nil 'local)) + +(defun ada-adjust-case-skeleton () + "Adjust the case of the text inserted by a skeleton." + (save-excursion + (let ((aa-end (point))) + (ada-adjust-case-region + (progn (goto-char (symbol-value 'beg)) (forward-word-strictly -1) + (point)) + (goto-char aa-end))))) + +(defun ada-region-selected () + "Should we operate on an active region?" + (if (fboundp 'use-region-p) + (use-region-p) + (region-active-p))) + +;;----------------------------------------------------------------- +;; auto-casing +;; Since Ada is case-insensitive, the Ada mode provides an extensive set of +;; functions to auto-case identifiers, keywords, ... +;; The basic rules for autocasing are defined through the variables +;; `ada-case-attribute', `ada-case-keyword' and `ada-case-identifier'. These +;; are references to the functions that will do the actual casing. +;; +;; However, in most cases, the user will want to define some exceptions to +;; these casing rules. This is done through a list of files, that contain +;; one word per line. These files are stored in `ada-case-exception-file'. +;; For backward compatibility, this variable can also be a string. +;;----------------------------------------------------------------- + +(defun ada-save-exceptions-to-file (file-name) + "Save the casing exception lists to the file FILE-NAME. +Casing exception lists are `ada-case-exception' and `ada-case-exception-substring'." + (find-file (expand-file-name file-name)) + (erase-buffer) + (mapc (lambda (x) (insert (car x) "\n")) + (sort (copy-sequence ada-case-exception) + (lambda(a b) (string< (car a) (car b))))) + (mapc (lambda (x) (insert "*" (car x) "\n")) + (sort (copy-sequence ada-case-exception-substring) + (lambda(a b) (string< (car a) (car b))))) + (save-buffer) + (kill-buffer nil) + ) + +(defun ada-create-case-exception (&optional word) + "Define WORD as an exception for the casing system. +If WORD is not given, then the current word in the buffer is used instead. +The new word is added to the first file in `ada-case-exception-file'. +The standard casing rules will no longer apply to this word." + (interactive) + (let ((file-name + (cond ((stringp ada-case-exception-file) + ada-case-exception-file) + ((listp ada-case-exception-file) + (car ada-case-exception-file)) + (t + (error (concat "No exception file specified. " + "See variable ada-case-exception-file")))))) + + (unless word + (with-syntax-table ada-mode-symbol-syntax-table + (save-excursion + (skip-syntax-backward "w") + (setq word (buffer-substring-no-properties + (point) (save-excursion (forward-word-strictly 1) + (point))))))) + + ;; Reread the exceptions file, in case it was modified by some other, + (ada-case-read-exceptions-from-file file-name) + + ;; If the word is already in the list, even with a different casing + ;; we simply want to replace it. + (if (and (not (equal ada-case-exception '())) + (assoc-string word ada-case-exception t)) + (setcar (assoc-string word ada-case-exception t) word) + (add-to-list 'ada-case-exception (cons word t))) + + (ada-save-exceptions-to-file file-name))) + +(defun ada-create-case-exception-substring (&optional word) + "Define the substring WORD as an exception for the casing system. +If WORD is not given, then the current word in the buffer is used instead, +or the selected region if any is active. +The new word is added to the first file in `ada-case-exception-file'. +When auto-casing a word, this substring will be special-cased, unless the +word itself has a special casing." + (interactive) + (let ((file-name + (cond ((stringp ada-case-exception-file) + ada-case-exception-file) + ((listp ada-case-exception-file) + (car ada-case-exception-file)) + (t + (error (concat "No exception file specified. " + "See variable ada-case-exception-file")))))) + + ;; Find the substring to define as an exception. Order is: the parameter, + ;; if any, or the selected region, or the word under the cursor + (cond + (word nil) + + ((ada-region-selected) + (setq word (buffer-substring-no-properties + (region-beginning) (region-end)))) + + (t + (let ((underscore-syntax (char-syntax ?_))) + (unwind-protect + (progn + (modify-syntax-entry ?_ "." (syntax-table)) + (save-excursion + (skip-syntax-backward "w") + (setq word (buffer-substring-no-properties + (point) + (save-excursion (forward-word-strictly 1) + (point)))))) + (modify-syntax-entry ?_ (make-string 1 underscore-syntax) + (syntax-table)))))) + + ;; Reread the exceptions file, in case it was modified by some other, + (ada-case-read-exceptions-from-file file-name) + + ;; If the word is already in the list, even with a different casing + ;; we simply want to replace it. + (if (and (not (equal ada-case-exception-substring '())) + (assoc-string word ada-case-exception-substring t)) + (setcar (assoc-string word ada-case-exception-substring t) word) + (add-to-list 'ada-case-exception-substring (cons word t)) + ) + + (ada-save-exceptions-to-file file-name) + + (message "%s" (concat "Defining " word " as a casing exception")))) + +(defun ada-case-read-exceptions-from-file (file-name) + "Read the content of the casing exception file FILE-NAME." + (if (file-readable-p (expand-file-name file-name)) + (let ((buffer (current-buffer))) + (find-file (expand-file-name file-name)) + (set-syntax-table ada-mode-symbol-syntax-table) + (widen) + (goto-char (point-min)) + (while (not (eobp)) + + ;; If the item is already in the list, even with an other casing, + ;; do not add it again. This way, the user can easily decide which + ;; priority should be applied to each casing exception + (let ((word (buffer-substring-no-properties + (point) (save-excursion (forward-word-strictly 1) + (point))))) + + ;; Handling a substring ? + (if (char-equal (string-to-char word) ?*) + (progn + (setq word (substring word 1)) + (unless (assoc-string word ada-case-exception-substring t) + (add-to-list 'ada-case-exception-substring (cons word t)))) + (unless (assoc-string word ada-case-exception t) + (add-to-list 'ada-case-exception (cons word t))))) + + (forward-line 1)) + (kill-buffer nil) + (set-buffer buffer))) + ) + +(defun ada-case-read-exceptions () + "Read all the casing exception files from `ada-case-exception-file'." + (interactive) + + ;; Reinitialize the casing exception list + (setq ada-case-exception '() + ada-case-exception-substring '()) + + (cond ((stringp ada-case-exception-file) + (ada-case-read-exceptions-from-file ada-case-exception-file)) + + ((listp ada-case-exception-file) + (mapcar 'ada-case-read-exceptions-from-file + ada-case-exception-file)))) + +(defun ada-adjust-case-substring () + "Adjust case of substrings in the previous word." + (interactive) + (let ((substrings ada-case-exception-substring) + (max (point)) + (case-fold-search t) + (underscore-syntax (char-syntax ?_)) + re) + + (save-excursion + (forward-word -1) + + (unwind-protect + (progn + (modify-syntax-entry ?_ "." (syntax-table)) + + (while substrings + (setq re (concat "\\b" (regexp-quote (caar substrings)) "\\b")) + + (save-excursion + (while (re-search-forward re max t) + (replace-match (caar substrings) t))) + (setq substrings (cdr substrings)) + ) + ) + (modify-syntax-entry ?_ (make-string 1 underscore-syntax) (syntax-table))) + ))) + +(defun ada-adjust-case-identifier () + "Adjust case of the previous identifier. +The auto-casing is done according to the value of `ada-case-identifier' +and the exceptions defined in `ada-case-exception-file'." + (interactive) + (if (or (equal ada-case-exception '()) + (equal (char-after) ?_)) + (progn + (funcall ada-case-identifier -1) + (ada-adjust-case-substring)) + + (progn + (let ((end (point)) + (start (save-excursion (skip-syntax-backward "w") + (point))) + match) + ;; If we have an exception, replace the word by the correct casing + (if (setq match (assoc-string (buffer-substring start end) + ada-case-exception t)) + + (progn + (delete-region start end) + (insert (car match))) + + ;; Else simply re-case the word + (funcall ada-case-identifier -1) + (ada-adjust-case-substring)))))) + +(defun ada-after-keyword-p () + "Return t if cursor is after a keyword that is not an attribute." + (save-excursion + (forward-word-strictly -1) + (and (not (and (char-before) + (or (= (char-before) ?_) + (= (char-before) ?'))));; unless we have a _ or ' + (looking-at (concat ada-keywords "[^_]"))))) + +(defun ada-adjust-case (&optional force-identifier) + "Adjust the case of the word before the character just typed. +If FORCE-IDENTIFIER is non-nil then also adjust keyword as identifier." + (if (not (bobp)) + (progn + (forward-char -1) + (if (and (not (bobp)) + ;; or if at the end of a character constant + (not (and (eq (following-char) ?') + (eq (char-before (1- (point))) ?'))) + ;; or if the previous character was not part of a word + (eq (char-syntax (char-before)) ?w) + ;; if in a string or a comment + (not (ada-in-string-or-comment-p)) + ;; if in a numeric literal + (not (ada-in-numeric-literal-p)) + ) + (if (save-excursion + (forward-word -1) + (or (= (point) (point-min)) + (backward-char 1)) + (= (following-char) ?')) + (funcall ada-case-attribute -1) + (if (and + (not force-identifier) ; (MH) + (ada-after-keyword-p)) + (funcall ada-case-keyword -1) + (ada-adjust-case-identifier)))) + (forward-char 1) + )) + ) + +(defun ada-adjust-case-interactive (arg) + "Adjust the case of the previous word, and process the character just typed. +ARG is the prefix the user entered with \\[universal-argument]." + (interactive "P") + + (if ada-auto-case + (let ((lastk last-command-event)) + + (with-syntax-table ada-mode-symbol-syntax-table + (cond ((memq lastk '(?\n ?\r)) + ;; Horrible kludge. + (insert " ") + (ada-adjust-case) + ;; horrible dekludge + (delete-char -1) + ;; some special keys and their bindings + (cond + ((eq lastk ?\n) + (funcall ada-lfd-binding)) + ((eq lastk ?\r) + (funcall ada-ret-binding)))) + ((eq lastk ?\C-i) (ada-tab)) + ;; Else just insert the character + ((self-insert-command (prefix-numeric-value arg)))) + ;; if there is a keyword in front of the underscore + ;; then it should be part of an identifier (MH) + (if (eq lastk ?_) + (ada-adjust-case t) + (ada-adjust-case)))) + + ;; Else, no auto-casing + (cond + ((eq last-command-event ?\n) + (funcall ada-lfd-binding)) + ((eq last-command-event ?\r) + (funcall ada-ret-binding)) + (t + (self-insert-command (prefix-numeric-value arg)))))) + +(defun ada-activate-keys-for-case () + ;; FIXME: Use post-self-insert-hook instead of changing key bindings. + "Modify the key bindings for all the keys that should readjust the casing." + (interactive) + ;; Save original key-bindings to allow swapping ret/lfd + ;; when casing is activated. + ;; The 'or ...' is there to be sure that the value will not + ;; be changed again when Ada mode is called more than once + (or ada-ret-binding (setq ada-ret-binding (key-binding "\C-M"))) + (or ada-lfd-binding (setq ada-lfd-binding (key-binding "\C-j"))) + + ;; Call case modifying function after certain keys. + (mapcar (function (lambda(key) (define-key + ada-mode-map + (char-to-string key) + 'ada-adjust-case-interactive))) + '( ?` ?_ ?# ?% ?& ?* ?\( ?\) ?- ?= ?+ + ?| ?\; ?: ?' ?\" ?< ?, ?. ?> ?/ ?\n 32 ?\r ))) + +(defun ada-loose-case-word (&optional _arg) + "Upcase first letter and letters following `_' in the following word. +No other letter is modified. +ARG is ignored, and is there for compatibility with `capitalize-word' only." + (interactive) + (save-excursion + (let ((end (save-excursion (skip-syntax-forward "w") (point))) + (first t)) + (skip-syntax-backward "w") + (while (and (or first (search-forward "_" end t)) + (< (point) end)) + (and first + (setq first nil)) + (insert-char (upcase (following-char)) 1) + (delete-char 1))))) + +(defun ada-no-auto-case (&optional _arg) + "Do nothing. ARG is ignored. +This function can be used for the auto-casing variables in Ada mode, to +adapt to unusual auto-casing schemes. Since it does nothing, you can for +instance use it for `ada-case-identifier' if you don't want any special +auto-casing for identifiers, whereas keywords have to be lower-cased. +See also `ada-auto-case' to disable auto casing altogether." + nil) + +(defun ada-capitalize-word (&optional _arg) + "Upcase first letter and letters following `_', lower case other letters. +ARG is ignored, and is there for compatibility with `capitalize-word' only." + (interactive) + (let ((end (save-excursion (skip-syntax-forward "w") (point))) + (begin (save-excursion (skip-syntax-backward "w") (point)))) + (capitalize-region begin end))) + +(defun ada-adjust-case-region (from to) + "Adjust the case of all words in the region between FROM and TO. +Attention: This function might take very long for big regions!" + (interactive "*r") + (let ((begin nil) + (end nil) + (keywordp nil) + (attribp nil)) + (message "Adjusting case ...") + (with-syntax-table ada-mode-symbol-syntax-table + (save-excursion + (goto-char to) + ;; + ;; loop: look for all identifiers, keywords, and attributes + ;; + (while (re-search-backward "\\<\\(\\sw+\\)\\>" from t) + (setq end (match-end 1)) + (setq attribp + (and (> (point) from) + (save-excursion + (forward-char -1) + (setq attribp (looking-at "'.[^']"))))) + (or + ;; do nothing if it is a string or comment + (ada-in-string-or-comment-p) + (progn + ;; + ;; get the identifier or keyword or attribute + ;; + (setq begin (point)) + (setq keywordp (looking-at ada-keywords)) + (goto-char end) + ;; + ;; casing according to user-option + ;; + (if attribp + (funcall ada-case-attribute -1) + (if keywordp + (funcall ada-case-keyword -1) + (ada-adjust-case-identifier))) + (goto-char begin)))) + (message "Adjusting case ... Done"))))) + +(defun ada-adjust-case-buffer () + "Adjust the case of all words in the whole buffer. +ATTENTION: This function might take very long for big buffers!" + (interactive "*") + (ada-adjust-case-region (point-min) (point-max))) + + +;;-------------------------------------------------------------- +;; Format Parameter Lists +;; Some special algorithms are provided to indent the parameter lists in +;; subprogram declarations. This is done in two steps: +;; - First parses the parameter list. The returned list has the following +;; format: +;; ( ( in? out? access? ) +;; ... ) +;; This is done in `ada-scan-paramlist'. +;; - Delete and recreate the parameter list in function +;; `ada-insert-paramlist'. +;; Both steps are called from `ada-format-paramlist'. +;; Note: Comments inside the parameter list are lost. +;; The syntax has to be correct, or the reformatting will fail. +;;-------------------------------------------------------------- + +(defun ada-format-paramlist () + "Reformat the parameter list point is in." + (interactive) + (let ((begin nil) + (end nil) + (delend nil) + (paramlist nil)) + (with-syntax-table ada-mode-symbol-syntax-table + + ;; check if really inside parameter list + (or (ada-in-paramlist-p) + (error "Not in parameter list")) + + ;; find start of current parameter-list + (ada-search-ignore-string-comment + (concat ada-subprog-start-re "\\|\\" ) t nil) + (down-list 1) + (backward-char 1) + (setq begin (point)) + + ;; find end of parameter-list + (forward-sexp 1) + (setq delend (point)) + (delete-char -1) + (insert "\n") + + ;; find end of last parameter-declaration + (forward-comment -1000) + (setq end (point)) + + ;; build a list of all elements of the parameter-list + (setq paramlist (ada-scan-paramlist (1+ begin) end)) + + ;; delete the original parameter-list + (delete-region begin delend) + + ;; insert the new parameter-list + (goto-char begin) + (ada-insert-paramlist paramlist)))) + +(defun ada-scan-paramlist (begin end) + "Scan the parameter list found in between BEGIN and END. +Return the equivalent internal parameter list." + (let ((paramlist (list)) + (param (list)) + (notend t) + (apos nil) + (epos nil) + (semipos nil) + (match-cons nil)) + + (goto-char begin) + + ;; loop until end of last parameter + (while notend + + ;; find first character of parameter-declaration + (ada-goto-next-non-ws) + (setq apos (point)) + + ;; find last character of parameter-declaration + (if (setq match-cons + (ada-search-ignore-string-comment "[ \t\n]*;" nil end t)) + (progn + (setq epos (car match-cons)) + (setq semipos (cdr match-cons))) + (setq epos end)) + + ;; read name(s) of parameter(s) + (goto-char apos) + (looking-at "\\(\\(\\sw\\|[_, \t\n]\\)*\\(\\sw\\|_\\)\\)[ \t\n]*:[^=]") + + (setq param (list (match-string 1))) + (ada-search-ignore-string-comment ":" nil epos t 'search-forward) + + ;; look for 'in' + (setq apos (point)) + (setq param + (append param + (list + (consp + (ada-search-ignore-string-comment + "in" nil epos t 'word-search-forward))))) + + ;; look for 'out' + (goto-char apos) + (setq param + (append param + (list + (consp + (ada-search-ignore-string-comment + "out" nil epos t 'word-search-forward))))) + + ;; look for 'access' + (goto-char apos) + (setq param + (append param + (list + (consp + (ada-search-ignore-string-comment + "access" nil epos t 'word-search-forward))))) + + ;; skip 'in'/'out'/'access' + (goto-char apos) + (ada-goto-next-non-ws) + (while (looking-at "\\<\\(in\\|out\\|access\\)\\>") + (forward-word-strictly 1) + (ada-goto-next-non-ws)) + + ;; read type of parameter + ;; We accept spaces in the name, since some software like Rose + ;; generates something like: "A : B 'Class" + (looking-at "\\<\\(\\sw\\|[_.' \t]\\)+\\>") + (setq param + (append param + (list (match-string 0)))) + + ;; read default-expression, if there is one + (goto-char (setq apos (match-end 0))) + (setq param + (append param + (list + (if (setq match-cons + (ada-search-ignore-string-comment + ":=" nil epos t 'search-forward)) + (buffer-substring (car match-cons) epos) + nil)))) + + ;; add this parameter-declaration to the list + (setq paramlist (append paramlist (list param))) + + ;; check if it was the last parameter + (if (eq epos end) + (setq notend nil) + (goto-char semipos)) + ) + (reverse paramlist))) + +(defun ada-insert-paramlist (paramlist) + "Insert a formatted PARAMLIST in the buffer." + (let ((i (length paramlist)) + (parlen 0) + (typlen 0) + (inp nil) + (outp nil) + (accessp nil) + (column nil) + (firstcol nil)) + + ;; loop until last parameter + (while (not (zerop i)) + (setq i (1- i)) + + ;; get max length of parameter-name + (setq parlen (max parlen (length (nth 0 (nth i paramlist))))) + + ;; get max length of type-name + (setq typlen (max typlen (length (nth 4 (nth i paramlist))))) + + ;; is there any 'in' ? + (setq inp (or inp (nth 1 (nth i paramlist)))) + + ;; is there any 'out' ? + (setq outp (or outp (nth 2 (nth i paramlist)))) + + ;; is there any 'access' ? + (setq accessp (or accessp (nth 3 (nth i paramlist)))) + ) + + ;; does paramlist already start on a separate line ? + (if (save-excursion + (re-search-backward "^.\\|[^ \t]" nil t) + (looking-at "^.")) + ;; yes => re-indent it + (progn + (ada-indent-current) + (save-excursion + (if (looking-at "\\(is\\|return\\)") + (replace-match " \\1")))) + + ;; no => insert it where we are after removing any whitespace + (fixup-whitespace) + (save-excursion + (cond + ((looking-at "[ \t]*\\(\n\\|;\\)") + (replace-match "\\1")) + ((looking-at "[ \t]*\\(is\\|return\\)") + (replace-match " \\1")))) + (insert " ")) + + (insert "(") + (ada-indent-current) + + (setq firstcol (current-column)) + (setq i (length paramlist)) + + ;; loop until last parameter + (while (not (zerop i)) + (setq i (1- i)) + (setq column firstcol) + + ;; insert parameter-name, space and colon + (insert (nth 0 (nth i paramlist))) + (indent-to (+ column parlen 1)) + (insert ": ") + (setq column (current-column)) + + ;; insert 'in' or space + (if (nth 1 (nth i paramlist)) + (insert "in ") + (if (and + (or inp + accessp) + (not (nth 3 (nth i paramlist)))) + (insert " "))) + + ;; insert 'out' or space + (if (nth 2 (nth i paramlist)) + (insert "out ") + (if (and + (or outp + accessp) + (not (nth 3 (nth i paramlist)))) + (insert " "))) + + ;; insert 'access' + (if (nth 3 (nth i paramlist)) + (insert "access ")) + + (setq column (current-column)) + + ;; insert type-name and, if necessary, space and default-expression + (insert (nth 4 (nth i paramlist))) + (if (nth 5 (nth i paramlist)) + (progn + (indent-to (+ column typlen 1)) + (insert (nth 5 (nth i paramlist))))) + + ;; check if it was the last parameter + (if (zerop i) + (insert ")") + ;; no => insert ';' and newline and indent + (insert ";") + (newline) + (indent-to firstcol)) + ) + + ;; if anything follows, except semicolon, newline, is or return + ;; put it in a new line and indent it + (unless (looking-at "[ \t]*\\(;\\|\n\\|is\\|return\\)") + (ada-indent-newline-indent)) + )) + + + +;;;---------------------------------------------------------------- +;; Indentation Engine +;; All indentations are indicated as a two-element string: +;; - position of reference in the buffer +;; - offset to indent from this position (can also be a symbol or a list +;; that are evaluated) +;; Thus the total indentation for a line is the column number of the reference +;; position plus whatever value the evaluation of the second element provides. +;; This mechanism is used so that the Ada mode can "explain" how the +;; indentation was calculated, by showing which variables were used. +;; +;; The indentation itself is done in only one pass: first we try to guess in +;; what context we are by looking at the following keyword or punctuation +;; sign. If nothing remarkable is found, just try to guess the indentation +;; based on previous lines. +;; +;; The relevant functions for indentation are: +;; - `ada-indent-region': Re-indent a region of text +;; - `ada-justified-indent-current': Re-indent the current line and shows the +;; calculation that were done +;; - `ada-indent-current': Re-indent the current line +;; - `ada-get-current-indent': Calculate the indentation for the current line, +;; based on the context (see above). +;; - `ada-get-indent-*': Calculate the indentation in a specific context. +;; For efficiency, these functions do not check they are in the correct +;; context. +;;;---------------------------------------------------------------- + +(defun ada-indent-region (beg end) + "Indent the region between BEG end END." + (interactive "*r") + (goto-char beg) + (let ((block-done 0) + (lines-remaining (count-lines beg end)) + (msg (format "%%4d out of %4d lines remaining ..." + (count-lines beg end))) + (endmark (copy-marker end))) + ;; catch errors while indenting + (while (< (point) endmark) + (if (> block-done 39) + (progn + (setq lines-remaining (- lines-remaining block-done) + block-done 0) + (message msg lines-remaining))) + (if (= (char-after) ?\n) nil + (ada-indent-current)) + (forward-line 1) + (setq block-done (1+ block-done))) + (message "Indenting ... done"))) + +(defun ada-indent-newline-indent () + "Indent the current line, insert a newline and then indent the new line." + (interactive "*") + (ada-indent-current) + (newline) + (ada-indent-current)) + +(defun ada-indent-newline-indent-conditional () + "Insert a newline and indent it. +The original line is re-indented if `ada-indent-after-return' is non-nil." + (interactive "*") + ;; If at end of buffer (entering brand new code), some indentation + ;; fails. For example, a block label requires whitespace following + ;; the : to be recognized. So we do the newline first, then + ;; go back and indent the original line. + (newline) + (if ada-indent-after-return + (progn + (forward-char -1) + (ada-indent-current) + (forward-char 1))) + (ada-indent-current)) + +(defun ada-justified-indent-current () + "Indent the current line and explain how the calculation was done." + (interactive) + + (let ((cur-indent (ada-indent-current))) + + (let ((line (save-excursion + (goto-char (car cur-indent)) + (count-lines 1 (point))))) + + (if (equal (cdr cur-indent) '(0)) + (message (concat "same indentation as line " (number-to-string line))) + (message "%s" (mapconcat (lambda(x) + (cond + ((symbolp x) + (symbol-name x)) + ((numberp x) + (number-to-string x)) + ((listp x) + (concat "- " (symbol-name (cadr x)))) + )) + (cdr cur-indent) + " + ")))) + (save-excursion + (goto-char (car cur-indent)) + (sit-for 1)))) + +(defun ada-batch-reformat () + "Re-indent and re-case all the files found on the command line. +This function should be used from the command line, with a +command like: + emacs -batch -l ada-mode -f ada-batch-reformat file1 file2 ..." + + (while command-line-args-left + (let ((source (car command-line-args-left))) + (message "Formatting %s" source) + (find-file source) + (ada-indent-region (point-min) (point-max)) + (ada-adjust-case-buffer) + (write-file source)) + (setq command-line-args-left (cdr command-line-args-left))) + (message "Done") + (kill-emacs 0)) + +(defsubst ada-goto-previous-word () + "Move point to the beginning of the previous word of Ada code. +Return the new position of point or nil if not found." + (ada-goto-next-word t)) + +(defun ada-indent-current () + "Indent current line as Ada code. +Return the calculation that was done, including the reference point +and the offset." + (interactive) + (let ((orgpoint (point-marker)) + cur-indent tmp-indent + prev-indent) + + (unwind-protect + (with-syntax-table ada-mode-symbol-syntax-table + + ;; This needs to be done here so that the advice is not always + ;; activated (this might interact badly with other modes) + (if (featurep 'xemacs) + (ad-activate 'parse-partial-sexp t)) + + (save-excursion + (setq cur-indent + + ;; Not First line in the buffer ? + (if (save-excursion (zerop (forward-line -1))) + (progn + (back-to-indentation) + (ada-get-current-indent)) + + ;; first line in the buffer + (list (point-min) 0)))) + + ;; Evaluate the list to get the column to indent to + ;; prev-indent contains the column to indent to + (if cur-indent + (setq prev-indent (save-excursion (goto-char (car cur-indent)) + (current-column)) + tmp-indent (cdr cur-indent)) + (setq prev-indent 0 tmp-indent '())) + + (while (not (null tmp-indent)) + (cond + ((numberp (car tmp-indent)) + (setq prev-indent (+ prev-indent (car tmp-indent)))) + (t + (setq prev-indent (+ prev-indent (eval (car tmp-indent))))) + ) + (setq tmp-indent (cdr tmp-indent))) + + ;; only re-indent if indentation is different then the current + (if (= (save-excursion (back-to-indentation) (current-column)) prev-indent) + nil + (beginning-of-line) + (delete-horizontal-space) + (indent-to prev-indent)) + ;; + ;; restore position of point + ;; + (goto-char orgpoint) + (if (< (current-column) (current-indentation)) + (back-to-indentation))) + + (if (featurep 'xemacs) + (ad-deactivate 'parse-partial-sexp))) + + cur-indent)) + +(defun ada-get-current-indent () + "Return the indentation to use for the current line." + (let (column + pos + match-cons + result + (orgpoint (save-excursion + (beginning-of-line) + (forward-comment -10000) + (forward-line 1) + (point)))) + + (setq result + (cond + + ;;----------------------------- + ;; in open parenthesis, but not in parameter-list + ;;----------------------------- + + ((and ada-indent-to-open-paren + (not (ada-in-paramlist-p)) + (setq column (ada-in-open-paren-p))) + + ;; check if we have something like this (Table_Component_Type => + ;; Source_File_Record) + (save-excursion + + ;; Align the closing parenthesis on the opening one + (if (= (following-char) ?\)) + (save-excursion + (goto-char column) + (skip-chars-backward " \t") + (list (1- (point)) 0)) + + (if (and (skip-chars-backward " \t") + (= (char-before) ?\n) + (not (forward-comment -10000)) + (= (char-before) ?>)) + ;; ??? Could use a different variable + (list column 'ada-broken-indent) + + ;; We want all continuation lines to be indented the same + ;; (ada-broken-line from the opening parenthesis. However, in + ;; parameter list, each new parameter should be indented at the + ;; column as the opening parenthesis. + + ;; A special case to handle nested boolean expressions, as in + ;; ((B + ;; and then C) -- indented by ada-broken-indent + ;; or else D) -- indenting this line. + ;; ??? This is really a hack, we should have a proper way to go to + ;; ??? the beginning of the statement + + (if (= (char-before) ?\)) + (backward-sexp)) + + (if (memq (char-before) '(?, ?\; ?\( ?\))) + (list column 0) + (list column 'ada-continuation-indent) + ))))) + + ;;--------------------------- + ;; at end of buffer + ;;--------------------------- + + ((not (char-after)) + (ada-indent-on-previous-lines nil orgpoint orgpoint)) + + ;;--------------------------- + ;; starting with e + ;;--------------------------- + + ((= (downcase (char-after)) ?e) + (cond + + ;; ------- end ------ + + ((looking-at "end\\>") + (let ((label 0) + limit) + (save-excursion + (ada-goto-matching-start 1) + + ;; + ;; found 'loop' => skip back to 'while' or 'for' + ;; if 'loop' is not on a separate line + ;; Stop the search for 'while' and 'for' when a ';' is encountered. + ;; + (if (save-excursion + (beginning-of-line) + (looking-at ".+\\")) + (progn + (save-excursion + (setq limit (car (ada-search-ignore-string-comment ";" t)))) + (if (save-excursion + (and + (setq match-cons + (ada-search-ignore-string-comment ada-loop-start-re t limit)) + (not (looking-at "\\")))) + (progn + (goto-char (car match-cons)) + (save-excursion + (back-to-indentation) + (if (looking-at ada-block-label-re) + (setq label (- ada-label-indent)))))))) + + ;; found 'record' => + ;; if the keyword is found at the beginning of a line (or just + ;; after limited, we indent on it, otherwise we indent on the + ;; beginning of the type declaration) + ;; type A is (B : Integer; + ;; C : Integer) is record + ;; end record; -- This is badly indented otherwise + (if (looking-at "record") + (if (save-excursion + (beginning-of-line) + (looking-at "^[ \t]*\\(record\\|limited record\\)")) + (list (save-excursion (back-to-indentation) (point)) 0) + (list (save-excursion + (car (ada-search-ignore-string-comment "\\" t))) + 0)) + + ;; Else keep the same indentation as the beginning statement + (list (+ (save-excursion (back-to-indentation) (point)) label) 0))))) + + ;; ------ exception ---- + + ((looking-at "exception\\>") + (save-excursion + (ada-goto-matching-start 1) + (list (save-excursion (back-to-indentation) (point)) 0))) + + ;; else + + ((looking-at "else\\>") + (if (save-excursion (ada-goto-previous-word) + (looking-at "\\")) + (ada-indent-on-previous-lines nil orgpoint orgpoint) + (save-excursion + (ada-goto-matching-start 1 nil t) + (list (progn (back-to-indentation) (point)) 0)))) + + ;; elsif + + ((looking-at "elsif\\>") + (save-excursion + (ada-goto-matching-start 1 nil t) + (list (progn (back-to-indentation) (point)) 0))) + + )) + + ;;--------------------------- + ;; starting with w (when) + ;;--------------------------- + + ((and (= (downcase (char-after)) ?w) + (looking-at "when\\>")) + (save-excursion + (ada-goto-matching-start 1) + (list (save-excursion (back-to-indentation) (point)) + 'ada-when-indent))) + + ;;--------------------------- + ;; starting with t (then) + ;;--------------------------- + + ((and (= (downcase (char-after)) ?t) + (looking-at "then\\>")) + (if (save-excursion (ada-goto-previous-word) + (looking-at "and\\>")) + (ada-indent-on-previous-lines nil orgpoint orgpoint) + (save-excursion + ;; Select has been added for the statement: "select ... then abort" + (ada-search-ignore-string-comment + "\\<\\(elsif\\|if\\|select\\)\\>" t nil) + (list (progn (back-to-indentation) (point)) + 'ada-stmt-end-indent)))) + + ;;--------------------------- + ;; starting with l (loop) + ;;--------------------------- + + ((and (= (downcase (char-after)) ?l) + (looking-at "loop\\>")) + (setq pos (point)) + (save-excursion + (goto-char (match-end 0)) + (ada-goto-stmt-start) + (if (looking-at "\\<\\(loop\\|if\\)\\>") + (ada-indent-on-previous-lines nil orgpoint orgpoint) + (unless (looking-at ada-loop-start-re) + (ada-search-ignore-string-comment ada-loop-start-re + nil pos)) + (if (looking-at "\\") + (ada-indent-on-previous-lines nil orgpoint orgpoint) + (list (progn (back-to-indentation) (point)) 'ada-stmt-end-indent))))) + + ;;---------------------------- + ;; starting with l (limited) or r (record) + ;;---------------------------- + + ((or (and (= (downcase (char-after)) ?l) + (looking-at "limited\\>")) + (and (= (downcase (char-after)) ?r) + (looking-at "record\\>"))) + + (save-excursion + (ada-search-ignore-string-comment + "\\<\\(type\\|use\\)\\>" t nil) + (if (looking-at "\\") + (ada-search-ignore-string-comment "for" t nil nil + 'word-search-backward)) + (list (progn (back-to-indentation) (point)) + 'ada-indent-record-rel-type))) + + ;;--------------------------- + ;; starting with b (begin) + ;;--------------------------- + + ((and (= (downcase (char-after)) ?b) + (looking-at "begin\\>")) + (save-excursion + (if (ada-goto-decl-start t) + (list (progn (back-to-indentation) (point)) 0) + (ada-indent-on-previous-lines nil orgpoint orgpoint)))) + + ;;--------------------------- + ;; starting with i (is) + ;;--------------------------- + + ((and (= (downcase (char-after)) ?i) + (looking-at "is\\>")) + + (if (and ada-indent-is-separate + (save-excursion + (goto-char (match-end 0)) + (ada-goto-next-non-ws (point-at-eol)) + (looking-at "\\\\|\\"))) + (save-excursion + (ada-goto-stmt-start) + (list (progn (back-to-indentation) (point)) 'ada-indent)) + (save-excursion + (ada-goto-stmt-start) + (if (looking-at "\\") + (list (progn (back-to-indentation) (point)) 0) + (list (progn (back-to-indentation) (point)) 'ada-indent))))) + + ;;--------------------------- + ;; starting with r (return, renames) + ;;--------------------------- + + ((and (= (downcase (char-after)) ?r) + (looking-at "re\\(turn\\|names\\)\\>")) + + (save-excursion + (let ((var 'ada-indent-return)) + ;; If looking at a renames, skip the 'return' statement too + (if (looking-at "renames") + (let (pos) + (save-excursion + (setq pos (ada-search-ignore-string-comment ";\\|return\\>" t))) + (if (and pos + (= (downcase (char-after (car pos))) ?r)) + (goto-char (car pos))) + (setq var 'ada-indent-renames))) + + (forward-comment -1000) + (if (= (char-before) ?\)) + (forward-sexp -1) + (forward-word-strictly -1)) + + ;; If there is a parameter list, and we have a function declaration + ;; or access to subprogram declaration + (let ((num-back 1)) + (if (and (= (following-char) ?\() + (save-excursion + (or (progn + (backward-word-strictly 1) + (looking-at "\\(function\\|procedure\\)\\>")) + (progn + (backward-word-strictly 1) + (setq num-back 2) + (looking-at "\\(function\\|procedure\\)\\>"))))) + + ;; The indentation depends of the value of ada-indent-return + (if (<= (eval var) 0) + (list (point) (list '- var)) + (list (progn (backward-word-strictly num-back) (point)) + var)) + + ;; Else there is no parameter list, but we have a function + ;; Only do something special if the user want to indent + ;; relative to the "function" keyword + (if (and (> (eval var) 0) + (save-excursion (forward-word-strictly -1) + (looking-at "function\\>"))) + (list (progn (forward-word-strictly -1) (point)) var) + + ;; Else... + (ada-indent-on-previous-lines nil orgpoint orgpoint))))))) + + ;;-------------------------------- + ;; starting with 'o' or 'p' + ;; 'or' as statement-start + ;; 'private' as statement-start + ;;-------------------------------- + + ((and (or (= (downcase (char-after)) ?o) + (= (downcase (char-after)) ?p)) + (or (ada-looking-at-semi-or) + (ada-looking-at-semi-private))) + (save-excursion + ;; ??? Wasn't this done already in ada-looking-at-semi-or ? + (ada-goto-matching-start 1) + (list (progn (back-to-indentation) (point)) 0))) + + ;;-------------------------------- + ;; starting with 'd' (do) + ;;-------------------------------- + + ((and (= (downcase (char-after)) ?d) + (looking-at "do\\>")) + (save-excursion + (ada-goto-stmt-start) + (list (progn (back-to-indentation) (point)) 'ada-stmt-end-indent))) + + ;;-------------------------------- + ;; starting with '-' (comment) + ;;-------------------------------- + + ((= (char-after) ?-) + (if ada-indent-comment-as-code + + ;; Indent comments on previous line comments if required + ;; We must use a search-forward (even if the code is more complex), + ;; since we want to find the beginning of the comment. + (let (pos) + + (if (and ada-indent-align-comments + (save-excursion + (forward-line -1) + (beginning-of-line) + (while (and (not pos) + (search-forward "--" (point-at-eol) t)) + (unless (ada-in-string-p) + (setq pos (point)))) + pos)) + (list (- pos 2) 0) + + ;; Else always on previous line + (ada-indent-on-previous-lines nil orgpoint orgpoint))) + + ;; Else same indentation as the previous line + (list (save-excursion (back-to-indentation) (point)) 0))) + + ;;-------------------------------- + ;; starting with '#' (preprocessor line) + ;;-------------------------------- + + ((and (= (char-after) ?#) + (equal ada-which-compiler 'gnat) + (looking-at "#[ \t]*\\(if\\|els\\(e\\|if\\)\\|end[ \t]*if\\)")) + (list (point-at-bol) 0)) + + ;;-------------------------------- + ;; starting with ')' (end of a parameter list) + ;;-------------------------------- + + ((and (not (eobp)) (= (char-after) ?\))) + (save-excursion + (forward-char 1) + (backward-sexp 1) + (list (point) 0))) + + ;;--------------------------------- + ;; new/abstract/separate + ;;--------------------------------- + + ((looking-at "\\(new\\|abstract\\|separate\\)\\>") + (ada-indent-on-previous-lines nil orgpoint orgpoint)) + + ;;--------------------------------- + ;; package/function/procedure + ;;--------------------------------- + + ((and (or (= (downcase (char-after)) ?p) (= (downcase (char-after)) ?f)) + (looking-at "\\<\\(package\\|function\\|procedure\\)\\>")) + (save-excursion + ;; Go up until we find either a generic section, or the end of the + ;; previous subprogram/package, or 'overriding' for this function/procedure + (let (found) + (while (and (not found) + (ada-search-ignore-string-comment + "\\<\\(generic\\|end\\|begin\\|overriding\\|package\\|procedure\\|function\\)\\>" t)) + + ;; avoid "with procedure"... in generic parts + (save-excursion + (forward-word-strictly -1) + (setq found (not (looking-at "with")))))) + + (cond + ((looking-at "\\") + (list (progn (back-to-indentation) (point)) 0)) + + (t + (ada-indent-on-previous-lines nil orgpoint orgpoint))))) + + ;;--------------------------------- + ;; label + ;;--------------------------------- + + ((looking-at ada-label-re) + (if (ada-in-decl-p) + ;; ada-block-label-re matches variable declarations + (ada-indent-on-previous-lines nil orgpoint orgpoint) + (append (ada-indent-on-previous-lines nil orgpoint orgpoint) + '(ada-label-indent)))) + + )) + + ;;--------------------------------- + ;; Other syntaxes + ;;--------------------------------- + (or result (ada-indent-on-previous-lines nil orgpoint orgpoint)))) + +(defun ada-indent-on-previous-lines (&optional nomove orgpoint initial-pos) + "Calculate the indentation for the new line after ORGPOINT. +The result list is based on the previous lines in the buffer. +If NOMOVE is nil, moves point to the beginning of the current statement. +if INITIAL-POS is non-nil, moves point to INITIAL-POS before calculation." + (if initial-pos + (goto-char initial-pos)) + (let ((oldpoint (point))) + + ;; Is inside a parameter-list ? + (if (ada-in-paramlist-p) + (ada-get-indent-paramlist) + + ;; Move to beginning of current statement. If already at a + ;; statement start, move to beginning of enclosing statement. + (unless nomove + (ada-goto-stmt-start t)) + + ;; no beginning found => don't change indentation + (if (and (eq oldpoint (point)) + (not nomove)) + (ada-get-indent-nochange) + + (cond + ;; + ((and + ada-indent-to-open-paren + (ada-in-open-paren-p)) + (ada-get-indent-open-paren)) + ;; + ((looking-at "end\\>") + (ada-get-indent-end orgpoint)) + ;; + ((looking-at ada-loop-start-re) + (ada-get-indent-loop orgpoint)) + ;; + ((looking-at ada-subprog-start-re) + (ada-get-indent-subprog orgpoint)) + ;; + ((looking-at ada-block-start-re) + (ada-get-indent-block-start orgpoint)) + ;; + ((looking-at ada-block-label-re) ; also variable declaration + (ada-get-indent-block-label orgpoint)) + ;; + ((looking-at ada-goto-label-re) + (ada-get-indent-goto-label orgpoint)) + ;; + ((looking-at "\\(sub\\)?type\\>") + (ada-get-indent-type orgpoint)) + ;; + ;; "then" has to be included in the case of "select...then abort" + ;; statements, since (goto-stmt-start) at the beginning of + ;; the current function would leave the cursor on that position + ((looking-at "\\(\\(els\\)?if\\>\\)\\|then abort\\>") + (ada-get-indent-if orgpoint)) + ;; + ((looking-at "case\\>") + (ada-get-indent-case orgpoint)) + ;; + ((looking-at "when\\>") + (ada-get-indent-when orgpoint)) + ;; + ((looking-at "separate\\>") + (ada-get-indent-nochange)) + ;; + ((looking-at "with\\>\\|use\\>") + ;; Are we still in that statement, or are we in fact looking at + ;; the previous one ? + (if (save-excursion (search-forward ";" oldpoint t)) + (list (progn (back-to-indentation) (point)) 0) + (list (point) (if (looking-at "with") + 'ada-with-indent + 'ada-use-indent)))) + ;; + (t + (ada-get-indent-noindent orgpoint))))) + )) + +(defun ada-get-indent-open-paren () + "Calculate the indentation when point is behind an unclosed parenthesis." + (list (ada-in-open-paren-p) 0)) + +(defun ada-get-indent-nochange () + "Return the current indentation of the previous line." + (save-excursion + (forward-line -1) + (back-to-indentation) + (list (point) 0))) + +(defun ada-get-indent-paramlist () + "Calculate the indentation when point is inside a parameter list." + (save-excursion + (ada-search-ignore-string-comment "[^ \t\n]" t nil t) + (cond + ;; in front of the first parameter + ((= (char-after) ?\() + (goto-char (match-end 0)) + (list (point) 0)) + + ;; in front of another parameter + ((= (char-after) ?\;) + (goto-char (cdr (ada-search-ignore-string-comment "(\\|;" t nil t))) + (ada-goto-next-non-ws) + (list (point) 0)) + + ;; After an affectation (default parameter value in subprogram + ;; declaration) + ((and (= (following-char) ?=) (= (preceding-char) ?:)) + (back-to-indentation) + (list (point) 'ada-broken-indent)) + + ;; inside a parameter declaration + (t + (goto-char (cdr (ada-search-ignore-string-comment "(\\|;" t nil t))) + (ada-goto-next-non-ws) + (list (point) 'ada-broken-indent))))) + +(defun ada-get-indent-end (orgpoint) + "Calculate the indentation when point is just before an end statement. +ORGPOINT is the limit position used in the calculation." + (let ((defun-name nil) + (indent nil)) + + ;; is the line already terminated by ';' ? + (if (save-excursion + (ada-search-ignore-string-comment ";" nil orgpoint nil + 'search-forward)) + + ;; yes, look what's following 'end' + (progn + (forward-word-strictly 1) + (ada-goto-next-non-ws) + (cond + ;; + ;; loop/select/if/case/return + ;; + ((looking-at "\\<\\(loop\\|select\\|if\\|case\\|return\\)\\>") + (save-excursion (ada-check-matching-start (match-string 0))) + (list (save-excursion (back-to-indentation) (point)) 0)) + + ;; + ;; record + ;; + ((looking-at "\\") + (save-excursion + (ada-check-matching-start (match-string 0)) + ;; we are now looking at the matching "record" statement + (forward-word-strictly 1) + (ada-goto-stmt-start) + ;; now on the matching type declaration, or use clause + (unless (looking-at "\\(for\\|type\\)\\>") + (ada-search-ignore-string-comment "\\" t)) + (list (progn (back-to-indentation) (point)) 0))) + ;; + ;; a named block end + ;; + ((looking-at ada-ident-re) + (setq defun-name (match-string 0)) + (save-excursion + (ada-goto-matching-start 0) + (ada-check-defun-name defun-name)) + (list (progn (back-to-indentation) (point)) 0)) + ;; + ;; a block-end without name + ;; + ((= (char-after) ?\;) + (save-excursion + (ada-goto-matching-start 0) + (if (looking-at "\\") + (progn + (setq indent (list (point) 0)) + (if (ada-goto-decl-start t) + (list (progn (back-to-indentation) (point)) 0) + indent)) + (list (progn (back-to-indentation) (point)) 0) + ))) + ;; + ;; anything else - should maybe signal an error ? + ;; + (t + (list (save-excursion (back-to-indentation) (point)) + 'ada-broken-indent)))) + + (list (save-excursion (back-to-indentation) (point)) + 'ada-broken-indent)))) + +(defun ada-get-indent-case (orgpoint) + "Calculate the indentation when point is just before a case statement. +ORGPOINT is the limit position used in the calculation." + (let ((match-cons nil) + (opos (point))) + (cond + ;; + ;; case..is..when..=> + ;; + ((save-excursion + (setq match-cons (and + ;; the `=>' must be after the keyword `is'. + (ada-search-ignore-string-comment + "is" nil orgpoint nil 'word-search-forward) + (ada-search-ignore-string-comment + "[ \t\n]+=>" nil orgpoint)))) + (save-excursion + (goto-char (car match-cons)) + (unless (ada-search-ignore-string-comment "when" t opos) + (error "Missing `when' between `case' and `=>'")) + (list (save-excursion (back-to-indentation) (point)) 'ada-indent))) + ;; + ;; case..is..when + ;; + ((save-excursion + (setq match-cons (ada-search-ignore-string-comment + "when" nil orgpoint nil 'word-search-forward))) + (goto-char (cdr match-cons)) + (list (save-excursion (back-to-indentation) (point)) 'ada-broken-indent)) + ;; + ;; case..is + ;; + ((save-excursion + (setq match-cons (ada-search-ignore-string-comment + "is" nil orgpoint nil 'word-search-forward))) + (list (save-excursion (back-to-indentation) (point)) 'ada-when-indent)) + ;; + ;; incomplete case + ;; + (t + (list (save-excursion (back-to-indentation) (point)) + 'ada-broken-indent))))) + +(defun ada-get-indent-when (orgpoint) + "Calculate the indentation when point is just before a when statement. +ORGPOINT is the limit position used in the calculation." + (let ((cur-indent (save-excursion (back-to-indentation) (point)))) + (if (ada-search-ignore-string-comment "[ \t\n]*=>" nil orgpoint) + (list cur-indent 'ada-indent) + (list cur-indent 'ada-broken-indent)))) + +(defun ada-get-indent-if (orgpoint) + "Calculate the indentation when point is just before an if statement. +ORGPOINT is the limit position used in the calculation." + (let ((cur-indent (save-excursion (back-to-indentation) (point))) + (match-cons nil)) + ;; + ;; Move to the correct then (ignore all "and then") + ;; + (while (and (setq match-cons (ada-search-ignore-string-comment + "\\<\\(then\\|and[ \t]*then\\)\\>" + nil orgpoint)) + (= (downcase (char-after (car match-cons))) ?a))) + ;; If "then" was found (we are looking at it) + (if match-cons + (progn + ;; + ;; 'then' first in separate line ? + ;; => indent according to 'then', + ;; => else indent according to 'if' + ;; + (if (save-excursion + (back-to-indentation) + (looking-at "\\")) + (setq cur-indent (save-excursion (back-to-indentation) (point)))) + ;; skip 'then' + (forward-word-strictly 1) + (list cur-indent 'ada-indent)) + + (list cur-indent 'ada-broken-indent)))) + +(defun ada-get-indent-block-start (orgpoint) + "Calculate the indentation when point is at the start of a block. +ORGPOINT is the limit position used in the calculation." + (let ((pos nil)) + (cond + ((save-excursion + (forward-word-strictly 1) + (setq pos (ada-goto-next-non-ws orgpoint))) + (goto-char pos) + (save-excursion + (ada-indent-on-previous-lines t orgpoint))) + + ;; Special case for record types, for instance for: + ;; type A is (B : Integer; + ;; C : Integer) is record + ;; null; -- This is badly indented otherwise + ((looking-at "record") + + ;; If record is at the beginning of the line, indent from there + (if (save-excursion + (beginning-of-line) + (looking-at "^[ \t]*\\(record\\|limited record\\)")) + (list (save-excursion (back-to-indentation) (point)) 'ada-indent) + + ;; else indent relative to the type command + (list (save-excursion + (car (ada-search-ignore-string-comment "\\" t))) + 'ada-indent))) + + ;; Special case for label: + ((looking-at ada-block-label-re) + (list (- (save-excursion (back-to-indentation) (point)) ada-label-indent) 'ada-indent)) + + ;; nothing follows the block-start + (t + (list (save-excursion (back-to-indentation) (point)) 'ada-indent))))) + +(defun ada-get-indent-subprog (orgpoint) + "Calculate the indentation when point is just before a subprogram. +ORGPOINT is the limit position used in the calculation." + (let ((match-cons nil) + (cur-indent (save-excursion (back-to-indentation) (point))) + (foundis nil)) + ;; + ;; is there an 'is' in front of point ? + ;; + (if (save-excursion + (setq match-cons + (ada-search-ignore-string-comment + "\\<\\(is\\|do\\)\\>" nil orgpoint))) + ;; + ;; yes, then skip to its end + ;; + (progn + (setq foundis t) + (goto-char (cdr match-cons))) + ;; + ;; no, then goto next non-ws, if there is one in front of point + ;; + (progn + (unless (ada-goto-next-non-ws orgpoint) + (goto-char orgpoint)))) + + (cond + ;; + ;; nothing follows 'is' + ;; + ((and + foundis + (save-excursion + (not (ada-search-ignore-string-comment + "[^ \t\n]" nil orgpoint t)))) + (list cur-indent 'ada-indent)) + ;; + ;; is abstract/separate/new ... + ;; + ((and + foundis + (save-excursion + (setq match-cons + (ada-search-ignore-string-comment + "\\<\\(separate\\|new\\|abstract\\)\\>" + nil orgpoint)))) + (goto-char (car match-cons)) + (ada-search-ignore-string-comment ada-subprog-start-re t) + (ada-get-indent-noindent orgpoint)) + ;; + ;; something follows 'is' + ;; + ((and + foundis + (save-excursion (setq match-cons (ada-goto-next-non-ws orgpoint))) + (goto-char match-cons) + (ada-indent-on-previous-lines t orgpoint))) + ;; + ;; no 'is' but ';' + ;; + ((save-excursion + (ada-search-ignore-string-comment ";" nil orgpoint nil 'search-forward)) + (list cur-indent 0)) + ;; + ;; no 'is' or ';' + ;; + (t + (list cur-indent 'ada-broken-indent))))) + +(defun ada-get-indent-noindent (orgpoint) + "Calculate the indentation when point is just before a `noindent stmt'. +ORGPOINT is the limit position used in the calculation." + (let ((label 0)) + (save-excursion + (beginning-of-line) + + (cond + + ;; This one is called when indenting a line preceded by a multi-line + ;; subprogram declaration (in that case, we are at this point inside + ;; the parameter declaration list) + ((ada-in-paramlist-p) + (ada-previous-procedure) + (list (save-excursion (back-to-indentation) (point)) 0)) + + ;; This one is called when indenting the second line of a multi-line + ;; declaration section, in a declare block or a record declaration + ((looking-at "[ \t]*\\(\\sw\\|_\\)*[ \t]*,[ \t]*$") + (list (save-excursion (back-to-indentation) (point)) + 'ada-broken-decl-indent)) + + ;; This one is called in every other case when indenting a line at the + ;; top level + (t + (if (looking-at (concat "[ \t]*" ada-block-label-re)) + (setq label (- ada-label-indent)) + + (let (p) + + ;; "with private" or "null record" cases + (if (or (save-excursion + (and (ada-search-ignore-string-comment "\\" nil orgpoint) + (setq p (point)) + (save-excursion (forward-char -7);; skip back "private" + (ada-goto-previous-word) + (looking-at "with")))) + (save-excursion + (and (ada-search-ignore-string-comment "\\" nil orgpoint) + (setq p (point)) + (save-excursion (forward-char -6);; skip back "record" + (ada-goto-previous-word) + (looking-at "null"))))) + (progn + (goto-char p) + (re-search-backward "\\<\\(type\\|subtype\\)\\>" nil t) + (list (save-excursion (back-to-indentation) (point)) 0))))) + (if (save-excursion + (ada-search-ignore-string-comment ";" nil orgpoint nil + 'search-forward)) + (list (+ (save-excursion (back-to-indentation) (point)) label) 0) + (list (+ (save-excursion (back-to-indentation) (point)) label) + 'ada-broken-indent))))))) + +(defun ada-get-indent-block-label (orgpoint) + "Calculate the indentation when before a label or variable declaration. +ORGPOINT is the limit position used in the calculation." + (let ((match-cons nil) + (cur-indent (save-excursion (back-to-indentation) (point)))) + (ada-search-ignore-string-comment ":" nil) + (cond + ;; loop label + ((save-excursion + (setq match-cons (ada-search-ignore-string-comment + ada-loop-start-re nil orgpoint))) + (goto-char (car match-cons)) + (ada-get-indent-loop orgpoint)) + + ;; declare label + ((save-excursion + (setq match-cons (ada-search-ignore-string-comment + "\\" nil orgpoint))) + (goto-char (car match-cons)) + (list (save-excursion (back-to-indentation) (point)) 'ada-indent)) + + ;; variable declaration + ((ada-in-decl-p) + (if (save-excursion + (ada-search-ignore-string-comment ";" nil orgpoint)) + (list cur-indent 0) + (list cur-indent 'ada-broken-indent))) + + ;; nothing follows colon + (t + (list cur-indent '(- ada-label-indent)))))) + +(defun ada-get-indent-goto-label (orgpoint) + "Calculate the indentation when at a goto label." + (search-forward ">>") + (ada-goto-next-non-ws) + (if (>= (point) orgpoint) + ;; labeled statement is the one we need to indent + (list (- (point) ada-label-indent)) + ;; else indentation is indent for labeled statement + (ada-indent-on-previous-lines t orgpoint))) + +(defun ada-get-indent-loop (orgpoint) + "Calculate the indentation when just before a loop or a for ... use. +ORGPOINT is the limit position used in the calculation." + (let ((match-cons nil) + (pos (point)) + + ;; If looking at a named block, skip the label + (label (save-excursion + (back-to-indentation) + (if (looking-at ada-block-label-re) + (- ada-label-indent) + 0)))) + + (cond + + ;; + ;; statement complete + ;; + ((save-excursion + (ada-search-ignore-string-comment ";" nil orgpoint nil + 'search-forward)) + (list (+ (save-excursion (back-to-indentation) (point)) label) 0)) + ;; + ;; simple loop + ;; + ((looking-at "loop\\>") + (setq pos (ada-get-indent-block-start orgpoint)) + (if (equal label 0) + pos + (list (+ (car pos) label) (cadr pos)))) + + ;; + ;; 'for'- loop (or also a for ... use statement) + ;; + ((looking-at "for\\>") + (cond + ;; + ;; for ... use + ;; + ((save-excursion + (and + (goto-char (match-end 0)) + (ada-goto-next-non-ws orgpoint) + (forward-word-strictly 1) + (if (= (char-after) ?') (forward-word-strictly 1) t) + (ada-goto-next-non-ws orgpoint) + (looking-at "\\") + ;; + ;; check if there is a 'record' before point + ;; + (progn + (setq match-cons (ada-search-ignore-string-comment + "record" nil orgpoint nil 'word-search-forward)) + t))) + (if match-cons + (progn + (goto-char (car match-cons)) + (list (save-excursion (back-to-indentation) (point)) 'ada-indent)) + (list (save-excursion (back-to-indentation) (point)) 'ada-broken-indent)) + ) + + ;; + ;; for..loop + ;; + ((save-excursion + (setq match-cons (ada-search-ignore-string-comment + "loop" nil orgpoint nil 'word-search-forward))) + (goto-char (car match-cons)) + ;; + ;; indent according to 'loop', if it's first in the line; + ;; otherwise to 'for' + ;; + (unless (save-excursion + (back-to-indentation) + (looking-at "\\")) + (goto-char pos)) + (list (+ (save-excursion (back-to-indentation) (point)) label) + 'ada-indent)) + ;; + ;; for-statement is broken + ;; + (t + (list (+ (save-excursion (back-to-indentation) (point)) label) + 'ada-broken-indent)))) + + ;; + ;; 'while'-loop + ;; + ((looking-at "while\\>") + ;; + ;; while..loop ? + ;; + (if (save-excursion + (setq match-cons (ada-search-ignore-string-comment + "loop" nil orgpoint nil 'word-search-forward))) + + (progn + (goto-char (car match-cons)) + ;; + ;; indent according to 'loop', if it's first in the line; + ;; otherwise to 'while'. + ;; + (unless (save-excursion + (back-to-indentation) + (looking-at "\\")) + (goto-char pos)) + (list (+ (save-excursion (back-to-indentation) (point)) label) + 'ada-indent)) + + (list (+ (save-excursion (back-to-indentation) (point)) label) + 'ada-broken-indent)))))) + +(defun ada-get-indent-type (orgpoint) + "Calculate the indentation when before a type statement. +ORGPOINT is the limit position used in the calculation." + (let ((match-dat nil)) + (cond + ;; + ;; complete record declaration + ;; + ((save-excursion + (and + (setq match-dat (ada-search-ignore-string-comment + "end" nil orgpoint nil 'word-search-forward)) + (ada-goto-next-non-ws) + (looking-at "\\") + (forward-word-strictly 1) + (ada-goto-next-non-ws) + (= (char-after) ?\;))) + (goto-char (car match-dat)) + (list (save-excursion (back-to-indentation) (point)) 0)) + ;; + ;; record type + ;; + ((save-excursion + (setq match-dat (ada-search-ignore-string-comment + "record" nil orgpoint nil 'word-search-forward))) + (goto-char (car match-dat)) + (list (save-excursion (back-to-indentation) (point)) 'ada-indent)) + ;; + ;; complete type declaration + ;; + ((save-excursion + (ada-search-ignore-string-comment ";" nil orgpoint nil + 'search-forward)) + (list (save-excursion (back-to-indentation) (point)) 0)) + ;; + ;; "type ... is", but not "type ... is ...", which is broken + ;; + ((save-excursion + (and + (ada-search-ignore-string-comment "is" nil orgpoint nil + 'word-search-forward) + (not (ada-goto-next-non-ws orgpoint)))) + (list (save-excursion (back-to-indentation) (point)) 'ada-broken-indent)) + ;; + ;; broken statement + ;; + (t + (list (save-excursion (back-to-indentation) (point)) + 'ada-broken-indent))))) + + +;; ----------------------------------------------------------- +;; -- searching and matching +;; ----------------------------------------------------------- + +(defun ada-goto-stmt-start (&optional ignore-goto-label) + "Move point to the beginning of the statement that point is in or after. +Return the new position of point. +As a special case, if we are looking at a closing parenthesis, skip to the +open parenthesis." + (let ((match-dat nil) + (orgpoint (point))) + + (setq match-dat (ada-search-prev-end-stmt)) + (if match-dat + + ;; + ;; found a previous end-statement => check if anything follows + ;; + (unless (looking-at "declare") + (progn + (unless (save-excursion + (goto-char (cdr match-dat)) + (ada-goto-next-non-ws orgpoint ignore-goto-label)) + ;; + ;; nothing follows => it's the end-statement directly in + ;; front of point => search again + ;; + (setq match-dat (ada-search-prev-end-stmt))) + ;; + ;; if found the correct end-statement => goto next non-ws + ;; + (if match-dat + (goto-char (cdr match-dat))) + (ada-goto-next-non-ws) + )) + + ;; + ;; no previous end-statement => we are at the beginning of the + ;; accessible part of the buffer + ;; + (progn + (goto-char (point-min)) + ;; + ;; skip to the very first statement, if there is one + ;; + (unless (ada-goto-next-non-ws orgpoint) + (goto-char orgpoint)))) + (point))) + + +(defun ada-search-prev-end-stmt () + "Move point to previous end statement. +Return a cons cell whose car is the beginning and whose cdr +is the end of the match." + (let ((match-dat nil) + (found nil)) + + ;; search until found or beginning-of-buffer + (while + (and + (not found) + (setq match-dat (ada-search-ignore-string-comment + ada-end-stmt-re t))) + + (goto-char (car match-dat)) + (unless (ada-in-open-paren-p) + (cond + + ((and (looking-at + "\\<\\(record\\|loop\\|select\\|else\\|then\\)\\>") + (save-excursion + (ada-goto-previous-word) + (looking-at "\\<\\(end\\|or\\|and\\)\\>[ \t]*[^;]"))) + (forward-word-strictly -1)) + + ((looking-at "is") + (setq found + (and (save-excursion (ada-goto-previous-word) + (ada-goto-previous-word) + (not (looking-at "subtype"))) + + (save-excursion (goto-char (cdr match-dat)) + (ada-goto-next-non-ws) + ;; words that can go after an 'is' + (not (looking-at + (eval-when-compile + (concat "\\<" + (regexp-opt + '("separate" "access" "array" + "private" "abstract" "new") t) + "\\>\\|(")))))))) + + ((looking-at "private") + (save-excursion + (backward-word-strictly 1) + (setq found (not (looking-at "is"))))) + + (t + (setq found t)) + ))) + + (if found + match-dat + nil))) + +(defun ada-goto-next-non-ws (&optional limit skip-goto-label) + "Skip to next non-whitespace character. +Skips spaces, newlines and comments, and possibly goto labels. +Return `point' if moved, nil if not. +Stop the search at LIMIT. +Do not call this function from within a string." + (unless limit + (setq limit (point-max))) + (while (and (<= (point) limit) + (or (progn (forward-comment 10000) + (if (and (not (eobp)) + (save-excursion (forward-char 1) + (ada-in-string-p))) + (progn (forward-sexp 1) t))) + (and skip-goto-label + (looking-at ada-goto-label-re) + (progn + (goto-char (match-end 0)) + t))))) + (if (< (point) limit) + (point) + nil) + ) + + +(defun ada-goto-stmt-end (&optional limit) + "Move point to the end of the statement that point is in or before. +Return the new position of point or nil if not found. +Stop the search at LIMIT." + (if (ada-search-ignore-string-comment ada-end-stmt-re nil limit) + (point) + nil)) + + +(defun ada-goto-next-word (&optional backward) + "Move point to the beginning of the next word of Ada code. +If BACKWARD is non-nil, jump to the beginning of the previous word. +Return the new position of point or nil if not found." + (let ((match-cons nil) + (orgpoint (point))) + (unless backward + (skip-syntax-forward "w_")) + (if (setq match-cons + (ada-search-ignore-string-comment "\\sw\\|\\s_" backward nil t)) + ;; + ;; move to the beginning of the word found + ;; + (progn + (goto-char (car match-cons)) + (skip-syntax-backward "w_") + (point)) + ;; + ;; if not found, restore old position of point + ;; + (goto-char orgpoint) + 'nil))) + + +(defun ada-check-matching-start (keyword) + "Signal an error if matching block start is not KEYWORD. +Moves point to the matching block start." + (ada-goto-matching-start 0) + (unless (looking-at (concat "\\<" keyword "\\>")) + (error "Matching start is not `%s'" keyword))) + + +(defun ada-check-defun-name (defun-name) + "Check if the name of the matching defun really is DEFUN-NAME. +Assumes point to be already positioned by `ada-goto-matching-start'. +Moves point to the beginning of the declaration." + + ;; named block without a `declare'; ada-goto-matching-start leaves + ;; point at start of 'begin' for a block. + (if (save-excursion + (ada-goto-previous-word) + (looking-at (concat "\\<" defun-name "\\> *:"))) + t ; name matches + ;; else + ;; + ;; 'accept' or 'package' ? + ;; + (unless (looking-at ada-subprog-start-re) + (ada-goto-decl-start)) + ;; + ;; 'begin' of 'procedure'/'function'/'task' or 'declare' + ;; + (save-excursion + ;; + ;; a named 'declare'-block ? => jump to the label + ;; + (if (looking-at "\\") + (progn + (forward-comment -1) + (backward-word-strictly 1)) + ;; + ;; no, => 'procedure'/'function'/'task'/'protected' + ;; + (progn + (forward-word-strictly 2) + (backward-word-strictly 1) + ;; + ;; skip 'body' 'type' + ;; + (if (looking-at "\\<\\(body\\|type\\)\\>") + (forward-word-strictly 1)) + (forward-sexp 1) + (backward-sexp 1))) + ;; + ;; should be looking-at the correct name + ;; + (unless (looking-at (concat "\\<" defun-name "\\>")) + (error "Matching defun has different name: %s" + (buffer-substring (point) + (progn (forward-sexp 1) (point)))))))) + +(defun ada-goto-decl-start (&optional noerror) + "Move point to the declaration start of the current construct. +If NOERROR is non-nil, return nil if no match was found; +otherwise throw error." + (let ((nest-count 1) + (regexp (eval-when-compile + (concat "\\<" + (regexp-opt + '("is" "separate" "end" "declare" "if" "new" "begin" "generic" "when") t) + "\\>"))) + + ;; first should be set to t if we should stop at the first + ;; "begin" we encounter. + (first t) + (count-generic nil) + (stop-at-when nil) + ) + + ;; Ignore "when" most of the time, except if we are looking at the + ;; beginning of a block (structure: case .. is + ;; when ... => + ;; begin ... + ;; exception ... ) + (if (looking-at "begin") + (setq stop-at-when t)) + + (if (or + (looking-at "\\<\\(package\\|procedure\\|function\\)\\>") + (save-excursion + (ada-search-ignore-string-comment + "\\<\\(package\\|procedure\\|function\\|generic\\)\\>" t) + (looking-at "generic"))) + (setq count-generic t)) + + ;; search backward for interesting keywords + (while (and + (not (zerop nest-count)) + (ada-search-ignore-string-comment regexp t)) + ;; + ;; calculate nest-depth + ;; + (cond + ;; + ((looking-at "end") + (ada-goto-matching-start 1 noerror) + + ;; In some case, two begin..end block can follow each other closely, + ;; which we have to detect, as in + ;; procedure P is + ;; procedure Q is + ;; begin + ;; end; + ;; begin -- here we should go to procedure, not begin + ;; end + + (if (looking-at "begin") + (let ((loop-again t)) + (save-excursion + (while loop-again + ;; If begin was just there as the beginning of a block + ;; (with no declare) then do nothing, otherwise just + ;; register that we have to find the statement that + ;; required the begin + + (ada-search-ignore-string-comment + "\\<\\(declare\\|begin\\|end\\|procedure\\|function\\|task\\|package\\)\\>" + t) + + (if (looking-at "end") + (ada-goto-matching-start 1 noerror t) + + (setq loop-again nil) + (unless (looking-at "begin") + (setq nest-count (1+ nest-count)))) + )) + ))) + ;; + ((looking-at "generic") + (if count-generic + (progn + (setq first nil) + (setq nest-count (1- nest-count))))) + ;; + ((looking-at "if") + (save-excursion + (forward-word-strictly -1) + (unless (looking-at "\\") + (progn + (setq nest-count (1- nest-count)) + (setq first nil))))) + + ;; + ((looking-at "declare\\|generic") + (setq nest-count (1- nest-count)) + (setq first t)) + ;; + ((looking-at "is") + ;; look for things to ignore + (if + (or + ;; generic formal parameter + (looking-at "is[ t]+<>") + + ;; A type definition, or a case statement. Note that the + ;; goto-matching-start above on 'end record' leaves us at + ;; 'record', not at 'type'. + ;; + ;; We get to a case statement here by calling + ;; 'ada-move-to-end' from inside a case statement; then + ;; we are not ignoring 'when'. + (save-excursion + ;; Skip type discriminants or case argument function call param list + (forward-comment -10000) + (forward-char -1) + (if (= (char-after) ?\)) + (progn + (forward-char 1) + (backward-sexp 1) + (forward-comment -10000) + )) + ;; skip type or case argument name + (skip-chars-backward "a-zA-Z0-9_.'") + (ada-goto-previous-word) + (and + ;; if it's a protected type, it's the decl start we + ;; are looking for; since we didn't see the 'end' + ;; above, we are inside it. + (looking-at "\\<\\(sub\\)?type\\|case\\>") + (save-match-data + (ada-goto-previous-word) + (not (looking-at "\\")))) + ) ; end of type definition p + + ;; null procedure declaration + (save-excursion (ada-goto-next-word) (looking-at "\\")) + );; end or + ;; skip this construct + nil + ;; this is the right "is" + (setq nest-count (1- nest-count)) + (setq first nil))) + + ;; + ((looking-at "new") + (if (save-excursion + (ada-goto-previous-word) + (looking-at "is")) + (goto-char (match-beginning 0)))) + ;; + ((and first + (looking-at "begin")) + (setq nest-count 0)) + ;; + ((looking-at "when") + (save-excursion + (forward-word-strictly -1) + (unless (looking-at "\\") + (progn + (if stop-at-when + (setq nest-count (1- nest-count))) + )))) + ;; + ((looking-at "begin") + (setq first nil)) + ;; + (t + (setq nest-count (1+ nest-count)) + (setq first nil))) + + );; end of loop + + ;; check if declaration-start is really found + (if (and + (zerop nest-count) + (if (looking-at "is") + (ada-search-ignore-string-comment ada-subprog-start-re t) + (looking-at "declare\\|generic"))) + t + (if noerror nil + (error "No matching proc/func/task/declare/package/protected"))) + )) + +(defun ada-goto-matching-start (&optional nest-level noerror gotothen) + "Move point to the beginning of a block-start. +Which block depends on the value of NEST-LEVEL, which defaults to zero. +If NOERROR is non-nil, it only returns nil if no matching start was found. +If GOTOTHEN is non-nil, point moves to the `then' following `if'." + (let ((nest-count (if nest-level nest-level 0)) + (found nil) + + (last-was-begin '()) + ;; List all keywords encountered while traversing + ;; something like '("end" "end" "begin") + ;; This is removed from the list when "package", "procedure",... + ;; are seen. The goal is to find whether a package has an elaboration + ;; part + + (pos nil)) + + ;; search backward for interesting keywords + (while (and + (not found) + (ada-search-ignore-string-comment ada-matching-start-re t)) + + (unless (and (looking-at "\\") + (save-excursion + (forward-word-strictly -1) + (looking-at "\\"))) + (progn + ;; calculate nest-depth + (cond + ;; found block end => increase nest depth + ((looking-at "end") + (push nil last-was-begin) + (setq nest-count (1+ nest-count))) + + ;; found loop/select/record/case/if => check if it starts or + ;; ends a block + ((looking-at "loop\\|select\\|record\\|case\\|if") + (setq pos (point)) + (save-excursion + ;; check if keyword follows 'end' + (ada-goto-previous-word) + (if (looking-at "\\[ \t]*[^;]") + (progn + ;; it ends a block => increase nest depth + (setq nest-count (1+ nest-count) + pos (point)) + (push nil last-was-begin)) + + ;; it starts a block => decrease nest depth + (setq nest-count (1- nest-count)) + + ;; Some nested "begin .. end" blocks with no "declare"? + ;; => remove those entries + (while (car last-was-begin) + (setq last-was-begin (cdr (cdr last-was-begin)))) + + (setq last-was-begin (cdr last-was-begin)) + )) + (goto-char pos) + ) + + ;; found package start => check if it really is a block + ((looking-at "package") + (save-excursion + ;; ignore if this is just a renames statement + (let ((current (point)) + (pos (ada-search-ignore-string-comment + "\\<\\(is\\|renames\\|;\\)\\>" nil))) + (if pos + (goto-char (car pos)) + (error (concat + "No matching `is' or `renames' for `package' at" + " line " + (number-to-string (count-lines 1 (1+ current))))))) + (unless (looking-at "renames") + (progn + (forward-word-strictly 1) + (ada-goto-next-non-ws) + ;; ignore it if it is only a declaration with 'new' + ;; We could have package Foo is new .... + ;; or package Foo is separate; + ;; or package Foo is begin null; end Foo + ;; for elaboration code (elaboration) + (if (and (not (looking-at "\\<\\(new\\|separate\\|begin\\)\\>")) + (not (car last-was-begin))) + (setq nest-count (1- nest-count)))))) + + (setq last-was-begin (cdr last-was-begin)) + ) + ;; found task start => check if it has a body + ((looking-at "task") + (save-excursion + (forward-word-strictly 1) + (ada-goto-next-non-ws) + (cond + ((looking-at "\\")) + ((looking-at "\\") + ;; In that case, do nothing if there is a "is" + (forward-word-strictly 2);; skip "type" + (ada-goto-next-non-ws);; skip type name + + ;; Do nothing if we are simply looking at a simple + ;; "task type name;" statement with no block + (unless (looking-at ";") + (progn + ;; Skip the parameters + (if (looking-at "(") + (ada-search-ignore-string-comment ")" nil)) + (let ((tmp (ada-search-ignore-string-comment + "\\<\\(is\\|;\\)\\>" nil))) + (if tmp + (progn + (goto-char (car tmp)) + (if (looking-at "is") + (setq nest-count (1- nest-count))))))))) + (t + ;; Check if that task declaration had a block attached to + ;; it (i.e do nothing if we have just "task name;") + (unless (progn (forward-word-strictly 1) + (looking-at "[ \t]*;")) + (setq nest-count (1- nest-count)))))) + (setq last-was-begin (cdr last-was-begin)) + ) + + ((looking-at "declare") + ;; remove entry for begin and end (include nested begin..end + ;; groups) + (setq last-was-begin (cdr last-was-begin)) + (let ((count 1)) + (while (and (> count 0)) + (if (equal (car last-was-begin) t) + (setq count (1+ count)) + (setq count (1- count))) + (setq last-was-begin (cdr last-was-begin)) + ))) + + ((looking-at "protected") + ;; Ignore if this is just a declaration + (save-excursion + (let ((pos (ada-search-ignore-string-comment + "\\(\\\\|\\\\|;\\)" nil))) + (if pos + (goto-char (car pos))) + (if (looking-at "is") + ;; remove entry for end + (setq last-was-begin (cdr last-was-begin))))) + (setq nest-count (1- nest-count))) + + ((or (looking-at "procedure") + (looking-at "function")) + ;; Ignore if this is just a declaration + (save-excursion + (let ((pos (ada-search-ignore-string-comment + "\\(\\\\|\\\\|)[ \t]*;\\)" nil))) + (if pos + (goto-char (car pos))) + (if (looking-at "is") + ;; remove entry for begin and end + (setq last-was-begin (cdr (cdr last-was-begin)))))) + ) + + ;; all the other block starts + (t + (push (looking-at "begin") last-was-begin) + (setq nest-count (1- nest-count))) + + ) + + ;; match is found, if nest-depth is zero + (setq found (zerop nest-count))))) ; end of loop + + (if (bobp) + (point) + (if found + ;; + ;; match found => is there anything else to do ? + ;; + (progn + (cond + ;; + ;; found 'if' => skip to 'then', if it's on a separate line + ;; and GOTOTHEN is non-nil + ;; + ((and + gotothen + (looking-at "if") + (save-excursion + (ada-search-ignore-string-comment "then" nil nil nil + 'word-search-forward) + (back-to-indentation) + (looking-at "\\"))) + (goto-char (match-beginning 0))) + + ;; + ;; found 'do' => skip back to 'accept' or 'return' + ;; + ((looking-at "do") + (unless (ada-search-ignore-string-comment + "\\" t) + (error "Missing `accept' or `return' in front of `do'")))) + (point)) + + (if noerror + nil + (error "No matching start")))))) + + +(defun ada-goto-matching-end (&optional nest-level noerror) + "Move point to the end of a block. +Which block depends on the value of NEST-LEVEL, which defaults to zero. +If NOERROR is non-nil, it only returns nil if no matching start found." + (let ((nest-count (or nest-level 0)) + (regex (eval-when-compile + (concat "\\<" + (regexp-opt '("end" "loop" "select" "begin" "case" + "if" "task" "package" "record" "do" + "procedure" "function") t) + "\\>"))) + found + pos + + ;; First is used for subprograms: they are generally handled + ;; recursively, but of course we do not want to do that the + ;; first time (see comment below about subprograms) + (first (not (looking-at "declare")))) + + ;; If we are already looking at one of the keywords, this shouldn't count + ;; in the nesting loop below, so we just make sure we don't count it. + ;; "declare" is a special case because we need to look after the "begin" + ;; keyword + (if (looking-at "\\") + (forward-char 1)) + + ;; + ;; search forward for interesting keywords + ;; + (while (and + (not found) + (ada-search-ignore-string-comment regex nil)) + + ;; + ;; calculate nest-depth + ;; + (backward-word-strictly 1) + (cond + ;; procedures and functions need to be processed recursively, in + ;; case they are defined in a declare/begin block, as in: + ;; declare -- NL 0 (nested level) + ;; A : Boolean; + ;; procedure B (C : D) is + ;; begin -- NL 1 + ;; null; + ;; end B; -- NL 0, and we would exit + ;; begin + ;; end; -- we should exit here + ;; processing them recursively avoids the need for any special + ;; handling. + ;; Nothing should be done if we have only the specs or a + ;; generic instantiation. + + ((and (looking-at "\\")) + (if first + (forward-word-strictly 1) + + (setq pos (point)) + (ada-search-ignore-string-comment "is\\|;") + (if (= (char-before) ?s) + (progn + (ada-goto-next-non-ws) + (unless (looking-at "\\") + (progn + (goto-char pos) + (ada-goto-matching-end 0 t))))))) + + ;; found block end => decrease nest depth + ((looking-at "\\") + (setq nest-count (1- nest-count) + found (<= nest-count 0)) + ;; skip the following keyword + (if (progn + (skip-chars-forward "end") + (ada-goto-next-non-ws) + (looking-at "\\<\\(loop\\|select\\|record\\|case\\|if\\)\\>")) + (forward-word-strictly 1))) + + ;; found package start => check if it really starts a block, and is not + ;; in fact a generic instantiation for instance + ((looking-at "\\") + (ada-search-ignore-string-comment "is" nil nil nil + 'word-search-forward) + (ada-goto-next-non-ws) + ;; ignore and skip it if it is only a 'new' package + (if (looking-at "\\") + (goto-char (match-end 0)) + (setq nest-count (1+ nest-count) + found (<= nest-count 0)))) + + ;; all the other block starts + (t + (if (not first) + (setq nest-count (1+ nest-count))) + (setq found (<= nest-count 0)) + (forward-word-strictly 1))) ; end of 'cond' + + (setq first nil)) + + (if found + t + (if noerror + nil + (error "No matching end"))) + )) + + +(defun ada-search-ignore-string-comment + (search-re &optional backward limit paramlists search-func) + "Regexp-search for SEARCH-RE, ignoring comments, strings. +Returns a cons cell of begin and end of match data or nil, if not found. +If BACKWARD is non-nil, search backward; search forward otherwise. +The search stops at pos LIMIT. +If PARAMLISTS is nil, ignore parameter lists. +The search is done using SEARCH-FUNC. SEARCH-FUNC can be optimized +in case we are searching for a constant string. +Point is moved at the beginning of the SEARCH-RE." + (let (found + begin + end + parse-result) + + ;; FIXME: need to pass BACKWARD to search-func! + (unless search-func + (setq search-func (if backward 're-search-backward 're-search-forward))) + + ;; + ;; search until found or end-of-buffer + ;; We have to test that we do not look further than limit + ;; + (with-syntax-table ada-mode-symbol-syntax-table + (while (and (not found) + (or (not limit) + (or (and backward (<= limit (point))) + (>= limit (point)))) + (funcall search-func search-re limit 1)) + (setq begin (match-beginning 0)) + (setq end (match-end 0)) + (setq parse-result (parse-partial-sexp (point-at-bol) (point))) + (cond + ;; + ;; If inside a string, skip it (and the following comments) + ;; + ((ada-in-string-p parse-result) + (if (featurep 'xemacs) + (search-backward "\"" nil t) + (goto-char (nth 8 parse-result))) + (unless backward (forward-sexp 1))) + ;; + ;; If inside a comment, skip it (and the following comments) + ;; There is a special code for comments at the end of the file + ;; + ((ada-in-comment-p parse-result) + (if (featurep 'xemacs) + (progn + (forward-line 1) + (beginning-of-line) + (forward-comment -1)) + (goto-char (nth 8 parse-result))) + (unless backward + ;; at the end of the file, it is not possible to skip a comment + ;; so we just go at the end of the line + (if (forward-comment 1) + (progn + (forward-comment 1000) + (beginning-of-line)) + (end-of-line)))) + ;; + ;; directly in front of a comment => skip it, if searching forward + ;; + ((and (= (char-after begin) ?-) (= (char-after (1+ begin)) ?-)) + (unless backward (progn (forward-char -1) (forward-comment 1000)))) + + ;; + ;; found a parameter-list but should ignore it => skip it + ;; + ((and (not paramlists) (ada-in-paramlist-p)) + (if backward + (search-backward "(" nil t) + (search-forward ")" nil t))) + ;; + ;; found what we were looking for + ;; + (t + (setq found t))))) ; end of loop + + (if found + (cons begin end) + nil))) + +;; ------------------------------------------------------- +;; -- Testing the position of the cursor +;; ------------------------------------------------------- + +(defun ada-in-decl-p () + "Return t if point is inside a declarative part. +Assumes point to be at the end of a statement." + (or (ada-in-paramlist-p) + (save-excursion + (ada-goto-decl-start t)))) + + +(defun ada-looking-at-semi-or () + "Return t if looking at an `or' following a semicolon." + (save-excursion + (and (looking-at "\\") + (progn + (forward-word-strictly 1) + (ada-goto-stmt-start) + (looking-at "\\"))))) + + +(defun ada-looking-at-semi-private () + "Return t if looking at the start of a private section in a package. +Return nil if the private is part of the package name, as in +'private package A is...' (this can only happen at top level)." + (save-excursion + (and (looking-at "\\") + (not (looking-at "\\")))))))) + + +(defun ada-in-paramlist-p () + "Return t if point is inside the parameter-list of a declaration, but not a subprogram call or aggregate." + (save-excursion + (and + (ada-search-ignore-string-comment "(\\|)" t nil t) + ;; inside parentheses ? + (= (char-after) ?\() + + ;; We could be looking at two things here: + ;; operator definition: function "." ( + ;; subprogram definition: procedure .... ( + ;; Let's skip back over the first one + (progn + (skip-chars-backward " \t\n") + (if (= (char-before) ?\") + (backward-char 3) + (backward-word-strictly 1)) + t) + + ;; and now over the second one + (backward-word-strictly 1) + + ;; We should ignore the case when the reserved keyword is in a + ;; comment (for instance, when we have: + ;; -- .... package + ;; Test (A) + ;; we should return nil + + (not (ada-in-string-or-comment-p)) + + ;; right keyword two words before parenthesis ? + ;; Type is in this list because of discriminants + ;; pragma is not, because the syntax is that of a subprogram call. + (looking-at (eval-when-compile + (concat "\\<\\(" + "procedure\\|function\\|body\\|" + "task\\|entry\\|accept\\|" + "access[ \t]+procedure\\|" + "access[ \t]+function\\|" + "type\\)\\>")))))) + +(defun ada-search-ignore-complex-boolean (regexp backwardp) + "Search for REGEXP, ignoring comments, strings, `and then', `or else'. +If BACKWARDP is non-nil, search backward; search forward otherwise." + (let (result) + (while (and (setq result (ada-search-ignore-string-comment regexp backwardp)) + (save-excursion (forward-word-strictly -1) + (looking-at "and then\\|or else")))) + result)) + +(defun ada-in-open-paren-p () + "Non-nil if in an open parenthesis. +Return value is the position of the first non-ws behind the last unclosed +parenthesis, or nil." + (save-excursion + (let ((parse (parse-partial-sexp + (point) + (or (car (ada-search-ignore-complex-boolean + "\\<\\(;\\|is\\|then\\|loop\\|begin\\|else\\)\\>" + t)) + (point-min))))) + + (if (nth 1 parse) + (progn + (goto-char (1+ (nth 1 parse))) + + ;; Skip blanks, if they are not followed by a comment + ;; See: + ;; type A is ( Value_0, + ;; Value_1); + ;; type B is ( -- comment + ;; Value_2); + + (if (or (not ada-indent-handle-comment-special) + (not (looking-at "[ \t]+--"))) + (skip-chars-forward " \t")) + + (point)))))) + + +;; ----------------------------------------------------------- +;; -- Behavior Of TAB Key +;; ----------------------------------------------------------- + +(defun ada-tab () + "Do indenting or tabbing according to `ada-tab-policy'. +In Transient Mark mode, if the mark is active, operate on the contents +of the region. Otherwise, operate only on the current line." + (interactive) + (cond ((eq ada-tab-policy 'indent-rigidly) (ada-tab-hard)) + ((eq ada-tab-policy 'indent-auto) + (if (ada-region-selected) + (ada-indent-region (region-beginning) (region-end)) + (ada-indent-current))) + ((eq ada-tab-policy 'always-tab) (error "Not implemented")) + )) + +(defun ada-untab (_arg) + "Delete leading indenting according to `ada-tab-policy'." + ;; FIXME: ARG is ignored + (interactive "P") + (cond ((eq ada-tab-policy 'indent-rigidly) (ada-untab-hard)) + ((eq ada-tab-policy 'indent-auto) (error "Not implemented")) + ((eq ada-tab-policy 'always-tab) (error "Not implemented")) + )) + +(defun ada-indent-current-function () + "Ada mode version of the `indent-line-function'." + (interactive "*") + (let ((starting-point (point-marker))) + (beginning-of-line) + (ada-tab) + (if (< (point) starting-point) + (goto-char starting-point)) + (set-marker starting-point nil) + )) + +(defun ada-tab-hard () + "Indent current line to next tab stop." + (interactive) + (save-excursion + (beginning-of-line) + (insert-char ? ada-indent)) + (if (bolp) (forward-char ada-indent))) + +(defun ada-untab-hard () + "Indent current line to previous tab stop." + (interactive) + (indent-rigidly (point-at-bol) (point-at-eol) (- 0 ada-indent))) + + +;; ------------------------------------------------------------ +;; -- Miscellaneous +;; ------------------------------------------------------------ + +;; Not needed any more for Emacs 21.2, but still needed for backward +;; compatibility +(defun ada-remove-trailing-spaces () + "Remove trailing spaces in the whole buffer." + (interactive) + (save-match-data + (save-excursion + (save-restriction + (widen) + (goto-char (point-min)) + (while (re-search-forward "[ \t]+$" (point-max) t) + (replace-match "" nil nil)))))) + +(defun ada-gnat-style () + "Clean up comments, `(' and `,' for GNAT style checking switch." + (interactive) + (save-excursion + + ;; The \n is required, or the line after an empty comment line is + ;; simply ignored. + (goto-char (point-min)) + (while (re-search-forward "--[ \t]*\\([^-\n]\\)" nil t) + (replace-match "-- \\1") + (forward-line 1) + (beginning-of-line)) + + (goto-char (point-min)) + (while (re-search-forward "\\>(" nil t) + (if (not (ada-in-string-or-comment-p)) + (replace-match " ("))) + (goto-char (point-min)) + (while (re-search-forward ";--" nil t) + (forward-char -1) + (if (not (ada-in-string-or-comment-p)) + (replace-match "; --"))) + (goto-char (point-min)) + (while (re-search-forward "([ \t]+" nil t) + (if (not (ada-in-string-or-comment-p)) + (replace-match "("))) + (goto-char (point-min)) + (while (re-search-forward ")[ \t]+)" nil t) + (if (not (ada-in-string-or-comment-p)) + (replace-match "))"))) + (goto-char (point-min)) + (while (re-search-forward "\\>:" nil t) + (if (not (ada-in-string-or-comment-p)) + (replace-match " :"))) + + ;; Make sure there is a space after a ','. + ;; Always go back to the beginning of the match, since otherwise + ;; a statement like ('F','D','E') is incorrectly modified. + (goto-char (point-min)) + (while (re-search-forward ",[ \t]*\\(.\\)" nil t) + (if (not (save-excursion + (goto-char (match-beginning 0)) + (ada-in-string-or-comment-p))) + (replace-match ", \\1"))) + + ;; Operators should be surrounded by spaces. + (goto-char (point-min)) + (while (re-search-forward + "[ \t]*\\(/=\\|\\*\\*\\|:=\\|\\.\\.\\|[-:+*/]\\)[ \t]*" + nil t) + (goto-char (match-beginning 1)) + (if (or (looking-at "--") + (ada-in-string-or-comment-p)) + (progn + (forward-line 1) + (beginning-of-line)) + (cond + ((string= (match-string 1) "/=") + (replace-match " /= ")) + ((string= (match-string 1) "..") + (replace-match " .. ")) + ((string= (match-string 1) "**") + (replace-match " ** ")) + ((string= (match-string 1) ":=") + (replace-match " := ")) + (t + (replace-match " \\1 "))) + (forward-char 1))) + )) + + + +;; ------------------------------------------------------------- +;; -- Moving To Procedures/Packages/Statements +;; ------------------------------------------------------------- + +(defun ada-move-to-start () + "Move point to the matching start of the current Ada structure." + (interactive) + (let ((pos (point))) + (with-syntax-table ada-mode-symbol-syntax-table + + (save-excursion + ;; + ;; do nothing if in string or comment or not on 'end ...;' + ;; or if an error occurs during processing + ;; + (or + (ada-in-string-or-comment-p) + (and (progn + (or (looking-at "[ \t]*\\") + (backward-word-strictly 1)) + (or (looking-at "[ \t]*\\") + (backward-word-strictly 1)) + (or (looking-at "[ \t]*\\") + (error "Not on end ...;"))) + (ada-goto-matching-start 1) + (setq pos (point)) + + ;; + ;; on 'begin' => go on, according to user option + ;; + ada-move-to-declaration + (looking-at "\\") + (ada-goto-decl-start) + (setq pos (point)))) + + ) ; end of save-excursion + + ;; now really move to the found position + (goto-char pos)))) + +(defun ada-move-to-end () + "Move point to the end of the block around point. +Moves to `begin' if in a declarative part." + (interactive) + (let ((pos (point)) + decl-start) + (with-syntax-table ada-mode-symbol-syntax-table + + (save-excursion + + (cond + ;; Go to the beginning of the current word, and check if we are + ;; directly on 'begin' + ((save-excursion + (skip-syntax-backward "w") + (looking-at "\\")) + (ada-goto-matching-end 1)) + + ;; on first line of subprogram body + ;; Do nothing for specs or generic instantiation, since these are + ;; handled as the general case (find the enclosing block) + ;; We also need to make sure that we ignore nested subprograms + ((save-excursion + (and (skip-syntax-backward "w") + (looking-at "\\\\|\\" ) + (ada-search-ignore-string-comment "is\\|;") + (not (= (char-before) ?\;)) + )) + (skip-syntax-backward "w") + (ada-goto-matching-end 0 t)) + + ;; on first line of task declaration + ((save-excursion + (and (ada-goto-stmt-start) + (looking-at "\\" ) + (forward-word-strictly 1) + (ada-goto-next-non-ws) + (looking-at "\\"))) + (ada-search-ignore-string-comment "begin" nil nil nil + 'word-search-forward)) + ;; accept block start + ((save-excursion + (and (ada-goto-stmt-start) + (looking-at "\\" ))) + (ada-goto-matching-end 0)) + ;; package start + ((save-excursion + (setq decl-start (and (ada-goto-decl-start t) (point))) + (and decl-start (looking-at "\\"))) + (ada-goto-matching-end 1)) + + ;; On a "declare" keyword + ((save-excursion + (skip-syntax-backward "w") + (looking-at "\\")) + (ada-goto-matching-end 0 t)) + + ;; inside a 'begin' ... 'end' block + (decl-start + (goto-char decl-start) + (ada-goto-matching-end 0 t)) + + ;; (hopefully ;-) everything else + (t + (ada-goto-matching-end 1))) + (setq pos (point)) + ) + + ;; now really move to the position found + (goto-char pos)))) + +(defun ada-next-procedure () + "Move point to next procedure." + (interactive) + (end-of-line) + (if (re-search-forward ada-procedure-start-regexp nil t) + (goto-char (match-beginning 4)) + (error "No more functions/procedures/tasks"))) + +(defun ada-previous-procedure () + "Move point to previous procedure." + (interactive) + (beginning-of-line) + (if (re-search-backward ada-procedure-start-regexp nil t) + (goto-char (match-beginning 4)) + (error "No more functions/procedures/tasks"))) + +(defun ada-next-package () + "Move point to next package." + (interactive) + (end-of-line) + (if (re-search-forward ada-package-start-regexp nil t) + (goto-char (match-beginning 1)) + (error "No more packages"))) + +(defun ada-previous-package () + "Move point to previous package." + (interactive) + (beginning-of-line) + (if (re-search-backward ada-package-start-regexp nil t) + (goto-char (match-beginning 1)) + (error "No more packages"))) + + +;; ------------------------------------------------------------ +;; -- Define keymap and menus for Ada +;; ------------------------------------------------------------- + +(defun ada-create-keymap () + "Create the keymap associated with the Ada mode." + + ;; All non-standard keys go into ada-mode-extra-map + (define-key ada-mode-map ada-mode-extra-prefix ada-mode-extra-map) + + ;; Indentation and Formatting + (define-key ada-mode-map "\C-j" 'ada-indent-newline-indent-conditional) + (define-key ada-mode-map "\C-m" 'ada-indent-newline-indent-conditional) + (define-key ada-mode-map "\t" 'ada-tab) + (define-key ada-mode-map "\C-c\t" 'ada-justified-indent-current) + (define-key ada-mode-map "\C-c\C-l" 'ada-indent-region) + (define-key ada-mode-map [(shift tab)] 'ada-untab) + (define-key ada-mode-map "\C-c\C-f" 'ada-format-paramlist) + ;; We don't want to make meta-characters case-specific. + + ;; Movement + (define-key ada-mode-map "\M-\C-e" 'ada-next-procedure) + (define-key ada-mode-map "\M-\C-a" 'ada-previous-procedure) + (define-key ada-mode-map "\C-c\C-a" 'ada-move-to-start) + (define-key ada-mode-map "\C-c\C-e" 'ada-move-to-end) + + ;; Compilation + (unless (lookup-key ada-mode-map "\C-c\C-c") + (define-key ada-mode-map "\C-c\C-c" 'compile)) + + ;; Casing + (define-key ada-mode-map "\C-c\C-b" 'ada-adjust-case-buffer) + (define-key ada-mode-map "\C-c\C-t" 'ada-case-read-exceptions) + (define-key ada-mode-map "\C-c\C-y" 'ada-create-case-exception) + (define-key ada-mode-map "\C-c\C-\M-y" 'ada-create-case-exception-substring) + + ;; On XEmacs, you can easily specify whether DEL should deletes + ;; one character forward or one character backward. Take this into + ;; account + (define-key ada-mode-map + (if (boundp 'delete-key-deletes-forward) [backspace] "\177") + 'backward-delete-char-untabify) + + ;; Make body + (define-key ada-mode-map "\C-c\C-n" 'ada-make-subprogram-body) + + ;; Use predefined function of Emacs19 for comments (RE) + ;; FIXME: Made redundant with Emacs-21's standard comment-dwim binding on M-; + (define-key ada-mode-map "\C-c;" 'comment-region) + (define-key ada-mode-map "\C-c:" 'ada-uncomment-region) + + ;; The following keys are bound to functions defined in ada-xref.el or + ;; ada-prj,el., However, RMS rightly thinks that the code should be shared, + ;; and activated only if the right compiler is used + + (define-key ada-mode-map (if (featurep 'xemacs) '(shift button3) [S-mouse-3]) + 'ada-point-and-xref) + (define-key ada-mode-map [(control tab)] 'ada-complete-identifier) + + (define-key ada-mode-extra-map "o" 'ff-find-other-file) + (define-key ada-mode-map "\C-c5\C-d" 'ada-goto-declaration-other-frame) + (define-key ada-mode-map "\C-c\C-d" 'ada-goto-declaration) + (define-key ada-mode-map "\C-c\C-s" 'ada-xref-goto-previous-reference) + (define-key ada-mode-map "\C-c\C-c" 'ada-compile-application) + (define-key ada-mode-extra-map "c" 'ada-change-prj) + (define-key ada-mode-extra-map "d" 'ada-set-default-project-file) + (define-key ada-mode-extra-map "g" 'ada-gdb-application) + (define-key ada-mode-map "\C-c\C-m" 'ada-set-main-compile-application) + (define-key ada-mode-extra-map "r" 'ada-run-application) + (define-key ada-mode-map "\C-c\C-o" 'ada-goto-parent) + (define-key ada-mode-map "\C-c\C-r" 'ada-find-references) + (define-key ada-mode-extra-map "l" 'ada-find-local-references) + (define-key ada-mode-map "\C-c\C-v" 'ada-check-current) + (define-key ada-mode-extra-map "f" 'ada-find-file) + + (define-key ada-mode-extra-map "u" 'ada-prj-edit) + + (define-key ada-mode-map "\C-xnd" 'ada-narrow-to-defun); override narrow-to-defun + + ;; The templates, defined in ada-stmt.el + + (let ((map (make-sparse-keymap))) + (define-key map "h" 'ada-header) + (define-key map "\C-a" 'ada-array) + (define-key map "b" 'ada-exception-block) + (define-key map "d" 'ada-declare-block) + (define-key map "c" 'ada-case) + (define-key map "\C-e" 'ada-elsif) + (define-key map "e" 'ada-else) + (define-key map "\C-k" 'ada-package-spec) + (define-key map "k" 'ada-package-body) + (define-key map "\C-p" 'ada-procedure-spec) + (define-key map "p" 'ada-subprogram-body) + (define-key map "\C-f" 'ada-function-spec) + (define-key map "f" 'ada-for-loop) + (define-key map "i" 'ada-if) + (define-key map "l" 'ada-loop) + (define-key map "\C-r" 'ada-record) + (define-key map "\C-s" 'ada-subtype) + (define-key map "S" 'ada-tabsize) + (define-key map "\C-t" 'ada-task-spec) + (define-key map "t" 'ada-task-body) + (define-key map "\C-y" 'ada-type) + (define-key map "\C-v" 'ada-private) + (define-key map "u" 'ada-use) + (define-key map "\C-u" 'ada-with) + (define-key map "\C-w" 'ada-when) + (define-key map "w" 'ada-while-loop) + (define-key map "\C-x" 'ada-exception) + (define-key map "x" 'ada-exit) + (define-key ada-mode-extra-map "t" map)) + ) + + +(defun ada-create-menu () + "Create the Ada menu as shown in the menu bar." + (let ((m '("Ada" + ("Help" + ["Ada Mode" (info "ada-mode") t] + ["GNAT User's Guide" (info "gnat_ugn") + (eq ada-which-compiler 'gnat)] + ["GNAT Reference Manual" (info "gnat_rm") + (eq ada-which-compiler 'gnat)] + ["Gcc Documentation" (info "gcc") + (eq ada-which-compiler 'gnat)] + ["Gdb Documentation" (info "gdb") + (eq ada-which-compiler 'gnat)] + ["Ada95 Reference Manual" (info "arm95") t]) + ("Options" :included (derived-mode-p 'ada-mode) + ["Auto Casing" (setq ada-auto-case (not ada-auto-case)) + :style toggle :selected ada-auto-case] + ["Auto Indent After Return" + (setq ada-indent-after-return (not ada-indent-after-return)) + :style toggle :selected ada-indent-after-return] + ["Automatically Recompile For Cross-references" + (setq ada-xref-create-ali (not ada-xref-create-ali)) + :style toggle :selected ada-xref-create-ali + :included (eq ada-which-compiler 'gnat)] + ["Confirm Commands" + (setq ada-xref-confirm-compile (not ada-xref-confirm-compile)) + :style toggle :selected ada-xref-confirm-compile + :included (eq ada-which-compiler 'gnat)] + ["Show Cross-references In Other Buffer" + (setq ada-xref-other-buffer (not ada-xref-other-buffer)) + :style toggle :selected ada-xref-other-buffer + :included (eq ada-which-compiler 'gnat)] + ["Tight Integration With GNU Visual Debugger" + (setq ada-tight-gvd-integration (not ada-tight-gvd-integration)) + :style toggle :selected ada-tight-gvd-integration + :included (string-match "gvd" ada-prj-default-debugger)]) + ["Customize" (customize-group 'ada) + :included (fboundp 'customize-group)] + ["Check file" ada-check-current t] + ["Compile file" ada-compile-current t] + ["Set main and Build" ada-set-main-compile-application t] + ["Show main" ada-show-current-main t] + ["Build" ada-compile-application t] + ["Run" ada-run-application t] + ["Debug" ada-gdb-application (eq ada-which-compiler 'gnat)] + ["------" nil nil] + ("Project" + ["Show project" ada-show-current-project t] + ["Load..." ada-set-default-project-file t] + ["New..." ada-prj-new t] + ["Edit..." ada-prj-edit t]) + ("Goto" :included (derived-mode-p 'ada-mode) + ["Goto Declaration/Body" ada-goto-declaration + (eq ada-which-compiler 'gnat)] + ["Goto Body" ada-goto-body + (eq ada-which-compiler 'gnat)] + ["Goto Declaration Other Frame" + ada-goto-declaration-other-frame + (eq ada-which-compiler 'gnat)] + ["Goto Previous Reference" ada-xref-goto-previous-reference + (eq ada-which-compiler 'gnat)] + ["List Local References" ada-find-local-references + (eq ada-which-compiler 'gnat)] + ["List References" ada-find-references + (eq ada-which-compiler 'gnat)] + ["Goto Reference To Any Entity" ada-find-any-references + (eq ada-which-compiler 'gnat)] + ["Goto Parent Unit" ada-goto-parent + (eq ada-which-compiler 'gnat)] + ["--" nil nil] + ["Next compilation error" next-error t] + ["Previous Package" ada-previous-package t] + ["Next Package" ada-next-package t] + ["Previous Procedure" ada-previous-procedure t] + ["Next Procedure" ada-next-procedure t] + ["Goto Start Of Statement" ada-move-to-start t] + ["Goto End Of Statement" ada-move-to-end t] + ["-" nil nil] + ["Other File" ff-find-other-file t] + ["Other File Other Window" ada-ff-other-window t]) + ("Edit" :included (derived-mode-p 'ada-mode) + ["Search File On Source Path" ada-find-file t] + ["------" nil nil] + ["Complete Identifier" ada-complete-identifier t] + ["-----" nil nil] + ["Indent Line" ada-indent-current-function t] + ["Justify Current Indentation" ada-justified-indent-current t] + ["Indent Lines in Selection" ada-indent-region t] + ["Indent Lines in File" + (ada-indent-region (point-min) (point-max)) t] + ["Format Parameter List" ada-format-paramlist t] + ["-" nil nil] + ["Comment Selection" comment-region t] + ["Uncomment Selection" ada-uncomment-region t] + ["--" nil nil] + ["Fill Comment Paragraph" fill-paragraph t] + ["Fill Comment Paragraph Justify" + ada-fill-comment-paragraph-justify t] + ["Fill Comment Paragraph Postfix" + ada-fill-comment-paragraph-postfix t] + ["---" nil nil] + ["Adjust Case Selection" ada-adjust-case-region t] + ["Adjust Case in File" ada-adjust-case-buffer t] + ["Create Case Exception" ada-create-case-exception t] + ["Create Case Exception Substring" + ada-create-case-exception-substring t] + ["Reload Case Exceptions" ada-case-read-exceptions t] + ["----" nil nil] + ["Make body for subprogram" ada-make-subprogram-body t] + ["-----" nil nil] + ["Narrow to subprogram" ada-narrow-to-defun t]) + ("Templates" + :included (derived-mode-p 'ada-mode) + ["Header" ada-header t] + ["-" nil nil] + ["Package Body" ada-package-body t] + ["Package Spec" ada-package-spec t] + ["Function Spec" ada-function-spec t] + ["Procedure Spec" ada-procedure-spec t] + ["Proc/func Body" ada-subprogram-body t] + ["Task Body" ada-task-body t] + ["Task Spec" ada-task-spec t] + ["Declare Block" ada-declare-block t] + ["Exception Block" ada-exception-block t] + ["--" nil nil] + ["Entry" ada-entry t] + ["Entry family" ada-entry-family t] + ["Select" ada-select t] + ["Accept" ada-accept t] + ["Or accept" ada-or-accept t] + ["Or delay" ada-or-delay t] + ["Or terminate" ada-or-terminate t] + ["---" nil nil] + ["Type" ada-type t] + ["Private" ada-private t] + ["Subtype" ada-subtype t] + ["Record" ada-record t] + ["Array" ada-array t] + ["----" nil nil] + ["If" ada-if t] + ["Else" ada-else t] + ["Elsif" ada-elsif t] + ["Case" ada-case t] + ["-----" nil nil] + ["While Loop" ada-while-loop t] + ["For Loop" ada-for-loop t] + ["Loop" ada-loop t] + ["------" nil nil] + ["Exception" ada-exception t] + ["Exit" ada-exit t] + ["When" ada-when t]) + ))) + + (easy-menu-define ada-mode-menu ada-mode-map "Menu keymap for Ada mode" m) + (if (featurep 'xemacs) + (progn + (define-key ada-mode-map [menu-bar] ada-mode-menu) + (setq mode-popup-menu (cons "Ada mode" ada-mode-menu)))))) + + +;; ------------------------------------------------------- +;; Commenting/Uncommenting code +;; The following two calls are provided to enhance the standard +;; comment-region function, which only allows uncommenting if the +;; comment is at the beginning of a line. If the line have been re-indented, +;; we are unable to use comment-region, which makes no sense. +;; +;; In addition, we provide an interface to the standard comment handling +;; function for justifying the comments. +;; ------------------------------------------------------- + +(when (or (<= emacs-major-version 20) (featurep 'xemacs)) + (defadvice comment-region (before ada-uncomment-anywhere disable) + (if (and (consp arg) ;; a prefix with \C-u is of the form '(4), whereas + ;; \C-u 2 sets arg to '2' (fixed by S.Leake) + (derived-mode-p 'ada-mode)) + (save-excursion + (let ((cs (concat "^[ \t]*" (regexp-quote comment-start)))) + (goto-char beg) + (while (re-search-forward cs end t) + (replace-match comment-start)) + ))))) + +(defun ada-uncomment-region (beg end &optional arg) + "Uncomment region BEG .. END. +ARG gives number of comment characters." + (interactive "r\nP") + + ;; This advice is not needed anymore with Emacs21. However, for older + ;; versions, as well as for XEmacs, we still need to enable it. + (if (or (<= emacs-major-version 20) (featurep 'xemacs)) + (progn + (ad-activate 'comment-region) + (comment-region beg end (- (or arg 2))) + (ad-deactivate 'comment-region)) + (comment-region beg end (list (- (or arg 2)))) + (ada-indent-region beg end))) + +(defun ada-fill-comment-paragraph-justify () + "Fill current comment paragraph and justify each line as well." + (interactive) + (ada-fill-comment-paragraph 'full)) + +(defun ada-fill-comment-paragraph-postfix () + "Fill current comment paragraph and justify each line as well. +Adds `ada-fill-comment-postfix' at the end of each line." + (interactive) + (ada-fill-comment-paragraph 'full t)) + +(defun ada-fill-comment-paragraph (&optional justify postfix) + "Fill the current comment paragraph. +If JUSTIFY is non-nil, each line is justified as well. +If POSTFIX and JUSTIFY are non-nil, `ada-fill-comment-postfix' is appended +to each line filled and justified. +The paragraph is indented on the first line." + (interactive "P") + + ;; check if inside comment or just in front a comment + (if (and (not (ada-in-comment-p)) + (not (looking-at "[ \t]*--"))) + (error "Not inside comment")) + + (let* (indent from to + (opos (point-marker)) + + ;; Sets this variable to nil, otherwise it prevents + ;; fill-region-as-paragraph to work on Emacs <= 20.2 + (parse-sexp-lookup-properties nil) + + fill-prefix + (fill-column (current-fill-column))) + + ;; Find end of paragraph + (back-to-indentation) + (while (and (not (eobp)) (looking-at ".*--[ \t]*[^ \t\n]")) + (forward-line 1) + + ;; If we were at the last line in the buffer, create a dummy empty + ;; line at the end of the buffer. + (if (eobp) + (insert "\n") + (back-to-indentation))) + (beginning-of-line) + (setq to (point-marker)) + (goto-char opos) + + ;; Find beginning of paragraph + (back-to-indentation) + (while (and (not (bobp)) (looking-at ".*--[ \t]*[^ \t\n]")) + (forward-line -1) + (back-to-indentation)) + + ;; We want one line above the first one, unless we are at the beginning + ;; of the buffer + (unless (bobp) + (forward-line 1)) + (beginning-of-line) + (setq from (point-marker)) + + ;; Calculate the indentation we will need for the paragraph + (back-to-indentation) + (setq indent (current-column)) + ;; unindent the first line of the paragraph + (delete-region from (point)) + + ;; Remove the old postfixes + (goto-char from) + (while (re-search-forward "--\n" to t) + (replace-match "\n")) + + (goto-char (1- to)) + (setq to (point-marker)) + + ;; Indent and justify the paragraph + (setq fill-prefix ada-fill-comment-prefix) + (set-left-margin from to indent) + (if postfix + (setq fill-column (- fill-column (length ada-fill-comment-postfix)))) + + (fill-region-as-paragraph from to justify) + + ;; Add the postfixes if required + (if postfix + (save-restriction + (goto-char from) + (narrow-to-region from to) + (while (not (eobp)) + (end-of-line) + (insert-char ? (- fill-column (current-column))) + (insert ada-fill-comment-postfix) + (forward-line)) + )) + + ;; In Emacs <= 20.2 and XEmacs <=20.4, there is a bug, and a newline is + ;; inserted at the end. Delete it + (if (or (featurep 'xemacs) + (<= emacs-major-version 19) + (and (= emacs-major-version 20) + (<= emacs-minor-version 2))) + (progn + (goto-char to) + (end-of-line) + (delete-char 1))) + + (goto-char opos))) + + +;; --------------------------------------------------- +;; support for find-file.el +;; These functions are used by find-file to guess the file names from +;; unit names, and to find the other file (spec or body) from the current +;; file (body or spec). +;; It is also used to find in which function we are, so as to put the +;; cursor at the correct position. +;; Standard Ada does not force any relation between unit names and file names, +;; so some of these functions can only be a good approximation. However, they +;; are also overridden in `ada-xref'.el when we know that the user is using +;; GNAT. +;; --------------------------------------------------- + +;; Overridden when we work with GNAT, to use gnatkrunch +(defun ada-make-filename-from-adaname (adaname) + "Determine the filename in which ADANAME is found. +This matches the GNAT default naming convention, except for +pre-defined units." + (while (string-match "\\." adaname) + (setq adaname (replace-match "-" t t adaname))) + (downcase adaname) + ) + +(defun ada-other-file-name () + "Return the name of the other file. +The name returned is the body if `current-buffer' is the spec, +or the spec otherwise." + + (let ((is-spec nil) + (is-body nil) + (suffixes ada-spec-suffixes) + (name (buffer-file-name))) + + ;; Guess whether we have a spec or a body, and get the basename of the + ;; file. Since the extension may not start with '.', we can not use + ;; file-name-extension + (while (and (not is-spec) + suffixes) + (if (string-match (concat "\\(.*\\)" (car suffixes) "$") name) + (setq is-spec t + name (match-string 1 name))) + (setq suffixes (cdr suffixes))) + + (if (not is-spec) + (progn + (setq suffixes ada-body-suffixes) + (while (and (not is-body) + suffixes) + (if (string-match (concat "\\(.*\\)" (car suffixes) "$") name) + (setq is-body t + name (match-string 1 name))) + (setq suffixes (cdr suffixes))))) + + ;; If this wasn't in either list, return name itself + (if (not (or is-spec is-body)) + name + + ;; Else find the other possible names + (if is-spec + (setq suffixes ada-body-suffixes) + (setq suffixes ada-spec-suffixes)) + (setq is-spec name) + + (while suffixes + + ;; If we are using project file, search for the other file in all + ;; the possible src directories. + + (if (fboundp 'ada-find-src-file-in-dir) + (let ((other + (ada-find-src-file-in-dir + (file-name-nondirectory (concat name (car suffixes)))))) + (if other + (setq is-spec other))) + + ;; Else search in the current directory + (if (file-exists-p (concat name (car suffixes))) + (setq is-spec (concat name (car suffixes))))) + (setq suffixes (cdr suffixes))) + + is-spec))) + +(defun ada-which-function-are-we-in () + "Return the name of the function whose definition/declaration point is in. +Used in `ff-pre-load-hook'." + (setq ff-function-name nil) + (save-excursion + (end-of-line);; make sure we get the complete name + (or (if (re-search-backward ada-procedure-start-regexp nil t) + (setq ff-function-name (match-string 5))) + (if (re-search-backward ada-package-start-regexp nil t) + (setq ff-function-name (match-string 4)))) + )) + + +(defvar ada-last-which-function-line -1 + "Last line on which `ada-which-function' was called.") +(defvar ada-last-which-function-subprog 0 + "Last subprogram name returned by `ada-which-function'.") +(make-variable-buffer-local 'ada-last-which-function-subprog) +(make-variable-buffer-local 'ada-last-which-function-line) + + +(defun ada-which-function () + "Return the name of the function whose body the point is in. +This function works even in the case of nested subprograms, whereas the +standard Emacs function `which-function' does not. +Since the search can be long, the results are cached." + + (let ((line (count-lines 1 (point))) + (pos (point)) + end-pos + func-name indent + found) + + ;; If this is the same line as before, simply return the same result + (if (= line ada-last-which-function-line) + ada-last-which-function-subprog + + (save-excursion + ;; In case the current line is also the beginning of the body + (end-of-line) + + ;; Are we looking at "function Foo\n (paramlist)" + (skip-chars-forward " \t\n(") + + (condition-case nil + (up-list 1) + (error nil)) + + (skip-chars-forward " \t\n") + (if (looking-at "return") + (progn + (forward-word-strictly 1) + (skip-chars-forward " \t\n") + (skip-chars-forward "a-zA-Z0-9_'"))) + + ;; Can't simply do forward-word, in case the "is" is not on the + ;; same line as the closing parenthesis + (skip-chars-forward "is \t\n") + + ;; No look for the closest subprogram body that has not ended yet. + ;; Not that we expect all the bodies to be finished by "end ", + ;; or a simple "end;" indented in the same column as the start of + ;; the subprogram. The goal is to be as efficient as possible. + + (while (and (not found) + (re-search-backward ada-imenu-subprogram-menu-re nil t)) + + ;; Get the function name, but not the properties, or this changes + ;; the face in the mode line on Emacs 21 + (setq func-name (match-string-no-properties 3)) + (if (and (not (ada-in-comment-p)) + (not (save-excursion + (goto-char (match-end 0)) + (looking-at "[ \t\n]*new")))) + (save-excursion + (back-to-indentation) + (setq indent (current-column)) + (if (ada-search-ignore-string-comment + (concat "end[ \t]+" func-name "[ \t]*;\\|^" + (make-string indent ? ) "end;")) + (setq end-pos (point)) + (setq end-pos (point-max))) + (if (>= end-pos pos) + (setq found func-name)))) + ) + (setq ada-last-which-function-line line + ada-last-which-function-subprog found) + found)))) + +(defun ada-ff-other-window () + "Find other file in other window using `ff-find-other-file'." + (interactive) + (and (fboundp 'ff-find-other-file) + (ff-find-other-file t))) + +(defun ada-set-point-accordingly () + "Move to the function declaration that was set by `ff-which-function-are-we-in'." + (if ff-function-name + (progn + (goto-char (point-min)) + (unless (ada-search-ignore-string-comment + (concat ff-function-name "\\b") nil) + (goto-char (point-min)))))) + +(defun ada-get-body-name (&optional spec-name) + "Return the file name for the body of SPEC-NAME. +If SPEC-NAME is nil, return the body for the current package. +Return nil if no body was found." + (interactive) + + (unless spec-name (setq spec-name (buffer-file-name))) + + ;; Remove the spec extension. We can not simply remove the file extension, + ;; but we need to take into account the specific non-GNAT extensions that the + ;; user might have specified. + + (let ((suffixes ada-spec-suffixes) + end) + (while suffixes + (setq end (- (length spec-name) (length (car suffixes)))) + (if (string-equal (car suffixes) (substring spec-name end)) + (setq spec-name (substring spec-name 0 end))) + (setq suffixes (cdr suffixes)))) + + ;; If find-file.el was available, use its functions + (if (fboundp 'ff-get-file-name) + (ff-get-file-name ada-search-directories-internal + (ada-make-filename-from-adaname + (file-name-nondirectory + (file-name-sans-extension spec-name))) + ada-body-suffixes) + ;; Else emulate it very simply + (concat (ada-make-filename-from-adaname + (file-name-nondirectory + (file-name-sans-extension spec-name))) + ".adb"))) + + +;; --------------------------------------------------- +;; support for font-lock.el +;; Strings are a real pain in Ada because a single quote character is +;; overloaded as a string quote and type/instance delimiter. By default, a +;; single quote is given punctuation syntax in `ada-mode-syntax-table'. +;; So, for Font Lock mode purposes, we mark single quotes as having string +;; syntax when the gods that created Ada determine them to be. +;; +;; This only works in Emacs. See the comments before the grammar functions +;; at the beginning of this file for how this is done with XEmacs. +;; ---------------------------------------------------- + +(defconst ada-font-lock-syntactic-keywords + ;; Mark single quotes as having string quote syntax in 'c' instances. + ;; We used to explicitly avoid ''' as a special case for fear the buffer + ;; be highlighted as a string, but it seems this fear is unfounded. + ;; + ;; This sets the properties of the characters, so that ada-in-string-p + ;; correctly handles '"' too... + '(("[^a-zA-Z0-9)]\\('\\)[^\n]\\('\\)" (1 (7 . ?')) (2 (7 . ?'))) + ("^[ \t]*\\(#\\(if\\|else\\|elsif\\|end\\)\\)" (1 (11 . ?\n))))) + +(defvar ada-font-lock-keywords + (eval-when-compile + (list + ;; + ;; handle "type T is access function return S;" + (list "\\<\\(function[ \t]+return\\)\\>" '(1 font-lock-keyword-face) ) + + ;; preprocessor line + (list "^[ \t]*\\(#.*\n\\)" '(1 font-lock-type-face t)) + + ;; + ;; accept, entry, function, package (body), protected (body|type), + ;; pragma, procedure, task (body) plus name. + (list (concat + "\\<\\(" + "accept\\|" + "entry\\|" + "function\\|" + "package[ \t]+body\\|" + "package\\|" + "pragma\\|" + "procedure\\|" + "protected[ \t]+body\\|" + "protected[ \t]+type\\|" + "protected\\|" + "task[ \t]+body\\|" + "task[ \t]+type\\|" + "task" + "\\)\\>[ \t]*" + "\\(\\sw+\\(\\.\\sw*\\)*\\)?") + '(1 font-lock-keyword-face) '(2 font-lock-function-name-face nil t)) + ;; + ;; Optional keywords followed by a type name. + (list (concat ; ":[ \t]*" + "\\<\\(access[ \t]+all\\|access[ \t]+constant\\|access\\|constant\\|in[ \t]+reverse\\|\\|in[ \t]+out\\|in\\|out\\)\\>" + "[ \t]*" + "\\(\\sw+\\(\\.\\sw*\\)*\\)?") + '(1 font-lock-keyword-face nil t) '(2 font-lock-type-face nil t)) + + ;; + ;; Main keywords, except those treated specially below. + (concat "\\<" + (regexp-opt + '("abort" "abs" "abstract" "accept" "access" "aliased" "all" + "and" "array" "at" "begin" "case" "declare" "delay" "delta" + "digits" "do" "else" "elsif" "entry" "exception" "exit" "for" + "generic" "if" "in" "interface" "is" "limited" "loop" "mod" "not" + "null" "or" "others" "overriding" "private" "protected" "raise" + "range" "record" "rem" "renames" "requeue" "return" "reverse" + "select" "separate" "synchronized" "tagged" "task" "terminate" + "then" "until" "when" "while" "with" "xor") t) + "\\>") + ;; + ;; Anything following end and not already fontified is a body name. + '("\\<\\(end\\)\\>\\([ \t]+\\)?\\(\\(\\sw\\|[_.]\\)+\\)?" + (1 font-lock-keyword-face) (3 font-lock-function-name-face nil t)) + ;; + ;; Keywords followed by a type or function name. + (list (concat "\\<\\(" + "new\\|of\\|subtype\\|type" + "\\)\\>[ \t]*\\(\\sw+\\(\\.\\sw*\\)*\\)?[ \t]*\\((\\)?") + '(1 font-lock-keyword-face) + '(2 (if (match-beginning 4) + font-lock-function-name-face + font-lock-type-face) nil t)) + ;; + ;; Keywords followed by a (comma separated list of) reference. + ;; Note that font-lock only works on single lines, thus we can not + ;; correctly highlight a with_clause that spans multiple lines. + (list (concat "\\<\\(goto\\|raise\\|use\\|with\\)" + "[ \t]+\\([a-zA-Z0-9_., \t]+\\)\\W") + '(1 font-lock-keyword-face) '(2 font-lock-constant-face nil t)) + + ;; + ;; Goto tags. + '("<<\\(\\sw+\\)>>" 1 font-lock-constant-face) + + ;; Highlight based-numbers (R. Reagan ) + (list "\\([0-9]+#[[:xdigit:]_]+#\\)" '(1 font-lock-constant-face t)) + + ;; Ada unnamed numerical constants + (list "\\W\\([-+]?[0-9._]+\\)\\>" '(1 font-lock-constant-face)) + + )) + "Default expressions to highlight in Ada mode.") + + +;; --------------------------------------------------------- +;; Support for outline.el +;; --------------------------------------------------------- + +(defun ada-outline-level () + "This is so that `current-column' DTRT in otherwise-hidden text." + ;; patch from Dave Love + (let (buffer-invisibility-spec) + (save-excursion + (back-to-indentation) + (current-column)))) + +;; --------------------------------------------------------- +;; Support for narrow-to-region +;; --------------------------------------------------------- + +(defun ada-narrow-to-defun (&optional _arg) + "Make text outside current subprogram invisible. +The subprogram visible is the one that contains or follow point. +Optional ARG is ignored. +Use \\[widen] to go back to the full visibility for the buffer." + + (interactive) + (save-excursion + (let (end) + (widen) + (forward-line 1) + (ada-previous-procedure) + (setq end (point-at-bol)) + (ada-move-to-end) + (end-of-line) + (narrow-to-region end (point)) + (message + "Use M-x widen to get back to full visibility in the buffer")))) + +;; --------------------------------------------------------- +;; Automatic generation of code +;; The Ada mode has a set of function to automatically generate a subprogram +;; or package body from its spec. +;; These function only use a primary and basic algorithm, this could use a +;; lot of improvement. +;; When the user is using GNAT, we rather use gnatstub to generate an accurate +;; body. +;; ---------------------------------------------------------- + +(defun ada-gen-treat-proc (match) + "Make dummy body of a procedure/function specification. +MATCH is a cons cell containing the start and end locations of the last search +for `ada-procedure-start-regexp'." + (goto-char (car match)) + (let (func-found procname functype) + (cond + ((or (looking-at "^[ \t]*procedure") + (setq func-found (looking-at "^[ \t]*function"))) + ;; treat it as a proc/func + (forward-word-strictly 2) + (forward-word-strictly -1) + (setq procname (buffer-substring (point) (cdr match))) ; store proc name + + ;; goto end of procname + (goto-char (cdr match)) + + ;; skip over parameterlist + (unless (looking-at "[ \t\n]*\\(;\\|return\\)") + (forward-sexp)) + + ;; if function, skip over 'return' and result type. + (if func-found + (progn + (forward-word-strictly 1) + (skip-chars-forward " \t\n") + (setq functype (buffer-substring (point) + (progn + (skip-chars-forward + "a-zA-Z0-9_.") + (point)))))) + ;; look for next non WS + (cond + ((looking-at "[ \t]*;") + (delete-region (match-beginning 0) (match-end 0));; delete the ';' + (ada-indent-newline-indent) + (insert "is") + (ada-indent-newline-indent) + (if func-found + (progn + (insert "Result : " functype ";") + (ada-indent-newline-indent))) + (insert "begin") + (ada-indent-newline-indent) + (if func-found + (insert "return Result;") + (insert "null;")) + (ada-indent-newline-indent) + (insert "end " procname ";") + (ada-indent-newline-indent) + ) + + ((looking-at "[ \t\n]*is") + ;; do nothing + ) + + ((looking-at "[ \t\n]*rename") + ;; do nothing + ) + + (t + (message "unknown syntax")))) + (t + (if (looking-at "^[ \t]*task") + (progn + (message "Task conversion is not yet implemented") + (forward-word-strictly 2) + (if (looking-at "[ \t]*;") + (forward-line) + (ada-move-to-end)) + )))))) + +(defun ada-make-body () + "Create an Ada package body in the current buffer. +The spec must be the previously visited buffer. +This function typically is to be hooked into `ff-file-created-hook'." + (delete-region (point-min) (point-max)) + (insert-buffer-substring (car (cdr (buffer-list)))) + (goto-char (point-min)) + (ada-mode) + + (let (found ada-procedure-or-package-start-regexp) + (if (setq found + (ada-search-ignore-string-comment ada-package-start-regexp nil)) + (progn (goto-char (cdr found)) + (insert " body") + ) + (error "No package")) + + (setq ada-procedure-or-package-start-regexp + (concat ada-procedure-start-regexp + "\\|" + ada-package-start-regexp)) + + (while (setq found + (ada-search-ignore-string-comment + ada-procedure-or-package-start-regexp nil)) + (progn + (goto-char (car found)) + (if (looking-at ada-package-start-regexp) + (progn (goto-char (cdr found)) + (insert " body")) + (ada-gen-treat-proc found)))))) + + +(defun ada-make-subprogram-body () + "Create a dummy subprogram body in package body file from spec surrounding point." + (interactive) + (let* ((found (re-search-backward ada-procedure-start-regexp nil t)) + (spec (match-beginning 0)) + body-file) + (if found + (progn + (goto-char spec) + (if (and (re-search-forward "(\\|;" nil t) + (= (char-before) ?\()) + (progn + (ada-search-ignore-string-comment ")" nil) + (ada-search-ignore-string-comment ";" nil))) + (setq spec (buffer-substring spec (point))) + + ;; If find-file.el was available, use its functions + (setq body-file (ada-get-body-name)) + (if body-file + (find-file body-file) + (error "No body found for the package. Create it first")) + + (save-restriction + (widen) + (goto-char (point-max)) + (forward-comment -10000) + (re-search-backward "\\" nil t) + ;; Move to the beginning of the elaboration part, if any + (re-search-backward "^begin" nil t) + (newline) + (forward-char -1) + (insert spec) + (re-search-backward ada-procedure-start-regexp nil t) + (ada-gen-treat-proc (cons (match-beginning 0) (match-end 0))) + )) + (error "Not in subprogram spec")))) + +;; -------------------------------------------------------- +;; Global initializations +;; -------------------------------------------------------- + +;; Create the keymap once and for all. If we do that in ada-mode, +;; the keys changed in the user's .emacs have to be modified +;; every time +(ada-create-keymap) +(ada-create-menu) + +;; Add the default extensions (and set up speedbar) +(ada-add-extensions ".ads" ".adb") +;; This two files are generated by GNAT when running with -gnatD +(if (equal ada-which-compiler 'gnat) + (ada-add-extensions ".ads.dg" ".adb.dg")) + +;; Read the special cases for exceptions +(ada-case-read-exceptions) + +;; Setup auto-loading of the other Ada mode files. +(autoload 'ada-change-prj "ada-xref" nil t) +(autoload 'ada-check-current "ada-xref" nil t) +(autoload 'ada-compile-application "ada-xref" nil t) +(autoload 'ada-compile-current "ada-xref" nil t) +(autoload 'ada-complete-identifier "ada-xref" nil t) +(autoload 'ada-find-file "ada-xref" nil t) +(autoload 'ada-find-any-references "ada-xref" nil t) +(autoload 'ada-find-src-file-in-dir "ada-xref" nil t) +(autoload 'ada-find-local-references "ada-xref" nil t) +(autoload 'ada-find-references "ada-xref" nil t) +(autoload 'ada-gdb-application "ada-xref" nil t) +(autoload 'ada-goto-declaration "ada-xref" nil t) +(autoload 'ada-goto-declaration-other-frame "ada-xref" nil t) +(autoload 'ada-goto-parent "ada-xref" nil t) +(autoload 'ada-make-body-gnatstub "ada-xref" nil t) +(autoload 'ada-point-and-xref "ada-xref" nil t) +(autoload 'ada-reread-prj-file "ada-xref" nil t) +(autoload 'ada-run-application "ada-xref" nil t) +(autoload 'ada-set-default-project-file "ada-xref" nil t) +(autoload 'ada-xref-goto-previous-reference "ada-xref" nil t) +(autoload 'ada-set-main-compile-application "ada-xref" nil t) +(autoload 'ada-show-current-main "ada-xref" nil t) + +(autoload 'ada-customize "ada-prj" nil t) +(autoload 'ada-prj-edit "ada-prj" nil t) +(autoload 'ada-prj-new "ada-prj" nil t) +(autoload 'ada-prj-save "ada-prj" nil t) + +(autoload 'ada-array "ada-stmt" nil t) +(autoload 'ada-case "ada-stmt" nil t) +(autoload 'ada-declare-block "ada-stmt" nil t) +(autoload 'ada-else "ada-stmt" nil t) +(autoload 'ada-elsif "ada-stmt" nil t) +(autoload 'ada-exception "ada-stmt" nil t) +(autoload 'ada-exception-block "ada-stmt" nil t) +(autoload 'ada-exit "ada-stmt" nil t) +(autoload 'ada-for-loop "ada-stmt" nil t) +(autoload 'ada-function-spec "ada-stmt" nil t) +(autoload 'ada-header "ada-stmt" nil t) +(autoload 'ada-if "ada-stmt" nil t) +(autoload 'ada-loop "ada-stmt" nil t) +(autoload 'ada-package-body "ada-stmt" nil t) +(autoload 'ada-package-spec "ada-stmt" nil t) +(autoload 'ada-private "ada-stmt" nil t) +(autoload 'ada-procedure-spec "ada-stmt" nil t) +(autoload 'ada-record "ada-stmt" nil t) +(autoload 'ada-subprogram-body "ada-stmt" nil t) +(autoload 'ada-subtype "ada-stmt" nil t) +(autoload 'ada-tabsize "ada-stmt" nil t) +(autoload 'ada-task-body "ada-stmt" nil t) +(autoload 'ada-task-spec "ada-stmt" nil t) +(autoload 'ada-type "ada-stmt" nil t) +(autoload 'ada-use "ada-stmt" nil t) +(autoload 'ada-when "ada-stmt" nil t) +(autoload 'ada-while-loop "ada-stmt" nil t) +(autoload 'ada-with "ada-stmt" nil t) + +;;; provide ourselves +(provide 'ada-mode) + +;;; ada-mode.el ends here diff --git a/ada-mode/ada-prj.el b/ada-mode/ada-prj.el new file mode 100644 index 0000000..d9fa77c --- /dev/null +++ b/ada-mode/ada-prj.el @@ -0,0 +1,682 @@ +;;; ada-prj.el --- GUI editing of project files for the ada-mode + +;; Copyright (C) 1998-2019 Free Software Foundation, Inc. + +;; Author: Emmanuel Briot +;; Maintainer: Stephen Leake +;; Keywords: languages, ada, project file +;; Package: ada-mode + +;; 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 . + +;;; Commentary: + +;; This package provides a set of functions to easily edit the project +;; files used by the ada-mode. +;; The only function publicly available here is `ada-customize'. +;; See the documentation of the Ada mode for more information on the project +;; files. +;; Internally, a project file is represented as a property list, with each +;; field of the project file matching one property of the list. + +;;; Code: + + +;; ----- Requirements ----------------------------------------------------- + +(require 'cus-edit) +(require 'ada-xref) + +(eval-when-compile + (require 'ada-mode)) +(eval-when-compile (require 'cl-lib)) + +;; ----- Buffer local variables ------------------------------------------- + +(defvar ada-prj-current-values nil + "Hold the current value of the fields, This is a property list.") +(make-variable-buffer-local 'ada-prj-current-values) + +(defvar ada-prj-default-values nil + "Hold the default value for the fields, This is a property list.") +(make-variable-buffer-local 'ada-prj-default-values) + +(defvar ada-prj-ada-buffer nil + "Indicates what Ada source file was being edited.") + +(defvar ada-old-cross-prefix nil + "The cross-prefix associated with the currently loaded runtime library.") + + +;; ----- Functions -------------------------------------------------------- + +(defun ada-prj-new () + "Open a new project file." + (interactive) + (let* ((prj + (if (and ada-prj-default-project-file + (not (string= ada-prj-default-project-file ""))) + ada-prj-default-project-file + "default.adp")) + (filename (read-file-name "Project file: " + (if prj "" nil) + nil + nil + prj))) + (if (not (string= (file-name-extension filename t) ".adp")) + (error "File name extension for project files must be .adp")) + + (ada-customize nil filename))) + +(defun ada-prj-edit () + "Editing the project file associated with the current Ada buffer. +If there is none, opens a new project file." + (interactive) + (if ada-prj-default-project-file + (ada-customize) + (ada-prj-new))) + +(defun ada-prj-initialize-values (symbol _ada-buffer filename) + "Set SYMBOL to the property list of the project file FILENAME. +If FILENAME is null, read the file associated with ADA-BUFFER. +If no project file is found, return the default values." +;; FIXME: rationalize arguments; make ada-buffer optional? + (if (and filename + (not (string= filename "")) + (assoc filename ada-xref-project-files)) + (set symbol (copy-sequence (cdr (assoc filename ada-xref-project-files)))) + + ;; Set default values (except for the file name if this was given + ;; in the buffer + (set symbol (ada-default-prj-properties)) + (if (and filename (not (string= filename ""))) + (set symbol (plist-put (eval symbol) 'filename filename))) + )) + + +(defun ada-prj-save-specific-option (field) + "Return the string to print in the project file to save FIELD. +If the current value of FIELD is the default value, return an empty string." + (if (string= (plist-get ada-prj-current-values field) + (plist-get ada-prj-default-values field)) + "" + (concat (symbol-name field) + "=" (plist-get ada-prj-current-values field) "\n"))) + +(defun ada-prj-save () + "Save the edited project file." + (interactive) + (let ((file-name (or (plist-get ada-prj-current-values 'filename) + (read-file-name "Save project as: "))) + output) + (setq output + (concat + + ;; Save the fields that do not depend on the current buffer + ;; only if they are different from the default value + + (ada-prj-save-specific-option 'comp_opt) + (ada-prj-save-specific-option 'bind_opt) + (ada-prj-save-specific-option 'link_opt) + (ada-prj-save-specific-option 'gnatmake_opt) + (ada-prj-save-specific-option 'gnatfind_opt) + (ada-prj-save-specific-option 'cross_prefix) + (ada-prj-save-specific-option 'remote_machine) + (ada-prj-save-specific-option 'debug_cmd) + + ;; Always save the fields that depend on the current buffer + "main=" (plist-get ada-prj-current-values 'main) "\n" + "build_dir=" (plist-get ada-prj-current-values 'build_dir) "\n" + (ada-prj-set-list "check_cmd" + (plist-get ada-prj-current-values 'check_cmd)) "\n" + (ada-prj-set-list "make_cmd" + (plist-get ada-prj-current-values 'make_cmd)) "\n" + (ada-prj-set-list "comp_cmd" + (plist-get ada-prj-current-values 'comp_cmd)) "\n" + (ada-prj-set-list "run_cmd" + (plist-get ada-prj-current-values 'run_cmd)) "\n" + (ada-prj-set-list "src_dir" + (plist-get ada-prj-current-values 'src_dir) + t) "\n" + (ada-prj-set-list "obj_dir" + (plist-get ada-prj-current-values 'obj_dir) + t) "\n" + (ada-prj-set-list "debug_pre_cmd" + (plist-get ada-prj-current-values 'debug_pre_cmd)) + "\n" + (ada-prj-set-list "debug_post_cmd" + (plist-get ada-prj-current-values 'debug_post_cmd)) + "\n" + )) + + (find-file file-name) + (erase-buffer) + (insert output) + (save-buffer) + ;; kill the project buffer + (kill-buffer nil) + + ;; kill the editor buffer + (kill-buffer "*Edit Ada Mode Project*") + + ;; automatically set the new project file as the active one + (setq ada-prj-default-project-file file-name) + + ;; force Emacs to reread the project files + (ada-reread-prj-file file-name) + ) + ) + +(defun ada-prj-load-from-file (symbol) + "Load SYMBOL value from file. +One item per line should be found in the file." + (save-excursion + (let ((file (read-file-name "File name: " nil nil t)) + (buffer (current-buffer)) + line + list) + (find-file file) + (widen) + (goto-char (point-min)) + (while (not (eobp)) + (setq line (buffer-substring-no-properties (point) (point-at-eol))) + (cl-pushnew line list :test #'equal) + (forward-line 1)) + (kill-buffer nil) + (set-buffer buffer) + (setq ada-prj-current-values + (plist-put ada-prj-current-values + symbol + (append (plist-get ada-prj-current-values symbol) + (reverse list))))) + (ada-prj-display-page 2))) + +(defun ada-prj-subdirs-of (dir) + "Return a list of all the subdirectories of DIR, recursively." + (let ((subdirs (directory-files dir t "^[^.].*")) + (dirlist (list dir))) + (while subdirs + (if (file-directory-p (car subdirs)) + (let ((sub (ada-prj-subdirs-of (car subdirs)))) + (if sub + (setq dirlist (append sub dirlist))))) + (setq subdirs (cdr subdirs))) + dirlist)) + +(defun ada-prj-load-directory (field &optional file-name) + "Append to FIELD in the current project the subdirectories of FILE-NAME. +If FILE-NAME is nil, ask the user for the name." + + ;; Do not use an external dialog for this, since it wouldn't allow + ;; the user to select a directory + (let ((use-dialog-box nil)) + (unless file-name + (setq file-name (read-directory-name "Root directory: " nil nil t)))) + + (setq ada-prj-current-values + (plist-put ada-prj-current-values + field + (append (plist-get ada-prj-current-values field) + (reverse (ada-prj-subdirs-of + (expand-file-name file-name)))))) + (ada-prj-display-page 2)) + +(defun ada-prj-display-page (tab-num) + "Display page TAB-NUM in the notebook. +The current buffer must be the project editing buffer." + + (let ((inhibit-read-only t)) + (erase-buffer)) + + ;; Widget support in Emacs 21 requires that we clear the buffer first + (if (and (not (featurep 'xemacs)) (>= emacs-major-version 21)) + (progn + (setq widget-field-new nil + widget-field-list nil) + (mapc (lambda (x) (delete-overlay x)) (car (overlay-lists))) + (mapc (lambda (x) (delete-overlay x)) (cdr (overlay-lists))))) + + ;; Display the tabs + + (widget-insert "\n Project configuration.\n + ___________ ____________ ____________ ____________ ____________\n / ") + (widget-create 'push-button :notify + (lambda (&rest _dummy) (ada-prj-display-page 1)) "General") + (widget-insert " \\ / ") + (widget-create 'push-button :notify + (lambda (&rest _dummy) (ada-prj-display-page 2)) "Paths") + (widget-insert " \\ / ") + (widget-create 'push-button :notify + (lambda (&rest _dummy) (ada-prj-display-page 3)) "Switches") + (widget-insert " \\ / ") + (widget-create 'push-button :notify + (lambda (&rest _dummy) (ada-prj-display-page 4)) "Ada Menu") + (widget-insert " \\ / ") + (widget-create 'push-button :notify + (lambda (&rest _dummy) (ada-prj-display-page 5)) "Debugger") + (widget-insert " \\\n") + + ;; Display the currently selected page + + (cond + + ;; + ;; First page (General) + ;; + ((= tab-num 1) + (widget-insert "/ \\/______________\\/______________\\/______________\\/______________\\\n") + + (widget-insert "Project file name:\n") + (widget-insert (plist-get ada-prj-current-values 'filename)) + (widget-insert "\n\n") + (ada-prj-field 'casing "Casing Exceptions" +"List of files that contain casing exception +dictionaries. All these files contain one +identifier per line, with a special casing. +The first file has the highest priority." + t nil + (mapconcat (lambda(x) + (concat " " x)) + (ada-xref-get-project-field 'casing) + "\n") + ) + (ada-prj-field 'main "Executable file name" +"Name of the executable generated when you +compile your application. This should include +the full directory name, using ${build_dir} if +you wish.") + (ada-prj-field 'build_dir "Build directory" + "Reference directory for relative paths in +src_dir and obj_dir below. This is also the directory +where the compilation is done.") + (ada-prj-field 'remote_machine "Name of the remote machine (if any)" +"If you want to remotely compile, debug and +run your application, specify the name of a +remote machine here. This capability requires +the `rsh' protocol on the remote machine.") + (ada-prj-field 'cross_prefix "Prefix used in for the cross tool chain" +"When working on multiple cross targets, it is +most convenient to specify the prefix of the +tool chain here. For instance, on PowerPc +vxworks, you would enter `powerpc-wrs-vxworks-'. +To use JGNAT, enter `j'.") + ) + + + ;; + ;; Second page (Paths) + ;; + ((= tab-num 2) + (if (not (equal (plist-get ada-prj-current-values 'cross_prefix) + ada-old-cross-prefix)) + (progn + (setq ada-old-cross-prefix + (plist-get ada-prj-current-values 'cross_prefix)) + (ada-initialize-runtime-library ada-old-cross-prefix))) + + + (widget-insert "/_____________\\/ \\/______________\\/______________\\/______________\\\n") + (ada-prj-field 'src_dir "Source directories" +"Enter the list of directories where your Ada +sources can be found. These directories will be +used for the cross-references and for the default +compilation commands. +Note that src_dir includes both the build directory +and the standard runtime." + t t + (mapconcat (lambda(x) + (concat " " x)) + ada-xref-runtime-library-specs-path + "\n") + ) + (widget-insert "\n\n") + + (ada-prj-field 'obj_dir "Object directories" +"Enter the list of directories where the GNAT +library files (ALI files) can be found. These +files are used for cross-references and by the +gnatmake command. +Note that obj_dir includes both the build directory +and the standard runtime." + t t + (mapconcat (lambda(x) + (concat " " x)) + ada-xref-runtime-library-ali-path + "\n") + ) + (widget-insert "\n\n") + ) + + ;; + ;; Third page (Switches) + ;; + ((= tab-num 3) + (widget-insert "/_____________\\/______________\\/ \\/______________\\/______________\\\n") + (ada-prj-field 'comp_opt "Switches for the compiler" +"These switches are used in the default +compilation commands, both for compiling a +single file and rebuilding the whole project") + (ada-prj-field 'bind_opt "Switches for the binder" +"These switches are used in the default build +command and are passed to the binder") + (ada-prj-field 'link_opt "Switches for the linker" +"These switches are used in the default build +command and are passed to the linker") + (ada-prj-field 'gnatmake_opt "Switches for gnatmake" +"These switches are used in the default gnatmake +command.") + (ada-prj-field 'gnatfind_opt "Switches for gnatfind" +"The command gnatfind is run every time the Ada/Goto/List_References menu. +You should for instance add -a if you are working in an environment +where most ALI files are write-protected, since otherwise they get +ignored by gnatfind and you don't see the references within.") + ) + + ;; + ;; Fourth page + ;; + ((= tab-num 4) + (widget-insert "/_____________\\/______________\\/______________\\/ \\/______________\\\n") + (widget-insert +"All the fields below can use variable substitution. The syntax is ${name}, +where name is the name that appears after the Help buttons in this buffer. As +a special case, ${current} is replaced with the name of the file currently +edited, with directory name but no extension, whereas ${full_current} is +replaced with the name of the current file with directory name and +extension.\n") + (widget-insert +"The environment variables ADA_INCLUDE_PATH and ADA_OBJECTS_PATH are set to +${src_dir} and ${obj_dir} before running the compilation commands, so that you +don't need to specify the -aI and -aO switches on the command line\n") + (widget-insert +"You can reference any environment variable using the same ${...} syntax as +above, and put the name of the variable between the quotes.\n\n") + (ada-prj-field 'check_cmd + "Check syntax of a single file (menu Ada->Check File)" +"This command is run to check the syntax and semantics of a file. +The file name is added at the end of this command." t) + (ada-prj-field 'comp_cmd + "Compiling a single file (menu Ada->Compile File)" +"This command is run when the recompilation +of a single file is needed. The file name is +added at the end of this command." t) + (ada-prj-field 'make_cmd "Rebuilding the whole project (menu Ada->Build)" +"This command is run when you want to rebuild +your whole application. It is never issues +automatically and you will need to ask for it. +If remote_machine has been set, this command +will be executed on the remote machine." t) + (ada-prj-field 'run_cmd "Running the application (menu Ada->Run)" +"This command specifies how to run the +application, including any switch you need to +specify. If remote_machine has been set, this +command will be executed on the remote host." t) + ) + + ;; + ;; Fifth page + ;; + ((= tab-num 5) + (widget-insert "/_____________\\/______________\\/______________\\/______________\\/ \\\n") + (ada-prj-field 'debug_pre_cmd "Commands to execute before launching the +debugger" +"The following commands are executed one after the other before starting +the debugger. These can be used to set up your environment." t) + + (ada-prj-field 'debug_cmd "Debugging the application" +"Specifies how to debug the application, possibly +remotely if remote_machine has been set. We +recommend the following debuggers: + > gdb + > gvd --tty + > ddd --tty -fullname -toolbar") + + (ada-prj-field 'debug_post_cmd "Commands to execute in the debugger" +"The following commands are executed one in the debugger once it has been +started. These can be used to initialize the debugger, for instance to +connect to the target when working with cross-environments" t) + ) + + ) + + + (widget-insert "______________________________________________________________________\n\n ") + (widget-create 'push-button + :notify (lambda (&rest _ignore) + (setq ada-prj-current-values (ada-default-prj-properties)) + (ada-prj-display-page 1)) + "Reset to Default Values") + (widget-insert " ") + (widget-create 'push-button :notify (lambda (&rest _ignore) (kill-buffer nil)) + "Cancel") + (widget-insert " ") + (widget-create 'push-button :notify (lambda (&rest _ignore) (ada-prj-save)) + "Save") + (widget-insert "\n\n") + + (widget-setup) + (with-no-warnings + (beginning-of-buffer)) + ) + + +(defun ada-customize (&optional new-file filename) + "Edit the project file associated with the current buffer. +If there is none or NEW-FILE is non-nil, make a new one. +If FILENAME is given, edit that file." + (interactive) + + (let ((ada-buffer (current-buffer)) + (inhibit-read-only t)) + + ;; We can only edit interactively the standard ada-mode project files. If + ;; the user is using other formats for the project file (through hooks in + ;; `ada-load-project-hook', we simply edit the file + + (if (and (not new-file) + (or ada-prj-default-project-file filename) + (string= (file-name-extension + (or filename ada-prj-default-project-file)) + "gpr")) + (progn + (find-file ada-prj-default-project-file) + (add-hook 'after-save-hook 'ada-reread-prj-file t t) + ) + + (if filename + (ada-reread-prj-file filename) + (if (not (string= ada-prj-default-project-file "")) + (ada-reread-prj-file ada-prj-default-project-file) + (ada-reread-prj-file))) + + (switch-to-buffer "*Edit Ada Mode Project*") + + (ada-prj-initialize-values 'ada-prj-current-values + ada-buffer + ada-prj-default-project-file) + + (set (make-local-variable 'ada-prj-ada-buffer) ada-buffer) + + (use-local-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map custom-mode-map) + (define-key map "\C-x\C-s" 'ada-prj-save) + map)) + + ;; FIXME: Not sure if this works!! + (set (make-local-variable 'widget-keymap) + (let ((map (make-sparse-keymap))) + (set-keymap-parent map widget-keymap) + (define-key map "\C-x\C-s" 'ada-prj-save) + map)) + + (set (make-local-variable 'ada-old-cross-prefix) + (ada-xref-get-project-field 'cross-prefix)) + + (ada-prj-display-page 1) + ))) + +;; ---------------- Utilities -------------------------------- + +(defun ada-prj-set-list (string ada-list &optional is-directory) + "Prepend STRING to strings in ADA-LIST, return new-line separated string. +If IS-DIRECTORY is non-nil, each element of ADA-LIST is explicitly +converted to a directory name." + + (mapconcat (lambda (x) (concat string "=" + (if is-directory + (file-name-as-directory x) + x))) + ada-list "\n")) + + +(defun ada-prj-field-modified (widget &rest _dummy) + "Callback for modification of WIDGET. +Remaining args DUMMY are ignored. +Save the change in `ada-prj-current-values' so that selecting +another page and coming back keeps the new value." + (setq ada-prj-current-values + (plist-put ada-prj-current-values + (widget-get widget ':prj-field) + (widget-value widget)))) + +(defun ada-prj-display-help (widget _widget-modified event) + "Callback for help button in WIDGET. +Parameters WIDGET-MODIFIED, EVENT match :notify for the widget." + (let ((text (widget-get widget 'prj-help))) + (if event + ;; If we have a mouse-event, popup a menu + (widget-choose "Help" + (mapcar (lambda (a) (cons a t)) + (split-string text "\n")) + event) + ;; Else display the help string just before the next group of + ;; variables + (momentary-string-display + (concat "*****Help*****\n" text "\n**************\n") + (point-at-bol 2))))) + +(defun ada-prj-show-value (widget _widget-modified event) + "Show the current field value in WIDGET. +Parameters WIDGET-MODIFIED, EVENT match :notify for the widget." + (let* ((field (widget-get widget ':prj-field)) + (value (plist-get ada-prj-current-values field)) + (inhibit-read-only t) + w) + + ;; If the other widget is already visible, delete it + (if (widget-get widget 'prj-other-widget) + (progn + (widget-delete (widget-get widget 'prj-other-widget)) + (widget-put widget 'prj-other-widget nil) + (widget-put widget ':prj-field field) + (widget-default-value-set widget "Show Value") + ) + + ;; Else create it + (save-excursion + (mouse-set-point event) + (forward-line 1) + (beginning-of-line) + (setq w (widget-create 'editable-list + :entry-format "%i%d %v" + :notify 'ada-prj-field-modified + :help-echo (widget-get widget 'prj-help) + :value value + (list 'editable-field :keymap widget-keymap))) + (widget-put widget 'prj-other-widget w) + (widget-put w ':prj-field field) + (widget-put widget ':prj-field field) + (widget-default-value-set widget "Hide Value") + ) + ) + (widget-setup) + )) + +(defun ada-prj-field (field text help-text &optional is-list is-paths after-text) + "Create a widget to edit FIELD in the current buffer. +TEXT is a short explanation of what the field means, whereas HELP-TEXT +is the text displayed when the user pressed the help button. +If IS-LIST is non-nil, the field contains a list. Otherwise, it contains +a single string. +If IS-PATHS is true, some special buttons are added to load paths,... +AFTER-TEXT is inserted just after the widget." + (let ((value (plist-get ada-prj-current-values field)) + (inhibit-read-only t) + widget) + (unless value + (setq value + (if is-list '() ""))) + (widget-insert text) + (widget-insert ":") + (move-to-column 54 t) + (widget-put (widget-create 'push-button + :notify 'ada-prj-display-help + "Help") + 'prj-help + help-text) + (widget-insert (concat " (" (symbol-name field) ")\n")) + (if is-paths + (progn + (widget-create 'push-button + :notify + (list 'lambda '(&rest dummy) '(interactive) + (list 'ada-prj-load-from-file + (list 'quote field))) + "Load From File") + (widget-insert " ") + (widget-create 'push-button + :notify + (list 'lambda '(&rest dummy) '(interactive) + (list 'ada-prj-load-directory + (list 'quote field))) + "Load Recursive Directory") + (widget-insert "\n ${build_dir}\n"))) + + (setq widget + (if is-list + (if (< (length value) 15) + (widget-create 'editable-list + :entry-format "%i%d %v" + :notify 'ada-prj-field-modified + :help-echo help-text + :value value + (list 'editable-field :keymap widget-keymap)) + + (let ((w (widget-create 'push-button + :notify 'ada-prj-show-value + "Show value"))) + (widget-insert "\n") + (widget-put w 'prj-help help-text) + (widget-put w 'prj-other-widget nil) + w) + ) + (widget-create 'editable-field + :format "%v" + :notify 'ada-prj-field-modified + :help-echo help-text + :keymap widget-keymap + value))) + (widget-put widget ':prj-field field) + (if after-text + (widget-insert after-text)) + (widget-insert "\n") + )) + + +(provide 'ada-prj) + +;;; ada-prj.el ends here diff --git a/ada-mode/ada-stmt.el b/ada-mode/ada-stmt.el new file mode 100644 index 0000000..ef42b0d --- /dev/null +++ b/ada-mode/ada-stmt.el @@ -0,0 +1,486 @@ +;;; ada-stmt.el --- an extension to Ada mode for inserting statement templates + +;; Copyright (C) 1987, 1993-1994, 1996-2019 Free Software Foundation, +;; Inc. + +;; Authors: Daniel Pfeiffer +;; Markus Heritsch +;; Rolf Ebert +;; Maintainer: Stephen Leake +;; Keywords: languages, ada +;; Package: ada-mode + +;; 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 . + +;;; Commentary: +;; This file is now automatically loaded from ada-mode.el, and creates a submenu +;; in Ada/ on the menu bar. + +;;; History: + +;; Created May 1987. +;; Original version from V. Bowman as in ada.el of Emacs-18 +;; (borrowed heavily from Mick Jordan's Modula-2 package for GNU, +;; as modified by Peter Robinson, Michael Schmidt, and Tom Perrine.) +;; +;; Sep 1993. Daniel Pfeiffer (DP) +;; Introduced statement.el for smaller code and user configurability. +;; +;; Nov 1993. Rolf Ebert (RE) Moved the +;; skeleton generation into this separate file. The code still is +;; essentially written by DP +;; +;; Adapted Jun 1994. Markus Heritsch +;; (MH) +;; added menu bar support for templates +;; +;; 1994/12/02 Christian Egli +;; General cleanup and bug fixes. +;; +;; 1995/12/20 John Hutchison +;; made it work with skeleton.el from Emacs-19.30. Several +;; enhancements and bug fixes. + +;; BUGS: +;;;> I have the following suggestions for the function template: 1) I +;;;> don't want it automatically assigning it a name for the return variable. I +;;;> never want it to be called "Result" because that is nondescript. If you +;;;> must define a variable, give me the ability to specify its name. +;;;> +;;;> 2) You do not provide a type for variable 'Result'. Its type is the same +;;;> as the function's return type, which the template knows, so why force me +;;;> to type it in? +;;;> + +;;;It would be nice if one could configure such layout details separately +;;;without patching the LISP code. Maybe the metalanguage used in ada-stmt.el +;;;could be taken even further, providing the user with some nice syntax +;;;for describing layout. Then my own hacks would survive the next +;;;update of the package :-) + + +;;; Code: + +(require 'skeleton nil t) +(require 'easymenu) +(require 'ada-mode) + +(defun ada-func-or-proc-name () + "Return the name of the current function or procedure." + (save-excursion + (let ((case-fold-search t)) + (if (re-search-backward ada-procedure-start-regexp nil t) + (match-string 5) + "NAME?")))) + +;;; ---- statement skeletons ------------------------------------------ + +(define-skeleton ada-array + "Insert array type definition. +Prompt for component type and index subtypes." + () + "array (" ("index definition: " str ", " ) -2 ") of " _ ?\;) + + +(define-skeleton ada-case + "Build skeleton case statement. +Prompt for the selector expression. Also builds the first when clause." + "[selector expression]: " + "case " str " is" \n + > "when " ("discrete choice: " str " | ") -3 " =>" \n + > _ \n + < < "end case;") + + +(define-skeleton ada-when + "Start a case statement alternative with a when clause." + () + < "when " ("discrete choice: " str " | ") -3 " =>" \n + >) + + +(define-skeleton ada-declare-block + "Insert a block with a declare part. +Indent for the first declaration." + "[block name]: " + < str & ?: & \n + > "declare" \n + > _ \n + < "begin" \n + > \n + < "end " str | -1 ?\;) + + +(define-skeleton ada-exception-block + "Insert a block with an exception part. +Indent for the first line of code." + "[block name]: " + < str & ?: & \n + > "begin" \n + > _ \n + < "exception" \n + > \n + < "end " str | -1 ?\;) + + +(define-skeleton ada-exception + "Insert an indented exception part into a block." + () + < "exception" \n + >) + + +(define-skeleton ada-exit-1 + "Insert then exit condition of the exit statement, prompting for condition." + "[exit condition]: " + "when " str | -5) + + +(define-skeleton ada-exit + "Insert an exit statement, prompting for loop name and condition." + "[name of loop to exit]: " + "exit " str & ?\ (ada-exit-1) | -1 ?\;) + +;;;###autoload +(defun ada-header () + "Insert a descriptive header at the top of the file." + (interactive "*") + (save-excursion + (goto-char (point-min)) + (if (fboundp 'make-header) + (funcall (symbol-function 'make-header)) + (ada-header-tmpl)))) + + +(define-skeleton ada-header-tmpl + "Insert a comment block containing the module title, author, etc." + "[Description]: " + "-- -*- Mode: Ada -*-" + "\n" ada-fill-comment-prefix "Filename : " (buffer-name) + "\n" ada-fill-comment-prefix "Description : " str + "\n" ada-fill-comment-prefix "Author : " (user-full-name) + "\n" ada-fill-comment-prefix "Created On : " (current-time-string) + "\n" ada-fill-comment-prefix "Last Modified By: ." + "\n" ada-fill-comment-prefix "Last Modified On: ." + "\n" ada-fill-comment-prefix "Update Count : 0" + "\n" ada-fill-comment-prefix "Status : Unknown, Use with caution!" + "\n") + + +(define-skeleton ada-display-comment + "Inserts three comment lines, making a display comment." + () + "--\n" ada-fill-comment-prefix _ "\n--") + + +(define-skeleton ada-if + "Insert skeleton if statement, prompting for a boolean-expression." + "[condition]: " + "if " str " then" \n + > _ \n + < "end if;") + + +(define-skeleton ada-elsif + "Add an elsif clause to an if statement, +prompting for the boolean-expression." + "[condition]: " + < "elsif " str " then" \n + >) + + +(define-skeleton ada-else + "Add an else clause inside an if-then-end-if clause." + () + < "else" \n + >) + + +(define-skeleton ada-loop + "Insert a skeleton loop statement. The exit statement is added by hand." + "[loop name]: " + < str & ?: & \n + > "loop" \n + > _ \n + < "end loop " str | -1 ?\;) + + +(define-skeleton ada-for-loop-prompt-variable + "Prompt for the loop variable." + "[loop variable]: " + str) + + +(define-skeleton ada-for-loop-prompt-range + "Prompt for the loop range." + "[loop range]: " + str) + + +(define-skeleton ada-for-loop + "Build a skeleton for-loop statement, prompting for the loop parameters." + "[loop name]: " + < str & ?: & \n + > "for " + (ada-for-loop-prompt-variable) + " in " + (ada-for-loop-prompt-range) + " loop" \n + > _ \n + < "end loop " str | -1 ?\;) + + +(define-skeleton ada-while-loop-prompt-entry-condition + "Prompt for the loop entry condition." + "[entry condition]: " + str) + + +(define-skeleton ada-while-loop + "Insert a skeleton while loop statement." + "[loop name]: " + < str & ?: & \n + > "while " + (ada-while-loop-prompt-entry-condition) + " loop" \n + > _ \n + < "end loop " str | -1 ?\;) + + +(define-skeleton ada-package-spec + "Insert a skeleton package specification." + "[package name]: " + "package " str " is" \n + > _ \n + < "end " str ?\;) + + +(define-skeleton ada-package-body + "Insert a skeleton package body -- includes a begin statement." + "[package name]: " + "package body " str " is" \n + > _ \n +; < "begin" \n + < "end " str ?\;) + + +(define-skeleton ada-private + "Undent and start a private section of a package spec. Reindent." + () + < "private" \n + >) + + +(define-skeleton ada-function-spec-prompt-return + "Prompts for function result type." + "[result type]: " + str) + + +(define-skeleton ada-function-spec + "Insert a function specification. Prompts for name and arguments." + "[function name]: " + "function " str + " (" ("[parameter_specification]: " str "; " ) -2 ")" + " return " + (ada-function-spec-prompt-return) + ";" \n ) + + +(define-skeleton ada-procedure-spec + "Insert a procedure specification, prompting for its name and arguments." + "[procedure name]: " + "procedure " str + " (" ("[parameter_specification]: " str "; " ) -2 ")" + ";" \n ) + + +(define-skeleton ada-subprogram-body + "Insert frame for subprogram body. +Invoke right after `ada-function-spec' or `ada-procedure-spec'." + () + ;; Remove `;' from subprogram decl + (save-excursion + (let ((pos (1+ (point)))) + (ada-search-ignore-string-comment ada-subprog-start-re t nil) + (when (ada-search-ignore-string-comment "(" nil pos t 'search-forward) + (backward-char 1) + (forward-sexp 1))) + (if (looking-at ";") + (delete-char 1))) + " is" \n + _ \n + < "begin" \n + \n + < "exception" \n + "when others => null;" \n + < < "end " + (ada-func-or-proc-name) + ";" \n) + + +(define-skeleton ada-separate + "Finish a body stub with `separate'." + () + > "separate;" \n + <) + + +;(define-skeleton ada-with +; "Inserts a with clause, prompting for the list of units depended upon." +; "[list of units depended upon]: " +; "with " str ?\;) + +;(define-skeleton ada-use +; "Inserts a use clause, prompting for the list of packages used." +; "[list of packages used]: " +; "use " str ?\;) + + +(define-skeleton ada-record + "Insert a skeleton record type declaration." + () + "record" \n + > _ \n + < "end record;") + + +(define-skeleton ada-subtype + "Start insertion of a subtype declaration, prompting for the subtype name." + "[subtype name]: " + "subtype " str " is " _ ?\; + (not (message "insert subtype indication."))) + + +(define-skeleton ada-type + "Start insertion of a type declaration, prompting for the type name." + "[type name]: " + "type " str ?\( + ("[discriminant specs]: " str " ") + | (backward-delete-char 1) | ?\) + " is " + (not (message "insert type definition."))) + + +(define-skeleton ada-task-body + "Insert a task body, prompting for the task name." + "[task name]: " + "task body " str " is\n" + "begin\n" + > _ \n + < "end " str ";" ) + + +(define-skeleton ada-task-spec + "Insert a task specification, prompting for the task name." + "[task name]: " + "task " str + " (" ("[discriminant]: " str "; ") ") is\n" + > "entry " _ \n + <"end " str ";" ) + + +(define-skeleton ada-get-param1 + "Prompt for arguments and if any enclose them in brackets." + () + ("[parameter_specification]: " str "; " ) & -2 & ")") + + +(define-skeleton ada-get-param + "Prompt for arguments and if any enclose them in brackets." + () + " (" + (ada-get-param1) | -2) + + +(define-skeleton ada-entry + "Insert a task entry, prompting for the entry name." + "[entry name]: " + "entry " str + (ada-get-param) + ";" \n) + + +(define-skeleton ada-entry-family-prompt-discriminant + "Insert an entry specification, prompting for the entry name." + "[discriminant name]: " + str) + + +(define-skeleton ada-entry-family + "Insert an entry specification, prompting for the entry name." + "[entry name]: " + "entry " str + " (" (ada-entry-family-prompt-discriminant) ")" + (ada-get-param) + ";" \n) + + +(define-skeleton ada-select + "Insert a select block." + () + "select\n" + > _ \n + < "end select;") + + +(define-skeleton ada-accept-1 + "Insert a condition statement, prompting for the condition name." + "[condition]: " + "when " str | -5 ) + + +(define-skeleton ada-accept-2 + "Insert an accept statement, prompting for the name and arguments." + "[accept name]: " + > "accept " str + (ada-get-param) + " do" \n + > _ \n + < "end " str ";" ) + + +(define-skeleton ada-accept + "Insert an accept statement (prompt for condition, name and arguments)." + () + > (ada-accept-1) & " =>\n" + (ada-accept-2)) + + +(define-skeleton ada-or-accept + "Insert an accept alternative, prompting for the condition name." + () + < "or\n" + (ada-accept)) + + +(define-skeleton ada-or-delay + "Insert a delay alternative, prompting for the delay value." + "[delay value]: " + < "or\n" + > "delay " str ";") + + +(define-skeleton ada-or-terminate + "Insert a terminate alternative." + () + < "or\n" + > "terminate;") + + +(provide 'ada-stmt) + +;;; ada-stmt.el ends here diff --git a/ada-mode/ada-xref.el b/ada-mode/ada-xref.el new file mode 100644 index 0000000..c9c923e --- /dev/null +++ b/ada-mode/ada-xref.el @@ -0,0 +1,2359 @@ +;; ada-xref.el --- for lookup and completion in Ada mode + +;; Copyright (C) 1994-2019 Free Software Foundation, Inc. + +;; Author: Markus Heritsch +;; Rolf Ebert +;; Emmanuel Briot +;; Maintainer: Stephen Leake +;; Keywords: languages ada xref +;; Package: ada-mode + +;; 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 . + +;;; Commentary: + +;; This Package provides a set of functions to use the output of the +;; cross reference capabilities of the GNAT Ada compiler +;; for lookup and completion in Ada mode. +;; +;; If a file *.`adp' exists in the ada-file directory, then it is +;; read for configuration information. It is read only the first +;; time a cross-reference is asked for, and is not read later. + +;;; Code: + +;; ----- Requirements ----------------------------------------------------- + +(require 'compile) +(require 'comint) +(require 'find-file) +(require 'ada-mode) +(eval-when-compile (require 'cl-lib)) + +;; ------ User variables +(defcustom ada-xref-other-buffer t + "If nil, always display the cross-references in the same buffer. +Otherwise create either a new buffer or a new frame." + :type 'boolean :group 'ada) + +(defcustom ada-xref-create-ali nil + "If non-nil, run gcc whenever the cross-references are not up-to-date. +If nil, the cross-reference mode never runs gcc." + :type 'boolean :group 'ada) + +(defcustom ada-xref-confirm-compile nil + "If non-nil, ask for confirmation before compiling or running the application." + :type 'boolean :group 'ada) + +(defcustom ada-krunch-args "0" + "Maximum number of characters for filenames created by `gnatkr'. +Set to 0, if you don't use crunched filenames. This should be a string." + :type 'string :group 'ada) + +(defcustom ada-gnat-cmd "gnat" + "Default GNAT project file parser. +Will be run with args \"list -v -Pfile.gpr\". +Default is standard GNAT distribution; alternate \"gnatpath\" +is faster, available from Ada mode web site." + :type 'string :group 'ada) + +(defcustom ada-gnatls-args '("-v") + "Arguments to pass to `gnatls' to find location of the runtime. +Typical use is to pass `--RTS=soft-floats' on some systems that support it. + +You can also add `-I-' if you do not want the current directory to be included. +Otherwise, going from specs to bodies and back will first look for files in the +current directory. This only has an impact if you are not using project files, +but only ADA_INCLUDE_PATH." + :type '(repeat string) :group 'ada) + +(defcustom ada-prj-default-comp-opt "-gnatq -gnatQ" + "Default compilation options." + :type 'string :group 'ada) + +(defcustom ada-prj-default-bind-opt "" + "Default binder options." + :type 'string :group 'ada) + +(defcustom ada-prj-default-link-opt "" + "Default linker options." + :type 'string :group 'ada) + +(defcustom ada-prj-default-gnatmake-opt "-g" + "Default options for `gnatmake'." + :type 'string :group 'ada) + +(defcustom ada-prj-default-gpr-file "" + "Default GNAT project file. +If non-empty, this file is parsed to set the source and object directories for +the Ada mode project." + :type 'string :group 'ada) + +(defcustom ada-prj-ada-project-path-sep + (cond ((boundp 'path-separator) path-separator) ; 20.3+ + ((memq system-type '(windows-nt ms-dos)) ";") + (t ":")) + "Default separator for ada_project_path project variable." + :type 'string :group 'ada) + +(defcustom ada-prj-gnatfind-switches "-rf" + "Default switches to use for `gnatfind'. +You should modify this variable, for instance to add `-a', if you are working +in an environment where most ALI files are write-protected. +The command `gnatfind' is used every time you choose the menu +\"Show all references\"." + :type 'string :group 'ada) + +(defcustom ada-prj-default-check-cmd + (concat "${cross_prefix}gnatmake -u -c -gnatc ${gnatmake_opt} ${full_current}" + " -cargs ${comp_opt}") + "Default command to be used to compile a single file. +Emacs will substitute the current filename for ${full_current}, or add +the filename at the end. This is the same syntax as in the project file." + :type 'string :group 'ada) + +(defcustom ada-prj-default-comp-cmd + (concat "${cross_prefix}gnatmake -u -c ${gnatmake_opt} ${full_current} -cargs" + " ${comp_opt}") + "Default command to be used to compile a single file. +Emacs will substitute the current filename for ${full_current}, or add +the filename at the end. This is the same syntax as in the project file." + :type 'string :group 'ada) + +(defcustom ada-prj-default-debugger "${cross_prefix}gdb" + "Default name of the debugger." + :type 'string :group 'ada) + +(defcustom ada-prj-default-make-cmd + (concat "${cross_prefix}gnatmake -o ${main} ${main} ${gnatmake_opt} " + "-cargs ${comp_opt} -bargs ${bind_opt} -largs ${link_opt}") + "Default command to be used to compile the application. +This is the same syntax as in the project file." + :type 'string :group 'ada) + +(defcustom ada-prj-default-project-file "" + "Name of the current project file. +Emacs will not try to use the search algorithm to find the project file if +this string is not empty. It is set whenever a project file is found." + :type '(file :must-match t) :group 'ada) + +(defcustom ada-gnatstub-opts "-q -I${src_dir}" + "Options to pass to `gnatsub' to generate the body of a package. +This has the same syntax as in the project file (with variable substitution)." + :type 'string :group 'ada) + +(defcustom ada-always-ask-project nil + "If nil, use default values when no project file was found. +Otherwise, ask the user for the name of the project file to use." + :type 'boolean :group 'ada) + +(defconst ada-on-ms-windows (memq system-type '(windows-nt)) + "True if we are running on Windows.") + +(defcustom ada-tight-gvd-integration nil + "If non-nil, a new Emacs frame will be swallowed in GVD when debugging. +If GVD is not the debugger used, nothing happens." + :type 'boolean :group 'ada) + +(defcustom ada-xref-search-with-egrep t + "If non-nil, use grep -E to find the possible declarations for an entity. +This alternate method is used when the exact location was not found in the +information provided by GNAT. However, it might be expensive if you have a lot +of sources, since it will search in all the files in your project." + :type 'boolean :group 'ada) + +(defvar ada-load-project-hook nil + "Hook that is run when loading a project file. +Each function in this hook takes one argument FILENAME, that is the name of +the project file to load. +This hook should be used to support new formats for the project files. + +If the function can load the file with the given filename, it should create a +buffer that contains a conversion of the file to the standard format of the +project files, and return that buffer. (The usual \"src_dir=\" or \"obj_dir=\" +lines.) It should return nil if it doesn't know how to convert that project +file.") + + +;; ------- Nothing to be modified by the user below this +(defvar ada-last-prj-file "" + "Name of the last project file entered by the user.") + +(defconst ada-prj-file-extension ".adp" + "The extension used for project files.") + +(defvar ada-xref-runtime-library-specs-path '() + "Directories where the specs for the standard library is found. +This is used for cross-references.") + +(defvar ada-xref-runtime-library-ali-path '() + "Directories where the ali for the standard library is found. +This is used for cross-references.") + +(defvar ada-xref-pos-ring '() + "List of positions selected by the cross-references functions. +Used to go back to these positions.") + +(defvar ada-cd-command + (if (string-match "cmdproxy.exe" shell-file-name) + "cd /d" + "cd") + "Command to use to change to a specific directory. +On Windows systems using `cmdproxy.exe' as the shell, +we need to use `/d' or the drive is never changed.") + +(defvar ada-command-separator (if ada-on-ms-windows " && " "\n") + "Separator to use between multiple commands to `compile' or `start-process'. +`cmdproxy.exe' doesn't recognize multiple-line commands, so we have to use +\"&&\" for now.") + +(defconst ada-xref-pos-ring-max 16 + "Number of positions kept in the list `ada-xref-pos-ring'.") + +(defvar ada-operator-re + "\\+\\|-\\|/\\|\\*\\*\\|\\*\\|=\\|&\\|abs\\|mod\\|rem\\|and\\|not\\|or\\|xor\\|<=\\|<\\|>=\\|>" + "Regexp to match for operators.") + +(defvar ada-xref-project-files '() + "Associative list of project files with properties. +It has the format: (project project ...) +A project has the format: (project-file . project-plist) +\(See `apropos plist' for operations on property lists). +See `ada-default-prj-properties' for the list of valid properties. +The current project is retrieved with `ada-xref-current-project'. +Properties are retrieved with `ada-xref-get-project-field', set with +`ada-xref-set-project-field'. If project properties are accessed with no +project file, a (nil . default-properties) entry is created.") + + +;; ----- Identlist manipulation ------------------------------------------- +;; An identlist is a vector that is used internally to reference an identifier +;; To facilitate its use, we provide the following macros + +(defmacro ada-make-identlist () (make-vector 8 nil)) +(defmacro ada-name-of (identlist) (list 'aref identlist 0)) +(defmacro ada-line-of (identlist) (list 'aref identlist 1)) +(defmacro ada-column-of (identlist) (list 'aref identlist 2)) +(defmacro ada-file-of (identlist) (list 'aref identlist 3)) +(defmacro ada-ali-index-of (identlist) (list 'aref identlist 4)) +(defmacro ada-declare-file-of (identlist) (list 'aref identlist 5)) +(defmacro ada-references-of (identlist) (list 'aref identlist 6)) +(defmacro ada-on-declaration (identlist) (list 'aref identlist 7)) + +(defmacro ada-set-name (identlist name) (list 'aset identlist 0 name)) +(defmacro ada-set-line (identlist line) (list 'aset identlist 1 line)) +(defmacro ada-set-column (identlist col) (list 'aset identlist 2 col)) +(defmacro ada-set-file (identlist file) (list 'aset identlist 3 file)) +(defmacro ada-set-ali-index (identlist index) (list 'aset identlist 4 index)) +(defmacro ada-set-declare-file (identlist file) (list 'aset identlist 5 file)) +(defmacro ada-set-references (identlist ref) (list 'aset identlist 6 ref)) +(defmacro ada-set-on-declaration (ident value) (list 'aset ident 7 value)) + +(defsubst ada-get-ali-buffer (file) + "Read the ali file FILE into a new buffer, and return the buffer's name." + (find-file-noselect (ada-get-ali-file-name file))) + + +;; ----------------------------------------------------------------------- + +(defun ada-quote-cmd (cmd) + "Duplicate all `\\' characters in CMD so that it can be passed to `compile'." + (mapconcat 'identity (split-string cmd "\\\\") "\\\\")) + +(defun ada-find-executable (exec-name) + "Find the full path to the executable file EXEC-NAME. +If not found, throw an error. +On Windows systems, this will properly handle .exe extension as well." + (let ((result (or (ada-find-file-in-dir exec-name exec-path) + (ada-find-file-in-dir (concat exec-name ".exe") exec-path)))) + (if result + result + (error "`%s' not found in path" exec-name)))) + +(defun ada-initialize-runtime-library (cross-prefix) + "Initialize the variables for the runtime library location. +CROSS-PREFIX is the prefix to use for the `gnatls' command." + (let ((gnatls + (condition-case nil + ;; if gnatls not found, just give up (may not be using GNAT) + (ada-find-executable (concat cross-prefix "gnatls")) + (error nil)))) + (if gnatls + (save-excursion + (setq ada-xref-runtime-library-specs-path '() + ada-xref-runtime-library-ali-path '()) + (set-buffer (get-buffer-create "*gnatls*")) + (widen) + (erase-buffer) + ;; Even if we get an error, delete the *gnatls* buffer + (unwind-protect + (let ((status (apply 'call-process gnatls (append '(nil t nil) ada-gnatls-args)))) + (goto-char (point-min)) + + ;; Since we didn't provide all the inputs gnatls expects, it returns status 4 + (if (/= 4 status) + (error (buffer-substring (point) (line-end-position)))) + + ;; Source path + + (search-forward "Source Search Path:") + (forward-line 1) + (while (not (looking-at "^$")) + (back-to-indentation) + (add-to-list 'ada-xref-runtime-library-specs-path + (if (looking-at "") + "." + (buffer-substring-no-properties + (point) + (point-at-eol)))) + (forward-line 1)) + + ;; Object path + + (search-forward "Object Search Path:") + (forward-line 1) + (while (not (looking-at "^$")) + (back-to-indentation) + (add-to-list 'ada-xref-runtime-library-ali-path + (if (looking-at "") + "." + (buffer-substring-no-properties + (point) + (point-at-eol)))) + (forward-line 1)) + ) + (kill-buffer nil)))) + + (setq ada-xref-runtime-library-specs-path + (reverse ada-xref-runtime-library-specs-path)) + (setq ada-xref-runtime-library-ali-path + (reverse ada-xref-runtime-library-ali-path)) + )) + +(defun ada-gnat-parse-gpr (plist gpr-file) + "Set gpr_file, src_dir and obj_dir properties in PLIST by parsing GPR-FILE. +Return new value of PLIST. +GPR_FILE must be full path to file, normalized. +src_dir, obj_dir will include compiler runtime. +Assumes environment variable ADA_PROJECT_PATH is set properly." + (with-current-buffer (get-buffer-create "*gnatls*") + (erase-buffer) + + ;; this can take a long time; let the user know what's up + (message "Parsing %s ..." gpr-file) + + ;; Even if we get an error, delete the *gnatls* buffer + (unwind-protect + (let* ((cross-prefix (plist-get plist 'cross_prefix)) + (gnat (concat cross-prefix ada-gnat-cmd)) + ;; Putting quotes around gpr-file confuses gnatpath on Lynx; not clear why + (gpr-opt (concat "-P" gpr-file)) + (src-dir '()) + (obj-dir '()) + (status (call-process gnat nil t nil "list" "-v" gpr-opt))) + (goto-char (point-min)) + + (if (/= 0 status) + (error (buffer-substring (point) (line-end-position)))) + + ;; Source path + + (search-forward "Source Search Path:") + (forward-line 1) ; first directory in list + (while (not (looking-at "^$")) ; terminate on blank line + (back-to-indentation) ; skip whitespace + (cl-pushnew (if (looking-at "") + default-directory + (expand-file-name + (buffer-substring-no-properties + (point) (line-end-position)))) + src-dir :test #'equal) + (forward-line 1)) + + ;; Object path + + (search-forward "Object Search Path:") + (forward-line 1) + (while (not (looking-at "^$")) + (back-to-indentation) + (cl-pushnew (if (looking-at "") + default-directory + (expand-file-name + (buffer-substring-no-properties + (point) (line-end-position)))) + obj-dir :test #'equal) + (forward-line 1)) + + ;; Set properties + (setq plist (plist-put plist 'gpr_file gpr-file)) + (setq plist (plist-put plist 'src_dir src-dir)) + (plist-put plist 'obj_dir obj-dir) + ) + (kill-buffer nil) + (message "Parsing %s ... done" gpr-file) + ) + )) + +(defun ada-treat-cmd-string (cmd-string) + "Replace variable references ${var} in CMD-STRING with the appropriate value. +Also replace standard environment variables $var. +Assumes project exists. +As a special case, ${current} is replaced with the name of the current +file, minus extension but with directory, and ${full_current} is +replaced by the name including the extension." + + (while (string-match "\\(-[^-$IO]*[IO]\\)?\\${\\([^}]+\\)}" cmd-string) + (let (value + (name (match-string 2 cmd-string))) + (cond + ((string= name "current") + (setq value (file-name-sans-extension (buffer-file-name)))) + ((string= name "full_current") + (setq value (buffer-file-name))) + (t + (save-match-data + (setq value (ada-xref-get-project-field (intern name)))))) + + ;; Check if there is an environment variable with the same name + (if (null value) + (if (not (setq value (getenv name))) + (message "%s" (concat "No project or environment variable " name " found")))) + + (cond + ((null value) + (setq cmd-string (replace-match "" t t cmd-string))) + ((stringp value) + (setq cmd-string (replace-match value t t cmd-string))) + ((listp value) + (let ((prefix (match-string 1 cmd-string))) + (setq cmd-string (replace-match + (mapconcat (lambda(x) (concat prefix x)) value " ") + t t cmd-string))))) + )) + (substitute-in-file-name cmd-string)) + + +(defun ada-xref-get-project-field (field) + "Extract the value of FIELD from the current project file. +Project variables are substituted. + +Note that for src_dir and obj_dir, you should rather use +`ada-xref-get-src-dir-field' or `ada-xref-get-obj-dir-field' +which will in addition return the default paths." + + (let* ((project-plist (cdr (ada-xref-current-project))) + (value (plist-get project-plist field))) + + (cond + ((eq field 'gnatmake_opt) + (let ((gpr-file (plist-get project-plist 'gpr_file))) + (if (not (string= gpr-file "")) + (setq value (concat "-P\"" gpr-file "\" " value))))) + + ;; FIXME: check for src_dir, obj_dir here, rather than requiring user to do it + (t + nil)) + + ;; Substitute the ${...} constructs in all the strings, including + ;; inside lists + (cond + ((stringp value) + (ada-treat-cmd-string value)) + ((null value) + nil) + ((listp value) + (mapcar (lambda(x) (if x (ada-treat-cmd-string x) x)) value)) + (t + value) + ) + )) + +(defun ada-xref-get-src-dir-field () + "Return the full value for src_dir, including the default directories. +All the directories are returned as absolute directories." + + (let ((build-dir (ada-xref-get-project-field 'build_dir))) + (append + ;; Add ${build_dir} in front of the path + (list build-dir) + + (ada-get-absolute-dir-list (ada-xref-get-project-field 'src_dir) + build-dir) + + ;; Add the standard runtime at the end + ada-xref-runtime-library-specs-path))) + +(defun ada-xref-get-obj-dir-field () + "Return the full value for obj_dir, including the default directories. +All the directories are returned as absolute directories." + + (let ((build-dir (ada-xref-get-project-field 'build_dir))) + (append + ;; Add ${build_dir} in front of the path + (list build-dir) + + (ada-get-absolute-dir-list (ada-xref-get-project-field 'obj_dir) + build-dir) + + ;; Add the standard runtime at the end + ada-xref-runtime-library-ali-path))) + +(defun ada-xref-set-project-field (field value) + "Set FIELD to VALUE in current project. Assumes project exists." + ;; same algorithm to find project-plist as ada-xref-current-project + (let* ((file-name (ada-xref-current-project-file)) + (project-plist (cdr (assoc file-name ada-xref-project-files)))) + + (setq project-plist (plist-put project-plist field value)) + (setcdr (assoc file-name ada-xref-project-files) project-plist))) + +(defun ada-xref-update-project-menu () + "Update the menu Ada->Project, with the list of available project files." + ;; Create the standard items. + (let ((submenu + `("Project" + ["Load..." ada-set-default-project-file t] + ["New..." ada-prj-new t] + ["Edit..." ada-prj-edit t] + "---" + ;; Add the project files + ,@(mapcar + (lambda (x) + (let* ((name (or (car x) "")) + (command `(lambda () + "Select the current project file." + (interactive) + (ada-select-prj-file ,name)))) + (vector + (file-name-nondirectory name) + command + :button (cons + :toggle + (equal ada-prj-default-project-file + (car x)) + )))) + + (or ada-xref-project-files '(nil)))))) + + (easy-menu-add-item ada-mode-menu '() submenu))) + + +;;------------------------------------------------------------- +;;-- Searching a file anywhere on the source path. +;;-- +;;-- The following functions provide support for finding a file anywhere +;;-- on the source path, without providing an explicit directory. +;;-- They also provide file name completion in the minibuffer. +;;-- +;;-- Public subprograms: ada-find-file +;;-- +;;------------------------------------------------------------- + +(defun ada-do-file-completion (string predicate flag) + "Completion function when reading a file from the minibuffer. +Completion is attempted in all the directories in the source path, +as defined in the project file." + ;; FIXME: doc arguments + + ;; This function is not itself interactive, but it is called as part + ;; of the prompt of interactive functions, so we require a project + ;; file. + (ada-require-project-file) + (let (list + (dirs (ada-xref-get-src-dir-field))) + + (while dirs + (if (file-directory-p (car dirs)) + (setq list (append list (file-name-all-completions string (car dirs))))) + (setq dirs (cdr dirs))) + (cond ((equal flag 'lambda) + (assoc string list)) + (flag + list) + (t + (try-completion string + (mapcar (lambda (x) (cons x 1)) list) + predicate))))) + +;;;###autoload +(defun ada-find-file (filename) + "Open FILENAME, from anywhere in the source path. +Completion is available." + (interactive + (list (completing-read "File: " 'ada-do-file-completion))) + (let ((file (ada-find-src-file-in-dir filename))) + (if file + (find-file file) + (error "%s not found in src_dir" filename)))) + + +;; ----- Utilities ------------------------------------------------- + +(defun ada-require-project-file () + "If the current project does not exist, load or create a default one. +Should only be called from interactive functions." + (if (string= "" ada-prj-default-project-file) + (ada-reread-prj-file (ada-prj-find-prj-file t)))) + +(defun ada-xref-current-project-file () + "Return the current project file name; never nil. +Call `ada-require-project-file' first if a project must exist." + (if (not (string= "" ada-prj-default-project-file)) + ada-prj-default-project-file + (ada-prj-find-prj-file t))) + +(defun ada-xref-current-project () + "Return the current project. +Call `ada-require-project-file' first to ensure a project exists." + (let ((file-name (ada-xref-current-project-file))) + (assoc file-name ada-xref-project-files))) + +(defun ada-show-current-project () + "Display current project file name in message buffer." + (interactive) + (message (ada-xref-current-project-file))) + +(defun ada-show-current-main () + "Display current main file name in message buffer." + (interactive) + (message "ada-mode main: %s" (ada-xref-get-project-field 'main))) + +(defun ada-xref-push-pos (filename position) + "Push (FILENAME, POSITION) on the position ring for cross-references." + (setq ada-xref-pos-ring (cons (list position filename) ada-xref-pos-ring)) + (if (> (length ada-xref-pos-ring) ada-xref-pos-ring-max) + (setcdr (nthcdr (1- ada-xref-pos-ring-max) ada-xref-pos-ring) nil))) + +(defun ada-xref-goto-previous-reference () + "Go to the previous cross-reference we were on." + (interactive) + (if ada-xref-pos-ring + (let ((pos (car ada-xref-pos-ring))) + (setq ada-xref-pos-ring (cdr ada-xref-pos-ring)) + (find-file (car (cdr pos))) + (goto-char (car pos))))) + +(defun ada-set-default-project-file (file) + "Set FILE as the current project file." + (interactive "fProject file:") + (ada-parse-prj-file file) + (ada-select-prj-file file)) + +;; ------ Handling the project file ----------------------------- + +(defun ada-prj-find-prj-file (&optional no-user-question) + "Find the project file associated with the current buffer. +If the buffer is not in Ada mode, or not associated with a file, +return `ada-prj-default-project-file'. Otherwise, search for a file with +the same base name as the Ada file, but extension given by +`ada-prj-file-extension' (default .adp). If not found, search for *.adp +in the current directory; if several are found, and NO-USER-QUESTION +is non-nil, prompt the user to select one. If none are found, return +\"default.adp\"." + + (let (selected) + + (if (not (and (derived-mode-p 'ada-mode) + buffer-file-name)) + + ;; Not in an Ada buffer, or current buffer not associated + ;; with a file (for instance an emerge buffer) + (setq selected nil) + + ;; other cases: use a more complex algorithm + + (let* ((current-file (buffer-file-name)) + (first-choice (concat + (file-name-sans-extension current-file) + ada-prj-file-extension)) + (dir (file-name-directory current-file)) + + (prj-files (directory-files + dir t + (concat ".*" (regexp-quote + ada-prj-file-extension) "$"))) + (choice nil)) + + (cond + + ((file-exists-p first-choice) + ;; filename.adp + (setq selected first-choice)) + + ((= (length prj-files) 1) + ;; Exactly one project file was found in the current directory + (setq selected (car prj-files))) + + ((and (> (length prj-files) 1) (not no-user-question)) + ;; multiple project files in current directory, ask the user + (save-window-excursion + (with-output-to-temp-buffer "*choice list*" + (princ "There are more than one possible project file.\n") + (princ "Which one should we use ?\n\n") + (princ " no. file name \n") + (princ " --- ------------------------\n") + (let ((counter 1)) + (while (<= counter (length prj-files)) + (princ (format " %2d) %s\n" + counter + (nth (1- counter) prj-files))) + (setq counter (1+ counter)) + + ))) ; end of with-output-to ... + (setq choice nil) + (while (or + (not choice) + (not (integerp choice)) + (< choice 1) + (> choice (length prj-files))) + (setq choice (string-to-number + (read-from-minibuffer "Enter No. of your choice: ")))) + (setq selected (nth (1- choice) prj-files)))) + + ((= (length prj-files) 0) + ;; No project file in the current directory; ask user + (unless (or no-user-question (not ada-always-ask-project)) + (setq ada-last-prj-file + (read-file-name + (concat "project file [" ada-last-prj-file "]:") + nil ada-last-prj-file)) + (unless (string= ada-last-prj-file "") + (setq selected ada-last-prj-file)))) + ))) + + (or selected "default.adp") + )) + +(defun ada-default-prj-properties () + "Return the default project properties list with the current buffer as main." + + (let ((file (buffer-file-name nil))) + (list + ;; variable name alphabetical order + 'ada_project_path (or (getenv "ADA_PROJECT_PATH") "") + 'ada_project_path_sep ada-prj-ada-project-path-sep + 'bind_opt ada-prj-default-bind-opt + 'build_dir default-directory + 'casing (if (listp ada-case-exception-file) + ada-case-exception-file + (list ada-case-exception-file)) + 'check_cmd (list ada-prj-default-check-cmd) ;; FIXME: should not a list + 'comp_cmd (list ada-prj-default-comp-cmd) ;; FIXME: should not a list + 'comp_opt ada-prj-default-comp-opt + 'cross_prefix "" + 'debug_cmd (concat ada-prj-default-debugger + " ${main}" (if ada-on-ms-windows ".exe")) ;; FIXME: don't need .exe? + 'debug_post_cmd (list nil) + 'debug_pre_cmd (list (concat ada-cd-command " ${build_dir}")) + 'gnatmake_opt ada-prj-default-gnatmake-opt + 'gnatfind_opt ada-prj-gnatfind-switches + 'gpr_file ada-prj-default-gpr-file + 'link_opt ada-prj-default-link-opt + 'main (if file + (file-name-nondirectory + (file-name-sans-extension file)) + "") + 'make_cmd (list ada-prj-default-make-cmd) ;; FIXME: should not a list + 'obj_dir (list ".") + 'remote_machine "" + 'run_cmd (list (concat "./${main}" (if ada-on-ms-windows ".exe"))) + ;; FIXME: should not a list + ;; FIXME: don't need .exe? + 'src_dir (list ".") + ))) + +(defun ada-parse-prj-file (prj-file) + "Read PRJ-FILE, set project properties in `ada-xref-project-files'." + (let ((project (ada-default-prj-properties))) + + (setq prj-file (expand-file-name prj-file)) + (if (string= (file-name-extension prj-file) "gpr") + (setq project (ada-gnat-parse-gpr project prj-file)) + + (setq project (ada-parse-prj-file-1 prj-file project)) + ) + + ;; Store the project properties + (if (assoc prj-file ada-xref-project-files) + (setcdr (assoc prj-file ada-xref-project-files) project) + (add-to-list 'ada-xref-project-files (cons prj-file project))) + + (ada-xref-update-project-menu) + )) + +(defun ada-parse-prj-file-1 (prj-file project) + "Parse the Ada mode project file PRJ-FILE, set project properties in PROJECT. +Return new value of PROJECT." + (let ((ada-buffer (current-buffer)) + ;; fields that are lists or otherwise require special processing + ada_project_path casing comp_cmd check_cmd + debug_pre_cmd debug_post_cmd gpr_file make_cmd obj_dir src_dir run_cmd) + + ;; Give users a chance to use compiler-specific project file formats + (let ((buffer (run-hook-with-args-until-success + 'ada-load-project-hook prj-file))) + (unless buffer + ;; we load the project file with no warnings; if it does not + ;; exist, we stay in the Ada buffer; no project variable + ;; settings will be found. That works for the default + ;; "default.adp", which does not exist as a file. + (setq buffer (find-file-noselect prj-file nil))) + (set-buffer buffer)) + + (widen) + (goto-char (point-min)) + + ;; process each line + (while (not (eobp)) + + ;; ignore lines that don't have the format "name=value", put + ;; 'name', 'value' in match-string. + (if (looking-at "^\\([^=\n]+\\)=\\(.*\\)") + (cond + ;; FIXME: strip trailing spaces + ;; variable name alphabetical order + ((string= (match-string 1) "ada_project_path") + (cl-pushnew (expand-file-name + (substitute-in-file-name (match-string 2))) + ada_project_path :test #'equal)) + + ((string= (match-string 1) "build_dir") + (setq project + (plist-put project 'build_dir + (file-name-as-directory (match-string 2))))) + + ((string= (match-string 1) "casing") + (cl-pushnew (expand-file-name (substitute-in-file-name (match-string 2))) + casing :test #'equal)) + + ((string= (match-string 1) "check_cmd") + (cl-pushnew (match-string 2) check_cmd :test #'equal)) + + ((string= (match-string 1) "comp_cmd") + (cl-pushnew (match-string 2) comp_cmd :test #'equal)) + + ((string= (match-string 1) "debug_post_cmd") + (cl-pushnew (match-string 2) debug_post_cmd :test #'equal)) + + ((string= (match-string 1) "debug_pre_cmd") + (cl-pushnew (match-string 2) debug_pre_cmd :test #'equal)) + + ((string= (match-string 1) "gpr_file") + ;; expand now; path is relative to Emacs project file + (setq gpr_file (expand-file-name (match-string 2)))) + + ((string= (match-string 1) "make_cmd") + (cl-pushnew (match-string 2) make_cmd :test #'equal)) + + ((string= (match-string 1) "obj_dir") + (cl-pushnew (file-name-as-directory + (expand-file-name (match-string 2))) + obj_dir :test #'equal)) + + ((string= (match-string 1) "run_cmd") + (cl-pushnew (match-string 2) run_cmd :test #'equal)) + + ((string= (match-string 1) "src_dir") + (cl-pushnew (file-name-as-directory + (expand-file-name (match-string 2))) + src_dir :test #'equal)) + + (t + ;; any other field in the file is just copied + (setq project (plist-put project + (intern (match-string 1)) + (match-string 2)))))) + + (forward-line 1)) + + ;; done reading file + + ;; back to the user buffer + (set-buffer ada-buffer) + + ;; process accumulated lists + (if ada_project_path + (let ((sep (plist-get project 'ada_project_path_sep))) + (setq ada_project_path (reverse ada_project_path)) + (setq ada_project_path (mapconcat 'identity ada_project_path sep)) + (setq project (plist-put project 'ada_project_path ada_project_path)) + ;; env var needed now for ada-gnat-parse-gpr + (setenv "ADA_PROJECT_PATH" ada_project_path))) + + (if debug_post_cmd (setq project (plist-put project 'debug_post_cmd (reverse debug_post_cmd)))) + (if debug_pre_cmd (setq project (plist-put project 'debug_pre_cmd (reverse debug_pre_cmd)))) + (if casing (setq project (plist-put project 'casing (reverse casing)))) + (if check_cmd (setq project (plist-put project 'check_cmd (reverse check_cmd)))) + (if comp_cmd (setq project (plist-put project 'comp_cmd (reverse comp_cmd)))) + (if make_cmd (setq project (plist-put project 'make_cmd (reverse make_cmd)))) + (if run_cmd (setq project (plist-put project 'run_cmd (reverse run_cmd)))) + + (if gpr_file + (progn + (setq project (ada-gnat-parse-gpr project gpr_file)) + ;; append Ada source and object directories to others from Emacs project file + (setq src_dir (append (plist-get project 'src_dir) src_dir)) + (setq obj_dir (append (plist-get project 'obj_dir) obj_dir)) + (setq ada-xref-runtime-library-specs-path '() + ada-xref-runtime-library-ali-path '())) + ) + + ;; FIXME: gnatpath.exe doesn't output the runtime libraries, so always call ada-initialize-runtime-library + ;; if using a gpr_file, the runtime library directories are + ;; included in src_dir and obj_dir; otherwise they are in the + ;; 'runtime-library' variables. + ;; FIXME: always append to src_dir, obj_dir + (ada-initialize-runtime-library (or (ada-xref-get-project-field 'cross_prefix) "")) + ;;) + + (if obj_dir (setq project (plist-put project 'obj_dir (reverse obj_dir)))) + (if src_dir (setq project (plist-put project 'src_dir (reverse src_dir)))) + + project + )) + +(defun ada-select-prj-file (file) + "Select FILE as the current project file." + (interactive) + (setq ada-prj-default-project-file (expand-file-name file)) + + (let ((casing (ada-xref-get-project-field 'casing))) + (if casing + (progn + ;; FIXME: use ada-get-absolute-dir here + (setq ada-case-exception-file casing) + (ada-case-read-exceptions)))) + + (let ((ada_project_path (ada-xref-get-project-field 'ada_project_path))) + (if ada_project_path + ;; FIXME: use ada-get-absolute-dir, mapconcat here + (setenv "ADA_PROJECT_PATH" ada_project_path))) + + (setq compilation-search-path (ada-xref-get-src-dir-field)) + + (setq ada-search-directories-internal + ;; FIXME: why do we need directory-file-name here? + (append (mapcar 'directory-file-name compilation-search-path) + ada-search-directories)) + + ;; return t, for decent display in message buffer when called interactively + t) + +(defun ada-find-references (&optional pos arg local-only) + "Find all references to the entity under POS. +Calls gnatfind to find the references. +If ARG is non-nil, the contents of the old *gnatfind* buffer is preserved. +If LOCAL-ONLY is non-nil, only declarations in the current file are returned." + (interactive "d\nP") + (ada-require-project-file) + + (let* ((identlist (ada-read-identifier pos)) + (alifile (ada-get-ali-file-name (ada-file-of identlist))) + (process-environment (ada-set-environment))) + + (set-buffer (get-file-buffer (ada-file-of identlist))) + + ;; if the file is more recent than the executable + (if (or (buffer-modified-p (current-buffer)) + (file-newer-than-file-p (ada-file-of identlist) alifile)) + (ada-find-any-references (ada-name-of identlist) + (ada-file-of identlist) + nil nil local-only arg) + (ada-find-any-references (ada-name-of identlist) + (ada-file-of identlist) + (ada-line-of identlist) + (ada-column-of identlist) local-only arg))) + ) + +(defun ada-find-local-references (&optional pos arg) + "Find all references to the entity under POS. +Calls `gnatfind' to find the references. +If ARG is non-nil, the contents of the old *gnatfind* buffer is preserved." + (interactive "d\nP") + (ada-find-references pos arg t)) + +(defconst ada-gnatfind-buffer-name "*gnatfind*") + +(defun ada-find-any-references + (entity &optional file line column local-only append) + "Search for references to any entity whose name is ENTITY. +ENTITY was first found the location given by FILE, LINE and COLUMN. +If LOCAL-ONLY is non-nil, then list only the references in FILE, +which is much faster. +If APPEND is non-nil, then append the output of the command to the +existing buffer `*gnatfind*', if there is one." + (interactive "sEntity name: ") + (ada-require-project-file) + + ;; Prepare the gnatfind command. Note that we must protect the quotes + ;; around operators, so that they are correctly handled and can be + ;; processed (gnatfind \"+\":...). + (let* ((quote-entity + (if (= (aref entity 0) ?\") + (if ada-on-ms-windows + (concat "\\\"" (substring entity 1 -1) "\\\"") + (concat "'\"" (substring entity 1 -1) "\"'")) + entity)) + (switches (ada-xref-get-project-field 'gnatfind_opt)) + ;; FIXME: use gpr_file + (cross-prefix (ada-xref-get-project-field 'cross_prefix)) + (command (concat cross-prefix "gnat find " switches " " + quote-entity + (if file (concat ":" (file-name-nondirectory file))) + (if line (concat ":" line)) + (if column (concat ":" column)) + (if local-only (concat " " (file-name-nondirectory file))) + )) + old-contents) + + ;; If a project file is defined, use it + (if (and ada-prj-default-project-file + (not (string= ada-prj-default-project-file ""))) + (if (string-equal (file-name-extension ada-prj-default-project-file) + "gpr") + (setq command (concat command " -P\"" ada-prj-default-project-file "\"")) + (setq command (concat command " -p\"" ada-prj-default-project-file "\"")))) + + (if (and append (get-buffer ada-gnatfind-buffer-name)) + (with-current-buffer "*gnatfind*" + (setq old-contents (buffer-string)))) + + (let ((compilation-error "reference")) + (compilation-start command 'compilation-mode (lambda (_mode) ada-gnatfind-buffer-name))) + + ;; Hide the "Compilation" menu + (with-current-buffer ada-gnatfind-buffer-name + (local-unset-key [menu-bar compilation-menu]) + + (if old-contents + (progn + (goto-char 1) + (setq buffer-read-only nil) + (insert old-contents) + (setq buffer-read-only t) + (goto-char (point-max))))) + ) + ) + +(defalias 'ada-change-prj (symbol-function 'ada-set-default-project-file)) + +;; ----- Identifier Completion -------------------------------------------- +(defun ada-complete-identifier (pos) + "Try to complete the identifier around POS, using compiler cross-reference information." + (interactive "d") + (ada-require-project-file) + + ;; Initialize function-local variables and jump to the .ali buffer + ;; Note that for regexp search is case insensitive too + (let* ((curbuf (current-buffer)) + (identlist (ada-read-identifier pos)) + (sofar (concat "^[0-9]+[a-zA-Z][0-9]+[ *]\\(" + (regexp-quote (ada-name-of identlist)) + "[a-zA-Z0-9_]*\\)")) + (completed nil) + (symalist nil)) + + ;; Open the .ali file + (set-buffer (ada-get-ali-buffer (buffer-file-name))) + (goto-char (point-max)) + + ;; build an alist of possible completions + (while (re-search-backward sofar nil t) + (setq symalist (cons (cons (match-string 1) nil) symalist))) + + (setq completed (try-completion "" symalist)) + + ;; kills .ali buffer + (kill-buffer nil) + + ;; deletes the incomplete identifier in the buffer + (set-buffer curbuf) + (looking-at "[a-zA-Z0-9_]+") + (replace-match "") + ;; inserts the completed symbol + (insert completed) + )) + +;; ----- Cross-referencing ---------------------------------------- + +(defun ada-point-and-xref () + "Jump to the declaration of the entity below the cursor." + (interactive) + (mouse-set-point last-input-event) + (ada-goto-declaration (point))) + +(defun ada-point-and-xref-body () + "Jump to the body of the entity under the cursor." + (interactive) + (mouse-set-point last-input-event) + (ada-goto-body (point))) + +(defun ada-goto-body (pos &optional other-frame) + "Display the body of the entity around POS. +OTHER-FRAME non-nil means display in another frame. +If the entity doesn't have a body, display its declaration. +As a side effect, the buffer for the declaration is also open." + (interactive "d") + (ada-goto-declaration pos other-frame) + + ;; Temporarily force the display in the same buffer, since we + ;; already changed previously + (let ((ada-xref-other-buffer nil)) + (ada-goto-declaration (point) nil))) + +(defun ada-goto-declaration (pos &optional other-frame) + "Display the declaration of the identifier around POS. +The declaration is shown in another buffer if `ada-xref-other-buffer' is +non-nil. +If OTHER-FRAME is non-nil, display the cross-reference in another frame." + (interactive "d") + (ada-require-project-file) + (push-mark pos) + (ada-xref-push-pos (buffer-file-name) pos) + + ;; First try the standard algorithm by looking into the .ali file, but if + ;; that file was too old or even did not exist, try to look in the whole + ;; object path for a possible location. + (let ((identlist (ada-read-identifier pos))) + (condition-case err + (ada-find-in-ali identlist other-frame) + ;; File not found: print explicit error message + (ada-error-file-not-found + (message "%s%s" (error-message-string err) (nthcdr 1 err))) + + (error + (let ((ali-file (ada-get-ali-file-name (ada-file-of identlist)))) + + ;; If the ALI file was up-to-date, then we probably have a predefined + ;; entity, whose references are not given by GNAT + (if (and (file-exists-p ali-file) + (file-newer-than-file-p ali-file (ada-file-of identlist))) + (message "No cross-reference found -- may be a predefined entity.") + + ;; Else, look in every ALI file, except if the user doesn't want that + (if ada-xref-search-with-egrep + (ada-find-in-src-path identlist other-frame) + (message "Cross-referencing information is not up-to-date; please recompile.") + ))))))) + +(defun ada-goto-declaration-other-frame (pos) + "Display the declaration of the identifier around POS. +The declaration is shown in another frame if `ada-xref-other-buffer' is +non-nil." + (interactive "d") + (ada-goto-declaration pos t)) + +(defun ada-remote (command) + "Return the remote version of COMMAND, or COMMAND if remote_machine is nil." + (let ((machine (ada-xref-get-project-field 'remote_machine))) + (if (or (not machine) (string= machine "")) + command + (format "%s %s '(%s)'" + remote-shell-program + machine + command)))) + +(defun ada-get-absolute-dir-list (dir-list root-dir) + "Return the list of absolute directories found in DIR-LIST. +If a directory is a relative directory, ROOT-DIR is prepended. +Project and environment variables are substituted." + (mapcar (lambda (x) (expand-file-name x (ada-treat-cmd-string root-dir))) dir-list)) + +(defun ada-set-environment () + "Prepare an environment for Ada compilation. +This returns a new value to use for `process-environment', +but does not actually put it into use. +It modifies the source path and object path with the values found in the +project file." + (let ((include (getenv "ADA_INCLUDE_PATH")) + (objects (getenv "ADA_OBJECTS_PATH")) + (build-dir (ada-xref-get-project-field 'build_dir))) + (if include + (setq include (concat path-separator include))) + (if objects + (setq objects (concat path-separator objects))) + (cons + (concat "ADA_INCLUDE_PATH=" + (mapconcat (lambda(x) (expand-file-name x build-dir)) + (ada-xref-get-project-field 'src_dir) + path-separator) + include) + (cons + (concat "ADA_OBJECTS_PATH=" + (mapconcat (lambda(x) (expand-file-name x build-dir)) + (ada-xref-get-project-field 'obj_dir) + path-separator) + objects) + process-environment)))) + +(defun ada-compile-application (&optional arg) + "Compile the application, using the command found in the project file. +If ARG is not nil, ask for user confirmation." + (interactive "P") + (ada-require-project-file) + (let ((cmd (ada-xref-get-project-field 'make_cmd)) + (process-environment (ada-set-environment)) + (compilation-scroll-output t)) + + (setq compilation-search-path (ada-xref-get-src-dir-field)) + + ;; If no project file was found, ask the user + (unless cmd + (setq cmd '("") arg t)) + + ;; Make a single command from the list of commands, including the + ;; commands to run it on a remote machine. + (setq cmd (ada-remote (mapconcat 'identity cmd ada-command-separator))) + + (if (or ada-xref-confirm-compile arg) + (setq cmd (read-from-minibuffer "enter command to compile: " cmd))) + + ;; Insert newlines so as to separate the name of the commands to run + ;; and the output of the commands. This doesn't work with cmdproxy.exe, + ;; which gets confused by newline characters. + (if (not (string-match ".exe" shell-file-name)) + (setq cmd (concat cmd "\n\n"))) + + (compile (ada-quote-cmd cmd)))) + +(defun ada-set-main-compile-application () + "Set main project variable to current buffer, build main." + (interactive) + (ada-require-project-file) + (let* ((file (buffer-file-name (current-buffer))) + main) + (if (not file) + (error "No file for current buffer") + + (setq main + (if file + (file-name-nondirectory + (file-name-sans-extension file)) + "")) + (ada-xref-set-project-field 'main main) + (ada-compile-application)))) + +(defun ada-compile-current (&optional arg prj-field) + "Recompile the current file. +If ARG is non-nil, ask for user confirmation of the command. +PRJ-FIELD is the name of the field to use in the project file to get the +command, and should be either `comp_cmd' (default) or `check_cmd'." + (interactive "P") + (ada-require-project-file) + (let* ((field (if prj-field prj-field 'comp_cmd)) + (cmd (ada-xref-get-project-field field)) + (process-environment (ada-set-environment)) + (compilation-scroll-output t)) + + (unless cmd + (setq cmd '("") arg t)) + + ;; Make a single command from the list of commands, including the + ;; commands to run it on a remote machine. + (setq cmd (ada-remote (mapconcat 'identity cmd ada-command-separator))) + + ;; If no project file was found, ask the user + (if (or ada-xref-confirm-compile arg) + (setq cmd (read-from-minibuffer "enter command to compile: " cmd))) + + (compile (ada-quote-cmd cmd)))) + +(defun ada-check-current (&optional arg) + "Check the current file for syntax errors. +If ARG is non-nil, ask for user confirmation of the command." + (interactive "P") + (ada-compile-current arg 'check_cmd)) + +(defun ada-run-application (&optional arg) + "Run the application. +If ARG is non-nil, ask for user confirmation." + (interactive) + (ada-require-project-file) + + (let ((machine (ada-xref-get-project-field 'cross_prefix))) + (if (and machine (not (string= machine ""))) + (error "This feature is not supported yet for cross environments"))) + + (let ((command (ada-xref-get-project-field 'run_cmd))) + + ;; Guess the command if it wasn't specified + (if (not command) + (setq command (list (file-name-sans-extension (buffer-name))))) + + ;; Modify the command to run remotely + (setq command (ada-remote (mapconcat 'identity command + ada-command-separator))) + + ;; Ask for the arguments to the command if required + (if (or ada-xref-confirm-compile arg) + (setq command (read-from-minibuffer "Enter command to execute: " + command))) + + ;; Run the command + (with-current-buffer (get-buffer-create "*run*") + (setq buffer-read-only nil) + + (erase-buffer) + (start-process "run" (current-buffer) shell-file-name + "-c" command) + (comint-mode) + ;; Set these two variables to their default values, since otherwise + ;; the output buffer is scrolled so that only the last output line + ;; is visible at the top of the buffer. + (set (make-local-variable 'scroll-step) 0) + (set (make-local-variable 'scroll-conservatively) 0) + ) + (display-buffer "*run*") + + ;; change to buffer *run* for interactive programs + (other-window 1) + (switch-to-buffer "*run*") + )) + +(defun ada-gdb-application (&optional arg executable-name) + "Start the debugger on the application. +If ARG is non-nil, ask the user to confirm the command. +EXECUTABLE-NAME, if non-nil, is debugged instead of the file specified in the +project file." + (interactive "P") + (ada-require-project-file) + (let ((buffer (current-buffer)) + cmd pre-cmd post-cmd) + (setq cmd (if executable-name + (concat ada-prj-default-debugger " " executable-name) + (ada-xref-get-project-field 'debug_cmd)) + pre-cmd (ada-xref-get-project-field 'debug_pre_cmd) + post-cmd (ada-xref-get-project-field 'debug_post_cmd)) + + ;; If the command was not given in the project file, start a bare gdb + (if (not cmd) + (setq cmd (concat ada-prj-default-debugger + " " + (or executable-name + (file-name-sans-extension (buffer-file-name)))))) + + ;; For gvd, add an extra switch so that the Emacs window is completely + ;; swallowed inside the Gvd one + (if (and ada-tight-gvd-integration + (string-match "^[^ \t]*gvd" cmd)) + ;; Start a new frame, so that when gvd exists we do not kill Emacs + ;; We make sure that gvd swallows the new frame, not the one the + ;; user has been using until now + ;; The frame is made invisible initially, so that GtkPlug gets a + ;; chance to fully manage it. Then it works fine with Enlightenment + ;; as well + (let ((frame (make-frame '((visibility . nil))))) + (setq cmd (concat + cmd " --editor-window=" + (cdr (assoc 'outer-window-id (frame-parameters frame))))) + (select-frame frame))) + + ;; Add a -fullname switch + ;; Use the remote machine + (setq cmd (ada-remote (concat cmd " -fullname "))) + + ;; Ask for confirmation if required + (if (or arg ada-xref-confirm-compile) + (setq cmd (read-from-minibuffer "enter command to debug: " cmd))) + + (let ((old-comint-exec (symbol-function 'comint-exec))) + + ;; Do not add -fullname, since we can have a 'rsh' command in front. + ;; FIXME: This is evil but luckily a nop under Emacs-21.3.50 ! -stef + (fset 'gud-gdb-massage-args (lambda (_file args) args)) + + (setq pre-cmd (mapconcat 'identity pre-cmd ada-command-separator)) + (if (not (equal pre-cmd "")) + (setq pre-cmd (concat pre-cmd ada-command-separator))) + + (setq post-cmd (mapconcat 'identity post-cmd "\n")) + (if post-cmd + (setq post-cmd (concat post-cmd "\n"))) + + + ;; Temporarily replaces the definition of `comint-exec' so that we + ;; can execute commands before running gdb. + ;; FIXME: This is evil and not temporary !!! -stef + (fset 'comint-exec + `(lambda (buffer name command startfile switches) + (let (compilation-buffer-name-function) + (save-excursion + (setq compilation-buffer-name-function + (lambda(x) (buffer-name buffer))) + (compile (ada-quote-cmd + (concat ,pre-cmd + command " " + (mapconcat 'identity switches " ")))))) + )) + + ;; Tight integration should force the tty mode + (if (and (string-match "gvd" (comint-arguments cmd 0 0)) + ada-tight-gvd-integration + (not (string-match "--tty" cmd))) + (setq cmd (concat cmd "--tty"))) + + (if (and (string-match "jdb" (comint-arguments cmd 0 0)) + (boundp 'jdb)) + (funcall (symbol-function 'jdb) cmd) + (gdb cmd)) + + ;; Restore the standard fset command (or for instance C-U M-x shell + ;; wouldn't work anymore + + (fset 'comint-exec old-comint-exec) + + ;; Send post-commands to the debugger + (process-send-string (get-buffer-process (current-buffer)) post-cmd) + + ;; Move to the end of the debugger buffer, so that it is automatically + ;; scrolled from then on. + (goto-char (point-max)) + + ;; Display both the source window and the debugger window (the former + ;; above the latter). No need to show the debugger window unless it + ;; is going to have some relevant information. + (if (or (not (string-match "gvd" (comint-arguments cmd 0 0))) + (string-match "--tty" cmd)) + (split-window-below)) + (switch-to-buffer buffer) + ))) + +(defun ada-reread-prj-file (&optional filename) + "Reread either the current project, or FILENAME if non-nil. +If FILENAME is non-nil, set it as current project." + (interactive "P") + (if (not filename) + (setq filename ada-prj-default-project-file)) + (ada-parse-prj-file filename) + (ada-select-prj-file filename)) + +;; ------ Private routines + +(defun ada-xref-current (file &optional ali-file-name) + "Update the cross-references for FILE. +This in fact recompiles FILE to create ALI-FILE-NAME. +This function returns the name of the file that was recompiled to generate +the cross-reference information. Note that the ali file can then be deduced +by replacing the file extension with `.ali'." + ;; kill old buffer + (if (and ali-file-name + (get-file-buffer ali-file-name)) + (kill-buffer (get-file-buffer ali-file-name))) + + (let* ((name (convert-standard-filename file)) + (body-name (or (ada-get-body-name name) name))) + + ;; Always recompile the body when we can. We thus temporarily switch to a + ;; buffer than contains the body of the unit + (save-excursion + (let ((body-visible (find-buffer-visiting body-name)) + process) + (if body-visible + (set-buffer body-visible) + (find-file body-name)) + + ;; Execute the compilation. Note that we must wait for the end of the + ;; process, or the ALI file would still not be available. + ;; Unfortunately, the underlying `compile' command that we use is + ;; asynchronous. + (ada-compile-current) + (setq process (get-buffer-process "*compilation*")) + + (while (and process + (not (equal (process-status process) 'exit))) + (sit-for 1)) + + ;; remove the buffer for the body if it wasn't there before + (unless body-visible + (kill-buffer (find-buffer-visiting body-name))) + )) + body-name)) + +(defun ada-find-file-in-dir (file dir-list) + "Search for FILE in DIR-LIST." + (let (found) + (while (and (not found) dir-list) + (setq found (concat (file-name-as-directory (car dir-list)) + (file-name-nondirectory file))) + + (unless (file-exists-p found) + (setq found nil)) + (setq dir-list (cdr dir-list))) + found)) + +(defun ada-find-ali-file-in-dir (file) + "Find the ali file FILE, searching obj_dir for the current project. +Adds build_dir in front of the search path to conform to gnatmake's behavior, +and the standard runtime location at the end." + (ada-find-file-in-dir file (ada-xref-get-obj-dir-field))) + +(defun ada-find-src-file-in-dir (file) + "Find the source file FILE, searching src_dir for the current project. +Adds the standard runtime location at the end of the search path to conform +to gnatmake's behavior." + (ada-find-file-in-dir file (ada-xref-get-src-dir-field))) + +(defun ada-get-ali-file-name (file) + "Create the ali file name for the Ada file FILE. +The file is searched for in every directory shown in the obj_dir lines of +the project file." + + ;; This function has to handle the special case of non-standard + ;; file names (i.e. not .adb or .ads) + ;; The trick is the following: + ;; 1- replace the extension of the current file with .ali, + ;; and look for this file + ;; 2- If this file is found: + ;; grep the "^U" lines, and make sure we are not reading the + ;; .ali file for a spec file. If we are, go to step 3. + ;; 3- If the file is not found or step 2 failed: + ;; find the name of the "other file", ie the body, and look + ;; for its associated .ali file by substituting the extension + ;; + ;; We must also handle the case of separate packages and subprograms: + ;; 4- If no ali file was found, we try to modify the file name by removing + ;; everything after the last '-' or '.' character, so as to get the + ;; ali file for the parent unit. If we found an ali file, we check that + ;; it indeed contains the definition for the separate entity by checking + ;; the 'D' lines. This is done repeatedly, in case the direct parent is + ;; also a separate. + + (with-current-buffer (get-file-buffer file) + (let ((short-ali-file-name (concat (file-name-base file) ".ali")) + ali-file-name + is-spec) + + ;; If we have a non-standard file name, and this is a spec, we first + ;; look for the .ali file of the body, since this is the one that + ;; contains the most complete information. If not found, we will do what + ;; we can with the .ali file for the spec... + + (if (not (string= (file-name-extension file) "ads")) + (let ((specs ada-spec-suffixes)) + (while specs + (if (string-match (concat (regexp-quote (car specs)) "$") + file) + (setq is-spec t)) + (setq specs (cdr specs))))) + + (if is-spec + (setq ali-file-name + (ada-find-ali-file-in-dir + (concat (file-name-base (ada-other-file-name)) ".ali")))) + + + (setq ali-file-name + (or ali-file-name + + ;; Else we take the .ali file associated with the unit + (ada-find-ali-file-in-dir short-ali-file-name) + + + ;; else we did not find the .ali file Second chance: in case + ;; the files do not have standard names (such as for instance + ;; file_s.ada and file_b.ada), try to go to the other file + ;; and look for its ali file + (ada-find-ali-file-in-dir + (concat (file-name-base (ada-other-file-name)) ".ali")) + + + ;; If we still don't have an ali file, try to get the one + ;; from the parent unit, in case we have a separate entity. + (let ((parent-name (file-name-base file))) + + (while (and (not ali-file-name) + (string-match "^\\(.*\\)[.-][^.-]*" parent-name)) + + (setq parent-name (match-string 1 parent-name)) + (setq ali-file-name (ada-find-ali-file-in-dir + (concat parent-name ".ali"))) + ) + ali-file-name))) + + ;; If still not found, try to recompile the file + (if (not ali-file-name) + ;; Recompile only if the user asked for this, and search the ali + ;; filename again. We avoid a possible infinite recursion by + ;; temporarily disabling the automatic compilation. + + (if ada-xref-create-ali + (setq ali-file-name + (concat (file-name-sans-extension (ada-xref-current file)) + ".ali")) + + (error "`.ali' file not found; recompile your source file")) + + + ;; same if the .ali file is too old and we must recompile it + (if (and (file-newer-than-file-p file ali-file-name) + ada-xref-create-ali) + (ada-xref-current file ali-file-name))) + + ;; Always return the correct absolute file name + (expand-file-name ali-file-name)) + )) + +(defun ada-get-ada-file-name (file original-file) + "Create the complete file name (+directory) for FILE. +The original file (where the user was) is ORIGINAL-FILE. +Search in project file for possible paths." + + (save-excursion + + ;; If the buffer for original-file, use it to get the values from the + ;; project file, otherwise load the file and its project file + (let ((buffer (get-file-buffer original-file))) + (if buffer + (set-buffer buffer) + (find-file original-file))) + + ;; we choose the first possible completion and we + ;; return the absolute file name + (let ((filename (ada-find-src-file-in-dir file))) + (if filename + (expand-file-name filename) + (signal 'ada-error-file-not-found (file-name-nondirectory file))) + ))) + +(defun ada-find-file-number-in-ali (file) + "Return the file number for FILE in the associated ali file." + (set-buffer (ada-get-ali-buffer file)) + (goto-char (point-min)) + + (let ((begin (re-search-forward "^D"))) + (beginning-of-line) + (re-search-forward (concat "^D " (file-name-nondirectory file))) + (count-lines begin (point)))) + +(defun ada-read-identifier (pos) + "Return the identlist around POS and switch to the .ali buffer. +The returned list represents the entity, and can be manipulated through the +macros `ada-name-of', `ada-line-of', `ada-column-of', `ada-file-of',..." + + ;; If at end of buffer (e.g the buffer is empty), error + (if (>= (point) (point-max)) + (error "No identifier on point")) + + ;; goto first character of the identifier/operator (skip backward < and > + ;; since they are part of multiple character operators + (goto-char pos) + (skip-chars-backward "a-zA-Z0-9_<>") + + ;; check if it really is an identifier + (if (ada-in-comment-p) + (error "Inside comment")) + + (let (identifier identlist) + ;; Just in front of a string => we could have an operator declaration, + ;; as in "+", "-", .. + (if (= (char-after) ?\") + (forward-char 1)) + + ;; if looking at an operator + ;; This is only true if: + ;; - the symbol is +, -, ... + ;; - the symbol is made of letters, and not followed by _ or a letter + (if (and (looking-at ada-operator-re) + (or (not (= (char-syntax (char-after)) ?w)) + (not (or (= (char-syntax (char-after (match-end 0))) ?w) + (= (char-after (match-end 0)) ?_))))) + (progn + (if (and (= (char-before) ?\") + (= (char-after (+ (length (match-string 0)) (point))) ?\")) + (forward-char -1)) + (setq identifier (regexp-quote (concat "\"" (match-string 0) "\"")))) + + (if (ada-in-string-p) + (error "Inside string or character constant")) + (if (looking-at (concat ada-keywords "[^a-zA-Z_]")) + (error "No cross-reference available for reserved keyword")) + (if (looking-at "[a-zA-Z0-9_]+") + (setq identifier (match-string 0)) + (error "No identifier around"))) + + ;; Build the identlist + (setq identlist (ada-make-identlist)) + (ada-set-name identlist (downcase identifier)) + (ada-set-line identlist + (number-to-string (count-lines 1 (point)))) + (ada-set-column identlist + (number-to-string (1+ (current-column)))) + (ada-set-file identlist (buffer-file-name)) + identlist + )) + +(defun ada-get-all-references (identlist) + "Complete IDENTLIST with definition file and places where it is referenced. +Information is extracted from the ali file." + + (let ((ali-buffer (ada-get-ali-buffer (ada-file-of identlist))) + declaration-found) + (set-buffer ali-buffer) + (goto-char (point-min)) + (ada-set-on-declaration identlist nil) + + ;; First attempt: we might already be on the declaration of the identifier + ;; We want to look for the declaration only in a definite interval (after + ;; the "^X ..." line for the current file, and before the next "^X" line + + (if (re-search-forward + (concat "^X [0-9]+ " (file-name-nondirectory (ada-file-of identlist))) + nil t) + (let ((bound (save-excursion (re-search-forward "^X " nil t)))) + (setq declaration-found + (re-search-forward + (concat "^" (ada-line-of identlist) + "." (ada-column-of identlist) + "[ *]" (ada-name-of identlist) + "[{[(<= ]?\\(.*\\)$") bound t)) + (if declaration-found + (ada-set-on-declaration identlist t)) + )) + + ;; If declaration is still nil, then we were not on a declaration, and + ;; have to fall back on other algorithms + + (unless declaration-found + + ;; Since we already know the number of the file, search for a direct + ;; reference to it + (goto-char (point-min)) + (setq declaration-found t) + (ada-set-ali-index + identlist + (number-to-string (ada-find-file-number-in-ali + (ada-file-of identlist)))) + (unless (re-search-forward (concat (ada-ali-index-of identlist) + "|\\([0-9]+[^0-9][0-9]+\\(\n\\.\\)? \\)*" + (ada-line-of identlist) + "[^etpzkd<>=^]" + (ada-column-of identlist) "\\>") + nil t) + + ;; if we did not find it, it may be because the first reference + ;; is not required to have a 'unit_number|' item included. + ;; Or maybe we are already on the declaration... + (unless (re-search-forward + (concat + "^[0-9]+.[0-9]+[ *]" + (ada-name-of identlist) + "[ <{=([]\\(.\\|\n\\.\\)*\\<" + (ada-line-of identlist) + "[^0-9]" + (ada-column-of identlist) "\\>") + nil t) + + ;; If still not found, then either the declaration is unknown + ;; or the source file has been modified since the ali file was + ;; created + (setq declaration-found nil) + ) + ) + + ;; Last check to be completely sure we have found the correct line (the + ;; ali might not be up to date for instance) + (if declaration-found + (progn + (beginning-of-line) + ;; while we have a continuation line, go up one line + (while (looking-at "^\\.") + (forward-line -1) + (beginning-of-line)) + (unless (looking-at (concat "[0-9]+.[0-9]+[ *]" + (ada-name-of identlist) "[ <{=([]")) + (setq declaration-found nil)))) + + ;; Still no success ! The ali file must be too old, and we need to + ;; use a basic algorithm based on guesses. Note that this only happens + ;; if the user does not want us to automatically recompile files + ;; automatically + (unless declaration-found + (if (ada-xref-find-in-modified-ali identlist) + (setq declaration-found t) + ;; No more idea to find the declaration. Give up + (progn + (kill-buffer ali-buffer) + + (error "No declaration of %s found" (ada-name-of identlist)) + ))) + ) + + + ;; Now that we have found a suitable line in the .ali file, get the + ;; information available + (beginning-of-line) + (if declaration-found + (let ((current-line (buffer-substring + (point) (point-at-eol)))) + (save-excursion + (forward-line 1) + (beginning-of-line) + (while (looking-at "^\\.\\(.*\\)") + (setq current-line (concat current-line (match-string 1))) + (forward-line 1)) + ) + + (if (re-search-backward "^X [0-9]+ \\([a-zA-Z0-9_.-]+\\)" nil t) + + ;; If we can find the file + (condition-case err + (ada-set-declare-file + identlist + (ada-get-ada-file-name (match-string 1) + (ada-file-of identlist))) + + ;; Else clean up the ali file + (ada-error-file-not-found + (signal (car err) (cdr err))) + (error + (kill-buffer ali-buffer) + (error (error-message-string err))) + )) + + (ada-set-references identlist current-line) + )) + )) + +(defun ada-xref-find-in-modified-ali (identlist) + "Find the matching position for IDENTLIST in the current ali buffer. +This function is only called when the file was not up-to-date, so we need +to make some guesses. +This function is disabled for operators, and only works for identifiers." + + (unless (= (string-to-char (ada-name-of identlist)) ?\") + (progn + (let ((declist '()) ;;; ( (line_in_ali_file line_in_ada) ( ... )) + (my-regexp (concat "[ *]" + (regexp-quote (ada-name-of identlist)) " ")) + (line-ada "--") + (col-ada "--") + (line-ali 0) + (len 0) + (choice 0) + (ali-buffer (current-buffer))) + + (goto-char (point-max)) + (while (re-search-backward my-regexp nil t) + (save-excursion + (setq line-ali (count-lines 1 (point))) + (beginning-of-line) + ;; have a look at the line and column numbers + (if (looking-at "^\\([0-9]+\\).\\([0-9]+\\)[ *]") + (progn + (setq line-ada (match-string 1)) + (setq col-ada (match-string 2))) + (setq line-ada "--") + (setq col-ada "--") + ) + ;; construct a list with the file names and the positions within + (if (re-search-backward "^X [0-9]+ \\([a-zA-Z0-9._-]+\\)" nil t) + (cl-pushnew (list line-ali (match-string 1) line-ada col-ada) + declist :test #'equal) + ) + ) + ) + + ;; how many possible declarations have we found ? + (setq len (length declist)) + (cond + ;; none => error + ((= len 0) + (kill-buffer (current-buffer)) + (error "No declaration of %s recorded in .ali file" + (ada-name-of identlist))) + ;; one => should be the right one + ((= len 1) + (goto-char (point-min)) + (forward-line (1- (caar declist)))) + + ;; more than one => display choice list + (t + (save-window-excursion + (with-output-to-temp-buffer "*choice list*" + + (princ "Identifier is overloaded and Xref information is not up to date.\n") + (princ "Possible declarations are:\n\n") + (princ " no. in file at line col\n") + (princ " --- --------------------- ---- ----\n") + (let ((counter 0)) + (while (< counter len) + (princ (format " %2d) %-21s %4s %4s\n" + (1+ counter) + (ada-get-ada-file-name + (nth 1 (nth counter declist)) + (ada-file-of identlist)) + (nth 2 (nth counter declist)) + (nth 3 (nth counter declist)) + )) + (setq counter (1+ counter)) + ) ; end of while + ) ; end of let + ) ; end of with-output-to ... + (setq choice nil) + (while (or + (not choice) + (not (integerp choice)) + (< choice 1) + (> choice len)) + (setq choice + (string-to-number + (read-from-minibuffer "Enter No. of your choice: ")))) + ) + (set-buffer ali-buffer) + (goto-char (point-min)) + (forward-line (1- (car (nth (1- choice) declist)))) + )))))) + + +(defun ada-find-in-ali (identlist &optional other-frame) + "Look in the .ali file for the definition of the identifier in IDENTLIST. +If OTHER-FRAME is non-nil, and `ada-xref-other-buffer' is non-nil, +opens a new window to show the declaration." + + (ada-get-all-references identlist) + (let ((ali-line (ada-references-of identlist)) + (locations nil) + (start 0) + file line col) + + ;; Note: in some cases, an entity can have multiple references to the + ;; bodies (this is for instance the case for a separate subprogram, that + ;; has a reference both to the stub and to the real body). + ;; In that case, we simply go to each one in turn. + + ;; Get all the possible locations + (string-match "^\\([0-9]+\\)[a-zA-Z+*]\\([0-9]+\\)[ *]" ali-line) + (setq locations (list (list (match-string 1 ali-line) ;; line + (match-string 2 ali-line) ;; column + (ada-declare-file-of identlist)))) + (while (string-match "\\([0-9]+\\)[bc]\\(<[^>]+>\\)?\\([0-9]+\\)" + ali-line start) + (setq line (match-string 1 ali-line) + col (match-string 3 ali-line) + start (match-end 3)) + + ;; it there was a file number in the same line + ;; Make sure we correctly handle the case where the first file reference + ;; on the line is the type reference. + ;; 1U2 T(2|2r3) 34r23 + (if (string-match (concat "[^{(<0-9]\\([0-9]+\\)|\\([^|bc]+\\)?" + (match-string 0 ali-line)) + ali-line) + (let ((file-number (match-string 1 ali-line))) + (goto-char (point-min)) + (re-search-forward "^D \\([a-zA-Z0-9_.-]+\\)" nil t + (string-to-number file-number)) + (setq file (match-string 1)) + ) + ;; Else get the nearest file + (setq file (ada-declare-file-of identlist))) + + (setq locations (append locations (list (list line col file))))) + + ;; Add the specs at the end again, so that from the last body we go to + ;; the specs + (setq locations (append locations (list (car locations)))) + + ;; Find the new location we want to go to. + ;; If we are on none of the locations listed, we simply go to the specs. + + (setq line (caar locations) + col (nth 1 (car locations)) + file (nth 2 (car locations))) + + (while locations + (if (and (string= (caar locations) (ada-line-of identlist)) + (string= (nth 1 (car locations)) (ada-column-of identlist)) + (string= (file-name-nondirectory (nth 2 (car locations))) + (file-name-nondirectory (ada-file-of identlist)))) + (setq locations (cadr locations) + line (car locations) + col (nth 1 locations) + file (nth 2 locations) + locations nil) + (setq locations (cdr locations)))) + + ;; Find the file in the source path + (setq file (ada-get-ada-file-name file (ada-file-of identlist))) + + ;; Kill the .ali buffer + (kill-buffer (current-buffer)) + + ;; Now go to the buffer + (ada-xref-change-buffer file + (string-to-number line) + (1- (string-to-number col)) + identlist + other-frame) + )) + +(defun ada-find-in-src-path (identlist &optional other-frame) + "More general function for cross-references. +This function should be used when the standard algorithm that parses the +.ali file has failed, either because that file was too old or even did not +exist. +This function attempts to find the possible declarations for the identifier +anywhere in the object path. +This command requires the external `grep' program to be available. + +This works well when one is using an external library and wants to find +the declaration and documentation of the subprograms one is using." +;; FIXME: what does this function do? + (let (list + (dirs (ada-xref-get-obj-dir-field)) + (regexp (concat "[ *]" (ada-name-of identlist))) + line column + choice + file) + + ;; Do the grep in all the directories. We do multiple shell + ;; commands instead of one in case there is no .ali file in one + ;; of the directory and the shell stops because of that. + + (with-current-buffer (get-buffer-create "*grep*") + (while dirs + (insert (shell-command-to-string + (concat + "grep -E -i -h " + (shell-quote-argument (concat "^X|" regexp "( |$)")) + " " + (shell-quote-argument (file-name-as-directory (car dirs))) + "*.ali"))) + (setq dirs (cdr dirs))) + + ;; Now parse the output + (setq case-fold-search t) + (goto-char (point-min)) + (while (re-search-forward regexp nil t) + (save-excursion + (beginning-of-line) + (if (not (= (char-after) ?X)) + (progn + (looking-at "\\([0-9]+\\).\\([0-9]+\\)") + (setq line (match-string 1) + column (match-string 2)) + (re-search-backward "^X [0-9]+ \\(.*\\)$") + (setq file (list (match-string 1) line column)) + + ;; There could be duplicate choices, because of the structure + ;; of the .ali files + (unless (member file list) + (setq list (append list (list file)))))))) + + ;; Current buffer is still "*grep*" + (kill-buffer "*grep*") + ) + + ;; Now display the list of possible matches + (cond + + ;; No choice found => Error + ((null list) + (error "No cross-reference found, please recompile your file")) + + ;; Only one choice => Do the cross-reference + ((= (length list) 1) + (setq file (ada-find-src-file-in-dir (caar list))) + (if file + (ada-xref-change-buffer file + (string-to-number (nth 1 (car list))) + (string-to-number (nth 2 (car list))) + identlist + other-frame) + (error "%s not found in src_dir" (caar list))) + (message "This is only a (good) guess at the cross-reference.") + ) + + ;; Else, ask the user + (t + (save-window-excursion + (with-output-to-temp-buffer "*choice list*" + + (princ "Identifier is overloaded and Xref information is not up to date.\n") + (princ "Possible declarations are:\n\n") + (princ " no. in file at line col\n") + (princ " --- --------------------- ---- ----\n") + (let ((counter 0)) + (while (< counter (length list)) + (princ (format " %2d) %-21s %4s %4s\n" + (1+ counter) + (nth 0 (nth counter list)) + (nth 1 (nth counter list)) + (nth 2 (nth counter list)) + )) + (setq counter (1+ counter)) + ))) + (setq choice nil) + (while (or (not choice) + (not (integerp choice)) + (< choice 1) + (> choice (length list))) + (setq choice + (string-to-number + (read-from-minibuffer "Enter No. of your choice: ")))) + ) + (setq choice (1- choice)) + (kill-buffer "*choice list*") + + (setq file (ada-find-src-file-in-dir (car (nth choice list)))) + (if file + (ada-xref-change-buffer file + (string-to-number (nth 1 (nth choice list))) + (string-to-number (nth 2 (nth choice list))) + identlist + other-frame) + (signal 'ada-error-file-not-found (car (nth choice list)))) + (message "This is only a (good) guess at the cross-reference.") + )))) + +(defun ada-xref-change-buffer + (file line column identlist &optional other-frame) + "Select and display FILE, at LINE and COLUMN. +If we do not end on the same identifier as IDENTLIST, find the +closest match. Kills the .ali buffer at the end. +If OTHER-FRAME is non-nil, creates a new frame to show the file." + + (let (declaration-buffer) + + ;; Select and display the destination buffer + (if ada-xref-other-buffer + (if other-frame + (find-file-other-frame file) + (setq declaration-buffer (find-file-noselect file)) + (set-buffer declaration-buffer) + (switch-to-buffer-other-window declaration-buffer) + ) + (find-file file) + ) + + ;; move the cursor to the correct position + (push-mark) + (goto-char (point-min)) + (forward-line (1- line)) + (move-to-column column) + + ;; If we are not on the identifier, the ali file was not up-to-date. + ;; Try to find the nearest position where the identifier is found, + ;; this is probably the right one. + (unless (looking-at (ada-name-of identlist)) + (ada-xref-search-nearest (ada-name-of identlist))) + )) + + +(defun ada-xref-search-nearest (name) + "Search for NAME nearest to the position recorded in the Xref file. +Return the position of the declaration in the buffer, or nil if not found." + (let ((orgpos (point)) + (newpos nil) + (diff nil)) + + (goto-char (point-max)) + + ;; loop - look for all declarations of name in this file + (while (search-backward name nil t) + + ;; check if it really is a complete Ada identifier + (if (and + (not (save-excursion + (goto-char (match-end 0)) + (looking-at "_"))) + (not (ada-in-string-or-comment-p)) + (or + ;; variable declaration ? + (save-excursion + (skip-chars-forward "a-zA-Z_0-9" ) + (ada-goto-next-non-ws) + (looking-at ":[^=]")) + ;; procedure, function, task or package declaration ? + (save-excursion + (ada-goto-previous-word) + (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]\\>")))) + + ;; check if it is nearer than the ones before if any + (if (or (not diff) + (< (abs (- (point) orgpos)) diff)) + (progn + (setq newpos (point) + diff (abs (- newpos orgpos)))))) + ) + + (if newpos + (progn + (message "ATTENTION: this declaration is only a (good) guess ...") + (goto-char newpos)) + nil))) + + +;; Find the parent library file of the current file +(defun ada-goto-parent () + "Go to the parent library file." + (interactive) + (ada-require-project-file) + + (let ((buffer (ada-get-ali-buffer (buffer-file-name))) + (unit-name nil) + (body-name nil) + (ali-name nil)) + (with-current-buffer buffer + (goto-char (point-min)) + (re-search-forward "^U \\([^ \t%]+\\)%[bs][ \t]+\\([^ \t]+\\)") + (setq unit-name (match-string 1)) + (if (not (string-match "\\(.*\\)\\.[^.]+" unit-name)) + (progn + (kill-buffer buffer) + (error "No parent unit !")) + (setq unit-name (match-string 1 unit-name)) + ) + + ;; look for the file name for the parent unit specification + (goto-char (point-min)) + (re-search-forward (concat "^W " unit-name + "%s[ \t]+\\([^ \t]+\\)[ \t]+" + "\\([^ \t\n]+\\)")) + (setq body-name (match-string 1)) + (setq ali-name (match-string 2)) + (kill-buffer buffer) + ) + + (setq ali-name (ada-find-ali-file-in-dir ali-name)) + + (save-excursion + ;; Tries to open the new ali file to find the spec file + (if ali-name + (progn + (find-file ali-name) + (goto-char (point-min)) + (re-search-forward (concat "^U " unit-name "%s[ \t]+" + "\\([^ \t]+\\)")) + (setq body-name (match-string 1)) + (kill-buffer (current-buffer)) + ) + ) + ) + + (find-file body-name) + )) + +(defun ada-make-filename-from-adaname (adaname) + "Determine the filename in which ADANAME is found. +This is a GNAT specific function that uses gnatkrunch." + (let ((krunch-buf (generate-new-buffer "*gkrunch*")) + (cross-prefix (plist-get (cdr (ada-xref-current-project)) 'cross_prefix))) + (with-current-buffer krunch-buf + ;; send adaname to external process `gnatkr'. + ;; Add a dummy extension, since gnatkr versions have two different + ;; behaviors depending on the version: + ;; Up to 3.15: "AA.BB.CC" => aa-bb-cc + ;; After: "AA.BB.CC" => aa-bb.cc + (call-process (concat cross-prefix "gnatkr") nil krunch-buf nil + (concat adaname ".adb") ada-krunch-args) + ;; fetch output of that process + (setq adaname (buffer-substring + (point-min) + (progn + (goto-char (point-min)) + (end-of-line) + (point)))) + ;; Remove the extra extension we added above + (setq adaname (substring adaname 0 -4)) + + (kill-buffer krunch-buf))) + adaname + ) + +(defun ada-make-body-gnatstub (&optional interactive) + "Create an Ada package body in the current buffer. +This function uses the `gnat stub' program to create the body. +This function typically is to be hooked into `ff-file-created-hook'. +If INTERACTIVE is nil, assume this is called from `ff-file-created-hook'." + (interactive "p") + (ada-require-project-file) + + ;; If not interactive, assume we are being called from + ;; ff-file-created-hook. Then the current buffer is for the body + ;; file, but we will create a new one after gnat stub runs + (unless interactive + (set-buffer-modified-p nil) + (kill-buffer (current-buffer))) + + (save-some-buffers nil nil) + + ;; Make sure the current buffer is the spec, so gnat stub gets the + ;; right package parameter (this might not be the case if for + ;; instance the user was asked for a project file) + + (unless (buffer-file-name (car (buffer-list))) + (set-buffer (cadr (buffer-list)))) + + ;; Call the external process + (let* ((project-plist (cdr (ada-xref-current-project))) + (gnatstub-opts (ada-treat-cmd-string ada-gnatstub-opts)) + (gpr-file (plist-get project-plist 'gpr_file)) + (filename (buffer-file-name (car (buffer-list)))) + (output (concat (file-name-sans-extension filename) ".adb")) + (cross-prefix (plist-get project-plist 'cross_prefix)) + (gnatstub-cmd (concat cross-prefix "gnat stub" + (if (not (string= gpr-file "")) + (concat " -P\"" gpr-file "\"")) + " " gnatstub-opts " " filename)) + (buffer (get-buffer-create "*gnat stub*"))) + + (with-current-buffer buffer + (compilation-minor-mode 1) + (erase-buffer) + (insert gnatstub-cmd) + (newline) + ) + + (call-process shell-file-name nil buffer nil "-c" gnatstub-cmd) + + ;; clean up the output + + (if (file-exists-p output) + (progn + (find-file output) + (kill-buffer buffer)) + + ;; file not created; display the error message + (display-buffer buffer)))) + +(defun ada-xref-initialize () + "Function called by `ada-mode-hook' to initialize the ada-xref.el package. +For instance, it creates the gnat-specific menus, sets some hooks for +`find-file'." + (remove-hook 'ff-file-created-hook 'ada-make-body) ; from global hook + (remove-hook 'ff-file-created-hook 'ada-make-body t) ; from local hook + (add-hook 'ff-file-created-hook 'ada-make-body-gnatstub nil t) + + ;; Completion for file names in the mini buffer should ignore .ali files + (add-to-list 'completion-ignored-extensions ".ali") + + (ada-xref-update-project-menu) + ) + +;; ----- Add to ada-mode-hook --------------------------------------------- + +;; This must be done before initializing the Ada menu. +(add-hook 'ada-mode-hook 'ada-xref-initialize) + +;; Define a new error type +(define-error 'ada-error-file-not-found + "File not found in src-dir (check project file): " 'ada-mode-errors) + +(provide 'ada-xref) + +;;; ada-xref.el ends here diff --git a/ada-mode/doc/ada-mode.html b/ada-mode/doc/ada-mode.html new file mode 100644 index 0000000..6788acb --- /dev/null +++ b/ada-mode/doc/ada-mode.html @@ -0,0 +1,2288 @@ + + + + + + +Ada Mode + + + + + + + + + + + + + + + + + + +

Ada Mode

+ + + + + +
+
+

+Next:   [Contents][Index]

+
+

Ada Mode

+ +

Copyright © 1999–2019 Free Software Foundation, Inc. +

+
+

Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.3 or +any later version published by the Free Software Foundation; with no +Invariant Sections, with the Front-Cover Texts being “A GNU Manual”, +and with the Back-Cover Texts as in (a) below. A copy of the license +is included in the section entitled “GNU Free Documentation License”. +

+

(a) The FSF’s Back-Cover Text is: “You have the freedom to copy and +modify this GNU manual.” +

+ + + + +
+
+
+

+Next: , Previous: , Up: Ada Mode   [Contents][Index]

+
+

1 Overview

+ +

The Emacs mode for programming in Ada helps the user in understanding +existing code and facilitates writing new code. +

+

When the GNU Ada compiler GNAT is used, the cross-reference +information output by the compiler is used to provide powerful code +navigation (jump to definition, find all uses, etc.). +

+

When you open a file with a file extension of .ads or +.adb, Emacs will automatically load and activate Ada mode. +

+

Ada mode works without any customization, if you are using the GNAT +compiler (https://libre2.adacore.com/) and the GNAT default +naming convention. +

+

You must customize a few things if you are using a different compiler +or file naming convention; See Other compiler, See Non-standard file names. +

+

In addition, you may want to customize the indentation, +capitalization, and other things; See Other customization. +

+

Finally, for large Ada projects, you will want to set up an Emacs +Ada mode project file for each project; See Project files. Note +that these are different from the GNAT project files used by gnatmake +and other GNAT commands. +

+

See the Emacs info manual, section ’Running Debuggers Under Emacs’, +for general information on debugging. +

+
+
+
+
+

+Next: , Previous: , Up: Ada Mode   [Contents][Index]

+
+

2 Installation

+ +

Ada mode is part of the standard Emacs distribution; if you use that, +no files need to be installed. +

+

Ada mode is also available as a separate distribution, from the Emacs +Ada mode website +http://stephe-leake.org/emacs/ada-mode/emacs-ada-mode.html. The +separate distribution may be more recent. +

+

For installing the separate distribution, see the README file +in the distribution. +

+

To see what version of Ada mode you have installed, do M-x +ada-mode-version. +

+

The following files are provided with the Ada mode distribution: +

+
    +
  • ada-mode.el: The main file for Ada mode, providing indentation, +formatting of parameter lists, moving through code, comment handling +and automatic casing. + +
  • ada-prj.el: GUI editing of Ada mode project files, using Emacs +widgets. + +
  • ada-stmt.el: Ada statement templates. + +
  • ada-xref.el: GNAT cross-references, completion of identifiers, +and compilation. Also provides project files (which are not +GNAT-specific). + +
+ +
+
+
+
+

+Next: , Previous: , Up: Ada Mode   [Contents][Index]

+
+

3 Customizing Ada mode

+ +

Here we assume you are familiar with setting variables in Emacs, +either thru ’customize’ or in elisp (in your .emacs file). For +a basic introduction to customize, elisp, and Emacs in general, see +the tutorial in +The GNU Emacs Manual. +

+

These global Emacs settings are strongly recommended (put them in your +.emacs): +

+
+
(global-font-lock-mode t)
+(transient-mark-mode t)
+
+ +

(global-font-lock-mode t)’ turns on syntax +highlighting for all buffers (it is off by default because it may be +too slow for some machines). +

+

(transient-mark-mode t)’ highlights selected text. +

+

See the Emacs help for each of these variables for more information. +

+ + +
+
+ +

3.1 Non-standard file names

+ +

By default, Ada mode is configured to use the GNAT file naming +convention, where file names are a simple modification of the Ada +names, and the extension for specs and bodies are +‘.ads’ and ‘.adb’, respectively. +

+

Ada mode uses the file extensions to allow moving from a package body +to the corresponding spec and back. +

+

Ada mode supports a list of alternative file extensions for specs and bodies. +

+

For instance, if your spec and bodies files are called +unit_s.ada and unit_b.ada, respectively, you +can add the following to your .emacs file: +

+
+
(ada-add-extensions "_s.ada" "_b.ada")
+
+ +

You can define additional extensions: +

+
+
(ada-add-extensions ".ads" "_b.ada")
+(ada-add-extensions ".ads" ".body")
+
+ +

This means that whenever Ada mode looks for the body for a file +whose extension is .ads, it will take the first available file +that ends with either .adb, _b.ada or +.body. +

+

Similarly, if Ada mode is looking for a spec, it will look for +.ads or _s.ada. +

+

If the filename is not derived from the Ada name following the GNAT +convention, things are a little more complicated. You then need to +rewrite the function ada-make-filename-from-adaname. Doing that +is beyond the scope of this manual; see the current definitions in +ada-mode.el and ada-xref.el for examples. +

+
+
+
+ +

3.2 Other compiler

+ +

By default, Ada mode is configured to use the GNU Ada compiler GNAT. +

+

To use a different Ada compiler, you must specify the command lines +used to run that compiler, either in lisp variables or in Emacs +Ada mode project files. See Project file variables for the list +of project variables, and the corresponding lisp variables. +

+
+
+
+ +

3.3 Other customization

+ +

All user-settable Ada mode variables can be set via the menu +‘Ada | Customize’. Click on the ‘Help’ button there for help +on using customize. +

+

To modify a specific variable, you can directly call the function +customize-variable; just type M-x customize-variable +RET variable-name RET). +

+

Alternately, you can specify variable settings in the Emacs +configuration file, .emacs. This file is coded in Emacs lisp, +and the syntax to set a variable is the following: +

+
(setq variable-name value)
+
+ +
+
+
+
+
+

+Next: , Previous: , Up: Ada Mode   [Contents][Index]

+
+

4 Compiling Executing

+ +

Ada projects can be compiled, linked, and executed using commands on +the Ada menu. All of these commands can be customized via a project +file (see Project files), but the defaults are sufficient for using +the GNAT compiler for simple projects (single files, or several files +in a single directory). +

+

Even when no project file is used, the GUI project editor (menu +‘Ada | Project | Edit’) shows the settings of the various project +file variables referenced here. +

+ + +
+
+ +

4.1 Compile commands

+ +

Here are the commands for building and using an Ada project, as +listed in the Ada menu. +

+

In multi-file projects, there must be one file that is the main +program. That is given by the main project file variable; +it defaults to the current file if not yet set, but is also set by the +“set main and build” command. +

+
+
Check file
+

Compiles the current file in syntax check mode, by running +check_cmd defined in the current project file. This typically +runs faster than full compile mode, speeding up finding and fixing +compilation errors. +

+

This sets main only if it has not been set yet. +

+
+
Compile file
+

Compiles the current file, by running comp_cmd from the current +project file. +

+

This does not set main. +

+
+
Set main and Build
+

Sets main to the current file, then executes the Build +command. +

+
+
Show main
+

Display main in the message buffer. +

+
+
Build
+

Compiles all obsolete units of the current main, and links +main, by running make_cmd from the current project. +

+

This sets main only if it has not been set yet. +

+
+
Run
+

Executes the main program in a shell, displayed in a separate Emacs +buffer. This runs run_cmd from the current project. The +execution buffer allows for interactive input/output. +

+

To modify the run command, in particular to provide or change the +command line arguments, type C-u before invoking the command. +

+

This command is not available for a cross-compilation toolchain. +

+
+
+

It is important when using these commands to understand how +main is used and changed. +

+

Build runs ’gnatmake’ on the main unit. During a typical edit/compile +session, this is the only command you need to invoke, which is why it +is bound to C-c C-c. It will compile all files needed by the +main unit, and display compilation errors in any of them. +

+

Note that Build can be invoked from any Ada buffer; typically you will +be fixing errors in files other than the main, but you don’t have to +switch back to the main to invoke the compiler again. +

+

Novices and students typically work on single-file Ada projects. In +this case, C-c C-m will normally be the only command needed; it +will build the current file, rather than the last-built main. +

+

There are three ways to change main: +

+
    +
  1. Invoke ‘Ada | Set main and Build’, which sets main to +the current file. + +
  2. Invoke ‘Ada | Project | Edit’, edit main and +main, and click ‘[save]’ + +
  3. Invoke ‘Ada | Project | Load’, and load a project file that specifies main + +
+ +
+
+
+ +

4.2 Compiler errors

+ +

The Check file, Compile file, and Build commands +all place compilation errors in a separate buffer named +*compilation*. +

+

Each line in this buffer will become active: you can simply click on +it with the middle button of the mouse, or move point to it and press +RET. Emacs will then display the relevant source file and put +point on the line and column where the error was found. +

+

You can also press the C-x ` key (next-error), and Emacs +will jump to the first error. If you press that key again, it will +move you to the second error, and so on. +

+

Some error messages might also include references to other files. These +references are also clickable in the same way, or put point after the +line number and press RET. +

+
+
+
+
+ +

5 Project files

+ +

An Emacs Ada mode project file specifies what directories hold sources +for your project, and allows you to customize the compilation commands +and other things on a per-project basis. +

+

Note that Ada mode project files *.adp are different than GNAT +compiler project files *.gpr. However, Emacs Ada mode can use a +GNAT project file to specify the project directories. If no +other customization is needed, a GNAT project file can be used without +an Emacs Ada mode project file. +

+ + +
+
+
+

+Next: , Up: Project files   [Contents][Index]

+
+

5.1 Project File Overview

+ +

Project files have a simple syntax; they may be edited directly. Each +line specifies a project variable name and its value, separated by “=”: +

+
src_dir=/Projects/my_project/src_1
+src_dir=/Projects/my_project/src_2
+
+ +

Some variables (like src_dir) are lists; multiple occurrences +are concatenated. +

+

There must be no space between the variable name and “=”, and no +trailing spaces. +

+

Alternately, a GUI editor for project files is available (see GUI Editor). It uses Emacs widgets, similar to Emacs customize. +

+

The GUI editor also provides a convenient way to view current project +settings, if they have been modified using menu commands rather than +by editing the project file. +

+

After the first Ada mode build command is invoked, there is always a +current project file, given by the lisp variable +ada-prj-default-project-file. Currently, the only way to show +the current project file is to invoke the GUI editor. +

+

To find the project file the first time, Ada mode uses the following +search algorithm: +

+
    +
  • If ada-prj-default-project-file is set, use that. + +
  • Otherwise, search for a file in the current directory with +the same base name as the Ada file, but extension given by +ada-prj-file-extension (default ".adp"). + +
  • If not found, search for *.adp in the current directory; if +several are found, prompt the user to select one. + +
  • If none are found, use default.adp in the current directory (even +if it does not exist). + +
+ +

This algorithm always sets ada-prj-default-project-file, even +when the file does not actually exist. +

+

To change the project file before or after the first one is found, +invoke ‘Ada | Project | Load ...’. +

+

Or, in lisp, evaluate (ada-set-default-project-file "/path/file.adp"). +This sets ada-prj-default-project-file, and reads the project file. +

+

You can also specify a GNAT project file to ‘Ada | Project | Load +...’ or ada-set-default-project-file. Emacs Ada mode checks the +file extension; if it is .gpr, the file is treated as a GNAT +project file. Any other extension is treated as an Emacs Ada mode +project file. +

+
+
+
+ +

5.2 GUI Editor

+ +

The project file editor is invoked with the menu ‘Ada | Projects +| Edit’. +

+

Once in the buffer for editing the project file, you can save your +modification using the ‘[save]’ button at the bottom of the +buffer, or the C-x C-s binding. To cancel your modifications, +kill the buffer or click on the ‘[cancel]’ button. +

+
+
+
+
+

+Previous: , Up: Project files   [Contents][Index]

+
+

5.3 Project file variables

+ +

The following variables can be defined in a project file; some can +also be defined in lisp variables. +

+

To set a project variable that is a list, specify each element of the +list on a separate line in the project file. +

+

Any project variable can be referenced in other project variables, +using a shell-like notation. For instance, if the variable +comp_cmd contains ${comp_opt}, the value of the +comp_opt variable will be substituted when comp_cmd is +used. +

+

In addition, process environment variables can be referenced using the +same syntax, or the normal $var syntax. +

+

Most project variables have defaults that can be changed by setting +lisp variables; the table below identifies the lisp variable for each +project variable. Lisp variables corresponding to project variables +that are lists are lisp lists. +

+

In general, project variables are evaluated when referenced in +Emacs Ada mode commands. Relative file paths are expanded to +absolute relative to ${build_dir}. +

+

Here is the list of variables. In the default values, the current +directory "." is the project file directory. +

+
+
ada_project_path_sep [default: ":" or ";"]
+

Path separator for ADA_PROJECT_PATH. It defaults to the correct +value for a native implementation of GNAT for the current operating +system. The user must override this when using Windows native GNAT +with Cygwin Emacs, and perhaps in other cases. +

+

Lisp variable: ada-prj-ada-project-path-sep. +

+
+
ada_project_path [default: ""]
+

A list of directories to search for GNAT project files. +

+

If set, the ADA_PROJECT_PATH process environment variable is +set to this value in the Emacs process when the Emacs Ada mode project +is selected via menu ‘Ada | Project | Load’. +

+

For ada_project_path, relative file paths are expanded to +absolute when the Emacs Ada project file is read, rather than when the +project file is selected. +

+

For example if the project file is in the directory +/home/myproject, the environment variable GDS_ROOT is +set to /home/shared, and the project file contains: +

+
ada_project_path_sep=:
+ada_project_path=$GDS_ROOT/makerules
+ada_project_path=../opentoken
+
+

then as a result the environment variable ADA_PROJECT_PATH will +be set to "/home/shared/makerules:/home/opentoken/". +

+

The default value is not the current value of this environment +variable, because that will typically have been set by another +project, and will therefore be incorrect for this project. +

+

If you have the environment variable set correctly for all of your +projects, you do not need to set this project variable. +

+
+
bind_opt [default: ""]
+

Holds user binder options; used in the default build commands. +

+

Lisp variable: ada-prj-default-bind-opt. +

+
+
build_dir [default: "."]
+

The compile commands will be issued in this directory. +

+
+
casing [default: ("~/.emacs_case_exceptions")]
+

List of files containing casing exceptions. See the help on +ada-case-exception-file for more info. +

+

Lisp variable: ada-case-exception-file. +

+
+
check_cmd [default: "${cross_prefix}gnatmake -u -c -gnatc ${gnatmake_opt} ${full_current} -cargs ${comp_opt}"]
+

Command used to syntax check a single file. +The name of the file is substituted for full_current. +

+

Lisp variable: ada-prj-default-check-cmd +

+
+
comp_cmd [default: "${cross_prefix}gnatmake -u -c ${gnatmake_opt} ${full_current} -cargs ${comp_opt}"]
+

Command used to compile a single file. +The name of the file is substituted for full_current. +

+

Lisp variable: ada-prj-default-comp-cmd. +

+
+
comp_opt [default: "-gnatq -gnatQ"]
+

Holds user compiler options; used in the default compile commands. The +default value tells gnatmake to generate library files for +cross-referencing even when there are errors. +

+

If source code for the project is in multiple directories, the +appropriate compiler options must be added here. Set source search path for examples of this. Alternately, GNAT project files may +be used; Use GNAT project file. +

+

Lisp variable: ada-prj-default-comp-opt. +

+
+
cross_prefix [default: ""]
+

Name of target machine in a cross-compilation environment. Used in +default compile and build commands. +

+
+
debug_cmd [default: "${cross_prefix}gdb ${main}"]
+

Command used to debug the application +

+

Lisp variable: ada-prj-default-debugger. +

+
+
debug_post_cmd [default: ""]
+

Command executed after debug_cmd. +

+
+
debug_pre_cmd [default: "cd ${build_dir}"]
+

Command executed before debug_cmd. +

+
+
gnatfind_opt [default: "-rf"]
+

Holds user gnatfind options; used in the default find commands. +

+

Lisp variable: ada-prj-gnatfind-switches. +

+
+
gnatmake_opt [default: "-g"]
+

Holds user gnatmake options; used in the default build commands. +

+

Lisp variable: ada-prj-default-gnatmake-opt. +

+
+
gpr_file [default: ""]
+

Specify GNAT project file. +

+

If set, the source and object directories specified in the GNAT +project file are appended to src_dir and obj_dir. This +allows specifying Ada source directories with a GNAT project file, and +other source directories with the Emacs project file. +

+

In addition, -P{gpr_file} is added to the project variable +gnatmake_opt whenever it is referenced. With the default +project variables, this passes the project file to all gnatmake +commands. +

+

Lisp variable: ada-prj-default-gpr-file. +

+ +
+
link_opt [default: ""]
+

Holds user linker options; used in the default build commands. +

+

Lisp variable: ada-prj-default-link-opt. +

+
+
main [default: current file]
+

Specifies the name of the executable file for the project; used in the +default build commands. +

+
+
make_cmd [default: "${cross_prefix}gnatmake -o ${main} ${main} ${gnatmake_opt} -cargs ${comp_opt} -bargs ${bind_opt} -largs ${link_opt}"]
+

Command used to build the application. +

+

Lisp variable: ada-prj-default-make-cmd. +

+
+
obj_dir [default: "."]
+

A list of directories to search for library files. Ada mode searches +this list for the ‘.ali’ files generated by GNAT that contain +cross-reference information. +

+

The compiler commands must place the ‘.ali’ files in one of these +directories; the default commands do that. +

+
+
remote_machine [default: ""]
+

Name of the machine to log into before issuing the compile and build +commands. If this variable is empty, the command will be run on the +local machine. +

+
+
run_cmd [default: "./${main}"]
+

Command used to run the application. +

+
+
src_dir [default: "."]
+

A list of directories to search for source files, both for compile +commands and source navigation. +

+
+
+ +
+
+
+
+
+

+Next: , Previous: , Up: Ada Mode   [Contents][Index]

+
+

6 Compiling Examples

+ +

We present several small projects, and walk thru the process of +compiling, linking, and running them. +

+

The first example illustrates more Ada mode features than the others; +you should work thru that example before doing the others. +

+

All of these examples assume you are using GNAT. +

+

The source for these examples is available on the Emacs Ada mode +website mentioned in See Installation. +

+ + +
+
+ +

6.1 No project files

+

This example uses no project files. +

+

First, create a directory Example_1, containing: +

+

hello.adb: +

+
+
with Ada.Text_IO;
+procedure Hello
+is begin
+   Put_Line("Hello from hello.adb");
+end Hello;
+
+ +

Yes, this is missing “use Ada.Text_IO;” - we want to demonstrate +compiler error handling. +

+

hello_2.adb: +

+
+
with Hello_Pkg;
+procedure Hello_2
+is begin
+   Hello_Pkg.Say_Hello;
+end Hello_2;
+
+ +

This file has no errors. +

+

hello_pkg.ads: +

+
+
package Hello_Pkg is
+   procedure Say_Hello;
+end Hello_Pkg;
+
+ +

This file has no errors. +

+

hello_pkg.adb: +

+
+
with Ada.Text_IO;
+package Hello_Pkg is
+   procedure Say_Hello
+   is begin
+      Ada.Text_IO.Put_Line ("Hello from hello_pkg.adb");
+   end Say_Hello;
+end Hello_Pkg;
+
+ +

Yes, this is missing the keyword body; another compiler error +example. +

+

In buffer hello.adb, invoke ‘Ada | Check file’. You should +get a *compilation* buffer containing something like (the +directory paths will be different): +

+
+
cd c:/Examples/Example_1/
+gnatmake -u -c -gnatc -g c:/Examples/Example_1/hello.adb -cargs -gnatq -gnatQ
+gcc -c -Ic:/Examples/Example_1/ -gnatc -g -gnatq -gnatQ -I- c:/Examples/Example_1/hello.adb
+hello.adb:4:04: "Put_Line" is not visible
+hello.adb:4:04: non-visible declaration at a-textio.ads:264
+hello.adb:4:04: non-visible declaration at a-textio.ads:260
+gnatmake: "c:/Examples/Example_1/hello.adb" compilation error
+
+ +

If you have enabled font-lock, the lines with actual errors (starting +with hello.adb) are highlighted, with the file name in red. +

+

Now type C-x ` (on a PC keyboard, ` is next to 1). +Or you can click the middle mouse button on the first error line. The +compilation buffer scrolls to put the first error on the top line, and +point is put at the place of the error in the hello.adb buffer. +

+

To fix the error, change the line to be +

+
+
    Ada.Text_IO.Put_Line ("hello from hello.adb");
+
+ +

Now invoke ‘Ada | Show main’; this displays ‘Ada mode main: hello’. +

+

Now (in buffer hello.adb), invoke ‘Ada | Build’. You are +prompted to save the file (if you haven’t already). Then the +compilation buffer is displayed again, containing: +

+
+
cd c:/Examples/Example_1/
+gnatmake -o hello hello -g -cargs -gnatq -gnatQ -bargs  -largs
+gcc -c -g -gnatq -gnatQ hello.adb
+gnatbind -x hello.ali
+gnatlink hello.ali -o hello.exe -g
+
+ +

The compilation has succeeded without errors; hello.exe now +exists in the same directory as hello.adb. +

+

Now invoke ‘Ada | Run’. A *run* buffer is displayed, +containing +

+
+
Hello from hello.adb
+
+Process run finished
+
+ +

That completes the first part of this example. +

+

Now we will compile a multi-file project. Open the file +hello_2.adb, and invoke ‘Ada | Set main and Build’. This +finds an error in hello_pkg.adb: +

+
+
cd c:/Examples/Example_1/
+gnatmake -o hello_2 hello_2 -g -cargs -gnatq -gnatQ -bargs  -largs
+gcc -c -g -gnatq -gnatQ hello_pkg.adb
+hello_pkg.adb:2:08: keyword "body" expected here [see file name]
+gnatmake: "hello_pkg.adb" compilation error
+
+ +

This demonstrates that gnatmake finds the files needed by the main +program. However, it cannot find files in a different directory, +unless you use an Emacs Ada mode project file to specify the other directories; +See Set source search path, or a GNAT project file; Use GNAT project file. +

+

Invoke ‘Ada | Show main’; this displays Ada mode main: hello_2. +

+

Move to the error with C-x `, and fix the error by adding body: +

+
+
package body Hello_Pkg is
+
+ +

Now, while still in hello_pkg.adb, invoke ‘Ada | Build’. +gnatmake successfully builds hello_2. This demonstrates that +Emacs has remembered the main file, in the project variable +main, and used it for the Build command. +

+

Finally, again while in hello_pkg.adb, invoke ‘Ada | Run’. +The *run* buffer displays Hello from hello_pkg.adb. +

+

One final point. If you switch back to buffer hello.adb, and +invoke ‘Ada | Run’, hello_2.exe will be run. That is +because main is still set to hello_2, as you can +see when you invoke ‘Ada | Project | Edit’. +

+

There are three ways to change main: +

+
    +
  1. Invoke ‘Ada | Set main and Build’, which sets main to +the current file. + +
  2. Invoke ‘Ada | Project | Edit’, edit main, and click ‘[save]’ + +
  3. Invoke ‘Ada | Project | Load’, and load a project file that specifies main + +
+ +
+
+
+ +

6.2 Set compiler options

+ +

This example illustrates using an Emacs Ada mode project file to set a +compiler option. +

+

If you have files from Example_1 open in Emacs, you should +close them so you don’t get confused. Use menu ‘File | Close +(current buffer)’. +

+

In directory Example_2, create these files: +

+

hello.adb: +

+
+
with Ada.Text_IO;
+procedure Hello
+is begin
+   Put_Line("Hello from hello.adb");
+end Hello;
+
+ +

This is the same as hello.adb from Example_1. It has two +errors; missing “use Ada.Text_IO;”, and no space between +Put_Line and its argument list. +

+

hello.adp: +

+
+
comp_opt=-gnatyt
+
+ +

This tells the GNAT compiler to check for token spacing; in +particular, there must be a space preceding a parenthesis. +

+

In buffer hello.adb, invoke ‘Ada | Project | Load...’, and +select Example_2/hello.adp. +

+

Then, again in buffer hello.adb, invoke ‘Ada | Set main and +Build’. You should get a *compilation* buffer containing +something like (the directory paths will be different): +

+
+
cd c:/Examples/Example_2/
+gnatmake -o hello hello -g -cargs -gnatyt  -bargs  -largs
+gcc -c -g -gnatyt hello.adb
+hello.adb:4:04: "Put_Line" is not visible
+hello.adb:4:04: non-visible declaration at a-textio.ads:264
+hello.adb:4:04: non-visible declaration at a-textio.ads:260
+hello.adb:4:12: (style) space required
+gnatmake: "hello.adb" compilation error
+
+ +

Compare this to the compiler output in No project files; the +gnatmake option -cargs -gnatq -gnatQ has been replaced by +-cargs -gnaty, and an additional error is reported in +hello.adb on line 4. This shows that hello.adp is being +used to set the compiler options. +

+

Fixing the error, linking and running the code proceed as in No project files. +

+
+
+
+ +

6.3 Set source search path

+ +

In this example, we show how to deal with files in more than one +directory. We start with the same code as in No project files; +create those files (with the errors present) +

+

Create the directory Example_3, containing: +

+

hello_pkg.ads: +

+
+
package Hello_Pkg is
+   procedure Say_Hello;
+end Hello_Pkg;
+
+ +

hello_pkg.adb: +

+
+
with Ada.Text_IO;
+package Hello_Pkg is
+   procedure Say_Hello
+   is begin
+      Ada.Text_IO.Put_Line ("Hello from hello_pkg.adb");
+   end Say_Hello;
+end Hello_Pkg;
+
+ +

These are the same files from example 1; hello_pkg.adb has an +error on line 2. +

+

In addition, create a directory Example_3/Other, containing these files: +

+

Other/hello_3.adb: +

+
+
with Hello_Pkg;
+with Ada.Text_IO; use Ada.Text_IO;
+procedure Hello_3
+is begin
+   Hello_Pkg.Say_Hello;
+   Put_Line ("From hello_3");
+end Hello_3;
+
+ +

There are no errors in this file. +

+

Other/other.adp: +

+
+
src_dir=..
+comp_opt=-I..
+
+ +

Note that there must be no trailing spaces. +

+

In buffer hello_3.adb, invoke ‘Ada | Project | Load...’, and +select Example_3/Other/other.adp. +

+

Then, again in hello_3.adb, invoke ‘Ada | Set main and +Build’. You should get a *compilation* buffer containing +something like (the directory paths will be different): +

+
+
cd c:/Examples/Example_3/Other/
+gnatmake -o hello_3 hello_3 -g -cargs -I.. -bargs  -largs
+gcc -c -g -I.. hello_3.adb
+gcc -c -I./ -g -I.. -I- C:\Examples\Example_3\hello_pkg.adb
+hello_pkg.adb:2:08: keyword "body" expected here [see file name]
+gnatmake: "C:\Examples\Example_3\hello_pkg.adb" compilation error
+
+ +

Compare the -cargs option to the compiler output in Set compiler options; this shows that other.adp is being used to +set the compiler options. +

+

Move to the error with C-x `. Ada mode searches the list of +directories given by src_dir for the file mentioned in the +compiler error message. +

+

Fixing the error, linking and running the code proceed as in No project files. +

+
+
+
+ +

6.4 Use GNAT project file

+ +

In this example, we show how to use a GNAT project file, with no Ada +mode project file. +

+

Create the directory Example_4, containing: +

+

hello_pkg.ads: +

+
+
package Hello_Pkg is
+   procedure Say_Hello;
+end Hello_Pkg;
+
+ +

hello_pkg.adb: +

+
+
with Ada.Text_IO;
+package Hello_Pkg is
+   procedure Say_Hello
+   is begin
+      Ada.Text_IO.Put_Line ("Hello from hello_pkg.adb");
+   end Say_Hello;
+end Hello_Pkg;
+
+ +

These are the same files from example 1; hello_pkg.adb has an +error on line 2. +

+

In addition, create a directory Example_4/Gnat_Project, +containing these files: +

+

Gnat_Project/hello_4.adb: +

+
+
with Hello_Pkg;
+with Ada.Text_IO; use Ada.Text_IO;
+procedure Hello_4
+is begin
+   Hello_Pkg.Say_Hello;
+   Put_Line ("From hello_4");
+end Hello_4;
+
+ +

There are no errors in this file. +

+

Gnat_Project/hello_4.gpr: +

+
+
Project Hello_4 is
+   for Source_Dirs use (".", "..");
+end Hello_4;
+
+ +

In buffer hello_4.adb, invoke ‘Ada | Project | Load...’, and +select Example_4/Gnat_Project/hello_4.gpr. +

+

Then, again in hello_4.adb, invoke ‘Ada | Set main and +Build’. You should get a *compilation* buffer containing +something like (the directory paths will be different): +

+
+
cd c:/Examples/Example_4/Gnat_Project/
+gnatmake -o hello_4 hello_4 -Phello_4.gpr -cargs -gnatq -gnatQ -bargs  -largs
+gcc -c -g -gnatyt -gnatq -gnatQ -I- -gnatA c:\Examples\Example_4\Gnat_Project\hello_4.adb
+gcc -c -g -gnatyt -gnatq -gnatQ -I- -gnatA c:\Examples\Example_4\hello_pkg.adb
+hello_pkg.adb:2:08: keyword "body" expected here [see file name]
+gnatmake: "c:\examples\example_4\hello_pkg.adb" compilation error
+
+ +

Compare the gcc options to the compiler output in Set compiler options; this shows that hello_4.gpr is being used to +set the compiler options. +

+

Fixing the error, linking and running the code proceed as in No project files. +

+
+
+
+ +

6.5 Use multiple GNAT project files

+ +

In this example, we show how to use multiple GNAT project files, +specifying the GNAT project search path in an Ada mode project file. +

+

Create the directory Example_4 as specified in Use GNAT project file. +

+

Create the directory Example_5, containing: +

+

hello_5.adb: +

+
+
with Hello_Pkg;
+with Ada.Text_IO; use Ada.Text_IO;
+procedure Hello_5
+is begin
+   Hello_Pkg.Say_Hello;
+   Put_Line ("From hello_5");
+end Hello_5;
+
+ +

There are no errors in this file. +

+

hello_5.adp: +

+
+
ada_project_path=../Example_4/Gnat_Project
+gpr_file=hello_5.gpr
+
+ +

hello_5.gpr: +

+
+
with "hello_4";
+Project Hello_5 is
+   for Source_Dirs use (".");
+   package Compiler is
+      for Default_Switches ("Ada") use ("-g", "-gnatyt");
+   end Compiler;
+end Hello_5;
+
+ +

In buffer hello_5.adb, invoke ‘Ada | Project | Load...’, and +select Example_5/hello_5.adp. +

+

Then, again in hello_5.adb, invoke ‘Ada | Set main and +Build’. You should get a *compilation* buffer containing +something like (the directory paths will be different): +

+
+
cd c:/Examples/Example_5/
+gnatmake -o hello_5 hello_5 -Phello_5.gpr -g -cargs -gnatq -gnatQ -bargs  -largs
+gcc -c -g -gnatyt -g -gnatq -gnatQ -I- -gnatA c:\Examples\Example_5\hello_5.adb
+gcc -c -g -gnatyt -g -gnatq -gnatQ -I- -gnatA c:\Examples\Example_4\hello_pkg.adb
+hello_pkg.adb:2:08: keyword "body" expected here [see file name]
+gnatmake: "c:\examples\example_4\hello_pkg.adb" compilation error
+
+ +

Now type C-x `. Example_4/hello_pkg.adb is shown, +demonstrating that hello_5.gpr and hello_4.gpr are being +used to set the compilation search path. +

+
+
+
+
+ +

7 Moving Through Ada Code

+ +

There are several easy to use commands to navigate through Ada code. All +these functions are available through the Ada menu, and you can also +use the following key bindings or the command names. Some of these +menu entries are available only if the GNAT compiler is used, since +the implementation relies on the GNAT cross-referencing information. +

+
+
M-C-e
+

Move to the next function/procedure/task, which ever comes next +(ada-next-procedure). +

+
M-C-a
+

Move to previous function/procedure/task +(ada-previous-procedure). +

+
M-x ada-next-package
+

Move to next package. +

+
M-x ada-previous-package
+

Move to previous package. +

+
C-c C-a
+

Move to matching start of end (ada-move-to-start). If +point is at the end of a subprogram, this command jumps to the +corresponding begin if the user option +ada-move-to-declaration is nil (default), otherwise it jumps to +the subprogram declaration. +

+
C-c C-e
+

Move point to end of current block (ada-move-to-end). +

+
C-c o
+

Switch between corresponding spec and body file +(ff-find-other-file). If point is in a subprogram, position +point on the corresponding declaration or body in the other file. +

+
C-c c-d
+

Move from any reference to its declaration, for from a declaration to +its body (for procedures, tasks, private and incomplete types). +

+
C-c C-r
+

Runs the gnatfind command to search for all references to the +identifier surrounding point (ada-find-references). Use +C-x ` (next-error) to visit each reference (as for +compilation errors). +

+
+ +

If the ada-xref-create-ali variable is non-nil, Emacs +will try to run GNAT for you whenever cross-reference information is +needed, and is older than the current source file. +

+
+
+
+ +

8 Identifier completion

+ +

Emacs and Ada mode provide two general ways for the completion of +identifiers. This is an easy way to type faster: you just have to type +the first few letters of an identifiers, and then loop through all the +possible completions. +

+

The first method is general for Emacs. It works by parsing all open +files for possible completions. +

+

For instance, if the words ‘my_identifier’, ‘my_subprogram’ +are the only words starting with ‘my’ in any of the opened files, +then you will have this scenario: +

+
+
You type:  myM-/
+Emacs inserts:  ‘my_identifier’
+If you press M-/ once again, Emacs replaces ‘my_identifier’ with
+‘my_subprogram’.
+Pressing M-/ once more will bring you back to ‘my_identifier’.
+
+ +

This is a very fast way to do completion, and the casing of words will +also be respected. +

+

The second method (C-TAB) is specific to Ada mode and the GNAT +compiler. Emacs will search the cross-information for possible +completions. +

+

The main advantage is that this completion is more accurate: only +existing identifier will be suggested. +

+

On the other hand, this completion is a little bit slower and requires +that you have compiled your file at least once since you created that +identifier. +

+
+
C-TAB
+

Complete current identifier using cross-reference information. +

+
M-/
+

Complete identifier using buffer information (not Ada-specific). +

+
+ +
+
+
+ +

9 Automatic Smart Indentation

+ +

Ada mode comes with a full set of rules for automatic indentation. You +can also configure the indentation, via the following variables: +

+
+
ada-broken-indent (default value: 2)
+

Number of columns to indent the continuation of a broken line. +

+
+
ada-indent (default value: 3)
+

Number of columns for default indentation. +

+
+
ada-indent-record-rel-type (default value: 3)
+

Indentation for record relative to type or use. +

+
+
ada-indent-return (default value: 0)
+

Indentation for return relative to function (if +ada-indent-return is greater than 0), or the open parenthesis +(if ada-indent-return is negative or 0). Note that in the second +case, when there is no open parenthesis, the indentation is done +relative to function with the value of ada-broken-indent. +

+
+
ada-label-indent (default value: -4)
+

Number of columns to indent a label. +

+
+
ada-stmt-end-indent (default value: 0)
+

Number of columns to indent a statement end keyword on a separate line. +

+
+
ada-when-indent (default value: 3)
+

Indentation for when relative to exception or case. +

+
+
ada-indent-is-separate (default value: t)
+

Non-nil means indent is separate or is abstract if on a single line. +

+
+
ada-indent-to-open-paren (default value: t)
+

Non-nil means indent according to the innermost open parenthesis. +

+
+
ada-indent-after-return (default value: t)
+

Non-nil means that the current line will also be re-indented +before inserting a newline, when you press RET. +

+
+ +

Most of the time, the indentation will be automatic, i.e., when you +press RET, the cursor will move to the correct column on the +next line. +

+

You can also indent single lines, or the current region, with TAB. +

+

Another mode of indentation exists that helps you to set up your +indentation scheme. If you press C-c TAB, Ada mode will do +the following: +

+
    +
  • Reindent the current line, as TAB would do. +
  • Temporarily move the cursor to a reference line, i.e., the line that +was used to calculate the current indentation. +
  • Display in the message window the name of the variable that provided +the offset for the indentation. +
+ +

The exact indentation of the current line is the same as the one for the +reference line, plus an offset given by the variable. +

+
+
TAB
+

Indent the current line or the current region. +

+
C-M-\
+

Indent lines in the current region. +

+
C-c TAB
+

Indent the current line and display the name of the variable used for +indentation. +

+
+ +
+
+
+ +

10 Formatting Parameter Lists

+ +
+
C-c C-f
+

Format the parameter list (ada-format-paramlist). +

+
+ +

This aligns the declarations on the colon (‘:’) separating +argument names and argument types, and aligns the in, +out and in out keywords. +

+
+
+
+ +

11 Automatic Casing

+ +

Casing of identifiers, attributes and keywords is automatically +performed while typing when the variable ada-auto-case is set. +Every time you press a word separator, the previous word is +automatically cased. +

+

You can customize the automatic casing differently for keywords, +attributes and identifiers. The relevant variables are the following: +ada-case-keyword, ada-case-attribute and +ada-case-identifier. +

+

All these variables can have one of the following values: +

+
+
downcase-word
+

The word will be lowercase. For instance My_vARIable is +converted to my_variable. +

+
+
upcase-word
+

The word will be uppercase. For instance My_vARIable is +converted to MY_VARIABLE. +

+
+
ada-capitalize-word
+

The first letter and each letter following an underscore (‘_’) +are uppercase, others are lowercase. For instance My_vARIable +is converted to My_Variable. +

+
+
ada-loose-case-word
+

Characters after an underscore ‘_’ character are uppercase, +others are not modified. For instance My_vARIable is converted +to My_VARIable. +

+
+ +

Ada mode allows you to define exceptions to these rules, in a file +specified by the variable ada-case-exception-file +(default ~/.emacs_case_exceptions). Each line in this file +specifies the casing of one word or word fragment. Comments may be +included, separated from the word by a space. +

+

If the word starts with an asterisk (‘*’), it defines the casing +as a word fragment (or “substring”); part of a word between two +underscores or word boundary. +

+

For example: +

+
+
DOD        Department of Defense
+*IO
+GNAT       The GNAT compiler from Ada Core Technologies
+
+ +

The word fragment *IO applies to any word containing “_io”; +Text_IO, Hardware_IO, etc. +

+ +

There are two ways to add new items to this file: you can simply edit +it as you would edit any text file. Or you can position point on the +word you want to add, and select menu ‘Ada | Edit | Create Case +Exception’, or press C-c C-y (ada-create-case-exception). +The word will automatically be added to the current list of exceptions +and to the file. +

+

To define a word fragment case exception, select the word fragment, +then select menu ‘Ada | Edit | Create Case Exception Substring’. +

+

It is sometimes useful to have multiple exception files around (for +instance, one could be the standard Ada acronyms, the second some +company specific exceptions, and the last one some project specific +exceptions). If you set up the variable ada-case-exception-file +as a list of files, each of them will be parsed and used in your emacs +session. However, when you save a new exception through the menu, as +described above, the new exception will be added to the first file in +the list. +

+
+
C-c C-b
+

Adjust case in the whole buffer (ada-adjust-case-buffer). +

+
C-c C-y
+

Create a new entry in the exception dictionary, with the word under +the cursor (ada-create-case-exception) +

+
C-c C-t
+

Rereads the exception dictionary from the file +ada-case-exception-file (ada-case-read-exceptions). +

+
+ +
+
+
+
+

+Next: , Previous: , Up: Ada Mode   [Contents][Index]

+
+

12 Statement Templates

+ +

Templates are defined for most Ada statements, using the Emacs +“skeleton” package. They can be inserted in the buffer using the +following commands: +

+
+
C-c t b
+

exception Block (ada-exception-block). +

+
C-c t c
+

case (ada-case). +

+
C-c t d
+

declare Block (ada-declare-block). +

+
C-c t e
+

else (ada-else). +

+
C-c t f
+

for Loop (ada-for-loop). +

+
C-c t h
+

Header (ada-header). +

+
C-c t i
+

if (ada-if). +

+
C-c t k
+

package Body (ada-package-body). +

+
C-c t l
+

loop (ada-loop). +

+
C-c p
+

subprogram body (ada-subprogram-body). +

+
C-c t t
+

task Body (ada-task-body). +

+
C-c t w
+

while Loop (ada-while). +

+
C-c t u
+

use (ada-use). +

+
C-c t x
+

exit (ada-exit). +

+
C-c t C-a
+

array (ada-array). +

+
C-c t C-e
+

elsif (ada-elsif). +

+
C-c t C-f
+

function Spec (ada-function-spec). +

+
C-c t C-k
+

package Spec (ada-package-spec). +

+
C-c t C-p
+

procedure Spec (ada-package-spec. +

+
C-c t C-r
+

record (ada-record). +

+
C-c t C-s
+

subtype (ada-subtype). +

+
C-c t C-t
+

task Spec (ada-task-spec). +

+
C-c t C-u
+

with (ada-with). +

+
C-c t C-v
+

private (ada-private). +

+
C-c t C-w
+

when (ada-when). +

+
C-c t C-x
+

exception (ada-exception). +

+
C-c t C-y
+

type (ada-type). +

+
+ +
+
+
+ +

13 Comment Handling

+ +

By default, comment lines get indented like Ada code. There are a few +additional functions to handle comments: +

+
+
M-;
+

Start a comment in default column. +

+
M-j
+

Continue comment on next line. +

+
C-c ;
+

Comment the selected region (add ‘--’ at the beginning of lines). +

+
C-c :
+

Uncomment the selected region +

+
M-q
+

autofill the current comment. +

+
+ +
+
+
+
+

+Next: , Previous: , Up: Ada Mode   [Contents][Index]

+
+

Appendix A GNU Free Documentation License

+
Version 1.3, 3 November 2008 +
+ +
+
Copyright © 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
+https://fsf.org/
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+ +
    +
  1. PREAMBLE + +

    The purpose of this License is to make a manual, textbook, or other +functional and useful document free in the sense of freedom: to +assure everyone the effective freedom to copy and redistribute it, +with or without modifying it, either commercially or noncommercially. +Secondarily, this License preserves for the author and publisher a way +to get credit for their work, while not being considered responsible +for modifications made by others. +

    +

    This License is a kind of “copyleft”, which means that derivative +works of the document must themselves be free in the same sense. It +complements the GNU General Public License, which is a copyleft +license designed for free software. +

    +

    We have designed this License in order to use it for manuals for free +software, because free software needs free documentation: a free +program should come with manuals providing the same freedoms that the +software does. But this License is not limited to software manuals; +it can be used for any textual work, regardless of subject matter or +whether it is published as a printed book. We recommend this License +principally for works whose purpose is instruction or reference. +

    +
  2. APPLICABILITY AND DEFINITIONS + +

    This License applies to any manual or other work, in any medium, that +contains a notice placed by the copyright holder saying it can be +distributed under the terms of this License. Such a notice grants a +world-wide, royalty-free license, unlimited in duration, to use that +work under the conditions stated herein. The “Document”, below, +refers to any such manual or work. Any member of the public is a +licensee, and is addressed as “you”. You accept the license if you +copy, modify or distribute the work in a way requiring permission +under copyright law. +

    +

    A “Modified Version” of the Document means any work containing the +Document or a portion of it, either copied verbatim, or with +modifications and/or translated into another language. +

    +

    A “Secondary Section” is a named appendix or a front-matter section +of the Document that deals exclusively with the relationship of the +publishers or authors of the Document to the Document’s overall +subject (or to related matters) and contains nothing that could fall +directly within that overall subject. (Thus, if the Document is in +part a textbook of mathematics, a Secondary Section may not explain +any mathematics.) The relationship could be a matter of historical +connection with the subject or with related matters, or of legal, +commercial, philosophical, ethical or political position regarding +them. +

    +

    The “Invariant Sections” are certain Secondary Sections whose titles +are designated, as being those of Invariant Sections, in the notice +that says that the Document is released under this License. If a +section does not fit the above definition of Secondary then it is not +allowed to be designated as Invariant. The Document may contain zero +Invariant Sections. If the Document does not identify any Invariant +Sections then there are none. +

    +

    The “Cover Texts” are certain short passages of text that are listed, +as Front-Cover Texts or Back-Cover Texts, in the notice that says that +the Document is released under this License. A Front-Cover Text may +be at most 5 words, and a Back-Cover Text may be at most 25 words. +

    +

    A “Transparent” copy of the Document means a machine-readable copy, +represented in a format whose specification is available to the +general public, that is suitable for revising the document +straightforwardly with generic text editors or (for images composed of +pixels) generic paint programs or (for drawings) some widely available +drawing editor, and that is suitable for input to text formatters or +for automatic translation to a variety of formats suitable for input +to text formatters. A copy made in an otherwise Transparent file +format whose markup, or absence of markup, has been arranged to thwart +or discourage subsequent modification by readers is not Transparent. +An image format is not Transparent if used for any substantial amount +of text. A copy that is not “Transparent” is called “Opaque”. +

    +

    Examples of suitable formats for Transparent copies include plain +ASCII without markup, Texinfo input format, LaTeX input +format, SGML or XML using a publicly available +DTD, and standard-conforming simple HTML, +PostScript or PDF designed for human modification. Examples +of transparent image formats include PNG, XCF and +JPG. Opaque formats include proprietary formats that can be +read and edited only by proprietary word processors, SGML or +XML for which the DTD and/or processing tools are +not generally available, and the machine-generated HTML, +PostScript or PDF produced by some word processors for +output purposes only. +

    +

    The “Title Page” means, for a printed book, the title page itself, +plus such following pages as are needed to hold, legibly, the material +this License requires to appear in the title page. For works in +formats which do not have any title page as such, “Title Page” means +the text near the most prominent appearance of the work’s title, +preceding the beginning of the body of the text. +

    +

    The “publisher” means any person or entity that distributes copies +of the Document to the public. +

    +

    A section “Entitled XYZ” means a named subunit of the Document whose +title either is precisely XYZ or contains XYZ in parentheses following +text that translates XYZ in another language. (Here XYZ stands for a +specific section name mentioned below, such as “Acknowledgements”, +“Dedications”, “Endorsements”, or “History”.) To “Preserve the Title” +of such a section when you modify the Document means that it remains a +section “Entitled XYZ” according to this definition. +

    +

    The Document may include Warranty Disclaimers next to the notice which +states that this License applies to the Document. These Warranty +Disclaimers are considered to be included by reference in this +License, but only as regards disclaiming warranties: any other +implication that these Warranty Disclaimers may have is void and has +no effect on the meaning of this License. +

    +
  3. VERBATIM COPYING + +

    You may copy and distribute the Document in any medium, either +commercially or noncommercially, provided that this License, the +copyright notices, and the license notice saying this License applies +to the Document are reproduced in all copies, and that you add no other +conditions whatsoever to those of this License. You may not use +technical measures to obstruct or control the reading or further +copying of the copies you make or distribute. However, you may accept +compensation in exchange for copies. If you distribute a large enough +number of copies you must also follow the conditions in section 3. +

    +

    You may also lend copies, under the same conditions stated above, and +you may publicly display copies. +

    +
  4. COPYING IN QUANTITY + +

    If you publish printed copies (or copies in media that commonly have +printed covers) of the Document, numbering more than 100, and the +Document’s license notice requires Cover Texts, you must enclose the +copies in covers that carry, clearly and legibly, all these Cover +Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on +the back cover. Both covers must also clearly and legibly identify +you as the publisher of these copies. The front cover must present +the full title with all words of the title equally prominent and +visible. You may add other material on the covers in addition. +Copying with changes limited to the covers, as long as they preserve +the title of the Document and satisfy these conditions, can be treated +as verbatim copying in other respects. +

    +

    If the required texts for either cover are too voluminous to fit +legibly, you should put the first ones listed (as many as fit +reasonably) on the actual cover, and continue the rest onto adjacent +pages. +

    +

    If you publish or distribute Opaque copies of the Document numbering +more than 100, you must either include a machine-readable Transparent +copy along with each Opaque copy, or state in or with each Opaque copy +a computer-network location from which the general network-using +public has access to download using public-standard network protocols +a complete Transparent copy of the Document, free of added material. +If you use the latter option, you must take reasonably prudent steps, +when you begin distribution of Opaque copies in quantity, to ensure +that this Transparent copy will remain thus accessible at the stated +location until at least one year after the last time you distribute an +Opaque copy (directly or through your agents or retailers) of that +edition to the public. +

    +

    It is requested, but not required, that you contact the authors of the +Document well before redistributing any large number of copies, to give +them a chance to provide you with an updated version of the Document. +

    +
  5. MODIFICATIONS + +

    You may copy and distribute a Modified Version of the Document under +the conditions of sections 2 and 3 above, provided that you release +the Modified Version under precisely this License, with the Modified +Version filling the role of the Document, thus licensing distribution +and modification of the Modified Version to whoever possesses a copy +of it. In addition, you must do these things in the Modified Version: +

    +
      +
    1. Use in the Title Page (and on the covers, if any) a title distinct +from that of the Document, and from those of previous versions +(which should, if there were any, be listed in the History section +of the Document). You may use the same title as a previous version +if the original publisher of that version gives permission. + +
    2. List on the Title Page, as authors, one or more persons or entities +responsible for authorship of the modifications in the Modified +Version, together with at least five of the principal authors of the +Document (all of its principal authors, if it has fewer than five), +unless they release you from this requirement. + +
    3. State on the Title page the name of the publisher of the +Modified Version, as the publisher. + +
    4. Preserve all the copyright notices of the Document. + +
    5. Add an appropriate copyright notice for your modifications +adjacent to the other copyright notices. + +
    6. Include, immediately after the copyright notices, a license notice +giving the public permission to use the Modified Version under the +terms of this License, in the form shown in the Addendum below. + +
    7. Preserve in that license notice the full lists of Invariant Sections +and required Cover Texts given in the Document’s license notice. + +
    8. Include an unaltered copy of this License. + +
    9. Preserve the section Entitled “History”, Preserve its Title, and add +to it an item stating at least the title, year, new authors, and +publisher of the Modified Version as given on the Title Page. If +there is no section Entitled “History” in the Document, create one +stating the title, year, authors, and publisher of the Document as +given on its Title Page, then add an item describing the Modified +Version as stated in the previous sentence. + +
    10. Preserve the network location, if any, given in the Document for +public access to a Transparent copy of the Document, and likewise +the network locations given in the Document for previous versions +it was based on. These may be placed in the “History” section. +You may omit a network location for a work that was published at +least four years before the Document itself, or if the original +publisher of the version it refers to gives permission. + +
    11. For any section Entitled “Acknowledgements” or “Dedications”, Preserve +the Title of the section, and preserve in the section all the +substance and tone of each of the contributor acknowledgements and/or +dedications given therein. + +
    12. Preserve all the Invariant Sections of the Document, +unaltered in their text and in their titles. Section numbers +or the equivalent are not considered part of the section titles. + +
    13. Delete any section Entitled “Endorsements”. Such a section +may not be included in the Modified Version. + +
    14. Do not retitle any existing section to be Entitled “Endorsements” or +to conflict in title with any Invariant Section. + +
    15. Preserve any Warranty Disclaimers. +
    + +

    If the Modified Version includes new front-matter sections or +appendices that qualify as Secondary Sections and contain no material +copied from the Document, you may at your option designate some or all +of these sections as invariant. To do this, add their titles to the +list of Invariant Sections in the Modified Version’s license notice. +These titles must be distinct from any other section titles. +

    +

    You may add a section Entitled “Endorsements”, provided it contains +nothing but endorsements of your Modified Version by various +parties—for example, statements of peer review or that the text has +been approved by an organization as the authoritative definition of a +standard. +

    +

    You may add a passage of up to five words as a Front-Cover Text, and a +passage of up to 25 words as a Back-Cover Text, to the end of the list +of Cover Texts in the Modified Version. Only one passage of +Front-Cover Text and one of Back-Cover Text may be added by (or +through arrangements made by) any one entity. If the Document already +includes a cover text for the same cover, previously added by you or +by arrangement made by the same entity you are acting on behalf of, +you may not add another; but you may replace the old one, on explicit +permission from the previous publisher that added the old one. +

    +

    The author(s) and publisher(s) of the Document do not by this License +give permission to use their names for publicity for or to assert or +imply endorsement of any Modified Version. +

    +
  6. COMBINING DOCUMENTS + +

    You may combine the Document with other documents released under this +License, under the terms defined in section 4 above for modified +versions, provided that you include in the combination all of the +Invariant Sections of all of the original documents, unmodified, and +list them all as Invariant Sections of your combined work in its +license notice, and that you preserve all their Warranty Disclaimers. +

    +

    The combined work need only contain one copy of this License, and +multiple identical Invariant Sections may be replaced with a single +copy. If there are multiple Invariant Sections with the same name but +different contents, make the title of each such section unique by +adding at the end of it, in parentheses, the name of the original +author or publisher of that section if known, or else a unique number. +Make the same adjustment to the section titles in the list of +Invariant Sections in the license notice of the combined work. +

    +

    In the combination, you must combine any sections Entitled “History” +in the various original documents, forming one section Entitled +“History”; likewise combine any sections Entitled “Acknowledgements”, +and any sections Entitled “Dedications”. You must delete all +sections Entitled “Endorsements.” +

    +
  7. COLLECTIONS OF DOCUMENTS + +

    You may make a collection consisting of the Document and other documents +released under this License, and replace the individual copies of this +License in the various documents with a single copy that is included in +the collection, provided that you follow the rules of this License for +verbatim copying of each of the documents in all other respects. +

    +

    You may extract a single document from such a collection, and distribute +it individually under this License, provided you insert a copy of this +License into the extracted document, and follow this License in all +other respects regarding verbatim copying of that document. +

    +
  8. AGGREGATION WITH INDEPENDENT WORKS + +

    A compilation of the Document or its derivatives with other separate +and independent documents or works, in or on a volume of a storage or +distribution medium, is called an “aggregate” if the copyright +resulting from the compilation is not used to limit the legal rights +of the compilation’s users beyond what the individual works permit. +When the Document is included in an aggregate, this License does not +apply to the other works in the aggregate which are not themselves +derivative works of the Document. +

    +

    If the Cover Text requirement of section 3 is applicable to these +copies of the Document, then if the Document is less than one half of +the entire aggregate, the Document’s Cover Texts may be placed on +covers that bracket the Document within the aggregate, or the +electronic equivalent of covers if the Document is in electronic form. +Otherwise they must appear on printed covers that bracket the whole +aggregate. +

    +
  9. TRANSLATION + +

    Translation is considered a kind of modification, so you may +distribute translations of the Document under the terms of section 4. +Replacing Invariant Sections with translations requires special +permission from their copyright holders, but you may include +translations of some or all Invariant Sections in addition to the +original versions of these Invariant Sections. You may include a +translation of this License, and all the license notices in the +Document, and any Warranty Disclaimers, provided that you also include +the original English version of this License and the original versions +of those notices and disclaimers. In case of a disagreement between +the translation and the original version of this License or a notice +or disclaimer, the original version will prevail. +

    +

    If a section in the Document is Entitled “Acknowledgements”, +“Dedications”, or “History”, the requirement (section 4) to Preserve +its Title (section 1) will typically require changing the actual +title. +

    +
  10. TERMINATION + +

    You may not copy, modify, sublicense, or distribute the Document +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense, or distribute it is void, and +will automatically terminate your rights under this License. +

    +

    However, if you cease all violation of this License, then your license +from a particular copyright holder is reinstated (a) provisionally, +unless and until the copyright holder explicitly and finally +terminates your license, and (b) permanently, if the copyright holder +fails to notify you of the violation by some reasonable means prior to +60 days after the cessation. +

    +

    Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. +

    +

    Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, receipt of a copy of some or all of the same material does +not give you any rights to use it. +

    +
  11. FUTURE REVISIONS OF THIS LICENSE + +

    The Free Software Foundation may publish new, revised versions +of the GNU Free Documentation License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. See +https://www.gnu.org/licenses/. +

    +

    Each version of the License is given a distinguishing version number. +If the Document specifies that a particular numbered version of this +License “or any later version” applies to it, you have the option of +following the terms and conditions either of that specified version or +of any later version that has been published (not as a draft) by the +Free Software Foundation. If the Document does not specify a version +number of this License, you may choose any version ever published (not +as a draft) by the Free Software Foundation. If the Document +specifies that a proxy can decide which future versions of this +License can be used, that proxy’s public statement of acceptance of a +version permanently authorizes you to choose that version for the +Document. +

    +
  12. RELICENSING + +

    “Massive Multiauthor Collaboration Site” (or “MMC Site”) means any +World Wide Web server that publishes copyrightable works and also +provides prominent facilities for anybody to edit those works. A +public wiki that anybody can edit is an example of such a server. A +“Massive Multiauthor Collaboration” (or “MMC”) contained in the +site means any set of copyrightable works thus published on the MMC +site. +

    +

    “CC-BY-SA” means the Creative Commons Attribution-Share Alike 3.0 +license published by Creative Commons Corporation, a not-for-profit +corporation with a principal place of business in San Francisco, +California, as well as future copyleft versions of that license +published by that same organization. +

    +

    “Incorporate” means to publish or republish a Document, in whole or +in part, as part of another Document. +

    +

    An MMC is “eligible for relicensing” if it is licensed under this +License, and if all works that were first published under this License +somewhere other than this MMC, and subsequently incorporated in whole +or in part into the MMC, (1) had no cover texts or invariant sections, +and (2) were thus incorporated prior to November 1, 2008. +

    +

    The operator of an MMC Site may republish an MMC contained in the site +under CC-BY-SA on the same site at any time before August 1, 2009, +provided the MMC is eligible for relicensing. +

    +
+ +

ADDENDUM: How to use this License for your documents

+ +

To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and +license notices just after the title page: +

+
+
  Copyright (C)  year  your name.
+  Permission is granted to copy, distribute and/or modify this document
+  under the terms of the GNU Free Documentation License, Version 1.3
+  or any later version published by the Free Software Foundation;
+  with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+  Texts.  A copy of the license is included in the section entitled ``GNU
+  Free Documentation License''.
+
+ +

If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, +replace the “with…Texts.” line with this: +

+
+
    with the Invariant Sections being list their titles, with
+    the Front-Cover Texts being list, and with the Back-Cover Texts
+    being list.
+
+ +

If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. +

+

If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of +free software license, such as the GNU General Public License, +to permit their use in free software. +

+ +
+
+
+ +

Index

+ +
Jump to:   A +   +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Index Entry  Section

A
ada-adjust-case-buffer: Automatic Casing
ada-array: Statement Templates
ada-case: Statement Templates
ada-case-read-exceptions: Automatic Casing
ada-complete-identifier: Identifier completion
ada-create-case-exception: Automatic Casing
ada-declare-block: Statement Templates
ada-else: Statement Templates
ada-elsif: Statement Templates
ada-exception: Statement Templates
ada-exception-block: Statement Templates
ada-exit: Statement Templates
ada-find-references: Moving Through Ada Code
ada-for-loop: Statement Templates
ada-format-paramlist: Formatting Parameter Lists
ada-function-spec: Statement Templates
ada-goto-declaration: Moving Through Ada Code
ada-header: Statement Templates
ada-if: Statement Templates
ada-loop: Statement Templates
ada-move-to-end: Moving Through Ada Code
ada-move-to-start: Moving Through Ada Code
ada-next-package: Moving Through Ada Code
ada-next-procedure: Moving Through Ada Code
ada-package-body: Statement Templates
ada-package-spec: Statement Templates
ada-previous-package: Moving Through Ada Code
ada-previous-procedure: Moving Through Ada Code
ada-private: Statement Templates
ada-procedure-spec: Statement Templates
ada-record: Statement Templates
ada-subprogram-body: Statement Templates
ada-subtype: Statement Templates
ada-task-body: Statement Templates
ada-task-spec: Statement Templates
ada-type: Statement Templates
ada-use: Statement Templates
ada-when: Statement Templates
ada-while: Statement Templates
ada-with: Statement Templates

+
Jump to:   A +   +
+ +
+
+ + + + + diff --git a/ada-mode/doc/ada-mode.info b/ada-mode/doc/ada-mode.info new file mode 100644 index 0000000..e29172d --- /dev/null +++ b/ada-mode/doc/ada-mode.info @@ -0,0 +1,1983 @@ +This is ada-mode.info, produced by texi2any version 6.8 from +ada-mode.texi. + +Copyright © 1999–2019 Free Software Foundation, Inc. + + Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU Free Documentation License, + Version 1.3 or any later version published by the Free Software + Foundation; with no Invariant Sections, with the Front-Cover Texts + being “A GNU Manual”, and with the Back-Cover Texts as in (a) + below. A copy of the license is included in the section entitled + “GNU Free Documentation License”. + + (a) The FSF’s Back-Cover Text is: “You have the freedom to copy and + modify this GNU manual.” +INFO-DIR-SECTION Emacs editing modes +START-INFO-DIR-ENTRY +* Ada mode: (ada-mode). Emacs mode for editing and compiling Ada code. +END-INFO-DIR-ENTRY + + +File: ada-mode.info, Node: Top, Next: Overview, Up: (dir) + +Ada Mode +******** + +Copyright © 1999–2019 Free Software Foundation, Inc. + + Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU Free Documentation License, + Version 1.3 or any later version published by the Free Software + Foundation; with no Invariant Sections, with the Front-Cover Texts + being “A GNU Manual”, and with the Back-Cover Texts as in (a) + below. A copy of the license is included in the section entitled + “GNU Free Documentation License”. + + (a) The FSF’s Back-Cover Text is: “You have the freedom to copy and + modify this GNU manual.” + +* Menu: + +* Overview:: +* Installation:: Installing Ada mode on your system +* Customization:: Setting up Ada mode to your taste +* Compiling Executing:: Working with your application within Emacs +* Project files:: Describing the organization of your project +* Compiling Examples:: A small tutorial +* Moving Through Ada Code:: Moving easily through Ada sources +* Identifier completion:: Finishing words automatically +* Automatic Smart Indentation:: Indenting your code automatically as you type +* Formatting Parameter Lists:: Formatting subprograms’ parameter lists + automatically +* Automatic Casing:: Adjusting the case of words automatically +* Statement Templates:: Inserting code templates +* Comment Handling:: Reformatting comments easily +* GNU Free Documentation License:: The license for this documentation. +* Index:: + + +File: ada-mode.info, Node: Overview, Next: Installation, Prev: Top, Up: Top + +1 Overview +********** + +The Emacs mode for programming in Ada helps the user in understanding +existing code and facilitates writing new code. + + When the GNU Ada compiler GNAT is used, the cross-reference +information output by the compiler is used to provide powerful code +navigation (jump to definition, find all uses, etc.). + + When you open a file with a file extension of ‘.ads’ or ‘.adb’, Emacs +will automatically load and activate Ada mode. + + Ada mode works without any customization, if you are using the GNAT +compiler () and the GNAT default naming +convention. + + You must customize a few things if you are using a different compiler +or file naming convention; *Note Other compiler::, *Note Non-standard +file names::. + + In addition, you may want to customize the indentation, +capitalization, and other things; *Note Other customization::. + + Finally, for large Ada projects, you will want to set up an Emacs Ada +mode project file for each project; *Note Project files::. Note that +these are different from the GNAT project files used by gnatmake and +other GNAT commands. + + See the Emacs info manual, section ’Running Debuggers Under Emacs’, +for general information on debugging. + + +File: ada-mode.info, Node: Installation, Next: Customization, Prev: Overview, Up: Top + +2 Installation +************** + +Ada mode is part of the standard Emacs distribution; if you use that, no +files need to be installed. + + Ada mode is also available as a separate distribution, from the Emacs +Ada mode website +. The +separate distribution may be more recent. + + For installing the separate distribution, see the ‘README’ file in +the distribution. + + To see what version of Ada mode you have installed, do ‘M-x +ada-mode-version’. + + The following files are provided with the Ada mode distribution: + + • ‘ada-mode.el’: The main file for Ada mode, providing indentation, + formatting of parameter lists, moving through code, comment + handling and automatic casing. + + • ‘ada-prj.el’: GUI editing of Ada mode project files, using Emacs + widgets. + + • ‘ada-stmt.el’: Ada statement templates. + + • ‘ada-xref.el’: GNAT cross-references, completion of identifiers, + and compilation. Also provides project files (which are not + GNAT-specific). + + +File: ada-mode.info, Node: Customization, Next: Compiling Executing, Prev: Installation, Up: Top + +3 Customizing Ada mode +********************** + +Here we assume you are familiar with setting variables in Emacs, either +thru ’customize’ or in elisp (in your ‘.emacs’ file). For a basic +introduction to customize, elisp, and Emacs in general, see the tutorial +in *note The GNU Emacs Manual: (emacs)Top. + + These global Emacs settings are strongly recommended (put them in +your .emacs): + + (global-font-lock-mode t) + (transient-mark-mode t) + + ‘(global-font-lock-mode t)’ turns on syntax highlighting for all +buffers (it is off by default because it may be too slow for some +machines). + + ‘(transient-mark-mode t)’ highlights selected text. + + See the Emacs help for each of these variables for more information. + +* Menu: + +* Non-standard file names:: +* Other compiler:: +* Other customization:: + + +File: ada-mode.info, Node: Non-standard file names, Next: Other compiler, Up: Customization + +3.1 Non-standard file names +=========================== + +By default, Ada mode is configured to use the GNAT file naming +convention, where file names are a simple modification of the Ada names, +and the extension for specs and bodies are ‘.ads’ and ‘.adb’, +respectively. + + Ada mode uses the file extensions to allow moving from a package body +to the corresponding spec and back. + + Ada mode supports a list of alternative file extensions for specs and +bodies. + + For instance, if your spec and bodies files are called ‘UNIT_s.ada’ +and ‘UNIT_b.ada’, respectively, you can add the following to your +‘.emacs’ file: + + (ada-add-extensions "_s.ada" "_b.ada") + + You can define additional extensions: + + (ada-add-extensions ".ads" "_b.ada") + (ada-add-extensions ".ads" ".body") + + This means that whenever Ada mode looks for the body for a file whose +extension is ‘.ads’, it will take the first available file that ends +with either ‘.adb’, ‘_b.ada’ or ‘.body’. + + Similarly, if Ada mode is looking for a spec, it will look for ‘.ads’ +or ‘_s.ada’. + + If the filename is not derived from the Ada name following the GNAT +convention, things are a little more complicated. You then need to +rewrite the function ‘ada-make-filename-from-adaname’. Doing that is +beyond the scope of this manual; see the current definitions in +‘ada-mode.el’ and ‘ada-xref.el’ for examples. + + +File: ada-mode.info, Node: Other compiler, Next: Other customization, Prev: Non-standard file names, Up: Customization + +3.2 Other compiler +================== + +By default, Ada mode is configured to use the GNU Ada compiler GNAT. + + To use a different Ada compiler, you must specify the command lines +used to run that compiler, either in lisp variables or in Emacs Ada mode +project files. See *note Project file variables:: for the list of +project variables, and the corresponding lisp variables. + + +File: ada-mode.info, Node: Other customization, Prev: Other compiler, Up: Customization + +3.3 Other customization +======================= + +All user-settable Ada mode variables can be set via the menu ‘Ada | +Customize’. Click on the ‘Help’ button there for help on using +customize. + + To modify a specific variable, you can directly call the function +‘customize-variable’; just type ‘M-x customize-variable +VARIABLE-NAME ’). + + Alternately, you can specify variable settings in the Emacs +configuration file, ‘.emacs’. This file is coded in Emacs lisp, and the +syntax to set a variable is the following: + (setq variable-name value) + + +File: ada-mode.info, Node: Compiling Executing, Next: Project files, Prev: Customization, Up: Top + +4 Compiling Executing +********************* + +Ada projects can be compiled, linked, and executed using commands on the +Ada menu. All of these commands can be customized via a project file +(*note Project files::), but the defaults are sufficient for using the +GNAT compiler for simple projects (single files, or several files in a +single directory). + + Even when no project file is used, the GUI project editor (menu ‘Ada +| Project | Edit’) shows the settings of the various project file +variables referenced here. + +* Menu: + +* Compile commands:: +* Compiler errors:: + + +File: ada-mode.info, Node: Compile commands, Next: Compiler errors, Up: Compiling Executing + +4.1 Compile commands +==================== + +Here are the commands for building and using an Ada project, as listed +in the Ada menu. + + In multi-file projects, there must be one file that is the main +program. That is given by the ‘main’ project file variable; it defaults +to the current file if not yet set, but is also set by the “set main and +build” command. + +‘Check file’ + Compiles the current file in syntax check mode, by running + ‘check_cmd’ defined in the current project file. This typically + runs faster than full compile mode, speeding up finding and fixing + compilation errors. + + This sets ‘main’ only if it has not been set yet. + +‘Compile file’ + Compiles the current file, by running ‘comp_cmd’ from the current + project file. + + This does not set ‘main’. + +‘Set main and Build’ + Sets ‘main’ to the current file, then executes the Build command. + +‘Show main’ + Display ‘main’ in the message buffer. + +‘Build’ + Compiles all obsolete units of the current ‘main’, and links + ‘main’, by running ‘make_cmd’ from the current project. + + This sets ‘main’ only if it has not been set yet. + +‘Run’ + Executes the main program in a shell, displayed in a separate Emacs + buffer. This runs ‘run_cmd’ from the current project. The + execution buffer allows for interactive input/output. + + To modify the run command, in particular to provide or change the + command line arguments, type ‘C-u’ before invoking the command. + + This command is not available for a cross-compilation toolchain. + + It is important when using these commands to understand how ‘main’ is +used and changed. + + Build runs ’gnatmake’ on the main unit. During a typical +edit/compile session, this is the only command you need to invoke, which +is why it is bound to ‘C-c C-c’. It will compile all files needed by +the main unit, and display compilation errors in any of them. + + Note that Build can be invoked from any Ada buffer; typically you +will be fixing errors in files other than the main, but you don’t have +to switch back to the main to invoke the compiler again. + + Novices and students typically work on single-file Ada projects. In +this case, ‘C-c C-m’ will normally be the only command needed; it will +build the current file, rather than the last-built main. + + There are three ways to change ‘main’: + + 1. Invoke ‘Ada | Set main and Build’, which sets ‘main’ to the current + file. + + 2. Invoke ‘Ada | Project | Edit’, edit ‘main’ and ‘main’, and click + ‘[save]’ + + 3. Invoke ‘Ada | Project | Load’, and load a project file that + specifies ‘main’ + + +File: ada-mode.info, Node: Compiler errors, Prev: Compile commands, Up: Compiling Executing + +4.2 Compiler errors +=================== + +The ‘Check file’, ‘Compile file’, and ‘Build’ commands all place +compilation errors in a separate buffer named ‘*compilation*’. + + Each line in this buffer will become active: you can simply click on +it with the middle button of the mouse, or move point to it and press +. Emacs will then display the relevant source file and put point +on the line and column where the error was found. + + You can also press the ‘C-x `’ key (‘next-error’), and Emacs will +jump to the first error. If you press that key again, it will move you +to the second error, and so on. + + Some error messages might also include references to other files. +These references are also clickable in the same way, or put point after +the line number and press . + + +File: ada-mode.info, Node: Project files, Next: Compiling Examples, Prev: Compiling Executing, Up: Top + +5 Project files +*************** + +An Emacs Ada mode project file specifies what directories hold sources +for your project, and allows you to customize the compilation commands +and other things on a per-project basis. + + Note that Ada mode project files ‘*.adp’ are different than GNAT +compiler project files ‘*.gpr’. However, Emacs Ada mode can use a GNAT +project file to specify the project directories. If no other +customization is needed, a GNAT project file can be used without an +Emacs Ada mode project file. + +* Menu: + +* Project File Overview:: +* GUI Editor:: +* Project file variables:: + + +File: ada-mode.info, Node: Project File Overview, Next: GUI Editor, Up: Project files + +5.1 Project File Overview +========================= + +Project files have a simple syntax; they may be edited directly. Each +line specifies a project variable name and its value, separated by “=”: + src_dir=/Projects/my_project/src_1 + src_dir=/Projects/my_project/src_2 + + Some variables (like ‘src_dir’) are lists; multiple occurrences are +concatenated. + + There must be no space between the variable name and “=”, and no +trailing spaces. + + Alternately, a GUI editor for project files is available (*note GUI +Editor::). It uses Emacs widgets, similar to Emacs customize. + + The GUI editor also provides a convenient way to view current project +settings, if they have been modified using menu commands rather than by +editing the project file. + + After the first Ada mode build command is invoked, there is always a +current project file, given by the lisp variable +‘ada-prj-default-project-file’. Currently, the only way to show the +current project file is to invoke the GUI editor. + + To find the project file the first time, Ada mode uses the following +search algorithm: + + • If ‘ada-prj-default-project-file’ is set, use that. + + • Otherwise, search for a file in the current directory with the same + base name as the Ada file, but extension given by + ‘ada-prj-file-extension’ (default ‘".adp"’). + + • If not found, search for ‘*.adp’ in the current directory; if + several are found, prompt the user to select one. + + • If none are found, use ‘default.adp’ in the current directory (even + if it does not exist). + + This algorithm always sets ‘ada-prj-default-project-file’, even when +the file does not actually exist. + + To change the project file before or after the first one is found, +invoke ‘Ada | Project | Load ...’. + + Or, in lisp, evaluate ‘(ada-set-default-project-file +"/path/file.adp")’. This sets ‘ada-prj-default-project-file’, and reads +the project file. + + You can also specify a GNAT project file to ‘Ada | Project | Load +...’ or ‘ada-set-default-project-file’. Emacs Ada mode checks the file +extension; if it is ‘.gpr’, the file is treated as a GNAT project file. +Any other extension is treated as an Emacs Ada mode project file. + + +File: ada-mode.info, Node: GUI Editor, Next: Project file variables, Prev: Project File Overview, Up: Project files + +5.2 GUI Editor +============== + +The project file editor is invoked with the menu ‘Ada | Projects | +Edit’. + + Once in the buffer for editing the project file, you can save your +modification using the ‘[save]’ button at the bottom of the buffer, or +the ‘C-x C-s’ binding. To cancel your modifications, kill the buffer or +click on the ‘[cancel]’ button. + + +File: ada-mode.info, Node: Project file variables, Prev: GUI Editor, Up: Project files + +5.3 Project file variables +========================== + +The following variables can be defined in a project file; some can also +be defined in lisp variables. + + To set a project variable that is a list, specify each element of the +list on a separate line in the project file. + + Any project variable can be referenced in other project variables, +using a shell-like notation. For instance, if the variable ‘comp_cmd’ +contains ‘${comp_opt}’, the value of the ‘comp_opt’ variable will be +substituted when ‘comp_cmd’ is used. + + In addition, process environment variables can be referenced using +the same syntax, or the normal ‘$var’ syntax. + + Most project variables have defaults that can be changed by setting +lisp variables; the table below identifies the lisp variable for each +project variable. Lisp variables corresponding to project variables +that are lists are lisp lists. + + In general, project variables are evaluated when referenced in Emacs +Ada mode commands. Relative file paths are expanded to absolute +relative to ‘${build_dir}’. + + Here is the list of variables. In the default values, the current +directory ‘"."’ is the project file directory. + +‘ada_project_path_sep’ [default: ‘":" or ";"’] + Path separator for ‘ADA_PROJECT_PATH’. It defaults to the correct + value for a native implementation of GNAT for the current operating + system. The user must override this when using Windows native GNAT + with Cygwin Emacs, and perhaps in other cases. + + Lisp variable: ‘ada-prj-ada-project-path-sep’. + +‘ada_project_path’ [default: ‘""’] + A list of directories to search for GNAT project files. + + If set, the ‘ADA_PROJECT_PATH’ process environment variable is set + to this value in the Emacs process when the Emacs Ada mode project + is selected via menu ‘Ada | Project | Load’. + + For ‘ada_project_path’, relative file paths are expanded to + absolute when the Emacs Ada project file is read, rather than when + the project file is selected. + + For example if the project file is in the directory + ‘/home/myproject’, the environment variable ‘GDS_ROOT’ is set to + ‘/home/shared’, and the project file contains: + ada_project_path_sep=: + ada_project_path=$GDS_ROOT/makerules + ada_project_path=../opentoken + then as a result the environment variable ‘ADA_PROJECT_PATH’ will + be set to ‘"/home/shared/makerules:/home/opentoken/"’. + + The default value is not the current value of this environment + variable, because that will typically have been set by another + project, and will therefore be incorrect for this project. + + If you have the environment variable set correctly for all of your + projects, you do not need to set this project variable. + +‘bind_opt’ [default: ‘""’] + Holds user binder options; used in the default build commands. + + Lisp variable: ‘ada-prj-default-bind-opt’. + +‘build_dir’ [default: ‘"."’] + The compile commands will be issued in this directory. + +‘casing’ [default: ‘("~/.emacs_case_exceptions")’] + List of files containing casing exceptions. See the help on + ‘ada-case-exception-file’ for more info. + + Lisp variable: ‘ada-case-exception-file’. + +‘check_cmd’ [default: ‘"${cross_prefix}gnatmake -u -c -gnatc ${gnatmake_opt} ${full_current} -cargs ${comp_opt}"’] + Command used to syntax check a single file. The name of the file + is substituted for ‘full_current’. + + Lisp variable: ‘ada-prj-default-check-cmd’ + +‘comp_cmd’ [default: ‘"${cross_prefix}gnatmake -u -c ${gnatmake_opt} ${full_current} -cargs ${comp_opt}"’] + Command used to compile a single file. The name of the file is + substituted for ‘full_current’. + + Lisp variable: ‘ada-prj-default-comp-cmd’. + +‘comp_opt’ [default: ‘"-gnatq -gnatQ"’] + Holds user compiler options; used in the default compile commands. + The default value tells gnatmake to generate library files for + cross-referencing even when there are errors. + + If source code for the project is in multiple directories, the + appropriate compiler options must be added here. *note Set source + search path:: for examples of this. Alternately, GNAT project + files may be used; *note Use GNAT project file::. + + Lisp variable: ‘ada-prj-default-comp-opt’. + +‘cross_prefix’ [default: ‘""’] + Name of target machine in a cross-compilation environment. Used in + default compile and build commands. + +‘debug_cmd’ [default: ‘"${cross_prefix}gdb ${main}"’] + Command used to debug the application + + Lisp variable: ‘ada-prj-default-debugger’. + +‘debug_post_cmd’ [default: ‘""’] + Command executed after ‘debug_cmd’. + +‘debug_pre_cmd’ [default: ‘"cd ${build_dir}"’] + Command executed before ‘debug_cmd’. + +‘gnatfind_opt’ [default: ‘"-rf"’] + Holds user gnatfind options; used in the default find commands. + + Lisp variable: ‘ada-prj-gnatfind-switches’. + +‘gnatmake_opt’ [default: ‘"-g"’] + Holds user gnatmake options; used in the default build commands. + + Lisp variable: ‘ada-prj-default-gnatmake-opt’. + +‘gpr_file’ [default: ‘""’] + Specify GNAT project file. + + If set, the source and object directories specified in the GNAT + project file are appended to ‘src_dir’ and ‘obj_dir’. This allows + specifying Ada source directories with a GNAT project file, and + other source directories with the Emacs project file. + + In addition, ‘-P{gpr_file}’ is added to the project variable + ‘gnatmake_opt’ whenever it is referenced. With the default project + variables, this passes the project file to all gnatmake commands. + + Lisp variable: ‘ada-prj-default-gpr-file’. + +‘link_opt’ [default: ‘""’] + Holds user linker options; used in the default build commands. + + Lisp variable: ‘ada-prj-default-link-opt’. + +‘main’ [default: current file] + Specifies the name of the executable file for the project; used in + the default build commands. + +‘make_cmd’ [default: ‘"${cross_prefix}gnatmake -o ${main} ${main} ${gnatmake_opt} -cargs ${comp_opt} -bargs ${bind_opt} -largs ${link_opt}"’] + Command used to build the application. + + Lisp variable: ‘ada-prj-default-make-cmd’. + +‘obj_dir’ [default: ‘"."’] + A list of directories to search for library files. Ada mode + searches this list for the ‘.ali’ files generated by GNAT that + contain cross-reference information. + + The compiler commands must place the ‘.ali’ files in one of these + directories; the default commands do that. + +‘remote_machine’ [default: ‘""’] + Name of the machine to log into before issuing the compile and + build commands. If this variable is empty, the command will be run + on the local machine. + +‘run_cmd’ [default: ‘"./${main}"’] + Command used to run the application. + +‘src_dir’ [default: ‘"."’] + A list of directories to search for source files, both for compile + commands and source navigation. + + +File: ada-mode.info, Node: Compiling Examples, Next: Moving Through Ada Code, Prev: Project files, Up: Top + +6 Compiling Examples +******************** + +We present several small projects, and walk thru the process of +compiling, linking, and running them. + + The first example illustrates more Ada mode features than the others; +you should work thru that example before doing the others. + + All of these examples assume you are using GNAT. + + The source for these examples is available on the Emacs Ada mode +website mentioned in *Note Installation::. + +* Menu: + +* No project files:: Just menus +* Set compiler options:: A basic Ada mode project file +* Set source search path:: Source in multiple directories +* Use GNAT project file:: +* Use multiple GNAT project files:: + + +File: ada-mode.info, Node: No project files, Next: Set compiler options, Up: Compiling Examples + +6.1 No project files +==================== + +This example uses no project files. + + First, create a directory ‘Example_1’, containing: + + ‘hello.adb’: + + with Ada.Text_IO; + procedure Hello + is begin + Put_Line("Hello from hello.adb"); + end Hello; + + Yes, this is missing “use Ada.Text_IO;” - we want to demonstrate +compiler error handling. + + ‘hello_2.adb’: + + with Hello_Pkg; + procedure Hello_2 + is begin + Hello_Pkg.Say_Hello; + end Hello_2; + + This file has no errors. + + ‘hello_pkg.ads’: + + package Hello_Pkg is + procedure Say_Hello; + end Hello_Pkg; + + This file has no errors. + + ‘hello_pkg.adb’: + + with Ada.Text_IO; + package Hello_Pkg is + procedure Say_Hello + is begin + Ada.Text_IO.Put_Line ("Hello from hello_pkg.adb"); + end Say_Hello; + end Hello_Pkg; + + Yes, this is missing the keyword ‘body’; another compiler error +example. + + In buffer ‘hello.adb’, invoke ‘Ada | Check file’. You should get a +‘*compilation*’ buffer containing something like (the directory paths +will be different): + + cd c:/Examples/Example_1/ + gnatmake -u -c -gnatc -g c:/Examples/Example_1/hello.adb -cargs -gnatq -gnatQ + gcc -c -Ic:/Examples/Example_1/ -gnatc -g -gnatq -gnatQ -I- c:/Examples/Example_1/hello.adb + hello.adb:4:04: "Put_Line" is not visible + hello.adb:4:04: non-visible declaration at a-textio.ads:264 + hello.adb:4:04: non-visible declaration at a-textio.ads:260 + gnatmake: "c:/Examples/Example_1/hello.adb" compilation error + + If you have enabled font-lock, the lines with actual errors (starting +with ‘hello.adb’) are highlighted, with the file name in red. + + Now type ‘C-x `’ (on a PC keyboard, <`> is next to <1>). Or you can +click the middle mouse button on the first error line. The compilation +buffer scrolls to put the first error on the top line, and point is put +at the place of the error in the ‘hello.adb’ buffer. + + To fix the error, change the line to be + + Ada.Text_IO.Put_Line ("hello from hello.adb"); + + Now invoke ‘Ada | Show main’; this displays ‘Ada mode main: hello’. + + Now (in buffer ‘hello.adb’), invoke ‘Ada | Build’. You are prompted +to save the file (if you haven’t already). Then the compilation buffer +is displayed again, containing: + + cd c:/Examples/Example_1/ + gnatmake -o hello hello -g -cargs -gnatq -gnatQ -bargs -largs + gcc -c -g -gnatq -gnatQ hello.adb + gnatbind -x hello.ali + gnatlink hello.ali -o hello.exe -g + + The compilation has succeeded without errors; ‘hello.exe’ now exists +in the same directory as ‘hello.adb’. + + Now invoke ‘Ada | Run’. A ‘*run*’ buffer is displayed, containing + + Hello from hello.adb + + Process run finished + + That completes the first part of this example. + + Now we will compile a multi-file project. Open the file +‘hello_2.adb’, and invoke ‘Ada | Set main and Build’. This finds an +error in ‘hello_pkg.adb’: + + cd c:/Examples/Example_1/ + gnatmake -o hello_2 hello_2 -g -cargs -gnatq -gnatQ -bargs -largs + gcc -c -g -gnatq -gnatQ hello_pkg.adb + hello_pkg.adb:2:08: keyword "body" expected here [see file name] + gnatmake: "hello_pkg.adb" compilation error + + This demonstrates that gnatmake finds the files needed by the main +program. However, it cannot find files in a different directory, unless +you use an Emacs Ada mode project file to specify the other directories; +*Note Set source search path::, or a GNAT project file; *note Use GNAT +project file::. + + Invoke ‘Ada | Show main’; this displays ‘Ada mode main: hello_2’. + + Move to the error with ‘C-x `’, and fix the error by adding ‘body’: + + package body Hello_Pkg is + + Now, while still in ‘hello_pkg.adb’, invoke ‘Ada | Build’. gnatmake +successfully builds ‘hello_2’. This demonstrates that Emacs has +remembered the main file, in the project variable ‘main’, and used it +for the Build command. + + Finally, again while in ‘hello_pkg.adb’, invoke ‘Ada | Run’. The +‘*run*’ buffer displays ‘Hello from hello_pkg.adb’. + + One final point. If you switch back to buffer ‘hello.adb’, and +invoke ‘Ada | Run’, ‘hello_2.exe’ will be run. That is because ‘main’ +is still set to ‘hello_2’, as you can see when you invoke ‘Ada | Project +| Edit’. + + There are three ways to change ‘main’: + + 1. Invoke ‘Ada | Set main and Build’, which sets ‘main’ to the current + file. + + 2. Invoke ‘Ada | Project | Edit’, edit ‘main’, and click ‘[save]’ + + 3. Invoke ‘Ada | Project | Load’, and load a project file that + specifies ‘main’ + + +File: ada-mode.info, Node: Set compiler options, Next: Set source search path, Prev: No project files, Up: Compiling Examples + +6.2 Set compiler options +======================== + +This example illustrates using an Emacs Ada mode project file to set a +compiler option. + + If you have files from ‘Example_1’ open in Emacs, you should close +them so you don’t get confused. Use menu ‘File | Close (current +buffer)’. + + In directory ‘Example_2’, create these files: + + ‘hello.adb’: + + with Ada.Text_IO; + procedure Hello + is begin + Put_Line("Hello from hello.adb"); + end Hello; + + This is the same as ‘hello.adb’ from ‘Example_1’. It has two errors; +missing “use Ada.Text_IO;”, and no space between ‘Put_Line’ and its +argument list. + + ‘hello.adp’: + + comp_opt=-gnatyt + + This tells the GNAT compiler to check for token spacing; in +particular, there must be a space preceding a parenthesis. + + In buffer ‘hello.adb’, invoke ‘Ada | Project | Load...’, and select +‘Example_2/hello.adp’. + + Then, again in buffer ‘hello.adb’, invoke ‘Ada | Set main and Build’. +You should get a ‘*compilation*’ buffer containing something like (the +directory paths will be different): + + cd c:/Examples/Example_2/ + gnatmake -o hello hello -g -cargs -gnatyt -bargs -largs + gcc -c -g -gnatyt hello.adb + hello.adb:4:04: "Put_Line" is not visible + hello.adb:4:04: non-visible declaration at a-textio.ads:264 + hello.adb:4:04: non-visible declaration at a-textio.ads:260 + hello.adb:4:12: (style) space required + gnatmake: "hello.adb" compilation error + + Compare this to the compiler output in *note No project files::; the +gnatmake option ‘-cargs -gnatq -gnatQ’ has been replaced by ‘-cargs +-gnaty’, and an additional error is reported in ‘hello.adb’ on line 4. +This shows that ‘hello.adp’ is being used to set the compiler options. + + Fixing the error, linking and running the code proceed as in *note No +project files::. + + +File: ada-mode.info, Node: Set source search path, Next: Use GNAT project file, Prev: Set compiler options, Up: Compiling Examples + +6.3 Set source search path +========================== + +In this example, we show how to deal with files in more than one +directory. We start with the same code as in *note No project files::; +create those files (with the errors present) + + Create the directory ‘Example_3’, containing: + + ‘hello_pkg.ads’: + + package Hello_Pkg is + procedure Say_Hello; + end Hello_Pkg; + + ‘hello_pkg.adb’: + + with Ada.Text_IO; + package Hello_Pkg is + procedure Say_Hello + is begin + Ada.Text_IO.Put_Line ("Hello from hello_pkg.adb"); + end Say_Hello; + end Hello_Pkg; + + These are the same files from example 1; ‘hello_pkg.adb’ has an error +on line 2. + + In addition, create a directory ‘Example_3/Other’, containing these +files: + + ‘Other/hello_3.adb’: + + with Hello_Pkg; + with Ada.Text_IO; use Ada.Text_IO; + procedure Hello_3 + is begin + Hello_Pkg.Say_Hello; + Put_Line ("From hello_3"); + end Hello_3; + + There are no errors in this file. + + ‘Other/other.adp’: + + src_dir=.. + comp_opt=-I.. + + Note that there must be no trailing spaces. + + In buffer ‘hello_3.adb’, invoke ‘Ada | Project | Load...’, and select +‘Example_3/Other/other.adp’. + + Then, again in ‘hello_3.adb’, invoke ‘Ada | Set main and Build’. You +should get a ‘*compilation*’ buffer containing something like (the +directory paths will be different): + + cd c:/Examples/Example_3/Other/ + gnatmake -o hello_3 hello_3 -g -cargs -I.. -bargs -largs + gcc -c -g -I.. hello_3.adb + gcc -c -I./ -g -I.. -I- C:\Examples\Example_3\hello_pkg.adb + hello_pkg.adb:2:08: keyword "body" expected here [see file name] + gnatmake: "C:\Examples\Example_3\hello_pkg.adb" compilation error + + Compare the ‘-cargs’ option to the compiler output in *note Set +compiler options::; this shows that ‘other.adp’ is being used to set the +compiler options. + + Move to the error with ‘C-x `’. Ada mode searches the list of +directories given by ‘src_dir’ for the file mentioned in the compiler +error message. + + Fixing the error, linking and running the code proceed as in *note No +project files::. + + +File: ada-mode.info, Node: Use GNAT project file, Next: Use multiple GNAT project files, Prev: Set source search path, Up: Compiling Examples + +6.4 Use GNAT project file +========================= + +In this example, we show how to use a GNAT project file, with no Ada +mode project file. + + Create the directory ‘Example_4’, containing: + + ‘hello_pkg.ads’: + + package Hello_Pkg is + procedure Say_Hello; + end Hello_Pkg; + + ‘hello_pkg.adb’: + + with Ada.Text_IO; + package Hello_Pkg is + procedure Say_Hello + is begin + Ada.Text_IO.Put_Line ("Hello from hello_pkg.adb"); + end Say_Hello; + end Hello_Pkg; + + These are the same files from example 1; ‘hello_pkg.adb’ has an error +on line 2. + + In addition, create a directory ‘Example_4/Gnat_Project’, containing +these files: + + ‘Gnat_Project/hello_4.adb’: + + with Hello_Pkg; + with Ada.Text_IO; use Ada.Text_IO; + procedure Hello_4 + is begin + Hello_Pkg.Say_Hello; + Put_Line ("From hello_4"); + end Hello_4; + + There are no errors in this file. + + ‘Gnat_Project/hello_4.gpr’: + + Project Hello_4 is + for Source_Dirs use (".", ".."); + end Hello_4; + + In buffer ‘hello_4.adb’, invoke ‘Ada | Project | Load...’, and select +‘Example_4/Gnat_Project/hello_4.gpr’. + + Then, again in ‘hello_4.adb’, invoke ‘Ada | Set main and Build’. You +should get a ‘*compilation*’ buffer containing something like (the +directory paths will be different): + + cd c:/Examples/Example_4/Gnat_Project/ + gnatmake -o hello_4 hello_4 -Phello_4.gpr -cargs -gnatq -gnatQ -bargs -largs + gcc -c -g -gnatyt -gnatq -gnatQ -I- -gnatA c:\Examples\Example_4\Gnat_Project\hello_4.adb + gcc -c -g -gnatyt -gnatq -gnatQ -I- -gnatA c:\Examples\Example_4\hello_pkg.adb + hello_pkg.adb:2:08: keyword "body" expected here [see file name] + gnatmake: "c:\examples\example_4\hello_pkg.adb" compilation error + + Compare the ‘gcc’ options to the compiler output in *note Set +compiler options::; this shows that ‘hello_4.gpr’ is being used to set +the compiler options. + + Fixing the error, linking and running the code proceed as in *note No +project files::. + + +File: ada-mode.info, Node: Use multiple GNAT project files, Prev: Use GNAT project file, Up: Compiling Examples + +6.5 Use multiple GNAT project files +=================================== + +In this example, we show how to use multiple GNAT project files, +specifying the GNAT project search path in an Ada mode project file. + + Create the directory ‘Example_4’ as specified in *note Use GNAT +project file::. + + Create the directory ‘Example_5’, containing: + + ‘hello_5.adb’: + + with Hello_Pkg; + with Ada.Text_IO; use Ada.Text_IO; + procedure Hello_5 + is begin + Hello_Pkg.Say_Hello; + Put_Line ("From hello_5"); + end Hello_5; + + There are no errors in this file. + + ‘hello_5.adp’: + + ada_project_path=../Example_4/Gnat_Project + gpr_file=hello_5.gpr + + ‘hello_5.gpr’: + + with "hello_4"; + Project Hello_5 is + for Source_Dirs use ("."); + package Compiler is + for Default_Switches ("Ada") use ("-g", "-gnatyt"); + end Compiler; + end Hello_5; + + In buffer ‘hello_5.adb’, invoke ‘Ada | Project | Load...’, and select +‘Example_5/hello_5.adp’. + + Then, again in ‘hello_5.adb’, invoke ‘Ada | Set main and Build’. You +should get a ‘*compilation*’ buffer containing something like (the +directory paths will be different): + + cd c:/Examples/Example_5/ + gnatmake -o hello_5 hello_5 -Phello_5.gpr -g -cargs -gnatq -gnatQ -bargs -largs + gcc -c -g -gnatyt -g -gnatq -gnatQ -I- -gnatA c:\Examples\Example_5\hello_5.adb + gcc -c -g -gnatyt -g -gnatq -gnatQ -I- -gnatA c:\Examples\Example_4\hello_pkg.adb + hello_pkg.adb:2:08: keyword "body" expected here [see file name] + gnatmake: "c:\examples\example_4\hello_pkg.adb" compilation error + + Now type ‘C-x `’. ‘Example_4/hello_pkg.adb’ is shown, demonstrating +that ‘hello_5.gpr’ and ‘hello_4.gpr’ are being used to set the +compilation search path. + + +File: ada-mode.info, Node: Moving Through Ada Code, Next: Identifier completion, Prev: Compiling Examples, Up: Top + +7 Moving Through Ada Code +************************* + +There are several easy to use commands to navigate through Ada code. +All these functions are available through the Ada menu, and you can also +use the following key bindings or the command names. Some of these menu +entries are available only if the GNAT compiler is used, since the +implementation relies on the GNAT cross-referencing information. + +‘M-C-e’ + Move to the next function/procedure/task, which ever comes next + (‘ada-next-procedure’). +‘M-C-a’ + Move to previous function/procedure/task + (‘ada-previous-procedure’). +‘M-x ada-next-package’ + Move to next package. +‘M-x ada-previous-package’ + Move to previous package. +‘C-c C-a’ + Move to matching start of ‘end’ (‘ada-move-to-start’). If point is + at the end of a subprogram, this command jumps to the corresponding + ‘begin’ if the user option ‘ada-move-to-declaration’ is ‘nil’ + (default), otherwise it jumps to the subprogram declaration. +‘C-c C-e’ + Move point to end of current block (‘ada-move-to-end’). +‘C-c o’ + Switch between corresponding spec and body file + (‘ff-find-other-file’). If point is in a subprogram, position + point on the corresponding declaration or body in the other file. +‘C-c c-d’ + Move from any reference to its declaration, for from a declaration + to its body (for procedures, tasks, private and incomplete types). +‘C-c C-r’ + Runs the ‘gnatfind’ command to search for all references to the + identifier surrounding point (‘ada-find-references’). Use ‘C-x `’ + (‘next-error’) to visit each reference (as for compilation errors). + + If the ‘ada-xref-create-ali’ variable is non-‘nil’, Emacs will try to +run GNAT for you whenever cross-reference information is needed, and is +older than the current source file. + + +File: ada-mode.info, Node: Identifier completion, Next: Automatic Smart Indentation, Prev: Moving Through Ada Code, Up: Top + +8 Identifier completion +*********************** + +Emacs and Ada mode provide two general ways for the completion of +identifiers. This is an easy way to type faster: you just have to type +the first few letters of an identifiers, and then loop through all the +possible completions. + + The first method is general for Emacs. It works by parsing all open +files for possible completions. + + For instance, if the words ‘my_identifier’, ‘my_subprogram’ are the +only words starting with ‘my’ in any of the opened files, then you will +have this scenario: + + You type: myM-/ + Emacs inserts: ‘my_identifier’ + If you press M-/ once again, Emacs replaces ‘my_identifier’ with + ‘my_subprogram’. + Pressing M-/ once more will bring you back to ‘my_identifier’. + + This is a very fast way to do completion, and the casing of words +will also be respected. + + The second method (‘C-’) is specific to Ada mode and the GNAT +compiler. Emacs will search the cross-information for possible +completions. + + The main advantage is that this completion is more accurate: only +existing identifier will be suggested. + + On the other hand, this completion is a little bit slower and +requires that you have compiled your file at least once since you +created that identifier. + +‘C-’ + Complete current identifier using cross-reference information. +‘M-/’ + Complete identifier using buffer information (not Ada-specific). + + +File: ada-mode.info, Node: Automatic Smart Indentation, Next: Formatting Parameter Lists, Prev: Identifier completion, Up: Top + +9 Automatic Smart Indentation +***************************** + +Ada mode comes with a full set of rules for automatic indentation. You +can also configure the indentation, via the following variables: + +‘ada-broken-indent’ (default value: 2) + Number of columns to indent the continuation of a broken line. + +‘ada-indent’ (default value: 3) + Number of columns for default indentation. + +‘ada-indent-record-rel-type’ (default value: 3) + Indentation for ‘record’ relative to ‘type’ or ‘use’. + +‘ada-indent-return’ (default value: 0) + Indentation for ‘return’ relative to ‘function’ (if + ‘ada-indent-return’ is greater than 0), or the open parenthesis (if + ‘ada-indent-return’ is negative or 0). Note that in the second + case, when there is no open parenthesis, the indentation is done + relative to ‘function’ with the value of ‘ada-broken-indent’. + +‘ada-label-indent’ (default value: -4) + Number of columns to indent a label. + +‘ada-stmt-end-indent’ (default value: 0) + Number of columns to indent a statement ‘end’ keyword on a separate + line. + +‘ada-when-indent’ (default value: 3) + Indentation for ‘when’ relative to ‘exception’ or ‘case’. + +‘ada-indent-is-separate’ (default value: t) + Non-‘nil’ means indent ‘is separate’ or ‘is abstract’ if on a + single line. + +‘ada-indent-to-open-paren’ (default value: t) + Non-‘nil’ means indent according to the innermost open parenthesis. + +‘ada-indent-after-return’ (default value: t) + Non-‘nil’ means that the current line will also be re-indented + before inserting a newline, when you press . + + Most of the time, the indentation will be automatic, i.e., when you +press , the cursor will move to the correct column on the next +line. + + You can also indent single lines, or the current region, with . + + Another mode of indentation exists that helps you to set up your +indentation scheme. If you press ‘C-c ’, Ada mode will do the +following: + + • Reindent the current line, as would do. + • Temporarily move the cursor to a reference line, i.e., the line + that was used to calculate the current indentation. + • Display in the message window the name of the variable that + provided the offset for the indentation. + + The exact indentation of the current line is the same as the one for +the reference line, plus an offset given by the variable. + +‘’ + Indent the current line or the current region. +‘C-M-\’ + Indent lines in the current region. +‘C-c ’ + Indent the current line and display the name of the variable used + for indentation. + + +File: ada-mode.info, Node: Formatting Parameter Lists, Next: Automatic Casing, Prev: Automatic Smart Indentation, Up: Top + +10 Formatting Parameter Lists +***************************** + +‘C-c C-f’ + Format the parameter list (‘ada-format-paramlist’). + + This aligns the declarations on the colon (‘:’) separating argument +names and argument types, and aligns the ‘in’, ‘out’ and ‘in out’ +keywords. + + +File: ada-mode.info, Node: Automatic Casing, Next: Statement Templates, Prev: Formatting Parameter Lists, Up: Top + +11 Automatic Casing +******************* + +Casing of identifiers, attributes and keywords is automatically +performed while typing when the variable ‘ada-auto-case’ is set. Every +time you press a word separator, the previous word is automatically +cased. + + You can customize the automatic casing differently for keywords, +attributes and identifiers. The relevant variables are the following: +‘ada-case-keyword’, ‘ada-case-attribute’ and ‘ada-case-identifier’. + + All these variables can have one of the following values: + +‘downcase-word’ + The word will be lowercase. For instance ‘My_vARIable’ is + converted to ‘my_variable’. + +‘upcase-word’ + The word will be uppercase. For instance ‘My_vARIable’ is + converted to ‘MY_VARIABLE’. + +‘ada-capitalize-word’ + The first letter and each letter following an underscore (‘_’) are + uppercase, others are lowercase. For instance ‘My_vARIable’ is + converted to ‘My_Variable’. + +‘ada-loose-case-word’ + Characters after an underscore ‘_’ character are uppercase, others + are not modified. For instance ‘My_vARIable’ is converted to + ‘My_VARIable’. + + Ada mode allows you to define exceptions to these rules, in a file +specified by the variable ‘ada-case-exception-file’ (default +‘~/.emacs_case_exceptions’). Each line in this file specifies the +casing of one word or word fragment. Comments may be included, +separated from the word by a space. + + If the word starts with an asterisk (‘*’), it defines the casing as a +word fragment (or “substring”); part of a word between two underscores +or word boundary. + + For example: + + DOD Department of Defense + *IO + GNAT The GNAT compiler from Ada Core Technologies + + The word fragment ‘*IO’ applies to any word containing “_io”; +‘Text_IO’, ‘Hardware_IO’, etc. + + There are two ways to add new items to this file: you can simply edit +it as you would edit any text file. Or you can position point on the +word you want to add, and select menu ‘Ada | Edit | Create Case +Exception’, or press ‘C-c C-y’ (‘ada-create-case-exception’). The word +will automatically be added to the current list of exceptions and to the +file. + + To define a word fragment case exception, select the word fragment, +then select menu ‘Ada | Edit | Create Case Exception Substring’. + + It is sometimes useful to have multiple exception files around (for +instance, one could be the standard Ada acronyms, the second some +company specific exceptions, and the last one some project specific +exceptions). If you set up the variable ‘ada-case-exception-file’ as a +list of files, each of them will be parsed and used in your emacs +session. However, when you save a new exception through the menu, as +described above, the new exception will be added to the first file in +the list. + +‘C-c C-b’ + Adjust case in the whole buffer (‘ada-adjust-case-buffer’). +‘C-c C-y’ + Create a new entry in the exception dictionary, with the word under + the cursor (‘ada-create-case-exception’) +‘C-c C-t’ + Rereads the exception dictionary from the file + ‘ada-case-exception-file’ (‘ada-case-read-exceptions’). + + +File: ada-mode.info, Node: Statement Templates, Next: Comment Handling, Prev: Automatic Casing, Up: Top + +12 Statement Templates +********************** + +Templates are defined for most Ada statements, using the Emacs +“skeleton” package. They can be inserted in the buffer using the +following commands: + +‘C-c t b’ + exception Block (‘ada-exception-block’). +‘C-c t c’ + case (‘ada-case’). +‘C-c t d’ + declare Block (‘ada-declare-block’). +‘C-c t e’ + else (‘ada-else’). +‘C-c t f’ + for Loop (‘ada-for-loop’). +‘C-c t h’ + Header (‘ada-header’). +‘C-c t i’ + if (‘ada-if’). +‘C-c t k’ + package Body (‘ada-package-body’). +‘C-c t l’ + loop (‘ada-loop’). +‘C-c p’ + subprogram body (‘ada-subprogram-body’). +‘C-c t t’ + task Body (‘ada-task-body’). +‘C-c t w’ + while Loop (‘ada-while’). +‘C-c t u’ + use (‘ada-use’). +‘C-c t x’ + exit (‘ada-exit’). +‘C-c t C-a’ + array (‘ada-array’). +‘C-c t C-e’ + elsif (‘ada-elsif’). +‘C-c t C-f’ + function Spec (‘ada-function-spec’). +‘C-c t C-k’ + package Spec (‘ada-package-spec’). +‘C-c t C-p’ + procedure Spec (‘ada-package-spec’. +‘C-c t C-r’ + record (‘ada-record’). +‘C-c t C-s’ + subtype (‘ada-subtype’). +‘C-c t C-t’ + task Spec (‘ada-task-spec’). +‘C-c t C-u’ + with (‘ada-with’). +‘C-c t C-v’ + private (‘ada-private’). +‘C-c t C-w’ + when (‘ada-when’). +‘C-c t C-x’ + exception (‘ada-exception’). +‘C-c t C-y’ + type (‘ada-type’). + + +File: ada-mode.info, Node: Comment Handling, Next: GNU Free Documentation License, Prev: Statement Templates, Up: Top + +13 Comment Handling +******************* + +By default, comment lines get indented like Ada code. There are a few +additional functions to handle comments: + +‘M-;’ + Start a comment in default column. +‘M-j’ + Continue comment on next line. +‘C-c ;’ + Comment the selected region (add ‘--’ at the beginning of lines). +‘C-c :’ + Uncomment the selected region +‘M-q’ + autofill the current comment. + + +File: ada-mode.info, Node: GNU Free Documentation License, Next: Index, Prev: Comment Handling, Up: Top + +Appendix A GNU Free Documentation License +***************************************** + + Version 1.3, 3 November 2008 + + Copyright © 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. + + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + 0. PREAMBLE + + The purpose of this License is to make a manual, textbook, or other + functional and useful document “free” in the sense of freedom: to + assure everyone the effective freedom to copy and redistribute it, + with or without modifying it, either commercially or + noncommercially. Secondarily, this License preserves for the + author and publisher a way to get credit for their work, while not + being considered responsible for modifications made by others. + + This License is a kind of “copyleft”, which means that derivative + works of the document must themselves be free in the same sense. + It complements the GNU General Public License, which is a copyleft + license designed for free software. + + We have designed this License in order to use it for manuals for + free software, because free software needs free documentation: a + free program should come with manuals providing the same freedoms + that the software does. But this License is not limited to + software manuals; it can be used for any textual work, regardless + of subject matter or whether it is published as a printed book. We + recommend this License principally for works whose purpose is + instruction or reference. + + 1. APPLICABILITY AND DEFINITIONS + + This License applies to any manual or other work, in any medium, + that contains a notice placed by the copyright holder saying it can + be distributed under the terms of this License. Such a notice + grants a world-wide, royalty-free license, unlimited in duration, + to use that work under the conditions stated herein. The + “Document”, below, refers to any such manual or work. Any member + of the public is a licensee, and is addressed as “you”. You accept + the license if you copy, modify or distribute the work in a way + requiring permission under copyright law. + + A “Modified Version” of the Document means any work containing the + Document or a portion of it, either copied verbatim, or with + modifications and/or translated into another language. + + A “Secondary Section” is a named appendix or a front-matter section + of the Document that deals exclusively with the relationship of the + publishers or authors of the Document to the Document’s overall + subject (or to related matters) and contains nothing that could + fall directly within that overall subject. (Thus, if the Document + is in part a textbook of mathematics, a Secondary Section may not + explain any mathematics.) The relationship could be a matter of + historical connection with the subject or with related matters, or + of legal, commercial, philosophical, ethical or political position + regarding them. + + The “Invariant Sections” are certain Secondary Sections whose + titles are designated, as being those of Invariant Sections, in the + notice that says that the Document is released under this License. + If a section does not fit the above definition of Secondary then it + is not allowed to be designated as Invariant. The Document may + contain zero Invariant Sections. If the Document does not identify + any Invariant Sections then there are none. + + The “Cover Texts” are certain short passages of text that are + listed, as Front-Cover Texts or Back-Cover Texts, in the notice + that says that the Document is released under this License. A + Front-Cover Text may be at most 5 words, and a Back-Cover Text may + be at most 25 words. + + A “Transparent” copy of the Document means a machine-readable copy, + represented in a format whose specification is available to the + general public, that is suitable for revising the document + straightforwardly with generic text editors or (for images composed + of pixels) generic paint programs or (for drawings) some widely + available drawing editor, and that is suitable for input to text + formatters or for automatic translation to a variety of formats + suitable for input to text formatters. A copy made in an otherwise + Transparent file format whose markup, or absence of markup, has + been arranged to thwart or discourage subsequent modification by + readers is not Transparent. An image format is not Transparent if + used for any substantial amount of text. A copy that is not + “Transparent” is called “Opaque”. + + Examples of suitable formats for Transparent copies include plain + ASCII without markup, Texinfo input format, LaTeX input format, + SGML or XML using a publicly available DTD, and standard-conforming + simple HTML, PostScript or PDF designed for human modification. + Examples of transparent image formats include PNG, XCF and JPG. + Opaque formats include proprietary formats that can be read and + edited only by proprietary word processors, SGML or XML for which + the DTD and/or processing tools are not generally available, and + the machine-generated HTML, PostScript or PDF produced by some word + processors for output purposes only. + + The “Title Page” means, for a printed book, the title page itself, + plus such following pages as are needed to hold, legibly, the + material this License requires to appear in the title page. For + works in formats which do not have any title page as such, “Title + Page” means the text near the most prominent appearance of the + work’s title, preceding the beginning of the body of the text. + + The “publisher” means any person or entity that distributes copies + of the Document to the public. + + A section “Entitled XYZ” means a named subunit of the Document + whose title either is precisely XYZ or contains XYZ in parentheses + following text that translates XYZ in another language. (Here XYZ + stands for a specific section name mentioned below, such as + “Acknowledgements”, “Dedications”, “Endorsements”, or “History”.) + To “Preserve the Title” of such a section when you modify the + Document means that it remains a section “Entitled XYZ” according + to this definition. + + The Document may include Warranty Disclaimers next to the notice + which states that this License applies to the Document. These + Warranty Disclaimers are considered to be included by reference in + this License, but only as regards disclaiming warranties: any other + implication that these Warranty Disclaimers may have is void and + has no effect on the meaning of this License. + + 2. VERBATIM COPYING + + You may copy and distribute the Document in any medium, either + commercially or noncommercially, provided that this License, the + copyright notices, and the license notice saying this License + applies to the Document are reproduced in all copies, and that you + add no other conditions whatsoever to those of this License. You + may not use technical measures to obstruct or control the reading + or further copying of the copies you make or distribute. However, + you may accept compensation in exchange for copies. If you + distribute a large enough number of copies you must also follow the + conditions in section 3. + + You may also lend copies, under the same conditions stated above, + and you may publicly display copies. + + 3. COPYING IN QUANTITY + + If you publish printed copies (or copies in media that commonly + have printed covers) of the Document, numbering more than 100, and + the Document’s license notice requires Cover Texts, you must + enclose the copies in covers that carry, clearly and legibly, all + these Cover Texts: Front-Cover Texts on the front cover, and + Back-Cover Texts on the back cover. Both covers must also clearly + and legibly identify you as the publisher of these copies. The + front cover must present the full title with all words of the title + equally prominent and visible. You may add other material on the + covers in addition. Copying with changes limited to the covers, as + long as they preserve the title of the Document and satisfy these + conditions, can be treated as verbatim copying in other respects. + + If the required texts for either cover are too voluminous to fit + legibly, you should put the first ones listed (as many as fit + reasonably) on the actual cover, and continue the rest onto + adjacent pages. + + If you publish or distribute Opaque copies of the Document + numbering more than 100, you must either include a machine-readable + Transparent copy along with each Opaque copy, or state in or with + each Opaque copy a computer-network location from which the general + network-using public has access to download using public-standard + network protocols a complete Transparent copy of the Document, free + of added material. If you use the latter option, you must take + reasonably prudent steps, when you begin distribution of Opaque + copies in quantity, to ensure that this Transparent copy will + remain thus accessible at the stated location until at least one + year after the last time you distribute an Opaque copy (directly or + through your agents or retailers) of that edition to the public. + + It is requested, but not required, that you contact the authors of + the Document well before redistributing any large number of copies, + to give them a chance to provide you with an updated version of the + Document. + + 4. MODIFICATIONS + + You may copy and distribute a Modified Version of the Document + under the conditions of sections 2 and 3 above, provided that you + release the Modified Version under precisely this License, with the + Modified Version filling the role of the Document, thus licensing + distribution and modification of the Modified Version to whoever + possesses a copy of it. In addition, you must do these things in + the Modified Version: + + A. Use in the Title Page (and on the covers, if any) a title + distinct from that of the Document, and from those of previous + versions (which should, if there were any, be listed in the + History section of the Document). You may use the same title + as a previous version if the original publisher of that + version gives permission. + + B. List on the Title Page, as authors, one or more persons or + entities responsible for authorship of the modifications in + the Modified Version, together with at least five of the + principal authors of the Document (all of its principal + authors, if it has fewer than five), unless they release you + from this requirement. + + C. State on the Title page the name of the publisher of the + Modified Version, as the publisher. + + D. Preserve all the copyright notices of the Document. + + E. Add an appropriate copyright notice for your modifications + adjacent to the other copyright notices. + + F. Include, immediately after the copyright notices, a license + notice giving the public permission to use the Modified + Version under the terms of this License, in the form shown in + the Addendum below. + + G. Preserve in that license notice the full lists of Invariant + Sections and required Cover Texts given in the Document’s + license notice. + + H. Include an unaltered copy of this License. + + I. Preserve the section Entitled “History”, Preserve its Title, + and add to it an item stating at least the title, year, new + authors, and publisher of the Modified Version as given on the + Title Page. If there is no section Entitled “History” in the + Document, create one stating the title, year, authors, and + publisher of the Document as given on its Title Page, then add + an item describing the Modified Version as stated in the + previous sentence. + + J. Preserve the network location, if any, given in the Document + for public access to a Transparent copy of the Document, and + likewise the network locations given in the Document for + previous versions it was based on. These may be placed in the + “History” section. You may omit a network location for a work + that was published at least four years before the Document + itself, or if the original publisher of the version it refers + to gives permission. + + K. For any section Entitled “Acknowledgements” or “Dedications”, + Preserve the Title of the section, and preserve in the section + all the substance and tone of each of the contributor + acknowledgements and/or dedications given therein. + + L. Preserve all the Invariant Sections of the Document, unaltered + in their text and in their titles. Section numbers or the + equivalent are not considered part of the section titles. + + M. Delete any section Entitled “Endorsements”. Such a section + may not be included in the Modified Version. + + N. Do not retitle any existing section to be Entitled + “Endorsements” or to conflict in title with any Invariant + Section. + + O. Preserve any Warranty Disclaimers. + + If the Modified Version includes new front-matter sections or + appendices that qualify as Secondary Sections and contain no + material copied from the Document, you may at your option designate + some or all of these sections as invariant. To do this, add their + titles to the list of Invariant Sections in the Modified Version’s + license notice. These titles must be distinct from any other + section titles. + + You may add a section Entitled “Endorsements”, provided it contains + nothing but endorsements of your Modified Version by various + parties—for example, statements of peer review or that the text has + been approved by an organization as the authoritative definition of + a standard. + + You may add a passage of up to five words as a Front-Cover Text, + and a passage of up to 25 words as a Back-Cover Text, to the end of + the list of Cover Texts in the Modified Version. Only one passage + of Front-Cover Text and one of Back-Cover Text may be added by (or + through arrangements made by) any one entity. If the Document + already includes a cover text for the same cover, previously added + by you or by arrangement made by the same entity you are acting on + behalf of, you may not add another; but you may replace the old + one, on explicit permission from the previous publisher that added + the old one. + + The author(s) and publisher(s) of the Document do not by this + License give permission to use their names for publicity for or to + assert or imply endorsement of any Modified Version. + + 5. COMBINING DOCUMENTS + + You may combine the Document with other documents released under + this License, under the terms defined in section 4 above for + modified versions, provided that you include in the combination all + of the Invariant Sections of all of the original documents, + unmodified, and list them all as Invariant Sections of your + combined work in its license notice, and that you preserve all + their Warranty Disclaimers. + + The combined work need only contain one copy of this License, and + multiple identical Invariant Sections may be replaced with a single + copy. If there are multiple Invariant Sections with the same name + but different contents, make the title of each such section unique + by adding at the end of it, in parentheses, the name of the + original author or publisher of that section if known, or else a + unique number. Make the same adjustment to the section titles in + the list of Invariant Sections in the license notice of the + combined work. + + In the combination, you must combine any sections Entitled + “History” in the various original documents, forming one section + Entitled “History”; likewise combine any sections Entitled + “Acknowledgements”, and any sections Entitled “Dedications”. You + must delete all sections Entitled “Endorsements.” + + 6. COLLECTIONS OF DOCUMENTS + + You may make a collection consisting of the Document and other + documents released under this License, and replace the individual + copies of this License in the various documents with a single copy + that is included in the collection, provided that you follow the + rules of this License for verbatim copying of each of the documents + in all other respects. + + You may extract a single document from such a collection, and + distribute it individually under this License, provided you insert + a copy of this License into the extracted document, and follow this + License in all other respects regarding verbatim copying of that + document. + + 7. AGGREGATION WITH INDEPENDENT WORKS + + A compilation of the Document or its derivatives with other + separate and independent documents or works, in or on a volume of a + storage or distribution medium, is called an “aggregate” if the + copyright resulting from the compilation is not used to limit the + legal rights of the compilation’s users beyond what the individual + works permit. When the Document is included in an aggregate, this + License does not apply to the other works in the aggregate which + are not themselves derivative works of the Document. + + If the Cover Text requirement of section 3 is applicable to these + copies of the Document, then if the Document is less than one half + of the entire aggregate, the Document’s Cover Texts may be placed + on covers that bracket the Document within the aggregate, or the + electronic equivalent of covers if the Document is in electronic + form. Otherwise they must appear on printed covers that bracket + the whole aggregate. + + 8. TRANSLATION + + Translation is considered a kind of modification, so you may + distribute translations of the Document under the terms of section + 4. Replacing Invariant Sections with translations requires special + permission from their copyright holders, but you may include + translations of some or all Invariant Sections in addition to the + original versions of these Invariant Sections. You may include a + translation of this License, and all the license notices in the + Document, and any Warranty Disclaimers, provided that you also + include the original English version of this License and the + original versions of those notices and disclaimers. In case of a + disagreement between the translation and the original version of + this License or a notice or disclaimer, the original version will + prevail. + + If a section in the Document is Entitled “Acknowledgements”, + “Dedications”, or “History”, the requirement (section 4) to + Preserve its Title (section 1) will typically require changing the + actual title. + + 9. TERMINATION + + You may not copy, modify, sublicense, or distribute the Document + except as expressly provided under this License. Any attempt + otherwise to copy, modify, sublicense, or distribute it is void, + and will automatically terminate your rights under this License. + + However, if you cease all violation of this License, then your + license from a particular copyright holder is reinstated (a) + provisionally, unless and until the copyright holder explicitly and + finally terminates your license, and (b) permanently, if the + copyright holder fails to notify you of the violation by some + reasonable means prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is + reinstated permanently if the copyright holder notifies you of the + violation by some reasonable means, this is the first time you have + received notice of violation of this License (for any work) from + that copyright holder, and you cure the violation prior to 30 days + after your receipt of the notice. + + Termination of your rights under this section does not terminate + the licenses of parties who have received copies or rights from you + under this License. If your rights have been terminated and not + permanently reinstated, receipt of a copy of some or all of the + same material does not give you any rights to use it. + + 10. FUTURE REVISIONS OF THIS LICENSE + + The Free Software Foundation may publish new, revised versions of + the GNU Free Documentation License from time to time. Such new + versions will be similar in spirit to the present version, but may + differ in detail to address new problems or concerns. See + . + + Each version of the License is given a distinguishing version + number. If the Document specifies that a particular numbered + version of this License “or any later version” applies to it, you + have the option of following the terms and conditions either of + that specified version or of any later version that has been + published (not as a draft) by the Free Software Foundation. If the + Document does not specify a version number of this License, you may + choose any version ever published (not as a draft) by the Free + Software Foundation. If the Document specifies that a proxy can + decide which future versions of this License can be used, that + proxy’s public statement of acceptance of a version permanently + authorizes you to choose that version for the Document. + + 11. RELICENSING + + “Massive Multiauthor Collaboration Site” (or “MMC Site”) means any + World Wide Web server that publishes copyrightable works and also + provides prominent facilities for anybody to edit those works. A + public wiki that anybody can edit is an example of such a server. + A “Massive Multiauthor Collaboration” (or “MMC”) contained in the + site means any set of copyrightable works thus published on the MMC + site. + + “CC-BY-SA” means the Creative Commons Attribution-Share Alike 3.0 + license published by Creative Commons Corporation, a not-for-profit + corporation with a principal place of business in San Francisco, + California, as well as future copyleft versions of that license + published by that same organization. + + “Incorporate” means to publish or republish a Document, in whole or + in part, as part of another Document. + + An MMC is “eligible for relicensing” if it is licensed under this + License, and if all works that were first published under this + License somewhere other than this MMC, and subsequently + incorporated in whole or in part into the MMC, (1) had no cover + texts or invariant sections, and (2) were thus incorporated prior + to November 1, 2008. + + The operator of an MMC Site may republish an MMC contained in the + site under CC-BY-SA on the same site at any time before August 1, + 2009, provided the MMC is eligible for relicensing. + +ADDENDUM: How to use this License for your documents +==================================================== + +To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and license +notices just after the title page: + + Copyright (C) YEAR YOUR NAME. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.3 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover + Texts. A copy of the license is included in the section entitled ``GNU + Free Documentation License''. + + If you have Invariant Sections, Front-Cover Texts and Back-Cover +Texts, replace the “with...Texts.” line with this: + + with the Invariant Sections being LIST THEIR TITLES, with + the Front-Cover Texts being LIST, and with the Back-Cover Texts + being LIST. + + If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. + + If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of free +software license, such as the GNU General Public License, to permit +their use in free software. + + +File: ada-mode.info, Node: Index, Prev: GNU Free Documentation License, Up: Top + +Index +***** + +[index] +* Menu: + +* ada-adjust-case-buffer: Automatic Casing. (line 74) +* ada-array: Statement Templates. (line 39) +* ada-case: Statement Templates. (line 13) +* ada-case-read-exceptions: Automatic Casing. (line 79) +* ada-complete-identifier: Identifier completion. + (line 39) +* ada-create-case-exception: Automatic Casing. (line 54) +* ada-declare-block: Statement Templates. (line 15) +* ada-else: Statement Templates. (line 17) +* ada-elsif: Statement Templates. (line 41) +* ada-exception: Statement Templates. (line 61) +* ada-exception-block: Statement Templates. (line 11) +* ada-exit: Statement Templates. (line 37) +* ada-find-references: Moving Through Ada Code. + (line 37) +* ada-for-loop: Statement Templates. (line 19) +* ada-format-paramlist: Formatting Parameter Lists. + (line 7) +* ada-function-spec: Statement Templates. (line 43) +* ada-goto-declaration: Moving Through Ada Code. + (line 34) +* ada-header: Statement Templates. (line 21) +* ada-if: Statement Templates. (line 23) +* ada-loop: Statement Templates. (line 27) +* ada-move-to-end: Moving Through Ada Code. + (line 28) +* ada-move-to-start: Moving Through Ada Code. + (line 23) +* ada-next-package: Moving Through Ada Code. + (line 19) +* ada-next-procedure: Moving Through Ada Code. + (line 13) +* ada-package-body: Statement Templates. (line 25) +* ada-package-spec: Statement Templates. (line 45) +* ada-previous-package: Moving Through Ada Code. + (line 21) +* ada-previous-procedure: Moving Through Ada Code. + (line 16) +* ada-private: Statement Templates. (line 57) +* ada-procedure-spec: Statement Templates. (line 47) +* ada-record: Statement Templates. (line 49) +* ada-subprogram-body: Statement Templates. (line 29) +* ada-subtype: Statement Templates. (line 51) +* ada-task-body: Statement Templates. (line 31) +* ada-task-spec: Statement Templates. (line 53) +* ada-type: Statement Templates. (line 63) +* ada-use: Statement Templates. (line 35) +* ada-when: Statement Templates. (line 59) +* ada-while: Statement Templates. (line 33) +* ada-with: Statement Templates. (line 55) + + + +Tag Table: +Node: Top862 +Node: Overview2536 +Node: Installation3858 +Node: Customization5019 +Node: Non-standard file names5943 +Node: Other compiler7474 +Node: Other customization7978 +Node: Compiling Executing8652 +Node: Compile commands9328 +Node: Compiler errors12177 +Node: Project files13082 +Node: Project File Overview13795 +Node: GUI Editor16150 +Node: Project file variables16642 +Node: Compiling Examples23982 +Node: No project files24780 +Node: Set compiler options29651 +Node: Set source search path31696 +Node: Use GNAT project file34044 +Node: Use multiple GNAT project files36288 +Node: Moving Through Ada Code38239 +Node: Identifier completion40280 +Node: Automatic Smart Indentation41884 +Node: Formatting Parameter Lists44754 +Node: Automatic Casing45184 +Node: Statement Templates48588 +Node: Comment Handling50251 +Node: GNU Free Documentation License50806 +Node: Index76164 + +End Tag Table + + +Local Variables: +coding: utf-8 +End: diff --git a/ada-mode/doc/ada-mode.pdf b/ada-mode/doc/ada-mode.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c3f38399e9385e8e8ee5dcbb289b93eb495e2604 GIT binary patch literal 303898 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

Gg=9LJPtAz3j2 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 literal 0 HcmV?d00001 diff --git a/ada-mode/doc/ada-mode.texi b/ada-mode/doc/ada-mode.texi new file mode 100644 index 0000000..1ac90cd --- /dev/null +++ b/ada-mode/doc/ada-mode.texi @@ -0,0 +1,1526 @@ +\input texinfo @c -*-texinfo-*- +@setfilename ../../info/ada-mode.info +@settitle Ada Mode +@include docstyle.texi + +@copying +Copyright @copyright{} 1999--2019 Free Software Foundation, Inc. + +@quotation +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.3 or +any later version published by the Free Software Foundation; with no +Invariant Sections, with the Front-Cover Texts being ``A GNU Manual'', +and with the Back-Cover Texts as in (a) below. A copy of the license +is included in the section entitled ``GNU Free Documentation License''. + +(a) The FSF's Back-Cover Text is: ``You have the freedom to copy and +modify this GNU manual.'' +@end quotation +@end copying + +@dircategory Emacs editing modes +@direntry +* Ada mode: (ada-mode). Emacs mode for editing and compiling Ada code. +@end direntry + +@titlepage +@sp 10 +@title Ada Mode +@sp 2 +@subtitle An Emacs major mode for programming in Ada +@subtitle Ada Mode Version 4.00 +@sp 2 +@page +@vskip 0pt plus 1filll +@insertcopying +@end titlepage + +@contents + +@node Top +@top Ada Mode + +@ifnottex +@insertcopying +@end ifnottex + +@menu +* Overview:: +* Installation:: Installing Ada mode on your system +* Customization:: Setting up Ada mode to your taste +* Compiling Executing:: Working with your application within Emacs +* Project files:: Describing the organization of your project +* Compiling Examples:: A small tutorial +* Moving Through Ada Code:: Moving easily through Ada sources +* Identifier completion:: Finishing words automatically +* Automatic Smart Indentation:: Indenting your code automatically as you type +* Formatting Parameter Lists:: Formatting subprograms' parameter lists + automatically +* Automatic Casing:: Adjusting the case of words automatically +* Statement Templates:: Inserting code templates +* Comment Handling:: Reformatting comments easily +* GNU Free Documentation License:: The license for this documentation. +* Index:: +@end menu + + +@node Overview +@chapter Overview + +The Emacs mode for programming in Ada helps the user in understanding +existing code and facilitates writing new code. + +When the GNU Ada compiler GNAT is used, the cross-reference +information output by the compiler is used to provide powerful code +navigation (jump to definition, find all uses, etc.). + +When you open a file with a file extension of @file{.ads} or +@file{.adb}, Emacs will automatically load and activate Ada mode. + +Ada mode works without any customization, if you are using the GNAT +compiler (@url{https://libre2.adacore.com/}) and the GNAT default +naming convention. + +You must customize a few things if you are using a different compiler +or file naming convention; @xref{Other compiler}, @xref{Non-standard +file names}. + +In addition, you may want to customize the indentation, +capitalization, and other things; @xref{Other customization}. + +Finally, for large Ada projects, you will want to set up an Emacs +Ada mode project file for each project; @xref{Project files}. Note +that these are different from the GNAT project files used by gnatmake +and other GNAT commands. + +See the Emacs info manual, section 'Running Debuggers Under Emacs', +for general information on debugging. + +@node Installation +@chapter Installation + +Ada mode is part of the standard Emacs distribution; if you use that, +no files need to be installed. + +Ada mode is also available as a separate distribution, from the Emacs +Ada mode website +@uref{http://stephe-leake.org/emacs/ada-mode/emacs-ada-mode.html}. The +separate distribution may be more recent. + +For installing the separate distribution, see the @file{README} file +in the distribution. + +To see what version of Ada mode you have installed, do @kbd{M-x +ada-mode-version}. + +The following files are provided with the Ada mode distribution: + +@itemize @bullet + +@item +@file{ada-mode.el}: The main file for Ada mode, providing indentation, +formatting of parameter lists, moving through code, comment handling +and automatic casing. + +@item +@file{ada-prj.el}: GUI editing of Ada mode project files, using Emacs +widgets. + +@item +@file{ada-stmt.el}: Ada statement templates. + +@item +@file{ada-xref.el}: GNAT cross-references, completion of identifiers, +and compilation. Also provides project files (which are not +GNAT-specific). + +@end itemize + +@node Customization +@chapter Customizing Ada mode + +Here we assume you are familiar with setting variables in Emacs, +either thru 'customize' or in elisp (in your @file{.emacs} file). For +a basic introduction to customize, elisp, and Emacs in general, see +the tutorial in +@iftex +@cite{The GNU Emacs Manual}. +@end iftex +@ifhtml +@cite{The GNU Emacs Manual}. +@end ifhtml +@ifinfo +@ref{Top, , The GNU Emacs Manual, emacs, The GNU Emacs Manual}. +@end ifinfo + +These global Emacs settings are strongly recommended (put them in your +.emacs): + +@example +(global-font-lock-mode t) +(transient-mark-mode t) +@end example + +@samp{(global-font-lock-mode t)} turns on syntax +highlighting for all buffers (it is off by default because it may be +too slow for some machines). + +@samp{(transient-mark-mode t)} highlights selected text. + +See the Emacs help for each of these variables for more information. + +@menu +* Non-standard file names:: +* Other compiler:: +* Other customization:: +@end menu + +@node Non-standard file names +@section Non-standard file names + +By default, Ada mode is configured to use the GNAT file naming +convention, where file names are a simple modification of the Ada +names, and the extension for specs and bodies are +@samp{.ads} and @samp{.adb}, respectively. + +Ada mode uses the file extensions to allow moving from a package body +to the corresponding spec and back. + +Ada mode supports a list of alternative file extensions for specs and bodies. + +For instance, if your spec and bodies files are called +@file{@var{unit}_s.ada} and @file{@var{unit}_b.ada}, respectively, you +can add the following to your @file{.emacs} file: + +@example +(ada-add-extensions "_s.ada" "_b.ada") +@end example + +You can define additional extensions: + +@example +(ada-add-extensions ".ads" "_b.ada") +(ada-add-extensions ".ads" ".body") +@end example + +This means that whenever Ada mode looks for the body for a file +whose extension is @file{.ads}, it will take the first available file +that ends with either @file{.adb}, @file{_b.ada} or +@file{.body}. + +Similarly, if Ada mode is looking for a spec, it will look for +@file{.ads} or @file{_s.ada}. + +If the filename is not derived from the Ada name following the GNAT +convention, things are a little more complicated. You then need to +rewrite the function @code{ada-make-filename-from-adaname}. Doing that +is beyond the scope of this manual; see the current definitions in +@file{ada-mode.el} and @file{ada-xref.el} for examples. + +@node Other compiler +@section Other compiler + +By default, Ada mode is configured to use the GNU Ada compiler GNAT. + +To use a different Ada compiler, you must specify the command lines +used to run that compiler, either in lisp variables or in Emacs +Ada mode project files. See @ref{Project file variables} for the list +of project variables, and the corresponding lisp variables. + +@node Other customization +@section Other customization + +All user-settable Ada mode variables can be set via the menu +@samp{Ada | Customize}. Click on the @samp{Help} button there for help +on using customize. + +To modify a specific variable, you can directly call the function +@code{customize-variable}; just type @kbd{M-x customize-variable +@key{RET} @var{variable-name} @key{RET}}). + +Alternately, you can specify variable settings in the Emacs +configuration file, @file{.emacs}. This file is coded in Emacs lisp, +and the syntax to set a variable is the following: +@example +(setq variable-name value) +@end example + +@node Compiling Executing +@chapter Compiling Executing + +Ada projects can be compiled, linked, and executed using commands on +the Ada menu. All of these commands can be customized via a project +file (@pxref{Project files}), but the defaults are sufficient for using +the GNAT compiler for simple projects (single files, or several files +in a single directory). + +Even when no project file is used, the GUI project editor (menu +@samp{Ada | Project | Edit}) shows the settings of the various project +file variables referenced here. + +@menu +* Compile commands:: +* Compiler errors:: +@end menu + +@node Compile commands +@section Compile commands + +Here are the commands for building and using an Ada project, as +listed in the Ada menu. + +In multi-file projects, there must be one file that is the main +program. That is given by the @code{main} project file variable; +it defaults to the current file if not yet set, but is also set by the +``set main and build'' command. + +@table @code + +@item Check file +Compiles the current file in syntax check mode, by running +@code{check_cmd} defined in the current project file. This typically +runs faster than full compile mode, speeding up finding and fixing +compilation errors. + +This sets @code{main} only if it has not been set yet. + +@item Compile file +Compiles the current file, by running @code{comp_cmd} from the current +project file. + +This does not set @code{main}. + +@item Set main and Build +Sets @code{main} to the current file, then executes the Build +command. + +@item Show main +Display @code{main} in the message buffer. + +@item Build +Compiles all obsolete units of the current @code{main}, and links +@code{main}, by running @code{make_cmd} from the current project. + +This sets @code{main} only if it has not been set yet. + +@item Run +Executes the main program in a shell, displayed in a separate Emacs +buffer. This runs @code{run_cmd} from the current project. The +execution buffer allows for interactive input/output. + +To modify the run command, in particular to provide or change the +command line arguments, type @kbd{C-u} before invoking the command. + +This command is not available for a cross-compilation toolchain. + +@end table +It is important when using these commands to understand how +@code{main} is used and changed. + +Build runs 'gnatmake' on the main unit. During a typical edit/compile +session, this is the only command you need to invoke, which is why it +is bound to @kbd{C-c C-c}. It will compile all files needed by the +main unit, and display compilation errors in any of them. + +Note that Build can be invoked from any Ada buffer; typically you will +be fixing errors in files other than the main, but you don't have to +switch back to the main to invoke the compiler again. + +Novices and students typically work on single-file Ada projects. In +this case, @kbd{C-c C-m} will normally be the only command needed; it +will build the current file, rather than the last-built main. + +There are three ways to change @code{main}: + +@enumerate +@item +Invoke @samp{Ada | Set main and Build}, which sets @code{main} to +the current file. + +@item +Invoke @samp{Ada | Project | Edit}, edit @code{main} and +@code{main}, and click @samp{[save]} + +@item +Invoke @samp{Ada | Project | Load}, and load a project file that specifies @code{main} + +@end enumerate + +@node Compiler errors +@section Compiler errors + +The @code{Check file}, @code{Compile file}, and @code{Build} commands +all place compilation errors in a separate buffer named +@file{*compilation*}. + +Each line in this buffer will become active: you can simply click on +it with the middle button of the mouse, or move point to it and press +@key{RET}. Emacs will then display the relevant source file and put +point on the line and column where the error was found. + +You can also press the @kbd{C-x `} key (@code{next-error}), and Emacs +will jump to the first error. If you press that key again, it will +move you to the second error, and so on. + +Some error messages might also include references to other files. These +references are also clickable in the same way, or put point after the +line number and press @key{RET}. + +@node Project files +@chapter Project files + +An Emacs Ada mode project file specifies what directories hold sources +for your project, and allows you to customize the compilation commands +and other things on a per-project basis. + +Note that Ada mode project files @file{*.adp} are different than GNAT +compiler project files @file{*.gpr}. However, Emacs Ada mode can use a +GNAT project file to specify the project directories. If no +other customization is needed, a GNAT project file can be used without +an Emacs Ada mode project file. + +@menu +* Project File Overview:: +* GUI Editor:: +* Project file variables:: +@end menu + +@node Project File Overview +@section Project File Overview + +Project files have a simple syntax; they may be edited directly. Each +line specifies a project variable name and its value, separated by ``='': +@example +src_dir=/Projects/my_project/src_1 +src_dir=/Projects/my_project/src_2 +@end example + +Some variables (like @code{src_dir}) are lists; multiple occurrences +are concatenated. + +There must be no space between the variable name and ``='', and no +trailing spaces. + +Alternately, a GUI editor for project files is available (@pxref{GUI +Editor}). It uses Emacs widgets, similar to Emacs customize. + +The GUI editor also provides a convenient way to view current project +settings, if they have been modified using menu commands rather than +by editing the project file. + +After the first Ada mode build command is invoked, there is always a +current project file, given by the lisp variable +@code{ada-prj-default-project-file}. Currently, the only way to show +the current project file is to invoke the GUI editor. + +To find the project file the first time, Ada mode uses the following +search algorithm: + +@itemize @bullet +@item +If @code{ada-prj-default-project-file} is set, use that. + +@item +Otherwise, search for a file in the current directory with +the same base name as the Ada file, but extension given by +@code{ada-prj-file-extension} (default @code{".adp"}). + +@item +If not found, search for @file{*.adp} in the current directory; if +several are found, prompt the user to select one. + +@item +If none are found, use @file{default.adp} in the current directory (even +if it does not exist). + +@end itemize + +This algorithm always sets @code{ada-prj-default-project-file}, even +when the file does not actually exist. + +To change the project file before or after the first one is found, +invoke @samp{Ada | Project | Load ...}. + +Or, in lisp, evaluate @code{(ada-set-default-project-file "/path/file.adp")}. +This sets @code{ada-prj-default-project-file}, and reads the project file. + +You can also specify a GNAT project file to @samp{Ada | Project | Load +...} or @code{ada-set-default-project-file}. Emacs Ada mode checks the +file extension; if it is @code{.gpr}, the file is treated as a GNAT +project file. Any other extension is treated as an Emacs Ada mode +project file. + +@node GUI Editor +@section GUI Editor + +The project file editor is invoked with the menu @samp{Ada | Projects +| Edit}. + +Once in the buffer for editing the project file, you can save your +modification using the @samp{[save]} button at the bottom of the +buffer, or the @kbd{C-x C-s} binding. To cancel your modifications, +kill the buffer or click on the @samp{[cancel]} button. + +@node Project file variables +@section Project file variables + +The following variables can be defined in a project file; some can +also be defined in lisp variables. + +To set a project variable that is a list, specify each element of the +list on a separate line in the project file. + +Any project variable can be referenced in other project variables, +using a shell-like notation. For instance, if the variable +@code{comp_cmd} contains @code{$@{comp_opt@}}, the value of the +@code{comp_opt} variable will be substituted when @code{comp_cmd} is +used. + +In addition, process environment variables can be referenced using the +same syntax, or the normal @code{$var} syntax. + +Most project variables have defaults that can be changed by setting +lisp variables; the table below identifies the lisp variable for each +project variable. Lisp variables corresponding to project variables +that are lists are lisp lists. + +In general, project variables are evaluated when referenced in +Emacs Ada mode commands. Relative file paths are expanded to +absolute relative to @code{$@{build_dir@}}. + +Here is the list of variables. In the default values, the current +directory @code{"."} is the project file directory. + +@table @asis +@c defined in ada-default-prj-properties; alphabetical order + +@item @code{ada_project_path_sep} [default: @code{":" or ";"}] +Path separator for @code{ADA_PROJECT_PATH}. It defaults to the correct +value for a native implementation of GNAT for the current operating +system. The user must override this when using Windows native GNAT +with Cygwin Emacs, and perhaps in other cases. + +Lisp variable: @code{ada-prj-ada-project-path-sep}. + +@item @code{ada_project_path} [default: @code{""}] +A list of directories to search for GNAT project files. + +If set, the @code{ADA_PROJECT_PATH} process environment variable is +set to this value in the Emacs process when the Emacs Ada mode project +is selected via menu @samp{Ada | Project | Load}. + +For @code{ada_project_path}, relative file paths are expanded to +absolute when the Emacs Ada project file is read, rather than when the +project file is selected. + +For example if the project file is in the directory +@file{/home/myproject}, the environment variable @code{GDS_ROOT} is +set to @code{/home/shared}, and the project file contains: +@example +ada_project_path_sep=: +ada_project_path=$GDS_ROOT/makerules +ada_project_path=../opentoken +@end example +then as a result the environment variable @code{ADA_PROJECT_PATH} will +be set to @code{"/home/shared/makerules:/home/opentoken/"}. + +The default value is not the current value of this environment +variable, because that will typically have been set by another +project, and will therefore be incorrect for this project. + +If you have the environment variable set correctly for all of your +projects, you do not need to set this project variable. + +@item @code{bind_opt} [default: @code{""}] +Holds user binder options; used in the default build commands. + +Lisp variable: @code{ada-prj-default-bind-opt}. + +@item @code{build_dir} [default: @code{"."}] +The compile commands will be issued in this directory. + +@item @code{casing} [default: @code{("~/.emacs_case_exceptions")}] +List of files containing casing exceptions. See the help on +@code{ada-case-exception-file} for more info. +@c FIXME: section on case exceptions + +Lisp variable: @code{ada-case-exception-file}. + +@item @code{check_cmd} [default: @code{"$@{cross_prefix@}gnatmake -u -c -gnatc $@{gnatmake_opt@} $@{full_current@} -cargs $@{comp_opt@}"}] +Command used to syntax check a single file. +The name of the file is substituted for @code{full_current}. + +Lisp variable: @code{ada-prj-default-check-cmd} + +@item @code{comp_cmd} [default: @code{"$@{cross_prefix@}gnatmake -u -c $@{gnatmake_opt@} $@{full_current@} -cargs $@{comp_opt@}"}] +Command used to compile a single file. +The name of the file is substituted for @code{full_current}. + +Lisp variable: @code{ada-prj-default-comp-cmd}. + +@item @code{comp_opt} [default: @code{"-gnatq -gnatQ"}] +Holds user compiler options; used in the default compile commands. The +default value tells gnatmake to generate library files for +cross-referencing even when there are errors. + +If source code for the project is in multiple directories, the +appropriate compiler options must be added here. @ref{Set source +search path} for examples of this. Alternately, GNAT project files may +be used; @ref{Use GNAT project file}. + +Lisp variable: @code{ada-prj-default-comp-opt}. + +@item @code{cross_prefix} [default: @code{""}] +Name of target machine in a cross-compilation environment. Used in +default compile and build commands. + +@item @code{debug_cmd} [default: @code{"$@{cross_prefix@}gdb $@{main@}"}] +Command used to debug the application + +Lisp variable: @code{ada-prj-default-debugger}. + +@item @code{debug_post_cmd} [default: @code{""}] +Command executed after @code{debug_cmd}. + +@item @code{debug_pre_cmd} [default: @code{"cd $@{build_dir@}"}] +Command executed before @code{debug_cmd}. + +@item @code{gnatfind_opt} [default: @code{"-rf"}] +Holds user gnatfind options; used in the default find commands. + +Lisp variable: @code{ada-prj-gnatfind-switches}. + +@item @code{gnatmake_opt} [default: @code{"-g"}] +Holds user gnatmake options; used in the default build commands. + +Lisp variable: @code{ada-prj-default-gnatmake-opt}. + +@item @code{gpr_file} [default: @code{""}] +Specify GNAT project file. + +If set, the source and object directories specified in the GNAT +project file are appended to @code{src_dir} and @code{obj_dir}. This +allows specifying Ada source directories with a GNAT project file, and +other source directories with the Emacs project file. + +In addition, @code{-P@{gpr_file@}} is added to the project variable +@code{gnatmake_opt} whenever it is referenced. With the default +project variables, this passes the project file to all gnatmake +commands. + +Lisp variable: @code{ada-prj-default-gpr-file}. + +@c FIXME: add gnatstub-opts + +@item @code{link_opt} [default: @code{""}] +Holds user linker options; used in the default build commands. + +Lisp variable: @code{ada-prj-default-link-opt}. + +@item @code{main} [default: current file] +Specifies the name of the executable file for the project; used in the +default build commands. + +@item @code{make_cmd} [default: @code{"$@{cross_prefix@}gnatmake -o $@{main@} $@{main@} $@{gnatmake_opt@} -cargs $@{comp_opt@} -bargs $@{bind_opt@} -largs $@{link_opt@}"}] +Command used to build the application. + +Lisp variable: @code{ada-prj-default-make-cmd}. + +@item @code{obj_dir} [default: @code{"."}] +A list of directories to search for library files. Ada mode searches +this list for the @samp{.ali} files generated by GNAT that contain +cross-reference information. + +The compiler commands must place the @samp{.ali} files in one of these +directories; the default commands do that. + +@item @code{remote_machine} [default: @code{""}] +Name of the machine to log into before issuing the compile and build +commands. If this variable is empty, the command will be run on the +local machine. + +@item @code{run_cmd} [default: @code{"./$@{main@}"}] +Command used to run the application. + +@item @code{src_dir} [default: @code{"."}] +A list of directories to search for source files, both for compile +commands and source navigation. + +@end table + +@node Compiling Examples +@chapter Compiling Examples + +We present several small projects, and walk thru the process of +compiling, linking, and running them. + +The first example illustrates more Ada mode features than the others; +you should work thru that example before doing the others. + +All of these examples assume you are using GNAT. + +The source for these examples is available on the Emacs Ada mode +website mentioned in @xref{Installation}. + +@menu +* No project files:: Just menus +* Set compiler options:: A basic Ada mode project file +* Set source search path:: Source in multiple directories +* Use GNAT project file:: +* Use multiple GNAT project files:: +@end menu + +@node No project files +@section No project files +This example uses no project files. + +First, create a directory @file{Example_1}, containing: + +@file{hello.adb}: + +@example +with Ada.Text_IO; +procedure Hello +is begin + Put_Line("Hello from hello.adb"); +end Hello; +@end example + +Yes, this is missing ``use Ada.Text_IO;'' - we want to demonstrate +compiler error handling. + +@file{hello_2.adb}: + +@example +with Hello_Pkg; +procedure Hello_2 +is begin + Hello_Pkg.Say_Hello; +end Hello_2; +@end example + +This file has no errors. + +@file{hello_pkg.ads}: + +@example +package Hello_Pkg is + procedure Say_Hello; +end Hello_Pkg; +@end example + +This file has no errors. + +@file{hello_pkg.adb}: + +@example +with Ada.Text_IO; +package Hello_Pkg is + procedure Say_Hello + is begin + Ada.Text_IO.Put_Line ("Hello from hello_pkg.adb"); + end Say_Hello; +end Hello_Pkg; +@end example + +Yes, this is missing the keyword @code{body}; another compiler error +example. + +In buffer @file{hello.adb}, invoke @samp{Ada | Check file}. You should +get a @file{*compilation*} buffer containing something like (the +directory paths will be different): + +@smallexample +cd c:/Examples/Example_1/ +gnatmake -u -c -gnatc -g c:/Examples/Example_1/hello.adb -cargs -gnatq -gnatQ +gcc -c -Ic:/Examples/Example_1/ -gnatc -g -gnatq -gnatQ -I- c:/Examples/Example_1/hello.adb +hello.adb:4:04: "Put_Line" is not visible +hello.adb:4:04: non-visible declaration at a-textio.ads:264 +hello.adb:4:04: non-visible declaration at a-textio.ads:260 +gnatmake: "c:/Examples/Example_1/hello.adb" compilation error +@end smallexample + +If you have enabled font-lock, the lines with actual errors (starting +with @file{hello.adb}) are highlighted, with the file name in red. + +Now type @kbd{C-x `} (on a PC keyboard, @key{`} is next to @key{1}). +Or you can click the middle mouse button on the first error line. The +compilation buffer scrolls to put the first error on the top line, and +point is put at the place of the error in the @file{hello.adb} buffer. + +To fix the error, change the line to be + +@example + Ada.Text_IO.Put_Line ("hello from hello.adb"); +@end example + +Now invoke @samp{Ada | Show main}; this displays @samp{Ada mode main: hello}. + +Now (in buffer @file{hello.adb}), invoke @samp{Ada | Build}. You are +prompted to save the file (if you haven't already). Then the +compilation buffer is displayed again, containing: + +@example +cd c:/Examples/Example_1/ +gnatmake -o hello hello -g -cargs -gnatq -gnatQ -bargs -largs +gcc -c -g -gnatq -gnatQ hello.adb +gnatbind -x hello.ali +gnatlink hello.ali -o hello.exe -g +@end example + +The compilation has succeeded without errors; @file{hello.exe} now +exists in the same directory as @file{hello.adb}. + +Now invoke @samp{Ada | Run}. A @file{*run*} buffer is displayed, +containing + +@example +Hello from hello.adb + +Process run finished +@end example + +That completes the first part of this example. + +Now we will compile a multi-file project. Open the file +@file{hello_2.adb}, and invoke @samp{Ada | Set main and Build}. This +finds an error in @file{hello_pkg.adb}: + +@example +cd c:/Examples/Example_1/ +gnatmake -o hello_2 hello_2 -g -cargs -gnatq -gnatQ -bargs -largs +gcc -c -g -gnatq -gnatQ hello_pkg.adb +hello_pkg.adb:2:08: keyword "body" expected here [see file name] +gnatmake: "hello_pkg.adb" compilation error +@end example + +This demonstrates that gnatmake finds the files needed by the main +program. However, it cannot find files in a different directory, +unless you use an Emacs Ada mode project file to specify the other directories; +@xref{Set source search path}, or a GNAT project file; @ref{Use GNAT +project file}. + +Invoke @samp{Ada | Show main}; this displays @file{Ada mode main: hello_2}. + +Move to the error with @kbd{C-x `}, and fix the error by adding @code{body}: + +@example +package body Hello_Pkg is +@end example + +Now, while still in @file{hello_pkg.adb}, invoke @samp{Ada | Build}. +gnatmake successfully builds @file{hello_2}. This demonstrates that +Emacs has remembered the main file, in the project variable +@code{main}, and used it for the Build command. + +Finally, again while in @file{hello_pkg.adb}, invoke @samp{Ada | Run}. +The @file{*run*} buffer displays @code{Hello from hello_pkg.adb}. + +One final point. If you switch back to buffer @file{hello.adb}, and +invoke @samp{Ada | Run}, @file{hello_2.exe} will be run. That is +because @code{main} is still set to @code{hello_2}, as you can +see when you invoke @samp{Ada | Project | Edit}. + +There are three ways to change @code{main}: + +@enumerate +@item +Invoke @samp{Ada | Set main and Build}, which sets @code{main} to +the current file. + +@item +Invoke @samp{Ada | Project | Edit}, edit @code{main}, and click @samp{[save]} + +@item +Invoke @samp{Ada | Project | Load}, and load a project file that specifies @code{main} + +@end enumerate + +@node Set compiler options +@section Set compiler options + +This example illustrates using an Emacs Ada mode project file to set a +compiler option. + +If you have files from @file{Example_1} open in Emacs, you should +close them so you don't get confused. Use menu @samp{File | Close +(current buffer)}. + +In directory @file{Example_2}, create these files: + +@file{hello.adb}: + +@example +with Ada.Text_IO; +procedure Hello +is begin + Put_Line("Hello from hello.adb"); +end Hello; +@end example + +This is the same as @file{hello.adb} from @file{Example_1}. It has two +errors; missing ``use Ada.Text_IO;'', and no space between +@code{Put_Line} and its argument list. + +@file{hello.adp}: + +@example +comp_opt=-gnatyt +@end example + +This tells the GNAT compiler to check for token spacing; in +particular, there must be a space preceding a parenthesis. + +In buffer @file{hello.adb}, invoke @samp{Ada | Project | Load...}, and +select @file{Example_2/hello.adp}. + +Then, again in buffer @file{hello.adb}, invoke @samp{Ada | Set main and +Build}. You should get a @file{*compilation*} buffer containing +something like (the directory paths will be different): + +@example +cd c:/Examples/Example_2/ +gnatmake -o hello hello -g -cargs -gnatyt -bargs -largs +gcc -c -g -gnatyt hello.adb +hello.adb:4:04: "Put_Line" is not visible +hello.adb:4:04: non-visible declaration at a-textio.ads:264 +hello.adb:4:04: non-visible declaration at a-textio.ads:260 +hello.adb:4:12: (style) space required +gnatmake: "hello.adb" compilation error +@end example + +Compare this to the compiler output in @ref{No project files}; the +gnatmake option @code{-cargs -gnatq -gnatQ} has been replaced by +@code{-cargs -gnaty}, and an additional error is reported in +@file{hello.adb} on line 4. This shows that @file{hello.adp} is being +used to set the compiler options. + +Fixing the error, linking and running the code proceed as in @ref{No +project files}. + +@node Set source search path +@section Set source search path + +In this example, we show how to deal with files in more than one +directory. We start with the same code as in @ref{No project files}; +create those files (with the errors present) + +Create the directory @file{Example_3}, containing: + +@file{hello_pkg.ads}: + +@example +package Hello_Pkg is + procedure Say_Hello; +end Hello_Pkg; +@end example + +@file{hello_pkg.adb}: + +@example +with Ada.Text_IO; +package Hello_Pkg is + procedure Say_Hello + is begin + Ada.Text_IO.Put_Line ("Hello from hello_pkg.adb"); + end Say_Hello; +end Hello_Pkg; +@end example + +These are the same files from example 1; @file{hello_pkg.adb} has an +error on line 2. + +In addition, create a directory @file{Example_3/Other}, containing these files: + +@file{Other/hello_3.adb}: + +@example +with Hello_Pkg; +with Ada.Text_IO; use Ada.Text_IO; +procedure Hello_3 +is begin + Hello_Pkg.Say_Hello; + Put_Line ("From hello_3"); +end Hello_3; +@end example + +There are no errors in this file. + +@file{Other/other.adp}: + +@example +src_dir=.. +comp_opt=-I.. +@end example + +Note that there must be no trailing spaces. + +In buffer @file{hello_3.adb}, invoke @samp{Ada | Project | Load...}, and +select @file{Example_3/Other/other.adp}. + +Then, again in @file{hello_3.adb}, invoke @samp{Ada | Set main and +Build}. You should get a @file{*compilation*} buffer containing +something like (the directory paths will be different): + +@example +cd c:/Examples/Example_3/Other/ +gnatmake -o hello_3 hello_3 -g -cargs -I.. -bargs -largs +gcc -c -g -I.. hello_3.adb +gcc -c -I./ -g -I.. -I- C:\Examples\Example_3\hello_pkg.adb +hello_pkg.adb:2:08: keyword "body" expected here [see file name] +gnatmake: "C:\Examples\Example_3\hello_pkg.adb" compilation error +@end example + +Compare the @code{-cargs} option to the compiler output in @ref{Set +compiler options}; this shows that @file{other.adp} is being used to +set the compiler options. + +Move to the error with @kbd{C-x `}. Ada mode searches the list of +directories given by @code{src_dir} for the file mentioned in the +compiler error message. + +Fixing the error, linking and running the code proceed as in @ref{No +project files}. + +@node Use GNAT project file +@section Use GNAT project file + +In this example, we show how to use a GNAT project file, with no Ada +mode project file. + +Create the directory @file{Example_4}, containing: + +@file{hello_pkg.ads}: + +@example +package Hello_Pkg is + procedure Say_Hello; +end Hello_Pkg; +@end example + +@file{hello_pkg.adb}: + +@example +with Ada.Text_IO; +package Hello_Pkg is + procedure Say_Hello + is begin + Ada.Text_IO.Put_Line ("Hello from hello_pkg.adb"); + end Say_Hello; +end Hello_Pkg; +@end example + +These are the same files from example 1; @file{hello_pkg.adb} has an +error on line 2. + +In addition, create a directory @file{Example_4/Gnat_Project}, +containing these files: + +@file{Gnat_Project/hello_4.adb}: + +@example +with Hello_Pkg; +with Ada.Text_IO; use Ada.Text_IO; +procedure Hello_4 +is begin + Hello_Pkg.Say_Hello; + Put_Line ("From hello_4"); +end Hello_4; +@end example + +There are no errors in this file. + +@file{Gnat_Project/hello_4.gpr}: + +@example +Project Hello_4 is + for Source_Dirs use (".", ".."); +end Hello_4; +@end example + +In buffer @file{hello_4.adb}, invoke @samp{Ada | Project | Load...}, and +select @file{Example_4/Gnat_Project/hello_4.gpr}. + +Then, again in @file{hello_4.adb}, invoke @samp{Ada | Set main and +Build}. You should get a @file{*compilation*} buffer containing +something like (the directory paths will be different): + +@smallexample +cd c:/Examples/Example_4/Gnat_Project/ +gnatmake -o hello_4 hello_4 -Phello_4.gpr -cargs -gnatq -gnatQ -bargs -largs +gcc -c -g -gnatyt -gnatq -gnatQ -I- -gnatA c:\Examples\Example_4\Gnat_Project\hello_4.adb +gcc -c -g -gnatyt -gnatq -gnatQ -I- -gnatA c:\Examples\Example_4\hello_pkg.adb +hello_pkg.adb:2:08: keyword "body" expected here [see file name] +gnatmake: "c:\examples\example_4\hello_pkg.adb" compilation error +@end smallexample + +Compare the @code{gcc} options to the compiler output in @ref{Set +compiler options}; this shows that @file{hello_4.gpr} is being used to +set the compiler options. + +Fixing the error, linking and running the code proceed as in @ref{No +project files}. + +@node Use multiple GNAT project files +@section Use multiple GNAT project files + +In this example, we show how to use multiple GNAT project files, +specifying the GNAT project search path in an Ada mode project file. + +Create the directory @file{Example_4} as specified in @ref{Use GNAT +project file}. + +Create the directory @file{Example_5}, containing: + +@file{hello_5.adb}: + +@example +with Hello_Pkg; +with Ada.Text_IO; use Ada.Text_IO; +procedure Hello_5 +is begin + Hello_Pkg.Say_Hello; + Put_Line ("From hello_5"); +end Hello_5; +@end example + +There are no errors in this file. + +@file{hello_5.adp}: + +@example +ada_project_path=../Example_4/Gnat_Project +gpr_file=hello_5.gpr +@end example + +@file{hello_5.gpr}: + +@example +with "hello_4"; +Project Hello_5 is + for Source_Dirs use ("."); + package Compiler is + for Default_Switches ("Ada") use ("-g", "-gnatyt"); + end Compiler; +end Hello_5; +@end example + +In buffer @file{hello_5.adb}, invoke @samp{Ada | Project | Load...}, and +select @file{Example_5/hello_5.adp}. + +Then, again in @file{hello_5.adb}, invoke @samp{Ada | Set main and +Build}. You should get a @file{*compilation*} buffer containing +something like (the directory paths will be different): + +@smallexample +cd c:/Examples/Example_5/ +gnatmake -o hello_5 hello_5 -Phello_5.gpr -g -cargs -gnatq -gnatQ -bargs -largs +gcc -c -g -gnatyt -g -gnatq -gnatQ -I- -gnatA c:\Examples\Example_5\hello_5.adb +gcc -c -g -gnatyt -g -gnatq -gnatQ -I- -gnatA c:\Examples\Example_4\hello_pkg.adb +hello_pkg.adb:2:08: keyword "body" expected here [see file name] +gnatmake: "c:\examples\example_4\hello_pkg.adb" compilation error +@end smallexample + +Now type @kbd{C-x `}. @file{Example_4/hello_pkg.adb} is shown, +demonstrating that @file{hello_5.gpr} and @file{hello_4.gpr} are being +used to set the compilation search path. + +@node Moving Through Ada Code +@chapter Moving Through Ada Code + +There are several easy to use commands to navigate through Ada code. All +these functions are available through the Ada menu, and you can also +use the following key bindings or the command names. Some of these +menu entries are available only if the GNAT compiler is used, since +the implementation relies on the GNAT cross-referencing information. + +@table @kbd +@item M-C-e +@findex ada-next-procedure +Move to the next function/procedure/task, which ever comes next +(@code{ada-next-procedure}). +@item M-C-a +@findex ada-previous-procedure +Move to previous function/procedure/task +(@code{ada-previous-procedure}). +@item M-x ada-next-package +@findex ada-next-package +Move to next package. +@item M-x ada-previous-package +@findex ada-previous-package +Move to previous package. +@item C-c C-a +@findex ada-move-to-start +Move to matching start of @code{end} (@code{ada-move-to-start}). If +point is at the end of a subprogram, this command jumps to the +corresponding @code{begin} if the user option +@code{ada-move-to-declaration} is @code{nil} (default), otherwise it jumps to +the subprogram declaration. +@item C-c C-e +@findex ada-move-to-end +Move point to end of current block (@code{ada-move-to-end}). +@item C-c o +Switch between corresponding spec and body file +(@code{ff-find-other-file}). If point is in a subprogram, position +point on the corresponding declaration or body in the other file. +@item C-c c-d +@findex ada-goto-declaration +Move from any reference to its declaration, for from a declaration to +its body (for procedures, tasks, private and incomplete types). +@item C-c C-r +@findex ada-find-references +Runs the @file{gnatfind} command to search for all references to the +identifier surrounding point (@code{ada-find-references}). Use +@kbd{C-x `} (@code{next-error}) to visit each reference (as for +compilation errors). +@end table + +If the @code{ada-xref-create-ali} variable is non-@code{nil}, Emacs +will try to run GNAT for you whenever cross-reference information is +needed, and is older than the current source file. + +@node Identifier completion +@chapter Identifier completion + +Emacs and Ada mode provide two general ways for the completion of +identifiers. This is an easy way to type faster: you just have to type +the first few letters of an identifiers, and then loop through all the +possible completions. + +The first method is general for Emacs. It works by parsing all open +files for possible completions. + +For instance, if the words @samp{my_identifier}, @samp{my_subprogram} +are the only words starting with @samp{my} in any of the opened files, +then you will have this scenario: + +@example +You type: my@kbd{M-/} +Emacs inserts: @samp{my_identifier} +If you press @kbd{M-/} once again, Emacs replaces @samp{my_identifier} with +@samp{my_subprogram}. +Pressing @kbd{M-/} once more will bring you back to @samp{my_identifier}. +@end example + +This is a very fast way to do completion, and the casing of words will +also be respected. + +The second method (@kbd{C-@key{TAB}}) is specific to Ada mode and the GNAT +compiler. Emacs will search the cross-information for possible +completions. + +The main advantage is that this completion is more accurate: only +existing identifier will be suggested. + +On the other hand, this completion is a little bit slower and requires +that you have compiled your file at least once since you created that +identifier. + +@table @kbd +@item C-@key{TAB} +@findex ada-complete-identifier +Complete current identifier using cross-reference information. +@item M-/ +Complete identifier using buffer information (not Ada-specific). +@end table + +@node Automatic Smart Indentation +@chapter Automatic Smart Indentation + +Ada mode comes with a full set of rules for automatic indentation. You +can also configure the indentation, via the following variables: + +@table @asis +@item @code{ada-broken-indent} (default value: 2) +Number of columns to indent the continuation of a broken line. + +@item @code{ada-indent} (default value: 3) +Number of columns for default indentation. + +@item @code{ada-indent-record-rel-type} (default value: 3) +Indentation for @code{record} relative to @code{type} or @code{use}. + +@item @code{ada-indent-return} (default value: 0) +Indentation for @code{return} relative to @code{function} (if +@code{ada-indent-return} is greater than 0), or the open parenthesis +(if @code{ada-indent-return} is negative or 0). Note that in the second +case, when there is no open parenthesis, the indentation is done +relative to @code{function} with the value of @code{ada-broken-indent}. + +@item @code{ada-label-indent} (default value: -4) +Number of columns to indent a label. + +@item @code{ada-stmt-end-indent} (default value: 0) +Number of columns to indent a statement @code{end} keyword on a separate line. + +@item @code{ada-when-indent} (default value: 3) +Indentation for @code{when} relative to @code{exception} or @code{case}. + +@item @code{ada-indent-is-separate} (default value: t) +Non-@code{nil} means indent @code{is separate} or @code{is abstract} if on a single line. + +@item @code{ada-indent-to-open-paren} (default value: t) +Non-@code{nil} means indent according to the innermost open parenthesis. + +@item @code{ada-indent-after-return} (default value: t) +Non-@code{nil} means that the current line will also be re-indented +before inserting a newline, when you press @key{RET}. +@end table + +Most of the time, the indentation will be automatic, i.e., when you +press @key{RET}, the cursor will move to the correct column on the +next line. + +You can also indent single lines, or the current region, with @key{TAB}. + +Another mode of indentation exists that helps you to set up your +indentation scheme. If you press @kbd{C-c @key{TAB}}, Ada mode will do +the following: + +@itemize @bullet +@item +Reindent the current line, as @key{TAB} would do. +@item +Temporarily move the cursor to a reference line, i.e., the line that +was used to calculate the current indentation. +@item +Display in the message window the name of the variable that provided +the offset for the indentation. +@end itemize + +The exact indentation of the current line is the same as the one for the +reference line, plus an offset given by the variable. + +@table @kbd +@item @key{TAB} +Indent the current line or the current region. +@item C-M-\ +Indent lines in the current region. +@item C-c @key{TAB} +Indent the current line and display the name of the variable used for +indentation. +@end table + +@node Formatting Parameter Lists +@chapter Formatting Parameter Lists + +@table @kbd +@item C-c C-f +@findex ada-format-paramlist +Format the parameter list (@code{ada-format-paramlist}). +@end table + +This aligns the declarations on the colon (@samp{:}) separating +argument names and argument types, and aligns the @code{in}, +@code{out} and @code{in out} keywords. + +@node Automatic Casing +@chapter Automatic Casing + +Casing of identifiers, attributes and keywords is automatically +performed while typing when the variable @code{ada-auto-case} is set. +Every time you press a word separator, the previous word is +automatically cased. + +You can customize the automatic casing differently for keywords, +attributes and identifiers. The relevant variables are the following: +@code{ada-case-keyword}, @code{ada-case-attribute} and +@code{ada-case-identifier}. + +All these variables can have one of the following values: + +@table @code +@item downcase-word +The word will be lowercase. For instance @code{My_vARIable} is +converted to @code{my_variable}. + +@item upcase-word +The word will be uppercase. For instance @code{My_vARIable} is +converted to @code{MY_VARIABLE}. + +@item ada-capitalize-word +The first letter and each letter following an underscore (@samp{_}) +are uppercase, others are lowercase. For instance @code{My_vARIable} +is converted to @code{My_Variable}. + +@item ada-loose-case-word +Characters after an underscore @samp{_} character are uppercase, +others are not modified. For instance @code{My_vARIable} is converted +to @code{My_VARIable}. +@end table + +Ada mode allows you to define exceptions to these rules, in a file +specified by the variable @code{ada-case-exception-file} +(default @file{~/.emacs_case_exceptions}). Each line in this file +specifies the casing of one word or word fragment. Comments may be +included, separated from the word by a space. + +If the word starts with an asterisk (@samp{*}), it defines the casing +as a word fragment (or ``substring''); part of a word between two +underscores or word boundary. + +For example: + +@example +DOD Department of Defense +*IO +GNAT The GNAT compiler from Ada Core Technologies +@end example + +The word fragment @code{*IO} applies to any word containing ``_io''; +@code{Text_IO}, @code{Hardware_IO}, etc. + +@findex ada-create-case-exception +There are two ways to add new items to this file: you can simply edit +it as you would edit any text file. Or you can position point on the +word you want to add, and select menu @samp{Ada | Edit | Create Case +Exception}, or press @kbd{C-c C-y} (@code{ada-create-case-exception}). +The word will automatically be added to the current list of exceptions +and to the file. + +To define a word fragment case exception, select the word fragment, +then select menu @samp{Ada | Edit | Create Case Exception Substring}. + +It is sometimes useful to have multiple exception files around (for +instance, one could be the standard Ada acronyms, the second some +company specific exceptions, and the last one some project specific +exceptions). If you set up the variable @code{ada-case-exception-file} +as a list of files, each of them will be parsed and used in your emacs +session. However, when you save a new exception through the menu, as +described above, the new exception will be added to the first file in +the list. + +@table @kbd +@item C-c C-b +@findex ada-adjust-case-buffer +Adjust case in the whole buffer (@code{ada-adjust-case-buffer}). +@item C-c C-y +Create a new entry in the exception dictionary, with the word under +the cursor (@code{ada-create-case-exception}) +@item C-c C-t +@findex ada-case-read-exceptions +Rereads the exception dictionary from the file +@code{ada-case-exception-file} (@code{ada-case-read-exceptions}). +@end table + +@node Statement Templates +@chapter Statement Templates + +Templates are defined for most Ada statements, using the Emacs +``skeleton'' package. They can be inserted in the buffer using the +following commands: + +@table @kbd +@item C-c t b +@findex ada-exception-block +exception Block (@code{ada-exception-block}). +@item C-c t c +@findex ada-case +case (@code{ada-case}). +@item C-c t d +@findex ada-declare-block +declare Block (@code{ada-declare-block}). +@item C-c t e +@findex ada-else +else (@code{ada-else}). +@item C-c t f +@findex ada-for-loop +for Loop (@code{ada-for-loop}). +@item C-c t h +@findex ada-header +Header (@code{ada-header}). +@item C-c t i +@findex ada-if +if (@code{ada-if}). +@item C-c t k +@findex ada-package-body +package Body (@code{ada-package-body}). +@item C-c t l +@findex ada-loop +loop (@code{ada-loop}). +@item C-c p +@findex ada-subprogram-body +subprogram body (@code{ada-subprogram-body}). +@item C-c t t +@findex ada-task-body +task Body (@code{ada-task-body}). +@item C-c t w +@findex ada-while +while Loop (@code{ada-while}). +@item C-c t u +@findex ada-use +use (@code{ada-use}). +@item C-c t x +@findex ada-exit +exit (@code{ada-exit}). +@item C-c t C-a +@findex ada-array +array (@code{ada-array}). +@item C-c t C-e +@findex ada-elsif +elsif (@code{ada-elsif}). +@item C-c t C-f +@findex ada-function-spec +function Spec (@code{ada-function-spec}). +@item C-c t C-k +@findex ada-package-spec +package Spec (@code{ada-package-spec}). +@item C-c t C-p +@findex ada-procedure-spec +procedure Spec (@code{ada-package-spec}. +@item C-c t C-r +@findex ada-record +record (@code{ada-record}). +@item C-c t C-s +@findex ada-subtype +subtype (@code{ada-subtype}). +@item C-c t C-t +@findex ada-task-spec +task Spec (@code{ada-task-spec}). +@item C-c t C-u +@findex ada-with +with (@code{ada-with}). +@item C-c t C-v +@findex ada-private +private (@code{ada-private}). +@item C-c t C-w +@findex ada-when +when (@code{ada-when}). +@item C-c t C-x +@findex ada-exception +exception (@code{ada-exception}). +@item C-c t C-y +@findex ada-type +type (@code{ada-type}). +@end table + +@node Comment Handling +@chapter Comment Handling + +By default, comment lines get indented like Ada code. There are a few +additional functions to handle comments: + +@table @kbd +@item M-; +Start a comment in default column. +@item M-j +Continue comment on next line. +@item C-c ; +Comment the selected region (add @samp{--} at the beginning of lines). +@item C-c : +Uncomment the selected region +@item M-q +autofill the current comment. +@end table + +@node GNU Free Documentation License +@appendix GNU Free Documentation License +@include doclicense.texi + +@node Index +@unnumbered Index + +@printindex fn + +@bye diff --git a/ada-mode/doc/build.sh b/ada-mode/doc/build.sh new file mode 100755 index 0000000..a0799fe --- /dev/null +++ b/ada-mode/doc/build.sh @@ -0,0 +1,3 @@ +#! /usr/bin/env bash +texi2any -o ada-mode.info --no-split ada-mode.texi +texi2any --html -o ada-mode.html --no-split ada-mode.texi diff --git a/ada-mode/doc/clean.sh b/ada-mode/doc/clean.sh new file mode 100755 index 0000000..f7e90b1 --- /dev/null +++ b/ada-mode/doc/clean.sh @@ -0,0 +1,2 @@ +#! /bin/sh +rm ada-mode.aux ada-mode.fn ada-mode.log ada-mode.toc diff --git a/ada-mode/doc/doclicense.texi b/ada-mode/doc/doclicense.texi new file mode 100644 index 0000000..eaf3da0 --- /dev/null +++ b/ada-mode/doc/doclicense.texi @@ -0,0 +1,505 @@ +@c The GNU Free Documentation License. +@center Version 1.3, 3 November 2008 + +@c This file is intended to be included within another document, +@c hence no sectioning command or @node. + +@display +Copyright @copyright{} 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. +@uref{https://fsf.org/} + +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. +@end display + +@enumerate 0 +@item +PREAMBLE + +The purpose of this License is to make a manual, textbook, or other +functional and useful document @dfn{free} in the sense of freedom: to +assure everyone the effective freedom to copy and redistribute it, +with or without modifying it, either commercially or noncommercially. +Secondarily, this License preserves for the author and publisher a way +to get credit for their work, while not being considered responsible +for modifications made by others. + +This License is a kind of ``copyleft'', which means that derivative +works of the document must themselves be free in the same sense. It +complements the GNU General Public License, which is a copyleft +license designed for free software. + +We have designed this License in order to use it for manuals for free +software, because free software needs free documentation: a free +program should come with manuals providing the same freedoms that the +software does. But this License is not limited to software manuals; +it can be used for any textual work, regardless of subject matter or +whether it is published as a printed book. We recommend this License +principally for works whose purpose is instruction or reference. + +@item +APPLICABILITY AND DEFINITIONS + +This License applies to any manual or other work, in any medium, that +contains a notice placed by the copyright holder saying it can be +distributed under the terms of this License. Such a notice grants a +world-wide, royalty-free license, unlimited in duration, to use that +work under the conditions stated herein. The ``Document'', below, +refers to any such manual or work. Any member of the public is a +licensee, and is addressed as ``you''. You accept the license if you +copy, modify or distribute the work in a way requiring permission +under copyright law. + +A ``Modified Version'' of the Document means any work containing the +Document or a portion of it, either copied verbatim, or with +modifications and/or translated into another language. + +A ``Secondary Section'' is a named appendix or a front-matter section +of the Document that deals exclusively with the relationship of the +publishers or authors of the Document to the Document's overall +subject (or to related matters) and contains nothing that could fall +directly within that overall subject. (Thus, if the Document is in +part a textbook of mathematics, a Secondary Section may not explain +any mathematics.) The relationship could be a matter of historical +connection with the subject or with related matters, or of legal, +commercial, philosophical, ethical or political position regarding +them. + +The ``Invariant Sections'' are certain Secondary Sections whose titles +are designated, as being those of Invariant Sections, in the notice +that says that the Document is released under this License. If a +section does not fit the above definition of Secondary then it is not +allowed to be designated as Invariant. The Document may contain zero +Invariant Sections. If the Document does not identify any Invariant +Sections then there are none. + +The ``Cover Texts'' are certain short passages of text that are listed, +as Front-Cover Texts or Back-Cover Texts, in the notice that says that +the Document is released under this License. A Front-Cover Text may +be at most 5 words, and a Back-Cover Text may be at most 25 words. + +A ``Transparent'' copy of the Document means a machine-readable copy, +represented in a format whose specification is available to the +general public, that is suitable for revising the document +straightforwardly with generic text editors or (for images composed of +pixels) generic paint programs or (for drawings) some widely available +drawing editor, and that is suitable for input to text formatters or +for automatic translation to a variety of formats suitable for input +to text formatters. A copy made in an otherwise Transparent file +format whose markup, or absence of markup, has been arranged to thwart +or discourage subsequent modification by readers is not Transparent. +An image format is not Transparent if used for any substantial amount +of text. A copy that is not ``Transparent'' is called ``Opaque''. + +Examples of suitable formats for Transparent copies include plain +ASCII without markup, Texinfo input format, La@TeX{} input +format, SGML or XML using a publicly available +DTD, and standard-conforming simple HTML, +PostScript or PDF designed for human modification. Examples +of transparent image formats include PNG, XCF and +JPG@. Opaque formats include proprietary formats that can be +read and edited only by proprietary word processors, SGML or +XML for which the DTD and/or processing tools are +not generally available, and the machine-generated HTML, +PostScript or PDF produced by some word processors for +output purposes only. + +The ``Title Page'' means, for a printed book, the title page itself, +plus such following pages as are needed to hold, legibly, the material +this License requires to appear in the title page. For works in +formats which do not have any title page as such, ``Title Page'' means +the text near the most prominent appearance of the work's title, +preceding the beginning of the body of the text. + +The ``publisher'' means any person or entity that distributes copies +of the Document to the public. + +A section ``Entitled XYZ'' means a named subunit of the Document whose +title either is precisely XYZ or contains XYZ in parentheses following +text that translates XYZ in another language. (Here XYZ stands for a +specific section name mentioned below, such as ``Acknowledgements'', +``Dedications'', ``Endorsements'', or ``History''.) To ``Preserve the Title'' +of such a section when you modify the Document means that it remains a +section ``Entitled XYZ'' according to this definition. + +The Document may include Warranty Disclaimers next to the notice which +states that this License applies to the Document. These Warranty +Disclaimers are considered to be included by reference in this +License, but only as regards disclaiming warranties: any other +implication that these Warranty Disclaimers may have is void and has +no effect on the meaning of this License. + +@item +VERBATIM COPYING + +You may copy and distribute the Document in any medium, either +commercially or noncommercially, provided that this License, the +copyright notices, and the license notice saying this License applies +to the Document are reproduced in all copies, and that you add no other +conditions whatsoever to those of this License. You may not use +technical measures to obstruct or control the reading or further +copying of the copies you make or distribute. However, you may accept +compensation in exchange for copies. If you distribute a large enough +number of copies you must also follow the conditions in section 3. + +You may also lend copies, under the same conditions stated above, and +you may publicly display copies. + +@item +COPYING IN QUANTITY + +If you publish printed copies (or copies in media that commonly have +printed covers) of the Document, numbering more than 100, and the +Document's license notice requires Cover Texts, you must enclose the +copies in covers that carry, clearly and legibly, all these Cover +Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on +the back cover. Both covers must also clearly and legibly identify +you as the publisher of these copies. The front cover must present +the full title with all words of the title equally prominent and +visible. You may add other material on the covers in addition. +Copying with changes limited to the covers, as long as they preserve +the title of the Document and satisfy these conditions, can be treated +as verbatim copying in other respects. + +If the required texts for either cover are too voluminous to fit +legibly, you should put the first ones listed (as many as fit +reasonably) on the actual cover, and continue the rest onto adjacent +pages. + +If you publish or distribute Opaque copies of the Document numbering +more than 100, you must either include a machine-readable Transparent +copy along with each Opaque copy, or state in or with each Opaque copy +a computer-network location from which the general network-using +public has access to download using public-standard network protocols +a complete Transparent copy of the Document, free of added material. +If you use the latter option, you must take reasonably prudent steps, +when you begin distribution of Opaque copies in quantity, to ensure +that this Transparent copy will remain thus accessible at the stated +location until at least one year after the last time you distribute an +Opaque copy (directly or through your agents or retailers) of that +edition to the public. + +It is requested, but not required, that you contact the authors of the +Document well before redistributing any large number of copies, to give +them a chance to provide you with an updated version of the Document. + +@item +MODIFICATIONS + +You may copy and distribute a Modified Version of the Document under +the conditions of sections 2 and 3 above, provided that you release +the Modified Version under precisely this License, with the Modified +Version filling the role of the Document, thus licensing distribution +and modification of the Modified Version to whoever possesses a copy +of it. In addition, you must do these things in the Modified Version: + +@enumerate A +@item +Use in the Title Page (and on the covers, if any) a title distinct +from that of the Document, and from those of previous versions +(which should, if there were any, be listed in the History section +of the Document). You may use the same title as a previous version +if the original publisher of that version gives permission. + +@item +List on the Title Page, as authors, one or more persons or entities +responsible for authorship of the modifications in the Modified +Version, together with at least five of the principal authors of the +Document (all of its principal authors, if it has fewer than five), +unless they release you from this requirement. + +@item +State on the Title page the name of the publisher of the +Modified Version, as the publisher. + +@item +Preserve all the copyright notices of the Document. + +@item +Add an appropriate copyright notice for your modifications +adjacent to the other copyright notices. + +@item +Include, immediately after the copyright notices, a license notice +giving the public permission to use the Modified Version under the +terms of this License, in the form shown in the Addendum below. + +@item +Preserve in that license notice the full lists of Invariant Sections +and required Cover Texts given in the Document's license notice. + +@item +Include an unaltered copy of this License. + +@item +Preserve the section Entitled ``History'', Preserve its Title, and add +to it an item stating at least the title, year, new authors, and +publisher of the Modified Version as given on the Title Page. If +there is no section Entitled ``History'' in the Document, create one +stating the title, year, authors, and publisher of the Document as +given on its Title Page, then add an item describing the Modified +Version as stated in the previous sentence. + +@item +Preserve the network location, if any, given in the Document for +public access to a Transparent copy of the Document, and likewise +the network locations given in the Document for previous versions +it was based on. These may be placed in the ``History'' section. +You may omit a network location for a work that was published at +least four years before the Document itself, or if the original +publisher of the version it refers to gives permission. + +@item +For any section Entitled ``Acknowledgements'' or ``Dedications'', Preserve +the Title of the section, and preserve in the section all the +substance and tone of each of the contributor acknowledgements and/or +dedications given therein. + +@item +Preserve all the Invariant Sections of the Document, +unaltered in their text and in their titles. Section numbers +or the equivalent are not considered part of the section titles. + +@item +Delete any section Entitled ``Endorsements''. Such a section +may not be included in the Modified Version. + +@item +Do not retitle any existing section to be Entitled ``Endorsements'' or +to conflict in title with any Invariant Section. + +@item +Preserve any Warranty Disclaimers. +@end enumerate + +If the Modified Version includes new front-matter sections or +appendices that qualify as Secondary Sections and contain no material +copied from the Document, you may at your option designate some or all +of these sections as invariant. To do this, add their titles to the +list of Invariant Sections in the Modified Version's license notice. +These titles must be distinct from any other section titles. + +You may add a section Entitled ``Endorsements'', provided it contains +nothing but endorsements of your Modified Version by various +parties---for example, statements of peer review or that the text has +been approved by an organization as the authoritative definition of a +standard. + +You may add a passage of up to five words as a Front-Cover Text, and a +passage of up to 25 words as a Back-Cover Text, to the end of the list +of Cover Texts in the Modified Version. Only one passage of +Front-Cover Text and one of Back-Cover Text may be added by (or +through arrangements made by) any one entity. If the Document already +includes a cover text for the same cover, previously added by you or +by arrangement made by the same entity you are acting on behalf of, +you may not add another; but you may replace the old one, on explicit +permission from the previous publisher that added the old one. + +The author(s) and publisher(s) of the Document do not by this License +give permission to use their names for publicity for or to assert or +imply endorsement of any Modified Version. + +@item +COMBINING DOCUMENTS + +You may combine the Document with other documents released under this +License, under the terms defined in section 4 above for modified +versions, provided that you include in the combination all of the +Invariant Sections of all of the original documents, unmodified, and +list them all as Invariant Sections of your combined work in its +license notice, and that you preserve all their Warranty Disclaimers. + +The combined work need only contain one copy of this License, and +multiple identical Invariant Sections may be replaced with a single +copy. If there are multiple Invariant Sections with the same name but +different contents, make the title of each such section unique by +adding at the end of it, in parentheses, the name of the original +author or publisher of that section if known, or else a unique number. +Make the same adjustment to the section titles in the list of +Invariant Sections in the license notice of the combined work. + +In the combination, you must combine any sections Entitled ``History'' +in the various original documents, forming one section Entitled +``History''; likewise combine any sections Entitled ``Acknowledgements'', +and any sections Entitled ``Dedications''. You must delete all +sections Entitled ``Endorsements.'' + +@item +COLLECTIONS OF DOCUMENTS + +You may make a collection consisting of the Document and other documents +released under this License, and replace the individual copies of this +License in the various documents with a single copy that is included in +the collection, provided that you follow the rules of this License for +verbatim copying of each of the documents in all other respects. + +You may extract a single document from such a collection, and distribute +it individually under this License, provided you insert a copy of this +License into the extracted document, and follow this License in all +other respects regarding verbatim copying of that document. + +@item +AGGREGATION WITH INDEPENDENT WORKS + +A compilation of the Document or its derivatives with other separate +and independent documents or works, in or on a volume of a storage or +distribution medium, is called an ``aggregate'' if the copyright +resulting from the compilation is not used to limit the legal rights +of the compilation's users beyond what the individual works permit. +When the Document is included in an aggregate, this License does not +apply to the other works in the aggregate which are not themselves +derivative works of the Document. + +If the Cover Text requirement of section 3 is applicable to these +copies of the Document, then if the Document is less than one half of +the entire aggregate, the Document's Cover Texts may be placed on +covers that bracket the Document within the aggregate, or the +electronic equivalent of covers if the Document is in electronic form. +Otherwise they must appear on printed covers that bracket the whole +aggregate. + +@item +TRANSLATION + +Translation is considered a kind of modification, so you may +distribute translations of the Document under the terms of section 4. +Replacing Invariant Sections with translations requires special +permission from their copyright holders, but you may include +translations of some or all Invariant Sections in addition to the +original versions of these Invariant Sections. You may include a +translation of this License, and all the license notices in the +Document, and any Warranty Disclaimers, provided that you also include +the original English version of this License and the original versions +of those notices and disclaimers. In case of a disagreement between +the translation and the original version of this License or a notice +or disclaimer, the original version will prevail. + +If a section in the Document is Entitled ``Acknowledgements'', +``Dedications'', or ``History'', the requirement (section 4) to Preserve +its Title (section 1) will typically require changing the actual +title. + +@item +TERMINATION + +You may not copy, modify, sublicense, or distribute the Document +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense, or distribute it is void, and +will automatically terminate your rights under this License. + +However, if you cease all violation of this License, then your license +from a particular copyright holder is reinstated (a) provisionally, +unless and until the copyright holder explicitly and finally +terminates your license, and (b) permanently, if the copyright holder +fails to notify you of the violation by some reasonable means prior to +60 days after the cessation. + +Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, receipt of a copy of some or all of the same material does +not give you any rights to use it. + +@item +FUTURE REVISIONS OF THIS LICENSE + +The Free Software Foundation may publish new, revised versions +of the GNU Free Documentation License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. See +@uref{https://www.gnu.org/licenses/}. + +Each version of the License is given a distinguishing version number. +If the Document specifies that a particular numbered version of this +License ``or any later version'' applies to it, you have the option of +following the terms and conditions either of that specified version or +of any later version that has been published (not as a draft) by the +Free Software Foundation. If the Document does not specify a version +number of this License, you may choose any version ever published (not +as a draft) by the Free Software Foundation. If the Document +specifies that a proxy can decide which future versions of this +License can be used, that proxy's public statement of acceptance of a +version permanently authorizes you to choose that version for the +Document. + +@item +RELICENSING + +``Massive Multiauthor Collaboration Site'' (or ``MMC Site'') means any +World Wide Web server that publishes copyrightable works and also +provides prominent facilities for anybody to edit those works. A +public wiki that anybody can edit is an example of such a server. A +``Massive Multiauthor Collaboration'' (or ``MMC'') contained in the +site means any set of copyrightable works thus published on the MMC +site. + +``CC-BY-SA'' means the Creative Commons Attribution-Share Alike 3.0 +license published by Creative Commons Corporation, a not-for-profit +corporation with a principal place of business in San Francisco, +California, as well as future copyleft versions of that license +published by that same organization. + +``Incorporate'' means to publish or republish a Document, in whole or +in part, as part of another Document. + +An MMC is ``eligible for relicensing'' if it is licensed under this +License, and if all works that were first published under this License +somewhere other than this MMC, and subsequently incorporated in whole +or in part into the MMC, (1) had no cover texts or invariant sections, +and (2) were thus incorporated prior to November 1, 2008. + +The operator of an MMC Site may republish an MMC contained in the site +under CC-BY-SA on the same site at any time before August 1, 2009, +provided the MMC is eligible for relicensing. + +@end enumerate + +@page +@heading ADDENDUM: How to use this License for your documents + +To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and +license notices just after the title page: + +@smallexample +@group + Copyright (C) @var{year} @var{your name}. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.3 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover + Texts. A copy of the license is included in the section entitled ``GNU + Free Documentation License''. +@end group +@end smallexample + +If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, +replace the ``with@dots{}Texts.''@: line with this: + +@smallexample +@group + with the Invariant Sections being @var{list their titles}, with + the Front-Cover Texts being @var{list}, and with the Back-Cover Texts + being @var{list}. +@end group +@end smallexample + +If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. + +If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of +free software license, such as the GNU General Public License, +to permit their use in free software. + +@c Local Variables: +@c ispell-local-pdict: "ispell-dict" +@c End: diff --git a/ada-mode/doc/docstyle.texi b/ada-mode/doc/docstyle.texi new file mode 100644 index 0000000..e740439 --- /dev/null +++ b/ada-mode/doc/docstyle.texi @@ -0,0 +1,19 @@ +@c Emacs documentation style settings +@documentencoding UTF-8 +@c These two require Texinfo 5.0 or later, so we use the older +@c equivalent @set variables supported in 4.11 and hence +@ignore +@codequotebacktick on +@codequoteundirected on +@end ignore +@set txicodequoteundirected +@set txicodequotebacktick +@iftex +@c It turns out TeX sometimes fails to hyphenate, so we help it here +@hyphenation{au-to-mat-i-cal-ly} +@hyphenation{spec-i-fied} +@hyphenation{work-a-round} +@hyphenation{work-a-rounds} +@hyphenation{un-marked} +@hyphenation{dic-tion-ary} +@end iftex diff --git a/config.org b/config.org index f9ff599..642d1af 100644 --- a/config.org +++ b/config.org @@ -951,6 +951,64 @@ (add-hook 'csharp-mode-hook #'lsp-deferred) #+end_src +** Ada +*** Old ada-mode + Unfortunately, the =ada-mode= on ELPA is hot garbage. It requires + a custom parser to be built from its sources, and as far as I can + tell it's completely broken: every version I've tried to build has + produced multiple compile errors. + + There was a more basic =ada-mode= built in to Emacs, and + thankfully someone else has already done the hard work of bundling + that up -- [[https://tkurtbond.github.io/posts/2022/07/09/using-the-old-version-of-ada-mode-for-emacs/][Using the old version of Ada Mode for Emacs]]. They've + provided a ZIP file with all the neccessary files bundled into it, + which can be grabbed with the following: + + #+begin_src shell + cd ~/Downloads + curl -LO https://tkurtbond.github.io/emacs/old-ada-mode.zip + unzip -d ~/.emacs.d old-ada-mode.zip + #+end_src + + The directory =~/.emacs.d/ada-mode= than has to be added to + [[help:load-path][load-path]] and autoloaded: + + #+begin_src emacs-lisp + (let* ((home (getenv "HOME")) + (path (concat home "/.emacs.d/ada-mode"))) + (add-to-list 'load-path path)) + + (autoload 'ada-mode "ada-mode") + #+end_src + +*** LSP + =lsp-mode= with =ada_language_server= provides all the IDE-esque + niceties: + + #+begin_src emacs-lisp + (add-hook 'ada-mode-hook #'lsp-deferred) + #+end_src + + [[https://github.com/AdaCore/ada_language_server][ada_language_server]] has to be installed manually. There are linux + builds available on the [[https://github.com/AdaCore/ada_language_server/releases][GitHub releases page]]. + +*** Indentation + Set the indent width to 4: + + #+begin_src emacs-lisp + (setq ada-indent 4) + #+end_src + + Ada is definitely a tabs language, if you ask me, so we want to + enable smart tabs. Since it's not supported out-of-the-box, Ada + support must be added: + + #+begin_src emacs-lisp + (smart-tabs-add-language-support ada ada-mode-hook + ((ada-indent-current-function . ada-indent) + (ada-indent-region . ada-indent))) + #+end_src + * Tool Integrations ** Git =magit= is truly a wonderful creation! Add keybinding for