(eval-and-compile
(defun ada-check-emacs-version (major minor &optional is-xemacs)
"Returns t if Emacs's version is greater or equal to MAJOR.MINOR.
If IS-XEMACS is non-nil, check for XEmacs instead of Emacs."
(let ((xemacs-running (or (string-match "Lucid" emacs-version)
(string-match "XEmacs" emacs-version))))
(and (or (and is-xemacs xemacs-running)
(not (or is-xemacs xemacs-running)))
(or (> emacs-major-version major)
(and (= emacs-major-version major)
(>= emacs-minor-version minor)))))))
(eval-and-compile
(defconst ada-xemacs (and (boundp 'running-xemacs)
(symbol-value 'running-xemacs))
"Return t if we are using XEmacs."))
(unless ada-xemacs
(require 'outline))
(eval-and-compile
(condition-case nil (require 'find-file) (error nil)))
(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 Ada source in Emacs."
: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; -- from ada-broken-decl-indent"
: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); -- from ada-broken-indent"
: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 '("~/.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. 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)
(defcustom ada-indent 3
"*Size of Ada indentation.
An example is :
procedure Foo is
begin
>>>>>>>>>>null; -- from ada-indent"
: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.
Nil means do not auto-indent comments."
: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 -- from ada-indent-record-rel-type"
: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; -- from ada-indent-return
>>>renames Foo; -- from ada-indent-renames"
: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; -- from ada-indent-return"
: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 restart the `ada-mode' to
reread this variable."
:type 'string :group 'ada)
(defcustom ada-fill-comment-postfix " --"
"*Text inserted at the end of each line when filling a comment paragraph.
with `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: -- from ada-label-indent"
:type 'integer :group 'ada)
(defcustom ada-language-version 'ada95
"*Do we program in `ada83' or `ada95'?"
:type '(choice (const ada83) (const ada95)) :group 'ada)
(defcustom ada-move-to-declaration nil
"*Non-nil means `ada-move-to-start' moves point 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
'("." "$ADA_INCLUDE_PATH" "/usr/adainclude" "/usr/local/adainclude"
"/opt/gnu/adainclude")
"*List of directories to search for Ada files.
See the description for the `ff-search-directories' variable.
Emacs will automatically add the paths defined in your project file, and if you
are using the GNAT compiler the output of the gnatls command to find where the
runtime really is."
:type '(repeat (choice :tag "Directory"
(const :tag "default" nil)
(directory :format "%v")))
:group 'ada)
(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 -- from ada-stmt-end-indent"
: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; -- from ada-use-indent"
: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 => -- from ada-when-indent"
: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; -- from ada-with-indent"
: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)
(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-abbrev-table nil
"Local abbrev table for Ada mode.")
(defvar ada-mode-syntax-table nil
"Syntax table to be used for editing Ada source code.")
(defvar ada-mode-symbol-syntax-table nil
"Syntax table for Ada, where `_' is a word constituent.")
(eval-when-compile
(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 keywords.
This variable is used to define `ada-83-keywords' and `ada-95-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-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'.")
(defconst ada-83-keywords
(eval-when-compile
(concat "\\<" (regexp-opt ada-83-string-keywords t) "\\>"))
"Regular expression for looking at Ada83 keywords.")
(defconst ada-95-keywords
(eval-when-compile
(concat "\\<" (regexp-opt
(append
'("abstract" "aliased" "protected" "requeue"
"tagged" "until")
ada-83-string-keywords) t) "\\>"))
"Regular expression for looking at Ada95 keywords.")
(defvar ada-keywords ada-95-keywords
"Regular expression for looking at Ada keywords.")
(defconst ada-ident-re
"\\(\\sw\\|[_.]\\)+"
"Regexp matching Ada (qualified) identifiers.")
(defvar ada-procedure-start-regexp
"^[ \t]*\\(procedure\\|function\\|task\\)[ \t\n]+\\(\\(\\sw\\|[_.]\\)+\\)"
"Regexp used to find Ada procedures/functions.")
(defvar ada-package-start-regexp
"^[ \t]*\\(package\\)"
"Regexp used to find Ada packages.")
(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]*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_.]\\)+\\<is\\>" "\\|"
"^[ \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"
"if" "task" "package" "record" "protected") t)
"\\>"))
"Regexp used in ada-goto-matching-start.")
(defvar ada-matching-decl-start-re
(eval-when-compile
(concat "\\<"
(regexp-opt
'("is" "separate" "end" "declare" "if" "new" "begin" "generic" "when") t)
"\\>"))
"Regexp used in ada-goto-matching-decl-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" "package" "procedure"
"protected" "task") t) "\\>"))
"Regexp for the start of a subprogram.")
(defvar ada-named-block-re
"[ \t]*\\(\\sw\\|_\\)+[ \t]*:[^=]"
"Regexp of the name of a block or loop.")
(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.")
(defvar ada-contextual-menu
(if ada-xemacs
'("Ada"
["Goto Declaration/Body"
(ada-call-from-contextual-menu 'ada-point-and-xref)
:included (and (functionp 'ada-point-and-xref)
ada-contextual-menu-on-identifier)]
["Goto Previous Reference"
(ada-call-from-contextual-menu 'ada-xref-goto-previous-reference)
:included (functionp 'ada-xref-goto-previous-reference)]
["List References" ada-find-references
:included ada-contextual-menu-on-identifier]
["-" nil nil]
["Other File" ff-find-other-file]
["Goto Parent Unit" ada-goto-parent]
)
(let ((map (make-sparse-keymap "Ada")))
(if (equal ada-which-compiler 'gnat)
(progn
(define-key-after map [Ref]
'(menu-item "Goto Declaration/Body"
(lambda()(interactive)
(ada-call-from-contextual-menu
'ada-point-and-xref))
:visible
(and (functionp 'ada-point-and-xref)
ada-contextual-menu-on-identifier))
t)
(define-key-after map [Prev]
'(menu-item "Goto Previous Reference"
(lambda()(interactive)
(ada-call-from-contextual-menu
'ada-xref-goto-previous-reference))
:visible
(functionp 'ada-xref-goto-previous-reference))
t)
(define-key-after map [List]
'(menu-item "List References"
ada-find-references
:visible ada-contextual-menu-on-identifier) t)
(define-key-after map [-] '("-" nil) t)
))
(define-key-after map [Other] '("Other file" . ff-find-other-file) t)
(define-key-after map [Parent] '("Goto Parent Unit" . ada-goto-parent)t)
map))
"Defines the 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."
)
(defconst ada-imenu-subprogram-menu-re
"^[ \t]*\\(procedure\\|function\\)[ \t\n]+\\(\\(\\sw\\|_\\)+\\)[ \t\n]*\\([ \t\n]\\|([^)]+)\\)[ \t\n]*\\(return[ \t\n]+\\(\\sw\\|[_.]\\)+[ \t\n]*\\)?is[ \t\n]")
(defvar ada-imenu-generic-expression
(list
(list nil ada-imenu-subprogram-menu-re 2)
(list "*Specs*"
(concat
"^[ \t]*\\(procedure\\|function\\)[ \t\n]+\\(\\(\\sw\\|_\\)+\\)"
"\\("
"\\([ \t\n]+\\|[ \t\n]*([^)]+)\\)" "\\([ \t\n]*return[ \t\n]+\\(\\sw\\|[_.]\\)+[ \t\n]*\\)?"
"\\)?;") 2)
'("*Tasks*" "^[ \t]*task[ \t]+\\(\\(body\\|type\\)[ \t]+\\)?\\(\\(\\sw\\|_\\)+\\)" 3)
'("*Type Defs*" "^[ \t]*\\(sub\\)?type[ \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 two submenus, one
for type and subtype definitions, the other for subprograms declarations.
The main menu will reference the bodies of the subprograms.")
(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)
"Replaces `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 this line:
foo.adb:61:11: [...] in call to size declared at foo.ads:11
both file locations can be clicked on and jumped to."
(interactive "d")
(goto-char pos)
(skip-chars-backward "-a-zA-Z0-9_:./\\")
(cond
((and (not (bolp))
(looking-at
"\\([-_.a-zA-Z0-9]+\\):\\([0-9]+\\)\\(:\\([0-9]+\\)\\)?"))
(let ((line (match-string 2))
(error-pos (point-marker))
source)
(save-excursion
(save-restriction
(widen)
(set-buffer (funcall (symbol-function 'compilation-find-file)
(point-marker) (match-string 1)
"./"))
(if (stringp line)
(goto-line (string-to-number line)))
(setq source (point-marker))))
(funcall (symbol-function 'compilation-goto-locus)
(cons source error-pos))
))
(t
(funcall (symbol-function 'compile-goto-error)))
)
(recenter))
(defun ada-create-syntax-table ()
"Create the two syntax tables use in the Ada mode.
The standard table declares `_' as a symbol constituent, the second one
declares it as a word constituent."
(interactive)
(setq ada-mode-syntax-table (make-syntax-table))
(set-syntax-table ada-mode-syntax-table)
(modify-syntax-entry ?% "$" ada-mode-syntax-table)
(modify-syntax-entry ?\" "\"" ada-mode-syntax-table)
(modify-syntax-entry ?: "." ada-mode-syntax-table)
(modify-syntax-entry ?\ (modify-syntax-entry ?& "." ada-mode-syntax-table)
(modify-syntax-entry ?\| "." ada-mode-syntax-table)
(modify-syntax-entry ?+ "." ada-mode-syntax-table)
(modify-syntax-entry ?* "." ada-mode-syntax-table)
(modify-syntax-entry ?/ "." ada-mode-syntax-table)
(modify-syntax-entry ?= "." ada-mode-syntax-table)
(modify-syntax-entry ?< "." ada-mode-syntax-table)
(modify-syntax-entry ?> "." ada-mode-syntax-table)
(modify-syntax-entry ?$ "." ada-mode-syntax-table)
(modify-syntax-entry ?\[ "." ada-mode-syntax-table)
(modify-syntax-entry ?\] "." ada-mode-syntax-table)
(modify-syntax-entry ?\{ "." ada-mode-syntax-table)
(modify-syntax-entry ?\} "." ada-mode-syntax-table)
(modify-syntax-entry ?. "." ada-mode-syntax-table)
(modify-syntax-entry ?\\ "." ada-mode-syntax-table)
(modify-syntax-entry ?\' "." ada-mode-syntax-table)
(modify-syntax-entry ?- ". 12" ada-mode-syntax-table)
(if ada-xemacs
(modify-syntax-entry ?# "<" ada-mode-syntax-table)
(modify-syntax-entry ?# "$" ada-mode-syntax-table))
(modify-syntax-entry ?\f "> " ada-mode-syntax-table)
(modify-syntax-entry ?\n "> " ada-mode-syntax-table)
(modify-syntax-entry ?_ "_" ada-mode-syntax-table)
(modify-syntax-entry ?\( "()" ada-mode-syntax-table)
(modify-syntax-entry ?\) ")(" ada-mode-syntax-table)
(setq ada-mode-symbol-syntax-table (copy-syntax-table ada-mode-syntax-table))
(modify-syntax-entry ?_ "w" ada-mode-symbol-syntax-table)
)
(if ada-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 "\\(#[0-9a-fA-F]*#\\)" 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)))))))
(defun ada-deactivate-properties ()
"Deactivate ada-mode's properties handling.
This would be a duplicate of font-lock if both are used at the same time."
(remove-hook 'after-change-functions 'ada-after-change-function t))
(defun ada-initialize-properties ()
"Initialize some special text properties in the whole buffer.
In particular, character constants are said to be strings, #...# are treated
as numbers instead of gnatprep comments."
(save-excursion
(save-restriction
(widen)
(goto-char (point-min))
(while (re-search-forward "'.'" nil t)
(add-text-properties (match-beginning 0) (match-end 0)
'(syntax-table ("'" . ?\"))))
(goto-char (point-min))
(while (re-search-forward "^[ \t]*#" nil t)
(add-text-properties (match-beginning 0) (match-end 0)
'(syntax-table (11 . 10))))
(set-buffer-modified-p nil)
;; Setting this only if font-lock is not set won't work
;; if the user activates or deactivates font-lock-mode,
;; but will make things faster most of the time
(make-local-hook 'after-change-functions)
(add-hook 'after-change-functions 'ada-after-change-function nil t)
)))
(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."
(let ((inhibit-point-motion-hooks t)
(eol (point)))
(save-excursion
(save-match-data
(beginning-of-line)
(remove-text-properties (point) eol '(syntax-table nil))
(while (re-search-forward "'.'" eol t)
(add-text-properties (match-beginning 0) (match-end 0)
'(syntax-table ("'" . ?\"))))
(beginning-of-line)
(if (looking-at "^[ \t]*#")
(add-text-properties (match-beginning 0) (match-end 0)
'(syntax-table (11 . 10))))
))))
;;------------------------------------------------------------------
;; Testing the grammatical context
;;------------------------------------------------------------------
(defsubst ada-in-comment-p (&optional parse-result)
"Returns t if inside a comment."
(nth 4 (or parse-result
(parse-partial-sexp
(save-excursion (beginning-of-line) (point)) (point)))))
(defsubst ada-in-string-p (&optional parse-result)
"Returns t if point is inside a string.
If parse-result is non-nil, use is instead of calling parse-partial-sexp."
(nth 3 (or parse-result
(parse-partial-sexp
(save-excursion (beginning-of-line) (point)) (point)))))
(defsubst ada-in-string-or-comment-p (&optional parse-result)
"Returns t if inside a comment or string."
(setq parse-result (or parse-result
(parse-partial-sexp
(save-excursion (beginning-of-line) (point)) (point))))
(or (ada-in-string-p parse-result) (ada-in-comment-p parse-result)))
;;------------------------------------------------------------------
;; 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)))
))
(let (choice)
(if ada-xemacs
(setq choice (funcall (symbol-function 'popup-menu)
ada-contextual-menu))
(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)
(condition-case nil
(progn
(require 'speedbar)
(funcall (symbol-function 'speedbar-add-supported-extension)
spec)
(funcall (symbol-function 'speedbar-add-supported-extension)
body)))
)
;;;###autoload
(defun ada-mode ()
"Ada mode is the major mode for editing Ada code.
Bindings are as follows: (Note: 'LFD' is control-j.)
Indent line '\\[ada-tab]'
Indent line, insert newline and indent the new line. '\\[newline-and-indent]'
Re-format the parameter-list point is in '\\[ada-format-paramlist]'
Indent all lines in region '\\[ada-indent-region]'
Adjust case of identifiers and keywords in region '\\[ada-adjust-case-region]'
Adjust case of identifiers and keywords in buffer '\\[ada-adjust-case-buffer]'
Fill comment paragraph, justify and append postfix '\\[fill-paragraph]'
Next func/proc/task '\\[ada-next-procedure]' Previous func/proc/task '\\[ada-previous-procedure]'
Next package '\\[ada-next-package]' Previous package '\\[ada-previous-package]'
Goto matching start of current 'end ... Goto end of current block '\\[ada-move-to-end]'
Comments are handled using standard GNU Emacs conventions, including:
Start a comment '\\[indent-for-comment]'
Comment region '\\[comment-region]'
Uncomment region '\\[ada-uncomment-region]'
Continue comment on next line '\\[indent-new-comment-line]'
If you use imenu.el:
Display index-menu of functions & procedures '\\[imenu]'
If you use find-file.el:
Switch to other file (Body <-> Spec) '\\[ff-find-other-file]'
or '\\[ff-mouse-find-other-file]
Switch to other file in other window '\\[ada-ff-other-window]'
or '\\[ff-mouse-find-other-file-other-window]
If you use this function in a spec and no body is available, it gets created with body stubs.
If you use ada-xref.el:
Goto declaration: '\\[ada-point-and-xref]' on the identifier
or '\\[ada-goto-declaration]' with point on the identifier
Complete identifier: '\\[ada-complete-identifier]'."
(interactive)
(kill-all-local-variables)
(set (make-local-variable 'require-final-newline) t)
(make-local-variable 'comment-start)
(if ada-fill-comment-prefix
(setq comment-start ada-fill-comment-prefix)
(setq comment-start "-- "))
;; 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
(set (make-local-variable 'comment-padding) 0)
(set (make-local-variable 'parse-sexp-ignore-comments) t)
(set (make-local-variable 'parse-sexp-lookup-properties) t)
(setq case-fold-search t)
(setq imenu-case-fold-search t)
(set (make-local-variable 'fill-paragraph-function)
'ada-fill-comment-paragraph)
(set (make-local-variable 'imenu-generic-expression)
ada-imenu-generic-expression)
;; Support for compile.el
;; We just substitute our own functions to go to the error.
(add-hook 'compilation-mode-hook
(lambda()
(set (make-local-variable 'compile-auto-highlight) 40)
;; 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
(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)
(setq ff-post-load-hooks 'ada-set-point-accordingly
ff-file-created-hooks 'ada-make-body)
(add-hook 'ff-pre-load-hooks 'ada-which-function-are-we-in)
;; Some special constructs for find-file.el
;; We do not need to add the construction for 'with', which is in the
;; standard find-file.el
(make-local-variable 'ff-special-constructs)
;; Go to the parent package :
(add-to-list 'ff-special-constructs
(cons (eval-when-compile
(concat "^\\(private[ \t]\\)?[ \t]*package[ \t]+"
"\\(body[ \t]+\\)?"
"\\(\\(\\sw\\|[_.]\\)+\\)\\.\\(\\sw\\|_\\)+[ \t\n]+is"))
(lambda ()
(setq fname (ff-get-file
ada-search-directories
(ada-make-filename-from-adaname
(match-string 3))
ada-spec-suffixes)))))
;; Another special construct for find-file.el : when in a separate clause,
;; go to the correct package.
(add-to-list 'ff-special-constructs
(cons "^separate[ \t\n]*(\\(\\(\\sw\\|[_.]\\)+\\))"
(lambda ()
(setq fname (ff-get-file
ada-search-directories
(ada-make-filename-from-adaname
(match-string 1))
ada-spec-suffixes)))))
;; Another special construct, that redefines the one in find-file.el. The
;; old one can handle only one possible type of extension for Ada files
;; remove from the list the standard "with..." that is put by find-file.el,
;; since it uses the old ada-spec-suffix variable
;; This one needs to replace the standard one defined in find-file.el (with
;; Emacs <= 20.4), since that one uses the old variable ada-spec-suffix
(let ((old-construct
(assoc "^with[ \t]+\\([a-zA-Z0-9_\\.]+\\)" ff-special-constructs))
(new-cdr
(lambda ()
(setq fname (ff-get-file
ada-search-directories
(ada-make-filename-from-adaname
(match-string 1))
ada-spec-suffixes)))))
(if old-construct
(setcdr old-construct new-cdr)
(add-to-list 'ff-special-constructs
(cons "^with[ \t]+\\([a-zA-Z0-9_\\.]+\\)"
new-cdr))))
;; 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-sort-function 'imenu--sort-by-name)
;; Support for which-function-mode is provided in ada-support (support
;; for nested subprograms)
;; 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 need to "M-x abbrev-mode"
(define-abbrev-table 'ada-mode-abbrev-table ())
(setq local-abbrev-table ada-mode-abbrev-table)
;; Support for indent-new-comment-line (Especially for XEmacs)
(setq comment-multi-line nil)
(setq major-mode 'ada-mode)
(setq mode-name "Ada")
(use-local-map ada-mode-map)
(easy-menu-add ada-mode-menu ada-mode-map)
(set-syntax-table ada-mode-syntax-table)
(if ada-clean-buffer-before-saving
(progn
;; remove all spaces at the end of lines in the whole buffer.
(add-hook 'local-write-file-hooks 'delete-trailing-whitespace)
;; convert all tabs to the correct number of spaces.
(add-hook 'local-write-file-hooks
(lambda () (untabify (point-min) (point-max))))))
(run-hooks 'ada-mode-hook)
;; Run this after the hook to give the users a chance to activate
;; font-lock-mode
(unless ada-xemacs
(ada-initialize-properties)
(make-local-hook 'font-lock-mode-hook)
(add-hook 'font-lock-mode-hook 'ada-deactivate-properties nil t))
;; the following has to be done after running the ada-mode-hook
;; because users might want to set the values of these variable
;; inside the hook (MH)
(cond ((eq ada-language-version 'ada83)
(setq ada-keywords ada-83-keywords))
((eq ada-language-version 'ada95)
(setq ada-keywords ada-95-keywords)))
(if ada-auto-case
(ada-activate-keys-for-case)))
;;-----------------------------------------------------------------
;; 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-create-case-exception (&optional word)
"Defines 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 words is added to the first file in `ada-case-exception-file'.
The standard casing rules will no longer apply to this word."
(interactive)
(let ((previous-syntax-table (syntax-table))
(exception-list '())
file-name
)
(cond ((stringp ada-case-exception-file)
(setq file-name ada-case-exception-file))
((listp ada-case-exception-file)
(setq file-name (car ada-case-exception-file)))
(t
(error "No exception file specified")))
(set-syntax-table ada-mode-symbol-syntax-table)
(unless word
(save-excursion
(skip-syntax-backward "w")
(setq word (buffer-substring-no-properties
(point) (save-excursion (forward-word 1) (point))))))
;; Reread the exceptions file, in case it was modified by some other,
;; and to keep the end-of-line comments that may exist in it.
(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))
(add-to-list 'exception-list
(list
(buffer-substring-no-properties
(point) (save-excursion (forward-word 1) (point)))
(buffer-substring-no-properties
(save-excursion (forward-word 1) (point))
(save-excursion (end-of-line) (point)))
t))
(forward-line 1))
(kill-buffer nil)
(set-buffer buffer)))
;; If the word is already in the list, even with a different casing
;; we simply want to replace it.
(if (and (not (equal exception-list '()))
(assoc-ignore-case word exception-list))
(setcar (assoc-ignore-case word exception-list)
word)
(add-to-list 'exception-list (list word "" t))
)
(if (and (not (equal ada-case-exception '()))
(assoc-ignore-case word ada-case-exception))
(setcar (assoc-ignore-case word ada-case-exception)
word)
(add-to-list 'ada-case-exception (cons word t))
)
;; Save the list in the file
(find-file (expand-file-name file-name))
(erase-buffer)
(mapcar (lambda (x) (insert (car x) (nth 1 x) "\n"))
(sort exception-list
(lambda(a b) (string< (car a) (car b)))))
(save-buffer)
(kill-buffer nil)
(set-syntax-table previous-syntax-table)
))
(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 1) (point)))))
(unless (assoc-ignore-case word ada-case-exception)
(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 '())
(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-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) ?_))
(funcall ada-case-identifier -1)
(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-ignore-case (buffer-substring start end)
ada-case-exception))
(progn
(delete-region start end)
(insert (car match)))
;; Else simply re-case the word
(funcall ada-case-identifier -1))))))
(defun ada-after-keyword-p ()
"Returns t if cursor is after a keyword that is not an attribute."
(save-excursion
(forward-word -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 just typed character.
If FORCE-IDENTIFIER is non-nil then also adjust keyword as identifier."
(forward-char -1)
(if (and (> (point) 1)
;; or if at the end of a character constant
(not (and (eq (char-after) ?')
(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 (save-excursion
(forward-word -1)
(or (= (point) (point-min))
(backward-char 1))
(= (char-after) ?'))
(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 \C-u."
(interactive "P")
(if ada-auto-case
(let ((lastk last-command-char)
(previous-syntax-table (syntax-table)))
(unwind-protect
(progn
(set-syntax-table ada-mode-symbol-syntax-table)
(cond ((or (eq lastk ?\n)
(eq lastk ?\r))
;; horrible kludge
(insert " ")
(ada-adjust-case)
;; horrible dekludge
(delete-backward-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))
)
;; Restore the syntax table
(set-syntax-table previous-syntax-table))
)
;; Else, no auto-casing
(cond
((eq last-command-char ?\n)
(funcall ada-lfd-binding))
((eq last-command-char ?\r)
(funcall ada-ret-binding))
(t
(self-insert-command (prefix-numeric-value arg))))
))
(defun ada-activate-keys-for-case ()
"Modifies 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)
"Does nothing.
This function can be used for the auto-casing variables in the ada-mode, to
adapt to unusal 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."
)
(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))))
(modify-syntax-entry ?_ "_")
(capitalize-region begin end)
(modify-syntax-entry ?_ "w")))
(defun ada-adjust-case-region (from to)
"Adjusts 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)
(previous-syntax-table (syntax-table)))
(message "Adjusting case ...")
(unwind-protect
(save-excursion
(set-syntax-table ada-mode-symbol-syntax-table)
(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"))
(set-syntax-table previous-syntax-table))))
(defun ada-adjust-case-buffer ()
"Adjusts 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:
;; ( (<Param_Name> in? out? access? <Type_Name> <Default_Expression>)
;; ... )
;; 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 reformating will fail.
;;--------------------------------------------------------------
(defun ada-format-paramlist ()
"Reformats the parameter list point is in."
(interactive)
(let ((begin nil)
(end nil)
(delend nil)
(paramlist nil)
(previous-syntax-table (syntax-table)))
(unwind-protect
(progn
(set-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 "\\|\\<body\\>" ) 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))
;; restore syntax-table
(set-syntax-table previous-syntax-table)
)))
(defun ada-scan-paramlist (begin end)
"Scan the parameter list found in between BEGIN and END.
Returns 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]* (progn
(setq epos (car match-cons))
(setq semipos (cdr match-cons)))
(setq epos end))
(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)
(setq apos (point))
(setq param
(append param
(list
(consp
(ada-search-ignore-string-comment
"in" nil epos t 'word-search-forward)))))
(goto-char apos)
(setq param
(append param
(list
(consp
(ada-search-ignore-string-comment
"out" nil epos t 'word-search-forward)))))
(goto-char apos)
(setq param
(append param
(list
(consp
(ada-search-ignore-string-comment
"access" nil epos t 'word-search-forward)))))
(goto-char apos)
(ada-goto-next-non-ws)
(while (looking-at "\\<\\(in\\|out\\|access\\)\\>")
(forward-word 1)
(ada-goto-next-non-ws))
(looking-at "\\<\\(\\sw\\|[_.' \t]\\)+\\>")
(setq param
(append param
(list (match-string 0))))
(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))))
(setq paramlist (append paramlist (list param)))
(if (eq epos end)
(setq notend nil)
(goto-char semipos))
)
(reverse paramlist)))
(defun ada-insert-paramlist (paramlist)
"Inserts a formatted PARAMLIST in the buffer."
(let ((i (length paramlist))
(parlen 0)
(typlen 0)
(inp nil)
(outp nil)
(accessp nil)
(column nil)
(firstcol nil))
(while (not (zerop i))
(setq i (1- i))
(setq parlen (max parlen (length (nth 0 (nth i paramlist)))))
(setq typlen (max typlen (length (nth 4 (nth i paramlist)))))
(setq inp (or inp (nth 1 (nth i paramlist))))
(setq outp (or outp (nth 2 (nth i paramlist))))
(setq accessp (or accessp (nth 3 (nth i paramlist))))
)
(if (save-excursion
(re-search-backward "^.\\|[^ \t]" nil t)
(looking-at "^."))
(progn
(ada-indent-current)
(save-excursion
(if (looking-at "\\(is\\|return\\)")
(replace-match " \\1"))))
(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))
(while (not (zerop i))
(setq i (1- i))
(setq column firstcol)
(insert (nth 0 (nth i paramlist)))
(indent-to (+ column parlen 1))
(insert ": ")
(setq column (current-column))
(if (nth 1 (nth i paramlist))
(insert "in ")
(if (and
(or inp
accessp)
(not (nth 3 (nth i paramlist))))
(insert " ")))
(if (nth 2 (nth i paramlist))
(insert "out ")
(if (and
(or outp
accessp)
(not (nth 3 (nth i paramlist))))
(insert " ")))
(if (nth 3 (nth i paramlist))
(insert "access "))
(setq column (current-column))
(insert (nth 4 (nth i paramlist)))
(if (nth 5 (nth i paramlist))
(progn
(indent-to (+ column typlen 1))
(insert (nth 5 (nth i paramlist)))))
(if (zerop i)
(insert ")")
(insert ";")
(newline)
(indent-to firstcol))
)
(unless (looking-at "[ \t]*\\(;\\|\n\\|is\\|return\\)")
(ada-indent-newline-indent))
))
(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)))
(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 ()
"Indents the current line, inserts a newline and then indents 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 indented first if `ada-indent-after-return' is non-nil.
This function is intended to be bound to the \C-m and \C-j keys."
(interactive "*")
(if ada-indent-after-return (ada-indent-current))
(newline)
(ada-indent-current))
(defun ada-justified-indent-current ()
"Indent the current line and explains how the calculation was done."
(interactive)
(let ((cur-indent (ada-indent-current)))
(message nil)
(if (equal (cdr cur-indent) '(0))
(message "same indentation")
(message (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 Unix/Windows 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 (concat "formating " 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 ()
"Moves point to the beginning of the previous word of Ada code.
Returns 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.
Returns the calculation that was done, including the reference point and the
offset."
(interactive)
(let ((previous-syntax-table (syntax-table))
(orgpoint (point-marker))
cur-indent tmp-indent
prev-indent)
(unwind-protect
(progn
(set-syntax-table ada-mode-symbol-syntax-table)
(if ada-xemacs
(ad-activate 'parse-partial-sexp t))
(save-excursion
(setq cur-indent
(if (save-excursion (zerop (forward-line -1)))
(progn
(back-to-indentation)
(ada-get-current-indent))
(list (point-min) 0))))
(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)))
(if (= (save-excursion (back-to-indentation) (current-column)) prev-indent)
nil
(beginning-of-line)
(delete-horizontal-space)
(indent-to prev-indent))
(goto-char orgpoint)
(if (< (current-column) (current-indentation))
(back-to-indentation)))
(set-syntax-table previous-syntax-table)
(if ada-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
((and ada-indent-to-open-paren
(not (ada-in-paramlist-p))
(setq column (ada-in-open-paren-p)))
(save-excursion
(if (and (skip-chars-backward " \t")
(= (char-before) ?\n)
(not (forward-comment -10000))
(= (char-before) ?>))
(list column 'ada-broken-indent)
(list column 0))))
((not (char-after))
(ada-indent-on-previous-lines nil orgpoint orgpoint))
((= (char-after) ?e)
(cond
((looking-at "end\\>")
(let ((label 0)
limit)
(save-excursion
(ada-goto-matching-start 1)
(if (save-excursion
(beginning-of-line)
(looking-at ".+\\<loop\\>"))
(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 "\\<loop\\>"))))
(progn
(goto-char (car match-cons))
(save-excursion
(beginning-of-line)
(if (looking-at ada-named-block-re)
(setq label (- ada-label-indent))))))))
(list (+ (save-excursion (back-to-indentation) (point)) label) 0))))
((looking-at "exception\\>")
(save-excursion
(ada-goto-matching-start 1)
(list (save-excursion (back-to-indentation) (point)) 0)))
((looking-at "else\\>")
(if (save-excursion (ada-goto-previous-word)
(looking-at "\\<or\\>"))
(ada-indent-on-previous-lines nil orgpoint orgpoint)
(save-excursion
(ada-goto-matching-start 1 nil t)
(list (progn (back-to-indentation) (point)) 0))))
((looking-at "elsif\\>")
(save-excursion
(ada-goto-matching-start 1 nil t)
(list (progn (back-to-indentation) (point)) 0)))
))
((and (= (char-after) ?w)
(looking-at "when\\>"))
(save-excursion
(ada-goto-matching-start 1)
(list (save-excursion (back-to-indentation) (point))
'ada-when-indent)))
((and (= (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
(ada-search-ignore-string-comment
"\\<\\(elsif\\|if\\|select\\)\\>" t nil)
(list (progn (back-to-indentation) (point))
'ada-stmt-end-indent))))
((and (= (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 "\\<loop\\>")
(ada-indent-on-previous-lines nil orgpoint orgpoint)
(list (progn (back-to-indentation) (point)) 'ada-stmt-end-indent)))))
((and (= (char-after) ?b)
(looking-at "begin\\>"))
(save-excursion
(if (ada-goto-matching-decl-start t)
(list (progn (back-to-indentation) (point)) 0)
(ada-indent-on-previous-lines nil orgpoint orgpoint))))
((and (= (char-after) ?i)
(looking-at "is\\>"))
(if (and ada-indent-is-separate
(save-excursion
(goto-char (match-end 0))
(ada-goto-next-non-ws (save-excursion (end-of-line)
(point)))
(looking-at "\\<abstract\\>\\|\\<separate\\>")))
(save-excursion
(ada-goto-stmt-start)
(list (progn (back-to-indentation) (point)) 'ada-indent))
(save-excursion
(ada-goto-stmt-start)
(list (progn (back-to-indentation) (point)) 'ada-stmt-end-indent))))
((= (char-after) ?r)
(cond
((looking-at "record\\>")
(save-excursion
(ada-search-ignore-string-comment
"\\<\\(type\\|use\\)\\>" t nil)
(if (looking-at "\\<use\\>")
(ada-search-ignore-string-comment "for" t nil nil 'word-search-backward))
(list (progn (back-to-indentation) (point)) 'ada-indent-record-rel-type)))
((looking-at "re\\(turn\\|names\\)\\>")
(save-excursion
(let ((var 'ada-indent-return))
(if (looking-at "renames")
(let (pos)
(save-excursion
(setq pos (ada-search-ignore-string-comment ";\\|return\\>" t)))
(if (and pos
(= (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 -1))
(let ((num-back 1))
(if (and (= (char-after) ?\()
(save-excursion
(or (progn
(backward-word 1)
(looking-at "function\\>"))
(progn
(backward-word 1)
(setq num-back 2)
(looking-at "function\\>")))))
(if (<= (eval var) 0)
(list (point) (list '- var))
(list (progn (backward-word num-back) (point))
var))
(if (and (> (eval var) 0)
(save-excursion (forward-word -1)
(looking-at "function\\>")))
(list (progn (forward-word -1) (point)) var)
(ada-indent-on-previous-lines nil orgpoint orgpoint)))))))
))
((and (or (= (char-after) ?o)
(= (char-after) ?p))
(or (ada-looking-at-semi-or)
(ada-looking-at-semi-private)))
(save-excursion
(ada-goto-matching-start 1)
(list (progn (back-to-indentation) (point)) 0)))
((and (= (char-after) ?d)
(looking-at "do\\>"))
(save-excursion
(ada-goto-stmt-start)
(list (progn (back-to-indentation) (point)) 'ada-stmt-end-indent)))
((= (char-after) ?-)
(if ada-indent-comment-as-code
(let (pos)
(if (and ada-indent-align-comments
(save-excursion
(forward-line -1)
(beginning-of-line)
(while (and (not pos)
(search-forward "--"
(save-excursion
(end-of-line) (point))
t))
(unless (ada-in-string-p)
(setq pos (point))))
pos))
(list (- pos 2) 0)
(ada-indent-on-previous-lines nil orgpoint orgpoint)))
(list (save-excursion (back-to-indentation) (point)) 0)))
((and (= (char-after) ?#)
(equal ada-which-compiler 'gnat)
(looking-at "#[ \t]*\\(if\\|els\\(e\\|if\\)\\|end[ \t]*if\\)"))
(list (save-excursion (beginning-of-line) (point)) 0))
((and (not (eobp)) (= (char-after) ?\)))
(save-excursion
(forward-char 1)
(backward-sexp 1)
(list (point) 0)))
((looking-at "\\(new\\|abstract\\|separate\\)\\>")
(ada-indent-on-previous-lines nil orgpoint orgpoint))
((and (or (= (char-after) ?p) (= (char-after) ?f))
(looking-at "\\<\\(package\\|function\\|procedure\\)\\>"))
(save-excursion
(let (found)
(while (and (not found)
(ada-search-ignore-string-comment
"\\<\\(generic\\|end\\|begin\\|package\\|procedure\\|function\\)\\>" t))
(save-excursion
(forward-word -1)
(setq found (not (looking-at "with"))))))
(if (looking-at "generic")
(list (progn (back-to-indentation) (point)) 0)
(ada-indent-on-previous-lines nil orgpoint orgpoint))))
((looking-at "\\(\\sw\\|_\\)+[ \t\n]*:[^=]")
(if (ada-in-decl-p)
(ada-indent-on-previous-lines nil orgpoint orgpoint)
(append (ada-indent-on-previous-lines nil orgpoint orgpoint)
'(ada-label-indent))))
))
(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)))
(if (ada-in-paramlist-p)
(ada-get-indent-paramlist)
(unless nomove
(ada-goto-stmt-start))
(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 "\\(sub\\)?type\\>")
(ada-get-indent-type orgpoint))
((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 "\\(\\sw\\|_\\)+[ \t\n]*:[^=]")
(ada-get-indent-label orgpoint))
((looking-at "separate\\>")
(ada-get-indent-nochange))
((looking-at "with\\>\\|use\\>")
(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 ()
"Calculates 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 ()
"Calculates the indentation when point is inside a parameter list."
(save-excursion
(ada-search-ignore-string-comment "[^ \t\n]" t nil t)
(cond
((= (char-after) ?\()
(goto-char (match-end 0))
(list (point) 0))
((= (char-after) ?\ (goto-char (cdr (ada-search-ignore-string-comment "(\\|;" t nil t)))
(ada-goto-next-non-ws)
(list (point) 0))
(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)
"Calculates 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))
(if (save-excursion
(ada-search-ignore-string-comment ";" nil orgpoint nil
'search-forward))
(progn
(forward-word 1)
(ada-goto-next-non-ws)
(cond
((looking-at "\\<\\(loop\\|select\\|if\\|case\\)\\>")
(save-excursion (ada-check-matching-start (match-string 0)))
(list (save-excursion (back-to-indentation) (point)) 0))
((looking-at "\\<record\\>")
(save-excursion
(ada-check-matching-start (match-string 0))
(forward-word 1)
(ada-goto-stmt-start)
(unless (looking-at "\\(for\\|type\\)\\>")
(ada-search-ignore-string-comment "\\<type\\>" t))
(list (progn (back-to-indentation) (point)) 0)))
((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))
((= (char-after) ?\ (save-excursion
(ada-goto-matching-start 0)
(if (looking-at "\\<begin\\>")
(progn
(setq indent (list (point) 0))
(if (ada-goto-matching-decl-start t)
(list (progn (back-to-indentation) (point)) 0)
indent)))))
(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)
"Calculates 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
((save-excursion
(setq match-cons (and
(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)))
((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))
((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))
(t
(list (save-excursion (back-to-indentation) (point))
'ada-broken-indent)))))
(defun ada-get-indent-when (orgpoint)
"Calculates 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)
"Calculates 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))
(while (and (setq match-cons (ada-search-ignore-string-comment
"\\<\\(then\\|and[ \t]*then\\)\\>"
nil orgpoint))
(= (char-after (car match-cons)) ?a)))
(if match-cons
(progn
(if (save-excursion
(back-to-indentation)
(looking-at "\\<then\\>"))
(setq cur-indent (save-excursion (back-to-indentation) (point))))
(forward-word 1)
(list cur-indent 'ada-indent))
(list cur-indent 'ada-broken-indent))))
(defun ada-get-indent-block-start (orgpoint)
"Calculates 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 1)
(setq pos (ada-goto-next-non-ws orgpoint)))
(goto-char pos)
(save-excursion
(ada-indent-on-previous-lines t orgpoint)))
(t
(list (save-excursion (back-to-indentation) (point)) 'ada-indent)))))
(defun ada-get-indent-subprog (orgpoint)
"Calculates 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))
(if (save-excursion
(setq match-cons
(ada-search-ignore-string-comment
"\\<\\(is\\|do\\)\\>" nil orgpoint)))
(progn
(setq foundis t)
(goto-char (cdr match-cons)))
(progn
(unless (ada-goto-next-non-ws orgpoint)
(goto-char orgpoint))))
(cond
((and
foundis
(save-excursion
(not (ada-search-ignore-string-comment
"[^ \t\n]" nil orgpoint t))))
(list cur-indent 'ada-indent))
((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))
((and
foundis
(save-excursion (setq match-cons (ada-goto-next-non-ws orgpoint)))
(goto-char match-cons)
(ada-indent-on-previous-lines t orgpoint)))
((save-excursion
(ada-search-ignore-string-comment ";" nil orgpoint nil 'search-forward))
(list cur-indent 0))
(t
(list cur-indent 'ada-broken-indent)))))
(defun ada-get-indent-noindent (orgpoint)
"Calculates 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
((ada-in-paramlist-p)
(ada-previous-procedure)
(list (save-excursion (back-to-indentation) (point)) 0))
((looking-at "[ \t]*\\(\\sw\\|_\\)*[ \t]*,[ \t]*$")
(list (save-excursion (back-to-indentation) (point))
'ada-broken-decl-indent))
(t
(if (looking-at ada-named-block-re)
(setq label (- ada-label-indent))
(let (p)
(if (or (save-excursion
(and (ada-search-ignore-string-comment "\\<private\\>" nil orgpoint)
(setq p (point))
(save-excursion (forward-char -7) (ada-goto-previous-word)
(looking-at "with"))))
(save-excursion
(and (ada-search-ignore-string-comment "\\<record\\>" nil orgpoint)
(setq p (point))
(save-excursion (forward-char -6) (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-label (orgpoint)
"Calculates 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
((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))
((save-excursion
(setq match-cons (ada-search-ignore-string-comment
"\\<declare\\|begin\\>" nil orgpoint)))
(goto-char (car match-cons))
(list (save-excursion (back-to-indentation) (point)) 'ada-indent))
((ada-in-decl-p)
(if (save-excursion
(ada-search-ignore-string-comment ";" nil orgpoint))
(list cur-indent 0)
(list cur-indent 'ada-broken-indent)))
(t
(list cur-indent '(- ada-label-indent))))))
(defun ada-get-indent-loop (orgpoint)
"Calculates 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))
(label (save-excursion
(beginning-of-line)
(if (looking-at ada-named-block-re)
(- ada-label-indent)
0))))
(cond
((save-excursion
(ada-search-ignore-string-comment ";" nil orgpoint nil
'search-forward))
(list (+ (save-excursion (back-to-indentation) (point)) label) 0))
((looking-at "loop\\>")
(setq pos (ada-get-indent-block-start orgpoint))
(if (equal label 0)
pos
(list (+ (car pos) label) (cdr pos))))
((looking-at "for\\>")
(cond
((save-excursion
(and
(goto-char (match-end 0))
(ada-goto-next-non-ws orgpoint)
(forward-word 1)
(if (= (char-after) ?') (forward-word 1) t)
(ada-goto-next-non-ws orgpoint)
(looking-at "\\<use\\>")
(progn
(setq match-cons (ada-search-ignore-string-comment
"record" nil orgpoint nil 'word-search-forward))
t)))
(if match-cons
(goto-char (car match-cons)))
(list (save-excursion (back-to-indentation) (point)) 'ada-indent))
((save-excursion
(setq match-cons (ada-search-ignore-string-comment
"loop" nil orgpoint nil 'word-search-forward)))
(goto-char (car match-cons))
(unless (save-excursion
(back-to-indentation)
(looking-at "\\<loop\\>"))
(goto-char pos))
(list (+ (save-excursion (back-to-indentation) (point)) label)
'ada-indent))
(t
(list (+ (save-excursion (back-to-indentation) (point)) label)
'ada-broken-indent))))
((looking-at "while\\>")
(if (save-excursion
(setq match-cons (ada-search-ignore-string-comment
"loop" nil orgpoint nil 'word-search-forward)))
(progn
(goto-char (car match-cons))
(unless (save-excursion
(back-to-indentation)
(looking-at "\\<loop\\>"))
(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)
"Calculates the indentation when before a type statement.
ORGPOINT is the limit position used in the calculation."
(let ((match-dat nil))
(cond
((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 "\\<record\\>")
(forward-word 1)
(ada-goto-next-non-ws)
(= (char-after) ?\ (goto-char (car match-dat))
(list (save-excursion (back-to-indentation) (point)) 0))
((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))
((save-excursion
(ada-search-ignore-string-comment ";" nil orgpoint nil
'search-forward))
(list (save-excursion (back-to-indentation) (point)) 0))
((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))
(t
(list (save-excursion (back-to-indentation) (point))
'ada-broken-indent)))))
(defun ada-goto-stmt-start ()
"Moves point to the beginning of the statement that point is in or after.
Returns 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
(unless (looking-at "declare")
(progn
(unless (save-excursion
(goto-char (cdr match-dat))
(ada-goto-next-non-ws orgpoint))
(setq match-dat (ada-search-prev-end-stmt)))
(if match-dat
(goto-char (cdr match-dat)))
(ada-goto-next-non-ws)
))
(progn
(goto-char (point-min))
(unless (ada-goto-next-non-ws orgpoint)
(goto-char orgpoint))))
(point)))
(defun ada-search-prev-end-stmt ()
"Moves point to previous end-statement.
Returns a cons cell whose car is the beginning and whose cdr the end of the
match."
(let ((match-dat nil)
(found nil))
(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)
(if (and (looking-at
"\\<\\(record\\|loop\\|select\\|else\\|then\\)\\>")
(save-excursion
(ada-goto-previous-word)
(looking-at "\\<\\(end\\|or\\|and\\)\\>[ \t]*[^;]")))
(forward-word -1)
(save-excursion
(goto-char (cdr match-dat))
(ada-goto-next-non-ws)
(looking-at "(")
(unless (looking-at
(eval-when-compile
(concat "\\<"
(regexp-opt '("separate" "access" "array"
"abstract" "new") t)
"\\>\\|(")))
(setq found t))))
))
(if found
match-dat
nil)))
(defun ada-goto-next-non-ws (&optional limit)
"Skips white spaces, newlines and comments to next non-ws character.
Stop the search at LIMIT.
Do not call this function from within a string."
(unless limit
(setq limit (point-max)))
(while (and (<= (point) limit)
(progn (forward-comment 10000)
(if (and (not (eobp))
(save-excursion (forward-char 1)
(ada-in-string-p)))
(progn (forward-sexp 1) t)))))
(if (< (point) limit)
(point)
nil)
)
(defun ada-goto-stmt-end (&optional limit)
"Moves point to the end of the statement that point is in or before.
Returns 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)
"Moves point to the beginning of the next word of Ada code.
If BACKWARD is non-nil, jump to the beginning of the previous word.
Returns the new position of point or nil if not found."
(let ((match-cons nil)
(orgpoint (point))
(old-syntax (char-to-string (char-syntax ?_))))
(modify-syntax-entry ?_ "w")
(unless backward
(skip-syntax-forward "w"))
(if (setq match-cons
(if backward
(ada-search-ignore-string-comment "\\w" t nil t)
(ada-search-ignore-string-comment "\\w" nil nil t)))
(progn
(goto-char (car match-cons))
(skip-syntax-backward "w")
(point))
(goto-char orgpoint)
'nil)
(modify-syntax-entry ?_ old-syntax))
)
(defun ada-check-matching-start (keyword)
"Signals 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)
"Checks 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."
(if (save-excursion
(ada-goto-previous-word)
(looking-at (concat "\\<" defun-name "\\> *:")))
t (unless (looking-at ada-subprog-start-re)
(ada-goto-matching-decl-start))
(save-excursion
(if (looking-at "\\<declare\\>")
(ada-goto-stmt-start)
(progn
(forward-word 2)
(backward-word 1)
(if (looking-at "\\<\\(body\\|type\\)\\>")
(forward-word 1))
(forward-sexp 1)
(backward-sexp 1)))
(unless (looking-at (concat "\\<" defun-name "\\>"))
(error "matching defun has different name: %s"
(buffer-substring (point)
(progn (forward-sexp 1) (point))))))))
(defun ada-goto-matching-decl-start (&optional noerror recursive)
"Moves point to the matching declaration start of the current 'begin'.
If NOERROR is non-nil, it only returns nil if no match was found."
(let ((nest-count 1)
(first (not recursive))
(count-generic nil)
(stop-at-when nil)
)
(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))
(while (and
(not (zerop nest-count))
(ada-search-ignore-string-comment ada-matching-decl-start-re t))
(cond
((looking-at "end")
(ada-goto-matching-start 1 noerror)
(if (looking-at "begin")
(let ((loop-again t))
(save-excursion
(while loop-again
(ada-search-ignore-string-comment
"\\<\\(declare\\|begin\\|end\\|procedure\\|function\\|task\\|package\\)\\>"
t)
(if (looking-at "end")
(ada-goto-matching-decl-start 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 -1)
(unless (looking-at "\\<end[ \t\n]*if\\>")
(progn
(setq nest-count (1- nest-count))
(setq first nil)))))
((looking-at "declare\\|generic")
(setq nest-count (1- nest-count))
(setq first nil))
((looking-at "is")
(if (or (looking-at "is[ \t]+<>")
(save-excursion
(forward-comment -10000)
(forward-char -1)
(if (= (char-after) ?\))
(progn
(forward-char 1)
(backward-sexp 1)
(forward-comment -10000)
))
(skip-chars-backward "a-zA-Z0-9_.'")
(ada-goto-previous-word)
(and
(looking-at "\\<\\(sub\\)?type\\>")
(save-match-data
(ada-goto-previous-word)
(not (looking-at "\\<protected\\>"))))
)) (goto-char (match-beginning 0))
(progn
(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")
(if stop-at-when
(setq nest-count (1- nest-count)))
(setq first nil))
(t
(setq nest-count (1+ nest-count))
(setq first nil)))
)
(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)
"Moves 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)
(pos nil))
(while (and
(not found)
(ada-search-ignore-string-comment ada-matching-start-re t))
(unless (and (looking-at "\\<record\\>")
(save-excursion
(forward-word -1)
(looking-at "\\<null\\>")))
(progn
(cond
((looking-at "end")
(setq nest-count (1+ nest-count)))
((looking-at "loop\\|select\\|record\\|case\\|if")
(setq pos (point))
(save-excursion
(ada-goto-previous-word)
(if (looking-at "\\<end\\>[ \t]*[^;]")
(progn
(setq nest-count (1+ nest-count))
(setq pos (point)))
(setq nest-count (1- nest-count))))
(goto-char pos))
((looking-at "package")
(save-excursion
(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 (point-min)
(1+ current)))))))
(unless (looking-at "renames")
(progn
(forward-word 1)
(ada-goto-next-non-ws)
(if (not (looking-at "\\<\\(new\\|separate\\)\\>"))
(setq nest-count (1- nest-count)))))))
((looking-at "task")
(save-excursion
(forward-word 1)
(ada-goto-next-non-ws)
(cond
((looking-at "\\<body\\>"))
((looking-at "\\<type\\>")
(forward-word 2) (ada-goto-next-non-ws)
(unless (looking-at ";")
(progn
(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
(unless (progn (forward-word 1)
(looking-at "[ \t]*;"))
(setq nest-count (1- nest-count)))))))
(t
(setq nest-count (1- nest-count))))
(setq found (zerop nest-count)))))
(if found
(progn
(cond
((and
gotothen
(looking-at "if")
(save-excursion
(ada-search-ignore-string-comment "then" nil nil nil
'word-search-forward)
(back-to-indentation)
(looking-at "\\<then\\>")))
(goto-char (match-beginning 0)))
((looking-at "do")
(unless (ada-search-ignore-string-comment "accept" t nil nil
'word-search-backward)
(error "missing 'accept' in front of 'do'"))))
(point))
(if noerror
nil
(error "no matching start")))))
(defun ada-goto-matching-end (&optional nest-level noerror)
"Moves 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 found no matching start."
(let ((nest-count (if nest-level nest-level 0))
(found nil))
(while (and
(not found)
(ada-search-ignore-string-comment
(eval-when-compile
(concat "\\<"
(regexp-opt '("end" "loop" "select" "begin" "case"
"if" "task" "package" "record" "do") t)
"\\>")) nil))
(backward-word 1)
(cond
((looking-at "\\<end\\>")
(setq nest-count (1- nest-count))
(if (progn
(skip-chars-forward "end")
(ada-goto-next-non-ws)
(looking-at "\\<\\(loop\\|select\\|record\\|case\\|if\\)\\>"))
(forward-word 1)))
((looking-at "\\<package\\>")
(ada-search-ignore-string-comment "is" nil nil nil
'word-search-forward)
(ada-goto-next-non-ws)
(if (looking-at "\\<new\\>")
(goto-char (match-end 0))
(setq nest-count (1+ nest-count))))
(t
(setq nest-count (1+ nest-count))
(forward-word 1)))
(setq found (zerop nest-count)))
(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.
If PARAMLISTS is nil, ignore parameter lists. Returns a cons cell of
begin and end of match data or nil, if not found.
The search is done using SEARCH-FUNC, which should search backward if
BACKWARD is non-nil, forward otherwise. SEARCH-FUNC can be optimized in case
we are searching for a constant string.
The search stops at pos LIMIT.
Point is moved at the beginning of the search-re."
(let (found
begin
end
parse-result
(previous-syntax-table (syntax-table)))
(unless search-func
(setq search-func (if backward 're-search-backward 're-search-forward)))
(set-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
(save-excursion (beginning-of-line) (point))
(point)))
(cond
((ada-in-string-p parse-result)
(if ada-xemacs
(search-backward "\"" nil t)
(goto-char (nth 8 parse-result)))
(unless backward (forward-sexp 1)))
((ada-in-comment-p parse-result)
(if ada-xemacs
(progn
(forward-line 1)
(beginning-of-line)
(forward-comment -1))
(goto-char (nth 8 parse-result)))
(unless backward
(if (forward-comment 1)
(progn
(forward-comment 1000)
(beginning-of-line))
(end-of-line))))
((and (= (char-after begin) ?-) (= (char-after (1+ begin)) ?-))
(unless backward (progn (forward-char -1) (forward-comment 1000))))
((and (not paramlists) (ada-in-paramlist-p))
(if backward
(search-backward "(" nil t)
(search-forward ")" nil t)))
(t
(setq found t))))
(set-syntax-table previous-syntax-table)
(if found
(cons begin end)
nil)))
(defun ada-in-decl-p ()
"Returns 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-matching-decl-start t))))
(defun ada-looking-at-semi-or ()
"Returns t if looking-at an 'or' following a semicolon."
(save-excursion
(and (looking-at "\\<or\\>")
(progn
(forward-word 1)
(ada-goto-stmt-start)
(looking-at "\\<or\\>")))))
(defun ada-looking-at-semi-private ()
"Returns t if looking at the start of a private section in a package.
Returns 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 "\\<private\\>")
(not (looking-at "\\<private[ \t]*\\(package\\|generic\\)"))
(progn (forward-comment -1000)
(or (= (char-before) ?\ (and (forward-word -3)
(looking-at "\\<package\\>")))))))
(defun ada-in-paramlist-p ()
"Returns t if point is inside a parameter-list."
(save-excursion
(and
(ada-search-ignore-string-comment "(\\|)" t nil t)
(= (char-after) ?\()
(progn
(skip-syntax-backward " ")
(if (= (char-before) ?\")
(backward-char 3)
(backward-word 1))
t)
;; and now over the second one
(backward-word 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
(looking-at (eval-when-compile
(concat "\\<\\("
"procedure\\|function\\|body\\|"
"task\\|entry\\|accept\\|"
"access[ \t]+procedure\\|"
"access[ \t]+function\\|"
"pragma\\|"
"type\\)\\>"))))))
(defun ada-search-ignore-complex-boolean (regexp backwardp)
"Like `ada-search-ignore-string-comment', except that it also ignores
boolean expressions 'and then' and 'or else'."
(let (result)
(while (and (setq result (ada-search-ignore-string-comment regexp backwardp))
(save-excursion (forward-word -1)
(looking-at "and then\\|or else"))))
result))
(defun ada-in-open-paren-p ()
"Returns 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
"\\<\\( t))
(point-min)))))
(if (nth 1 parse)
(progn
(goto-char (1+ (nth 1 parse)))
(skip-chars-forward " \t")
(point))))))
(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, operates only on the current line."
(interactive)
(cond ((eq ada-tab-policy 'indent-rigidly) (ada-tab-hard))
((eq ada-tab-policy 'indent-auto)
(if (or (and ada-xemacs (funcall (symbol-function 'region-active-p)))
(and (not ada-xemacs)
(symbol-value 'transient-mark-mode)
(symbol-value 'mark-active)))
(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'."
(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 (save-excursion (= (point) (progn (beginning-of-line) (point))))
(forward-char ada-indent)))
(defun ada-untab-hard ()
"indent current line to previous tab stop."
(interactive)
(let ((bol (save-excursion (progn (beginning-of-line) (point))))
(eol (save-excursion (progn (end-of-line) (point)))))
(indent-rigidly bol eol (- 0 ada-indent))))
(defun ada-gnat-style ()
"Clean up comments, `(' and `,' for GNAT style checking switch."
(interactive)
(save-excursion
(goto-char (point-min))
(while (re-search-forward "--[ \t]*\\([^-]\\)" nil t)
(replace-match "-- \\1"))
(goto-char (point-min))
(while (re-search-forward "\\>(" nil t)
(replace-match " ("))
(goto-char (point-min))
(while (re-search-forward "([ \t]+" nil t)
(replace-match "("))
(goto-char (point-min))
(while (re-search-forward ")[ \t]+)" nil t)
(replace-match "))"))
(goto-char (point-min))
(while (re-search-forward "\\>:" nil t)
(replace-match " :"))
(goto-char (point-min))
(while (re-search-forward ",\\<" nil t)
(replace-match ", "))
(goto-char (point-min))
(while (re-search-forward "[ \t]*\\.\\.[ \t]*" nil t)
(replace-match " .. "))
(goto-char (point-min))
(while (re-search-forward "[ \t]*\\([-:+*/]\\)[ \t]*" nil t)
(if (not (ada-in-string-or-comment-p))
(progn
(forward-char -1)
(cond
((looking-at "/=")
(replace-match " /= "))
((looking-at ":=")
(replace-match ":= "))
((not (looking-at "--"))
(replace-match " \\1 ")))
(forward-char 2))))
))
(defun ada-move-to-start ()
"Moves point to the matching start of the current Ada structure."
(interactive)
(let ((pos (point))
(previous-syntax-table (syntax-table)))
(unwind-protect
(progn
(set-syntax-table ada-mode-symbol-syntax-table)
(message "searching for block start ...")
(save-excursion
(or
(ada-in-string-or-comment-p)
(and (progn
(or (looking-at "[ \t]*\\<end\\>")
(backward-word 1))
(or (looking-at "[ \t]*\\<end\\>")
(backward-word 1))
(or (looking-at "[ \t]*\\<end\\>")
(error "not on end ...;")))
(ada-goto-matching-start 1)
(setq pos (point))
ada-move-to-declaration
(looking-at "\\<begin\\>")
(ada-goto-matching-decl-start)
(setq pos (point))))
)
(goto-char pos)
(message "searching for block start ... done"))
(set-syntax-table previous-syntax-table))))
(defun ada-move-to-end ()
"Moves point to the matching end of the block around point.
Moves to 'begin' if in a declarative part."
(interactive)
(let ((pos (point))
(previous-syntax-table (syntax-table)))
(unwind-protect
(progn
(set-syntax-table ada-mode-symbol-syntax-table)
(message "searching for block end ...")
(save-excursion
(forward-char 1)
(cond
((save-excursion
(ada-goto-previous-word)
(looking-at "\\<begin\\>"))
(ada-goto-matching-end 1))
((save-excursion
(and (ada-goto-stmt-start)
(looking-at "\\<function\\>\\|\\<procedure\\>" )))
(ada-search-ignore-string-comment "begin" nil nil nil
'word-search-forward))
((save-excursion
(and (ada-goto-stmt-start)
(looking-at "\\<task\\>" )
(forward-word 1)
(ada-goto-next-non-ws)
(looking-at "\\<body\\>")))
(ada-search-ignore-string-comment "begin" nil nil nil
'word-search-forward))
((save-excursion
(and (ada-goto-stmt-start)
(looking-at "\\<accept\\>" )))
(ada-goto-matching-end 0))
((save-excursion
(and (ada-goto-matching-decl-start t)
(looking-at "\\<package\\>")))
(ada-goto-matching-end 1))
((save-excursion
(ada-goto-matching-decl-start t))
(ada-search-ignore-string-comment "begin" nil nil nil
'word-search-forward))
(t
(ada-goto-matching-end 1)))
(setq pos (point))
)
(goto-char pos)
(message "searching for block end ... done"))
(set-syntax-table previous-syntax-table))))
(defun ada-next-procedure ()
"Moves point to next procedure."
(interactive)
(end-of-line)
(if (re-search-forward ada-procedure-start-regexp nil t)
(goto-char (match-beginning 1))
(error "No more functions/procedures/tasks")))
(defun ada-previous-procedure ()
"Moves point to previous procedure."
(interactive)
(beginning-of-line)
(if (re-search-backward ada-procedure-start-regexp nil t)
(goto-char (match-beginning 1))
(error "No more functions/procedures/tasks")))
(defun ada-next-package ()
"Moves 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 ()
"Moves 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")))
(defun ada-create-keymap ()
"Create the keymap associated with the Ada mode."
(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)
(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)
(unless (lookup-key ada-mode-map "\C-c\C-c")
(define-key ada-mode-map "\C-c\C-c" 'compile))
(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)
(if (boundp 'delete-key-deletes-forward)
(define-key ada-mode-map [backspace] 'backward-delete-char-untabify)
(define-key ada-mode-map "\177" 'backward-delete-char-untabify))
(define-key ada-mode-map "\C-c\C-n" 'ada-make-subprogram-body)
(define-key ada-mode-map "\C-c;" 'comment-region)
(define-key ada-mode-map "\C-c:" 'ada-uncomment-region)
)
(defun ada-create-menu ()
"Create the ada menu as shown in the menu bar.
This function is designed to be extensible, so that each compiler-specific file
can add its own items."
(autoload 'easy-menu-define "easymenu")
(let ((m '("Ada"
("Help" ["Ada Mode" (info "ada-mode") t])))
(option '(["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]))
(goto '(["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 '(["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 Buffer" ada-adjust-case-buffer t]
["Create Case Exception" ada-create-case-exception t]
["Reload Case Exceptions" ada-case-read-exceptions t]
["----" nil nil]
["Make body for subprogram" ada-make-subprogram-body t]))
)
(setq m (append m (list (append '("Options"
:included (eq major-mode 'ada-mode))
option))))
(when (fboundp 'customize-group)
(setq m (append m '(["Customize" (customize-group 'ada)]))))
(setq m (append m (list (append '("Goto"
:included (eq major-mode 'ada-mode))
goto)
(append '("Edit"
:included (eq major-mode 'ada-mode))
edit))))
(easy-menu-define ada-mode-menu ada-mode-map "Menu keymap for Ada mode" m)
(easy-menu-add ada-mode-menu ada-mode-map)
(when ada-xemacs
(define-key ada-mode-map [menu-bar] ada-mode-menu)
(setq mode-popup-menu (cons "Ada mode" ada-mode-menu)))))
(defadvice comment-region (before ada-uncomment-anywhere)
(if (and arg
(< arg 0)
(string= mode-name "Ada"))
(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)
"Delete `comment-start' at the beginning of a line in the region."
(interactive "r\nP")
(if (or (<= emacs-major-version 20) (boundp 'running-xemacs))
(progn
(ad-activate 'comment-region)
(comment-region beg end (- (or arg 1)))
(ad-deactivate 'comment-region))
(comment-region beg end (list (- (or arg 1))))))
(defun ada-fill-comment-paragraph-justify ()
"Fills current comment paragraph and justifies each line as well."
(interactive)
(ada-fill-comment-paragraph 'full))
(defun ada-fill-comment-paragraph-postfix ()
"Fills current comment paragraph and justifies 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)
"Fills 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 filled and justified line.
The paragraph is indented on the first line."
(interactive "P")
(if (and (not (ada-in-comment-p))
(not (looking-at "[ \t]*--")))
(error "not inside comment"))
(let* ((indent)
(from)
(to)
(opos (point-marker))
(parse-sexp-lookup-properties nil)
fill-prefix
(fill-column (current-fill-column)))
(back-to-indentation)
(while (and (not (eobp)) (looking-at "--[ \t]*[^ \t\n]"))
(forward-line 1)
(if (eolp)
(insert "\n")
(back-to-indentation)))
(beginning-of-line)
(setq to (point-marker))
(goto-char opos)
(back-to-indentation)
(while (and (not (bobp)) (looking-at "--[ \t]*[^ \t\n]"))
(forward-line -1)
(back-to-indentation))
(unless (bobp)
(forward-line 1))
(beginning-of-line)
(setq from (point-marker))
(back-to-indentation)
(setq indent (current-column))
(delete-region from (point))
(goto-char from)
(while (re-search-forward "--\n" to t)
(replace-match "\n"))
(goto-char (+ from 2))
(while (re-search-forward "^-- *" to t)
(replace-match " "))
(goto-char (1- to))
(setq to (point-marker))
(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)
(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))
))
(if (or ada-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)))
(defun ada-make-filename-from-adaname (adaname)
"Determine the filename in which ADANAME is found.
This is a generic function, independent from any compiler."
(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)))
(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 (not (or is-spec is-body))
name
(if is-spec
(setq suffixes ada-body-suffixes)
(setq suffixes ada-spec-suffixes))
(setq is-spec name)
(while suffixes
(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.
Redefines the function `ff-which-function-are-we-in'."
(setq ff-function-name nil)
(save-excursion
(end-of-line) (if (or (re-search-backward ada-procedure-start-regexp nil t)
(re-search-backward ada-package-start-regexp nil t))
(setq ff-function-name (match-string 0)))
))
(defvar ada-last-which-function-line -1
"Last 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 ()
"Returns 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.
Note that this function expects subprogram bodies to be terminated by
'end <name>;', not 'end;'.
Since the search can be long, the results are cached."
(let ((line (count-lines (point-min) (point)))
(pos (point))
end-pos
func-name
found)
(if (= line ada-last-which-function-line)
ada-last-which-function-subprog
(save-excursion
(end-of-line)
(while (and (ada-in-paramlist-p)
(= (forward-line 1) 0))
(end-of-line))
(skip-chars-forward "is \t\n")
(while (and (not found)
(re-search-backward ada-imenu-subprogram-menu-re nil t))
(setq func-name (match-string 2))
(if (and (not (ada-in-comment-p))
(not (save-excursion
(goto-char (match-end 0))
(looking-at "[ \t\n]*new"))))
(save-excursion
(if (ada-search-ignore-string-comment
(concat "end[ \t]+" func-name "[ \t]*;"))
(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)
"Returns the file name for the body of SPEC-NAME.
If SPEC-NAME is nil, returns the body for the current package.
Returns nil if no body was found."
(interactive)
(unless spec-name (setq spec-name (buffer-file-name)))
(if (functionp 'ff-get-file)
(ff-get-file-name ada-search-directories
(ada-make-filename-from-adaname
(file-name-nondirectory
(file-name-sans-extension spec-name)))
ada-body-suffixes)
(concat (ada-make-filename-from-adaname
(file-name-nondirectory
(file-name-sans-extension spec-name)))
".adb")))
(defconst ada-font-lock-syntactic-keywords
'(("\\('\\)[^'\n]\\('\\)" (1 (7 . ?')) (2 (7 . ?')))
("^[ \t]*\\(#\\(if\\|else\\|elsif\\|end\\)\\)" (1 (11 . ?\n)))
))
(defvar ada-font-lock-keywords
(eval-when-compile
(list
(list "\\<\\(function[ \t]+return\\)\\>" '(1 font-lock-keyword-face) )
(list "^[ \t]*\\(#.*\n\\)" '(1 font-lock-type-face t))
(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))
(list (concat "\\<\\(access[ \t]+all\\|access\\|constant\\|in[ \t]+out\\|in\\|out\\)\\>"
"[ \t]*"
"\\(\\sw+\\(\\.\\sw*\\)*\\)?")
'(1 font-lock-keyword-face nil t) '(2 font-lock-type-face nil t))
(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" "is" "limited" "loop" "mod" "not"
"null" "or" "others" "private" "protected" "raise"
"range" "record" "rem" "renames" "requeue" "return" "reverse"
"select" "separate" "tagged" "task" "terminate" "then" "until"
"when" "while" "xor") t)
"\\>")
'("\\<\\(end\\)\\>\\([ \t]+\\)?\\(\\(\\sw\\|[_.]\\)+\\)?"
(1 font-lock-keyword-face) (3 font-lock-function-name-face nil t))
(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))
(list (concat "\\<\\(goto\\|raise\\|use\\|with\\)\\>" "[ \t\n]*\\(\\(\\sw\\|[_.|, \t\n]\\)+\\)\\W")
'(1 font-lock-keyword-face) '(2 font-lock-reference-face nil t))
'("<<\\(\\sw+\\)>>" 1 font-lock-reference-face)
))
"Default expressions to highlight in Ada mode.")
(defun ada-outline-level ()
"This is so that `current-column` DTRT in otherwise-hidden text"
(let (buffer-invisibility-spec)
(save-excursion
(back-to-indentation)
(current-column))))
(defun ada-gen-treat-proc (match)
"Make dummy body of a procedure/function specification.
MATCH is a cons cell containing the start and end location 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")))
(forward-word 2)
(forward-word -1)
(setq procname (buffer-substring (point) (cdr match)))
(goto-char (cdr match))
(unless (looking-at "[ \t\n]*\\(;\\|return\\)")
(forward-sexp))
(if func-found
(progn
(forward-word 1)
(skip-chars-forward " \t\n")
(setq functype (buffer-substring (point)
(progn
(skip-chars-forward
"a-zA-Z0-9_\.")
(point))))))
(cond
((looking-at "[ \t]*;")
(delete-region (match-beginning 0) (match-end 0)) (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")
)
((looking-at "[ \t\n]*rename")
)
(t
(message "unknown syntax"))))
(t
(if (looking-at "^[ \t]*task")
(progn
(message "Task conversion is not yet implemented")
(forward-word 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 potential old buffer contents is deleted first, then we copy the
spec buffer in here and modify it to make it a body.
This function typically is to be hooked into `ff-file-created-hooks'."
(interactive)
(delete-region (point-min) (point-max))
(insert-buffer (car (cdr (buffer-list))))
(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 ()
"Make one dummy subprogram body 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)))
(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 "\\<end\\>" nil t)
(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"))))
(ada-create-keymap)
(ada-create-menu)
(ada-create-syntax-table)
(ada-add-extensions ".ads" ".adb")
(if (equal ada-which-compiler 'gnat)
(ada-add-extensions ".ads.dg" ".adb.dg"))
(ada-case-read-exceptions)
(if (equal ada-which-compiler 'gnat)
(progn
(require 'ada-xref)
(condition-case nil (require 'ada-prj) (error nil))
))
(condition-case nil (require 'ada-stmt) (error nil))
(provide 'ada-mode)