Mercurial > emacs
view lisp/progmodes/ada-mode.el @ 11759:51816af03215
(info-insert-file-contents): Don't use
(file-name-directory fullname) if it is nil.
(info-insert-file-contents): Fix Apr 19 change.
author | Richard M. Stallman <rms@gnu.org> |
---|---|
date | Mon, 08 May 1995 23:23:37 +0000 |
parents | 3cf67df24e7f |
children | ab2739454f2a |
line wrap: on
line source
;;; ada-mode.el - An Emacs major-mode for editing Ada source. ;;; Copyright (C) 1994, 1995 Free Software Foundation, Inc. ;;; Authors: Markus Heritsch <Markus.Heritsch@studbox.uni-stuttgart.de> ;;; Rolf Ebert <ebert@inf.enst.fr> ;;; This file is part of GNU Emacs. ;; GNU Emacs is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ;;; This mode is a complete rewrite of a major mode for editing Ada 83 ;;; and Ada 94 source code under Emacs-19. It contains completely new ;;; indenting code and support for code browsing (see ada-xref). ;;; USAGE ;;; ===== ;;; Emacs should enter ada-mode when you load an ada source (*.ada). ;;; ;;; When you have entered ada-mode, you may get more info by pressing ;;; C-h m. You may also get online help describing various functions by: ;;; C-h d <Name of function you want described> ;;; HISTORY ;;; ======= ;;; The first Ada mode for GNU Emacs was written by V. Broman in ;;; 1985. He based his work on the already existing Modula-2 mode. ;;; This was distributed as ada.el in versions of Emacs prior to 19.29. ;;; ;;; Lynn Slater wrote an extensive Ada mode in 1989. It consisted of ;;; several files with support for dired commands and other nice ;;; things. It is currently available from the PAL ;;; (wuarchive.wustl.edu:/languages/ada) as ada-mode-1.06a.tar.Z. ;;; ;;; The probably very first Ada mode (called electric-ada.el) was ;;; written by Steven D. Litvintchouk and Steven M. Rosen for the ;;; Gosling Emacs. L. Slater based his development on ada.el and ;;; electric-ada.el. ;;; ;;; The current Ada mode is a complete rewrite by M. Heritsch and ;;; R. Ebert. Some ideas from the ada-mode mailing list have been ;;; added. Some of the functionality of L. Slater's mode has not ;;; (yet) been recoded in this new mode. Perhaps you prefer sticking ;;; to his version. ;;; KNOWN BUGS / BUGREPORTS ;;; ======================= ;;; ;;; In the presence of comments and/or incorrect syntax ;;; ada-format-paramlist produces weird results. ;;; ;;; Indentation is sometimes wrong at the very beginning of the buffer. ;;; So please try it on different locations. If it's still wrong then ;;; report the bug. ;;; ;;; At the moment the browsing functions are limited to the use of the ;;; separate packages "find-file.el" and "ada-xref.el" (ada-xref.el is ;;; only for GNAT users). ;;; ;;; indenting of some tasking constructs is not yet supported. ;;; ;;; `reformat-region' sometimes generates some weird indentation. ;;; ;;;> I have the following suggestions for the function template: 1) I ;;;> don't want it automatically assigning it a name for the return variable. I ;;;> never want it to be called "Result" because that is nondescriptive. If you ;;;> must define a variable, give me the ability to specify its name. ;;;> ;;;> 2) You do not provide a type for variable 'Result'. Its type is the same ;;;> as the function's return type, which the template knows, so why force me ;;;> to type it in? ;;;> ;;;As always, different users have different tastes. ;;;It would be nice if one could configure such layout details separately ;;;without patching the LISP code. Maybe the metalanguage used in ada-stmt.el ;;;could be taken even further, providing the user with some nice syntax ;;;for describing layout. Then my own hacks would survive the next ;;;update of the package :-) ;;;By the way, there are some more quirks: ;;;1) text entered in prompt mode (*) is not converted to upper case (I have ;;; choosen upper case for indentifiers). ;;; (*) I would like to suggest the term "template code" instead of ;;; "pseudo code". ;;; There are quite a few problems in the crossreferencing part. These ;;; are partly due to errors in gnatf. One of the major bugs in ;;; ada-xref is, that we do not wait for gnatf to rebuild the xref file. ;;; We start the job, but do not wait for finishing. ;;; LCD Archive Entry: ;;; ada-mode|Rolf Ebert|<ebert@inf.enst.fr> ;;; |Major-mode for Ada ;;; |$Date: 1995/04/04 03:00:59 $|$Revision: 1.4 $| (defconst ada-mode-version (substring "$Revision: 1.4 $" 11 -2) "$Id: ada-mode.el,v 1.4 1995/04/04 03:00:59 kwzh Exp kwzh $ Report bugs to: Rolf Ebert <ebert@inf.enst.fr>") ;;;-------------------- ;;; USER OPTIONS ;;;-------------------- ;; ---- configure indentation (defvar ada-indent 3 "*Defines the size of Ada indentation.") (defvar ada-broken-indent 2 "*# of columns to indent the continuation of a broken line.") (defvar ada-label-indent -4 "*# of columns to indent a label.") (defvar ada-stmt-end-indent 0 "*# of columns to indent a statement end keyword in a separate line. Examples are 'is', 'loop', 'record', ...") (defvar ada-when-indent 3 "*Defines the indentation for 'when' relative to 'exception' or 'case'.") (defvar ada-indent-record-rel-type 3 "*Defines the indentation for 'record' relative to 'type' or 'use'.") (defvar ada-indent-comment-as-code t "*If non-nil, comment-lines get indented as ada-code.") (defvar ada-indent-is-separate t "*If non-nil, 'is separate' or 'is abstract' on a separate line are indented.") (defvar ada-indent-to-open-paren t "*If non-nil, following lines get indented according to the innermost open parenthesis.") (defvar ada-search-paren-line-count-limit 5 "*Search that many non-blank non-comment lines for an open parenthesis. Values higher than about 5 horribly slow down the indenting.") ;; ---- other user options (defvar ada-tab-policy 'indent-auto "*Control behaviour of the TAB key. Must be one of 'indent-rigidly, 'indent-auto, 'gei, 'indent-af or 'always-tab. 'indent-rigidly : always adds ada-indent blanks at the beginning of the line. 'indent-auto : use indentation functions in this file. 'gei : use David K}gedal's Generic Indentation Engine. 'indent-af : use Gary E. Barnes' ada-format.el 'always-tab : do indent-relative.") (defvar ada-move-to-declaration nil "*If non-nil, ada-move-to-start moves point to the subprog-declaration, not to 'begin'.") (defvar ada-spec-suffix ".ads" "*Suffix of Ada specification files.") (defvar ada-body-suffix ".adb" "*Suffix of Ada body files.") (defvar ada-language-version 'ada94 "*Do we program in 'ada83 or 'ada94?") (defvar ada-case-keyword 'downcase-word "*downcase-word, upcase-word, ada-loose-case-word or capitalize-word to adjust ada keywords case.") (defvar ada-case-identifier 'ada-loose-case-word "*downcase-word, upcase-word, ada-loose-case-word or capitalize-word to adjust ada identifier case.") (defvar ada-auto-case t "*Non-nil automatically changes casing of preceeding word while typing. Casing is done according to ada-case-keyword and ada-case-identifier.") (defvar ada-clean-buffer-before-saving nil "*If non-nil, remove-trailing-spaces and untabify buffer before saving.") (defvar ada-mode-hook nil "*List of functions to call when Ada Mode is invoked. This is a good place to add Ada environment specific bindings.") (defvar ada-external-pretty-print-program "aimap" "*External pretty printer to call from within Ada Mode.") (defvar ada-tmp-directory "/tmp/" "*Directory to store the temporary file for the Ada pretty printer.") (defvar ada-fill-comment-prefix "-- " "*This is inserted in the first columns when filling a comment paragraph.") (defvar ada-fill-comment-postfix " --" "*This is inserted at the end of each line when filling a comment paragraph with ada-fill-comment-paragraph postfix.") (defvar ada-krunch-args "250" "*Argument of gnatk8, a string containing the max number of characters. Set to a big number, if you dont use crunched filenames.") ;;; ---- end of user configurable variables (defvar ada-mode-abbrev-table nil "Abbrev table used in Ada mode.") (define-abbrev-table 'ada-mode-abbrev-table ()) (defvar ada-mode-map () "Local keymap used for ada-mode.") (defvar ada-mode-syntax-table nil "Syntax table to be used for editing Ada source code.") (defconst ada-83-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\\)\\>" "regular expression for looking at Ada83 keywords.") (defconst ada-94-keywords "\\<\\(abort\\|abs\\|abstract\\|accept\\|access\\|aliased\\|\ 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\\|protected\\|raise\\|\ range\\|record\\|rem\\|renames\\|requeue\\|return\\|reverse\\|\ select\\|separate\\|subtype\\|tagged\\|task\\|terminate\\|then\\|\ type\\|until\\|use\\|when\\|while\\|with\\|xor\\)\\>" "regular expression for looking at Ad94 keywords.") (defvar ada-keywords ada-94-keywords "regular expression for looking at Ada keywords.") (defvar ada-ret-binding nil "Variable to save key binding of RET when casing is activated.") (defvar ada-lfd-binding nil "Variable to save key binding of LFD when casing is activated.") ;;; ---- Regexps to find procedures/functions/packages (defvar ada-procedure-start-regexp "^[ \t]*\\(procedure\\|function\\|task\\)[ \t\n]+\\([a-zA-Z0-9_\\.]+\\)" "Regexp used to find Ada procedures/functions.") (defvar ada-package-start-regexp "^[ \t]*\\(package\\)" "Regexp used to find Ada packages") ;;; ---- regexps for indentation functions (defvar ada-block-start-re "\\<\\(begin\\|select\\|declare\\|private\\|or\\|generic\\|\ exception\\|loop\\|record\\|else\\)\\>" "Regexp for keywords starting ada-blocks.") (defvar ada-end-stmt-re "\\(;\\|=>\\|\\<\\(begin\\|record\\|loop\\|select\\|do\\|\ exception\\|declare\\|generic\\|private\\)\\>\\)" "Regexp of possible ends for a non-broken statement. 'end' means that there has to start a new statement after these.") (defvar ada-loop-start-re "\\<\\(for\\|while\\|loop\\)\\>" "Regexp for the start of a loop.") (defvar ada-subprog-start-re "\\<\\(procedure\\|function\\|task\\|accept\\)\\>" "Regexp for the start of a subprogram.") ;;;------------- ;;; functions ;;;------------- (defun ada-create-syntax-table () "Create the syntax table for ada-mode." ;; This syntax table is a merge of two syntax tables I found ;; in the two ada modes in the old ada.el and the old ;; electric-ada.el. (jsl) ;; There still remains the problem, if the underscore '_' is a word ;; constituent or not. (re) ;; The Emacs doc clearly states that it is a symbol, and that is what most ;; on the ada-mode list prefer. (re) ;; For some functions, the syntactical meaning of '_' is temporaryly ;; changed to 'w'. (mh) (setq ada-mode-syntax-table (make-syntax-table)) (set-syntax-table ada-mode-syntax-table) ;; define string brackets (% is alternative string bracket) (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 ?\{ "." 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) ;; a single hyphen is punctuation, but a double hyphen starts a comment (modify-syntax-entry ?- ". 12" ada-mode-syntax-table) ;; and \f and \n end a comment (modify-syntax-entry ?\f "> " ada-mode-syntax-table) (modify-syntax-entry ?\n "> " ada-mode-syntax-table) ;; define what belongs in ada symbols (modify-syntax-entry ?_ "_" ada-mode-syntax-table) ;; define parentheses to match (modify-syntax-entry ?\( "()" ada-mode-syntax-table) (modify-syntax-entry ?\) ")(" ada-mode-syntax-table) ) ;;;###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]' Call external pretty printer program '\\[ada-call-pretty-printer]' Adjust case of identifiers and keywords in region '\\[ada-adjust-case-region]' Adjust case of identifiers and keywords in buffer '\\[ada-adjust-case-buffer]' Call EXTERNAL pretty printer (if you have one) '\\[ada-call-pretty-printer]' Fill comment paragraph '\\[ada-fill-comment-paragraph]' Fill comment paragraph and justify each line '\\[ada-fill-comment-paragraph-justify]' Fill comment paragraph, justify and append postfix '\\[ada-fill-comment-paragraph-postfix]' 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 ...;' '\\[ada-move-to-start]' 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 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]' Execute Gnatf: '\\[ada-gnatf-current]'" (interactive) (kill-all-local-variables) (make-local-variable 'require-final-newline) (setq require-final-newline t) (make-local-variable 'comment-start) (setq comment-start "-- ") ;; comment end must be set because it may hold a wrong value if ;; this buffer had been in another mode before. RE (make-local-variable 'comment-end) (setq comment-end "") (make-local-variable 'comment-start-skip) ;; used by autofill (setq comment-start-skip "--+[ \t]*") (make-local-variable 'indent-line-function) (setq indent-line-function 'ada-indent-current-function) (make-local-variable 'fill-column) (setq fill-column 75) (make-local-variable 'comment-column) (setq comment-column 40) (make-local-variable 'parse-sexp-ignore-comments) (setq parse-sexp-ignore-comments t) (make-local-variable 'case-fold-search) (setq case-fold-search t) (make-local-variable 'fill-paragraph-function) (setq fill-paragraph-function 'ada-fill-comment-paragraph) (make-local-variable 'font-lock-defaults) (setq font-lock-defaults '(ada-font-lock-keywords nil t ((?\_ . "w")))) (setq major-mode 'ada-mode) (setq mode-name "Ada") (setq blink-matching-paren t) (use-local-map ada-mode-map) (if ada-mode-syntax-table (set-syntax-table ada-mode-syntax-table) (ada-create-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 'ada-remove-trailing-spaces) ;; convert all tabs to the correct number of spaces. (add-hook 'local-write-file-hooks 'ada-untabify-buffer))) ;; add menu 'Ada' to the menu bar (ada-add-ada-menu) (run-hooks 'ada-mode-hook) ;; 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 'ada94) (setq ada-keywords ada-94-keywords))) (if ada-auto-case (ada-activate-keys-for-case))) ;;;-------------------------- ;;; Fill Comment Paragraph ;;;-------------------------- (defun ada-fill-comment-paragraph-justify () "Fills current comment paragraph and justifies each line as well." (interactive) (ada-fill-comment-paragraph t)) (defun ada-fill-comment-paragraph-postfix () "Fills current comment paragraph and justifies each line as well. Prompts for a postfix to be appended to each line." (interactive) (ada-fill-comment-paragraph t 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. If ada-indent-comment-as code is non-nil, the paragraph is idented." (interactive "P") (let ((opos (point-marker)) (begin nil) (end nil) (end-2 nil) (indent nil) (ada-fill-comment-old-postfix "") (fill-prefix nil)) ;; check if inside comment (if (not (ada-in-comment-p)) (error "not inside comment")) ;; prompt for postfix if wanted (if (and justify postfix) (setq ada-fill-comment-postfix (read-from-minibuffer "enter new postfix string: " ada-fill-comment-postfix))) ;; prompt for old postfix to remove if necessary (if (and justify postfix) (setq ada-fill-comment-old-postfix (read-from-minibuffer "enter already existing postfix string: " ada-fill-comment-postfix))) ;; ;; find limits of paragraph ;; (message "filling comment paragraph ...") (save-excursion (back-to-indentation) ;; find end of paragraph (while (and (looking-at "--.*$") (not (looking-at "--[ \t]*$"))) (forward-line 1) (back-to-indentation)) (beginning-of-line) (setq end (point-marker)) (goto-char opos) ;; find begin of paragraph (back-to-indentation) (while (and (looking-at "--.*$") (not (looking-at "--[ \t]*$"))) (forward-line -1) (back-to-indentation)) (forward-line 1) ;; get indentation to calculate width for filling (ada-indent-current) (back-to-indentation) (setq indent (current-column)) (setq begin (point-marker))) ;; delete old postfix if necessary (if (and justify postfix) (save-excursion (goto-char begin) (while (re-search-forward (concat ada-fill-comment-old-postfix "\n") end t) (replace-match "\n")))) ;; delete leading whitespace and uncomment (save-excursion (goto-char begin) (beginning-of-line) (while (re-search-forward "^[ \t]*--[ \t]*" end t) (replace-match ""))) ;; calculate fill width (setq fill-column (- fill-column indent (length ada-fill-comment-prefix) (if postfix (length ada-fill-comment-postfix) 0))) ;; fill paragraph (fill-region begin (1- end) justify) (setq fill-column (+ fill-column indent (length ada-fill-comment-prefix) (if postfix (length ada-fill-comment-postfix) 0))) ;; find end of second last line (save-excursion (goto-char end) (forward-line -2) (end-of-line) (setq end-2 (point-marker))) ;; re-comment and re-indent region (save-excursion (goto-char begin) (indent-to indent) (insert ada-fill-comment-prefix) (while (re-search-forward "\n" (1- end-2) t) (replace-match (concat "\n" ada-fill-comment-prefix)) (beginning-of-line) (indent-to indent))) ;; append postfix if wanted (if (and justify postfix ada-fill-comment-postfix) (progn ;; append postfix up to there (save-excursion (goto-char begin) (while (re-search-forward "\n" (1- end-2) t) (replace-match (concat ada-fill-comment-postfix "\n"))) ;; fill last line and append postfix (end-of-line) (insert-char ? (- fill-column (current-column) (length ada-fill-comment-postfix))) (insert ada-fill-comment-postfix)))) ;; delete the extra line that gets inserted somehow(??) (save-excursion (goto-char (1- end)) (end-of-line) (delete-char 1)) (message "filling comment paragraph ... done") (goto-char opos)) t) ;;;--------------------------------;;; ;;; Call External Pretty Printer ;;; ;;;--------------------------------;;; (defun ada-call-pretty-printer () "Calls the external Pretty Printer. The name is specified in ada-external-pretty-print-program. Saves the current buffer in a directory specified by ada-tmp-directory, starts the Pretty Printer as external process on that file and then reloads the beautyfied program in the buffer and cleans up ada-tmp-directory." (interactive) (let ((filename-with-path buffer-file-name) (curbuf (current-buffer)) (orgpos (point)) (mesgbuf nil) ;; for byte-compiling (file-path (file-name-directory buffer-file-name)) (filename-without-path (file-name-nondirectory buffer-file-name)) (tmp-file-with-directory (concat ada-tmp-directory (file-name-nondirectory buffer-file-name)))) ;; ;; save buffer in temporary file ;; (message "saving current buffer to temporary file ...") (write-file tmp-file-with-directory) (auto-save-mode nil) (message "saving current buffer to temporary file ... done") ;; ;; call external pretty printer program ;; (message "running external pretty printer ...") ;; create a temporary buffer for messages of pretty printer (setq mesgbuf (get-buffer-create "Pretty Printer Messages")) ;; execute pretty printer on temporary file (call-process ada-external-pretty-print-program nil mesgbuf t tmp-file-with-directory) ;; display messages if there are some (if (buffer-modified-p mesgbuf) ;; show the message buffer (display-buffer mesgbuf t) ;; kill the message buffer (kill-buffer mesgbuf)) (message "running external pretty printer ... done") ;; ;; kill current buffer and load pretty printer output ;; or restore old buffer ;; (if (y-or-n-p "Really replace current buffer with pretty printer output ? ") (progn (set-buffer-modified-p nil) (kill-buffer curbuf) (find-file tmp-file-with-directory)) (message "old buffer contents restored")) ;; ;; delete temporary file and restore information of current buffer ;; (delete-file tmp-file-with-directory) (set-visited-file-name filename-with-path) (auto-save-mode t) (goto-char orgpos))) ;;;--------------- ;;; auto-casing ;;;--------------- ;; from Philippe Waroquiers <philippe@cfmu.eurocontrol.be> ;; modifiedby RE and MH (defun ada-after-keyword-p () ;; returns t if cursor is after a keyword. (save-excursion (forward-word -1) (and (save-excursion (or (= (point) (point-min)) (backward-char 1)) (not (looking-at "_"))) ; (MH) (looking-at (concat ada-keywords "[^_]"))))) (defun ada-after-char-p () ;; returns t if after ada character "'". (save-excursion (if (> (point) 2) (progn (forward-char -2) (looking-at "'")) nil))) (defun ada-adjust-case (&optional force-identifier) "Adjust the case of the word before the just-typed character, according to ada-case-keyword and ada-case-identifier If FORCE-IDENTIFIER is non-nil then also adjust keyword as identifier." ; (MH) (forward-char -1) (if (and (> (point) 1) (not (or (ada-in-string-p) (ada-in-comment-p) (ada-after-char-p)))) (if (eq (char-syntax (char-after (1- (point)))) ?w) (if (and (not force-identifier) ; (MH) (ada-after-keyword-p)) (funcall ada-case-keyword -1) (funcall ada-case-identifier -1)))) (forward-char 1)) (defun ada-adjust-case-interactive (arg) (interactive "P") (let ((lastk last-command-char)) (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)) ((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)))) (defun ada-activate-keys-for-case () ;; save original keybindings 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 (MH) (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 ))) ;; deleted ?\t from above list ;; ;; added by MH ;; (defun ada-loose-case-word (&optional arg) "Capitalizes the first and the letters following _ ARG is ignored, it's there to fit the standard casing functions' style." (let ((pos (point)) (first t)) (skip-chars-backward "a-zA-Z0-9_") (while (or first (search-forward "_" pos t)) (and first (setq first nil)) (insert-char (upcase (following-char)) 1) (delete-char 1)) (goto-char pos))) ;; ;; added by MH ;; (defun ada-adjust-case-region (from to) "Adjusts the case of all identifiers and keywords in the region. ATTENTION: This function might take very long for big regions !" (interactive "*r") (let ((begin nil) (end nil) (keywordp nil) (reldiff nil)) (save-excursion (goto-char to) ;; ;; loop: look for all identifiers and keywords ;; (while (re-search-backward "[^a-zA-Z0-9_]\\([a-zA-Z0-9_]+\\)[^a-zA-Z0-9_]" from t) ;; ;; print status message ;; (setq reldiff (- (point) from)) (message (format "adjusting case ... %5d characters left" (- (point) from))) (forward-char 1) (or ;; do nothing if it is a string or comment (ada-in-string-or-comment-p) (progn ;; ;; get the identifier or keyword ;; (setq begin (point)) (setq keywordp (looking-at (concat ada-keywords "[^_]"))) (skip-chars-forward "a-zA-Z0-9_") ;; ;; casing according to user-option ;; (if keywordp (funcall ada-case-keyword -1) (funcall ada-case-identifier -1)) (goto-char begin)))) (message "adjusting case ... done")))) ;; ;; added by MH ;; (defun ada-adjust-case-buffer () "Adjusts the case of all identifiers and keywords 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 ;;; ;;;------------------------;;; (defun ada-format-paramlist () "Re-formats a parameter-list. ATTENTION: 1) Comments inside the list are killed ! 2) If the syntax is not correct (especially, if there are semicolons missing), it can get totally confused ! In such a case, use 'undo', correct the syntax and try again." (interactive) (let ((begin nil) (end nil) (delend nil) (paramlist nil)) ;; ;; ATTENTION: modify sntax-table temporary ! ;; (modify-syntax-entry ?_ "w") ;; 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 "\\<\\(" "procedure\\|function\\|body\\|package\\|task\\|entry\\|accept" "\\)\\>") t nil) (ada-search-ignore-string-comment "(" nil nil t) (backward-char 1) (setq begin (point)) ;; ;; find end of parameter-list ;; (forward-sexp 1) (setq delend (point)) (delete-char -1) ;; ;; find end of last parameter-declaration ;; (ada-search-ignore-string-comment "[^ \t\n]" t nil t) (forward-char 1) (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 (1- delend)) ;; ;; insert the new parameter-list ;; (goto-char begin) (ada-insert-paramlist paramlist) ;; ;; restore syntax-table ;; (modify-syntax-entry ?_ "_"))) (defun ada-scan-paramlist (begin end) ;; Scans a parameter-list between BEGIN and END and returns a list ;; of its contents. ;; The list has the following format: ;; ;; Name of Param in? out? accept? Name of Type Default-Exp or nil ;; ;; ( ('Name_Param_1' t nil t Type_Param_1 ':= expression') ;; ('Name_Param_2' nil nil t Type_Param_2 nil) ) (let ((paramlist (list)) (param (list)) (notend t) (apos nil) (epos nil) (semipos nil) (match-cons nil)) (goto-char begin) ;; ;; loop until end of last parameter ;; (while notend ;; ;; find first character of parameter-declaration ;; (ada-goto-next-non-ws) (setq apos (point)) ;; ;; find last character of parameter-declaration ;; (if (setq match-cons (ada-search-ignore-string-comment "[ \t\n]*;" nil end t)) (progn (setq epos (car match-cons)) (setq semipos (cdr match-cons))) (setq epos end)) ;; ;; read name(s) of parameter(s) ;; (goto-char apos) (looking-at "\\([a-zA-Z0-9_, \t\n]*[a-zA-Z0-9_]\\)[ \t\n]*:[^=]") (setq param (list (buffer-substring (match-beginning 1) (match-end 1)))) (ada-search-ignore-string-comment ":" nil epos t) ;; ;; look for 'in' ;; (setq apos (point)) (setq param (append param (list (consp (ada-search-ignore-string-comment "\\<in\\>" nil epos t))))) ;; ;; look for 'out' ;; (goto-char apos) (setq param (append param (list (consp (ada-search-ignore-string-comment "\\<out\\>" nil epos t))))) ;; ;; look for 'accept' ;; (goto-char apos) (setq param (append param (list (consp (ada-search-ignore-string-comment "\\<accept\\>" nil epos t))))) ;; ;; skip 'in'/'out'/'accept' ;; (goto-char apos) (ada-goto-next-non-ws) (while (looking-at "\\<\\(in\\|out\\|accept\\)\\>") (forward-word 1) (ada-goto-next-non-ws)) ;; ;; read type of parameter ;; (looking-at "\\<[a-zA-Z0-9_\\.]+\\>") (setq param (append param (list (buffer-substring (match-beginning 0) (match-end 0))))) ;; ;; read default-expression, if there is one ;; (goto-char (setq apos (match-end 0))) (setq param (append param (list (if (setq match-cons (ada-search-ignore-string-comment ":=" nil epos t)) (buffer-substring (car match-cons) epos) nil)))) ;; ;; add this parameter-declaration to the list ;; (setq paramlist (append paramlist (list param))) ;; ;; check if it was the last parameter ;; (if (eq epos end) (setq notend nil) (goto-char semipos)) ) ; end of loop (reverse paramlist))) (defun ada-insert-paramlist (paramlist) ;; Inserts a formatted PARAMLIST in the buffer. ;; See doc of ada-scan-paramlist for the format. (let ((i (length paramlist)) (parlen 0) (typlen 0) (temp 0) (inp nil) (outp nil) (acceptp nil) (column nil) (orgpoint 0) (firstcol nil)) ;; ;; loop until last parameter ;; (while (not (zerop i)) (setq i (1- i)) ;; ;; get max length of parameter-name ;; (setq parlen (if (<= parlen (setq temp (length (nth 0 (nth i paramlist))))) temp parlen)) ;; ;; get max length of type-name ;; (setq typlen (if (<= typlen (setq temp (length (nth 4 (nth i paramlist))))) temp typlen)) ;; ;; is there any 'in' ? ;; (setq inp (or inp (nth 1 (nth i paramlist)))) ;; ;; is there any 'out' ? ;; (setq outp (or outp (nth 2 (nth i paramlist)))) ;; ;; is there any 'accept' ? ;; (setq acceptp (or acceptp (nth 3 (nth i paramlist))))) ; end of loop ;; ;; does paramlist already start on a separate line ? ;; (if (save-excursion (re-search-backward "^.\\|[^ \t]" nil t) (looking-at "^.")) ;; yes => re-indent it (ada-indent-current) ;; ;; no => insert newline and indent it ;; (progn (ada-indent-current) (newline) (delete-horizontal-space) (setq orgpoint (point)) (setq column (save-excursion (funcall (ada-indent-function) orgpoint))) (indent-to column) )) (insert "(") (setq firstcol (current-column)) (setq i (length paramlist)) ;; ;; loop until last parameter ;; (while (not (zerop i)) (setq i (1- i)) (setq column firstcol) ;; ;; insert parameter-name, space and colon ;; (insert (nth 0 (nth i paramlist))) (indent-to (+ column parlen 1)) (insert ": ") (setq column (current-column)) ;; ;; insert 'in' or space ;; (if (nth 1 (nth i paramlist)) (insert "in ") (if (and (or inp acceptp) (not (nth 3 (nth i paramlist)))) (insert " "))) ;; ;; insert 'out' or space ;; (if (nth 2 (nth i paramlist)) (insert "out ") (if (and (or outp acceptp) (not (nth 3 (nth i paramlist)))) (insert " "))) ;; ;; insert 'accept' ;; (if (nth 3 (nth i paramlist)) (insert "accept ")) (setq column (current-column)) ;; ;; insert type-name and, if necessary, space and default-expression ;; (insert (nth 4 (nth i paramlist))) (if (nth 5 (nth i paramlist)) (progn (indent-to (+ column typlen 1)) (insert (nth 5 (nth i paramlist))))) ;; ;; check if it was the last parameter ;; (if (not (zerop i)) ;; no => insert ';' and newline and indent (progn (insert ";") (newline) (indent-to firstcol)) ;; yes (insert ")")) ) ; end of loop ;; ;; if anything follows, except semicolon: ;; put it in a new line and indent it ;; (if (not (looking-at "[ \t]*[;\n]")) (ada-indent-newline-indent)) )) ;;;----------------------------;;; ;;; Move To Matching Start/End ;;; ;;;----------------------------;;; (defun ada-move-to-start () "Moves point to the matching start of the current end ... around point." (interactive) (let ((pos (point))) ;; ;; ATTENTION: modify sntax-table temporary ! ;; (modify-syntax-entry ?_ "w") (message "searching for block start ...") (save-excursion ;; ;; do nothing if in string or comment or not on 'end ...;' ;; or if an error occurs during processing ;; (or (ada-in-string-or-comment-p) (and (progn (or (looking-at "[ \t]*\\<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)) ;; ;; on 'begin' => go on, according to user option ;; ada-move-to-declaration (looking-at "\\<begin\\>") (ada-goto-matching-decl-start) (setq pos (point)))) ) ; end of save-excursion ;; now really move to the found position (goto-char pos) (message "searching for block start ... done") ;; ;; restore syntax-table ;; (modify-syntax-entry ?_ "_"))) (defun ada-move-to-end () "Moves point to the matching end of the current block around point. Moves to 'begin' if in a declarative part." (interactive) (let ((pos (point)) (decstart nil) (packdecl nil)) ;; ;; ATTENTION: modify sntax-table temporary ! ;; (modify-syntax-entry ?_ "w") (message "searching for block end ...") (save-excursion (forward-char 1) (cond ;; directly on 'begin' ((save-excursion (ada-goto-previous-word) (looking-at "\\<begin\\>")) (ada-goto-matching-end 1)) ;; on first line of defun declaration ((save-excursion (and (ada-goto-stmt-start) (looking-at "\\<function\\>\\|\\<procedure\\>" ))) (ada-search-ignore-string-comment "\\<begin\\>")) ;; on first line of task declaration ((save-excursion (and (ada-goto-stmt-start) (looking-at "\\<task\\>" ) (forward-word 1) (ada-search-ignore-string-comment "[^ \n\t]") (not (backward-char 1)) (looking-at "\\<body\\>"))) (ada-search-ignore-string-comment "\\<begin\\>")) ;; accept block start ((save-excursion (and (ada-goto-stmt-start) (looking-at "\\<accept\\>" ))) (ada-goto-matching-end 0)) ;; package start ((save-excursion (and (ada-goto-matching-decl-start t) (looking-at "\\<package\\>"))) (ada-goto-matching-end 1)) ;; inside a 'begin' ... 'end' block ((save-excursion (ada-goto-matching-decl-start t)) (ada-search-ignore-string-comment "\\<begin\\>")) ;; (hopefully ;-) everything else (t (ada-goto-matching-end 1))) (setq pos (point)) ) ; end of save-excursion ;; now really move to the found position (goto-char pos) (message "searching for block end ... done") ;; ;; restore syntax-table ;; (modify-syntax-entry ?_ "_"))) ;;;-----------------------------;;; ;;; Functions For Indentation ;;; ;;;-----------------------------;;; ;; ---- main functions for indentation (defun ada-indent-region (beg end) "Indents the region using ada-indent-current on each line." (interactive "*r") (goto-char beg) ;; catch errors while indenting (condition-case err (while (< (point) end) (message (format "indenting ... %4d lines left" (count-lines (point) end))) (ada-indent-current) (forward-line 1)) ;; show line number where the error occured (error (error (format "line %d: %s" (1+ (count-lines (point-min) (point))) err) nil))) (message "indenting ... done")) (defun ada-indent-newline-indent () "Indents the current line, inserts a newline and then indents the new line." (interactive "*") (let ((column) (orgpoint)) (ada-indent-current) (newline) (delete-horizontal-space) (setq orgpoint (point)) ;; ;; ATTENTION: modify syntax-table temporary ! ;; (modify-syntax-entry ?_ "w") (setq column (save-excursion (funcall (ada-indent-function) orgpoint))) ;; ;; restore syntax-table ;; (modify-syntax-entry ?_ "_") (indent-to column) ;; The following is needed to ensure that indentation will still be ;; correct if something follows behind point when typing LFD ;; For example: Imagine point to be there (*) when LFD is typed: ;; while cond loop ;; null; *end loop; ;; Result without the following statement would be: ;; while cond loop ;; null; ;; *end loop; ;; You would then have to type TAB to correct it. ;; If that doesn't bother you, you can comment out the following ;; statement to speed up indentation a LITTLE bit. (if (not (looking-at "[ \t]*$")) (ada-indent-current)) )) (defun ada-indent-current () "Indents current line as Ada code. This works by two steps: 1) It moves point to the end of the previous code-line. Then it calls the function to calculate the indentation for the following line as if a newline would be inserted there. The calculated column # is saved and the old position of point is restored. 2) Then another function is called to calculate the indentation for the current line, based on the previously calculated column #." (interactive) ;; ;; ATTENTION: modify sntax-table temporary ! ;; (modify-syntax-entry ?_ "w") (let ((line-end) (orgpoint (point-marker)) (cur-indent) (prev-indent) (prevline t)) ;; ;; first step ;; (save-excursion (if (ada-goto-prev-nonblank-line t) ;; ;; we are not in the first accessible line in the buffer ;; (progn (end-of-line) (forward-char 1) (setq line-end (point)) (setq prev-indent (save-excursion (funcall (ada-indent-function) line-end)))) (setq prevline nil))) (if prevline ;; ;; we are not in the first accessible line in the buffer ;; (progn ;; ;; second step ;; (back-to-indentation) (setq cur-indent (ada-get-current-indent prev-indent)) (delete-horizontal-space) (indent-to cur-indent) ;; ;; restore position of point ;; (goto-char orgpoint) (if (< (current-column) (current-indentation)) (back-to-indentation))))) ;; ;; restore syntax-table ;; (modify-syntax-entry ?_ "_")) (defun ada-get-current-indent (prev-indent) ;; Returns the column # to indent the current line to. ;; PREV-INDENT is the indentation resulting from the previous lines. (let ((column nil) (pos nil) (match-cons nil)) (cond ;; ;; in open parenthesis, but not in parameter-list ;; ((and ada-indent-to-open-paren (not (ada-in-paramlist-p)) (setq column (ada-in-open-paren-p))) ;; check if we have something like this (Table_Component_Type => ;; Source_File_Record,) (save-excursion (if (and (ada-search-ignore-string-comment "[^ \t]" t nil) (looking-at "\n") (ada-search-ignore-string-comment "[^ \t\n]" t nil) (looking-at ">")) (setq column (+ ada-broken-indent column)))) column) ;; ;; end ;; ((looking-at "\\<end\\>") (save-excursion (ada-goto-matching-start 1) ;; ;; found 'loop' => skip back to 'while' or 'for' ;; if 'loop' is not on a separate line ;; (if (and (looking-at "\\<loop\\>") (save-excursion (back-to-indentation) (not (looking-at "\\<loop\\>")))) (if (save-excursion (and (setq match-cons (ada-search-ignore-string-comment ada-loop-start-re t nil)) (not (looking-at "\\<loop\\>")))) (goto-char (car match-cons)))) (current-indentation))) ;; ;; exception ;; ((looking-at "\\<exception\\>") (save-excursion (ada-goto-matching-start 1) (current-indentation))) ;; ;; when ;; ((looking-at "\\<when\\>") (save-excursion (ada-goto-matching-start 1) (+ (current-indentation) ada-when-indent))) ;; ;; else ;; ((looking-at "\\<else\\>") (if (save-excursion (ada-goto-previous-word) (looking-at "\\<or\\>")) prev-indent (save-excursion (ada-goto-matching-start 1 nil t) (current-indentation)))) ;; ;; elsif ;; ((looking-at "\\<elsif\\>") (save-excursion (ada-goto-matching-start 1 nil t) (current-indentation))) ;; ;; then ;; ((looking-at "\\<then\\>") (if (save-excursion (ada-goto-previous-word) (looking-at "\\<and\\>")) prev-indent (save-excursion (ada-search-ignore-string-comment "\\<elsif\\>\\|\\<if\\>" t nil) (+ (current-indentation) ada-stmt-end-indent)))) ;; ;; loop ;; ((looking-at "\\<loop\\>") (setq pos (point)) (save-excursion (goto-char (match-end 0)) (ada-goto-stmt-start) (if (looking-at "\\<loop\\>\\|\\<if\\>") prev-indent (progn (if (not (looking-at ada-loop-start-re)) (ada-search-ignore-string-comment ada-loop-start-re nil pos)) (if (looking-at "\\<loop\\>") prev-indent (+ (current-indentation) ada-stmt-end-indent)))))) ;; ;; begin ;; ((looking-at "\\<begin\\>") (save-excursion (if (ada-goto-matching-decl-start t) (current-indentation) (progn (message "no matching declaration start") prev-indent)))) ;; ;; is ;; ((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) (+ (current-indentation) ada-indent)) (save-excursion (ada-goto-stmt-start) (+ (current-indentation) ada-stmt-end-indent)))) ;; ;; record ;; ((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)) (+ (current-indentation) ada-indent-record-rel-type))) ;; ;; or as statement-start ;; ((ada-looking-at-semi-or) (save-excursion (ada-goto-matching-start 1) (current-indentation))) ;; ;; private as statement-start ;; ((ada-looking-at-semi-private) (save-excursion (ada-goto-matching-decl-start) (current-indentation))) ;; ;; new/abstract/separate ;; ((looking-at "\\<\\(new\\|abstract\\|separate\\)\\>") (- prev-indent ada-indent (- ada-broken-indent))) ;; ;; return ;; ((looking-at "\\<return\\>") (save-excursion (forward-sexp -1) (if (and (looking-at "(") (save-excursion (backward-sexp 2) (looking-at "\\<function\\>"))) (1+ (current-column)) prev-indent))) ;; ;; do ;; ((looking-at "\\<do\\>") (save-excursion (ada-goto-stmt-start) (+ (current-indentation) ada-stmt-end-indent))) ;; ;; package/function/procedure ;; ((and (looking-at "\\<\\(package\\|function\\|procedure\\)\\>") (save-excursion (forward-char 1) (ada-goto-stmt-start) (looking-at "\\<\\(package\\|function\\|procedure\\)\\>"))) (save-excursion ;; look for 'generic' (if (and (ada-goto-matching-decl-start t) (looking-at "generic")) (current-column) prev-indent))) ;; ;; label ;; ((looking-at "\\<[a-zA-Z0-9_]+[ \t\n]*:[^=]") (if (ada-in-decl-p) prev-indent (+ prev-indent ada-label-indent))) ;; ;; identifier and other noindent-statements ;; ((looking-at "\\<[a-zA-Z0-9_]+[ \t\n]*") prev-indent) ;; ;; beginning of a parameter list ;; ((looking-at "(") prev-indent) ;; ;; end of a parameter list ;; ((looking-at ")") (save-excursion (forward-char 1) (backward-sexp 1) (current-column))) ;; ;; comment ;; ((looking-at "--") (if ada-indent-comment-as-code prev-indent (current-indentation))) ;; ;; unknown syntax - maybe this should signal an error ? ;; (t prev-indent)))) (defun ada-indent-function (&optional nomove) ;; Returns the function to calculate the indentation for the current ;; line according to the previous statement, ignoring the contents ;; of the current line after point. Moves point to the beginning of ;; the current statement, if NOMOVE is nil. (let ((orgpoint (point)) (func nil) (stmt-start nil)) ;; ;; inside a parameter-list ;; (if (ada-in-paramlist-p) (setq func 'ada-get-indent-paramlist) (progn ;; ;; move to beginning of current statement ;; (if (not nomove) (setq stmt-start (ada-goto-stmt-start))) ;; ;; no beginning found => don't change indentation ;; (if (and (eq orgpoint (point)) (not nomove)) (setq func 'ada-get-indent-nochange) (cond ;; ((and ada-indent-to-open-paren (ada-in-open-paren-p)) (setq func 'ada-get-indent-open-paren)) ;; ((looking-at "\\<end\\>") (setq func 'ada-get-indent-end)) ;; ((looking-at ada-loop-start-re) (setq func 'ada-get-indent-loop)) ;; ((looking-at ada-subprog-start-re) (setq func 'ada-get-indent-subprog)) ;; ((looking-at "\\<package\\>") (setq func 'ada-get-indent-subprog)) ; maybe it needs a ; special function ; sometimes ? ;; ((looking-at ada-block-start-re) (setq func 'ada-get-indent-block-start)) ;; ((looking-at "\\<type\\>") (setq func 'ada-get-indent-type)) ;; ((looking-at "\\<if\\>") (setq func 'ada-get-indent-if)) ;; ((looking-at "\\<elsif\\>") (setq func 'ada-get-indent-if)) ; maybe it needs a special ; function sometimes ? ;; ((looking-at "\\<case\\>") (setq func 'ada-get-indent-case)) ;; ((looking-at "\\<when\\>") (setq func 'ada-get-indent-when)) ;; ((looking-at "--") (setq func 'ada-get-indent-comment)) ;; ((looking-at "[a-zA-Z0-9_]+[ \t\n]*:[^=]") (setq func 'ada-get-indent-label)) ;; (t (setq func 'ada-get-indent-noindent)))))) func)) ;; ---- functions to return indentation for special cases (defun ada-get-indent-open-paren (orgpoint) ;; Returns the indentation (column #) for the new line after ORGPOINT. ;; Assumes point to be behind an open paranthesis not yet closed. (ada-in-open-paren-p)) (defun ada-get-indent-nochange (orgpoint) ;; Returns the indentation (column #) of the current line. (save-excursion (forward-line -1) (current-indentation))) (defun ada-get-indent-paramlist (orgpoint) ;; Returns the indentation (column #) for the new line after ORGPOINT. ;; Assumes point to be inside a parameter-list. (save-excursion (ada-search-ignore-string-comment "[^ \t\n]" t nil t) (cond ;; ;; in front of the first parameter ;; ((looking-at "(") (goto-char (match-end 0)) (current-column)) ;; ;; in front of another parameter ;; ((looking-at ";") (goto-char (cdr (ada-search-ignore-string-comment "(\\|;" t nil t))) (ada-goto-next-non-ws) (current-column)) ;; ;; inside a parameter declaration ;; (t (goto-char (cdr (ada-search-ignore-string-comment "(\\|;" t nil t))) (ada-goto-next-non-ws) (+ (current-column) ada-broken-indent))))) (defun ada-get-indent-end (orgpoint) ;; Returns the indentation (column #) for the new line after ORGPOINT. ;; Assumes point to be at the beginning of an end-statement. ;; Therefore it has to find the corresponding start. This can be a little ;; slow, if it has to search through big files with many nested blocks. ;; Signals an error if the corresponding block-start doesn't match. (let ((defun-name nil) (indent nil)) ;; ;; is the line already terminated by ';' ? ;; (if (save-excursion (ada-search-ignore-string-comment ";" nil orgpoint)) ;; ;; yes, look what's following 'end' ;; (progn (forward-word 1) (ada-goto-next-non-ws) (cond ;; ;; loop/select/if/case/record/select ;; ((looking-at "\\<\\(loop\\|select\\|if\\|case\\|record\\)\\>") (save-excursion (ada-check-matching-start (buffer-substring (match-beginning 0) (match-end 0))) (if (looking-at "\\<\\(loop\\|record\\)\\>") (progn (forward-word 1) (ada-goto-stmt-start))) ;; a label ? => skip it (if (looking-at "[a-zA-Z0-9_]+[ \n\t]+:") (progn (goto-char (match-end 0)) (ada-goto-next-non-ws))) ;; really looking-at the right thing ? (or (looking-at (concat "\\<\\(" "loop\\|select\\|if\\|case\\|" "record\\|while\\|type\\)\\>")) (progn (ada-search-ignore-string-comment (concat "\\<\\(" "loop\\|select\\|if\\|case\\|" "record\\|while\\|type\\)\\>"))) (backward-word 1)) (current-indentation))) ;; ;; a named block end ;; ((looking-at "[a-zA-Z0-9_]+") (setq defun-name (buffer-substring (match-beginning 0) (match-end 0))) (save-excursion (ada-goto-matching-start 0) (ada-check-defun-name defun-name) (current-indentation))) ;; ;; a block-end without name ;; ((looking-at ";") (save-excursion (ada-goto-matching-start 0) (if (looking-at "\\<begin\\>") (progn (setq indent (current-column)) (if (ada-goto-matching-decl-start t) (current-indentation) indent))))) ;; ;; anything else - should maybe signal an error ? ;; (t (+ (current-indentation) ada-broken-indent)))) (+ (current-indentation) ada-broken-indent)))) (defun ada-get-indent-case (orgpoint) ;; Returns the indentation (column #) for the new line after ORGPOINT. ;; Assumes point to be at the beginning of an case-statement. (let ((cur-indent (current-indentation)) (match-cons nil) (opos (point))) (cond ;; ;; case..is..when..=> ;; ((save-excursion (setq match-cons (ada-search-ignore-string-comment "[ \t\n]+=>" nil orgpoint))) (save-excursion (goto-char (car match-cons)) (if (not (ada-search-ignore-string-comment "\\<when\\>" t opos)) (error "missing 'when' between 'case' and '=>'")) (+ (current-indentation) ada-indent))) ;; ;; case..is..when ;; ((save-excursion (setq match-cons (ada-search-ignore-string-comment "\\<when\\>" nil orgpoint))) (goto-char (cdr match-cons)) (+ (current-indentation) ada-broken-indent)) ;; ;; case..is ;; ((save-excursion (setq match-cons (ada-search-ignore-string-comment "\\<is\\>" nil orgpoint))) (+ (current-indentation) ada-when-indent)) ;; ;; incomplete case ;; (t (+ (current-indentation) ada-broken-indent))))) (defun ada-get-indent-when (orgpoint) ;; Returns the indentation (column #) for the new line after ORGPOINT. ;; Assumes point to be at the beginning of an when-statement. (let ((cur-indent (current-indentation))) (if (ada-search-ignore-string-comment "[ \t\n]+=>" nil orgpoint) (+ cur-indent ada-indent) (+ cur-indent ada-broken-indent)))) (defun ada-get-indent-if (orgpoint) ;; Returns the indentation (column #) for the new line after ORGPOINT. ;; Assumes point to be at the beginning of an if-statement. (let ((cur-indent (current-indentation)) (match-cons nil)) ;; ;; if..then ? ;; (if (ada-search-but-not "\\<then\\>" "\\<and\\>[ \t\n]+\\<then\\>" nil orgpoint) (progn ;; ;; 'then' first in separate line ? ;; => indent according to 'then' ;; (if (save-excursion (back-to-indentation) (looking-at "\\<then\\>")) (setq cur-indent (current-indentation))) (forward-word 1) ;; ;; something follows 'then' ? ;; (if (setq match-cons (ada-search-ignore-string-comment "[^ \t\n]" nil orgpoint)) (progn (goto-char (car match-cons)) (+ ada-indent (- cur-indent (current-indentation)) (funcall (ada-indent-function t) orgpoint))) (+ cur-indent ada-indent))) (+ cur-indent ada-broken-indent)))) (defun ada-get-indent-block-start (orgpoint) ;; Returns the indentation (column #) for the new line after ;; ORGPOINT. Assumes point to be at the beginning of a block start ;; keyword. (let ((cur-indent (current-indentation)) (pos nil)) (cond ((save-excursion (forward-word 1) (setq pos (car (ada-search-ignore-string-comment "[^ \t\n]" nil orgpoint)))) (goto-char pos) (save-excursion (funcall (ada-indent-function t) orgpoint))) ;; ;; nothing follows the block-start ;; (t (+ (current-indentation) ada-indent))))) (defun ada-get-indent-subprog (orgpoint) ;; Returns the indentation (column #) for the new line after ORGPOINT. ;; Assumes point to be at the beginning of a subprog-/package-declaration. (let ((match-cons nil) (cur-indent (current-indentation)) (foundis nil) (addind 0) (fstart (point))) ;; ;; is there an 'is' in front of point ? ;; (if (save-excursion (setq match-cons (ada-search-ignore-string-comment "\\<is\\>\\|\\<do\\>" nil orgpoint))) ;; ;; yes, then skip to its end ;; (progn (setq foundis t) (goto-char (cdr match-cons))) ;; ;; no, then goto next non-ws, if there is one in front of point ;; (progn (if (ada-search-ignore-string-comment "[^ \t\n]" nil orgpoint) (ada-goto-next-non-ws) (goto-char orgpoint)))) (cond ;; ;; nothing follows 'is' ;; ((and foundis (save-excursion (not (ada-search-ignore-string-comment "[^ \t\n]" nil orgpoint t)))) (+ cur-indent ada-indent)) ;; ;; is abstract/separate/new ... ;; ((and foundis (save-excursion (setq match-cons (ada-search-ignore-string-comment "\\<\\(separate\\|new\\|abstract\\)\\>" nil orgpoint)))) (goto-char (car match-cons)) (ada-search-ignore-string-comment (concat ada-subprog-start-re "\\|\\<package\\>") t) (ada-get-indent-noindent orgpoint)) ;; ;; something follows 'is' ;; ((and foundis (save-excursion (ada-search-ignore-string-comment "[^ \t\n]" nil orgpoint)) (ada-goto-next-non-ws) (funcall (ada-indent-function t) orgpoint))) ;; ;; no 'is' but ';' ;; ((save-excursion (ada-search-ignore-string-comment ";" nil orgpoint)) cur-indent) ;; ;; no 'is' or ';' ;; (t (+ cur-indent ada-broken-indent))))) (defun ada-get-indent-noindent (orgpoint) ;; Returns the indentation (column #) for the new line after ORGPOINT. ;; Assumes point to be at the beginning of a 'noindent statement'. (if (save-excursion (ada-search-ignore-string-comment ";" nil orgpoint)) (current-indentation) (+ (current-indentation) ada-broken-indent))) (defun ada-get-indent-label (orgpoint) ;; Returns the indentation (column #) for the new line after ORGPOINT. ;; Assumes point to be at the beginning of a label or variable declaration. ;; Checks the context to decide if it's a label or a variable declaration. ;; This check might be a bit slow. (let ((match-cons nil) (cur-indent (current-indentation))) (goto-char (cdr (ada-search-ignore-string-comment ":"))) (cond ;; ;; loop label ;; ((save-excursion (setq match-cons (ada-search-ignore-string-comment ada-loop-start-re nil orgpoint))) (goto-char (car match-cons)) (ada-get-indent-loop orgpoint)) ;; ;; declare label ;; ((save-excursion (setq match-cons (ada-search-ignore-string-comment "\\<declare\\>" nil orgpoint))) (save-excursion (goto-char (car match-cons)) (+ (current-indentation) ada-indent))) ;; ;; complete statement following colon ;; ((save-excursion (ada-search-ignore-string-comment ";" nil orgpoint)) (if (ada-in-decl-p) cur-indent ; variable-declaration (- cur-indent ada-label-indent))) ; label ;; ;; broken statement ;; ((save-excursion (ada-search-ignore-string-comment "[^ \t\n]" nil orgpoint)) (if (ada-in-decl-p) (+ cur-indent ada-broken-indent) (+ cur-indent ada-broken-indent (- ada-label-indent)))) ;; ;; nothing follows colon ;; (t (if (ada-in-decl-p) (+ cur-indent ada-broken-indent) ; variable-declaration (- cur-indent ada-label-indent)))))) ; label (defun ada-get-indent-loop (orgpoint) ;; Returns the indentation (column #) for the new line after ORGPOINT. ;; Assumes point to be at the beginning of a loop statement ;; or (unfortunately) also a for ... use statement. (let ((match-cons nil) (pos (point))) (cond ;; ;; statement complete ;; ((save-excursion (ada-search-ignore-string-comment ";" nil orgpoint)) (current-indentation)) ;; ;; simple loop ;; ((looking-at "loop\\>") (ada-get-indent-block-start orgpoint)) ;; ;; 'for'- loop (or also a for ... use statement) ;; ((looking-at "for\\>") (cond ;; ;; for ... use ;; ((save-excursion (and (goto-char (match-end 0)) (ada-search-ignore-string-comment "[^ /n/t]" nil orgpoint) (not (backward-char 1)) (not (zerop (skip-chars-forward "_a-zA-Z0-9'"))) (ada-search-ignore-string-comment "[^ /n/t]" nil orgpoint) (not (backward-char 1)) (looking-at "\\<use\\>") ;; ;; check if there is a 'record' before point ;; (progn (setq match-cons (ada-search-ignore-string-comment "\\<record\\>" nil orgpoint)) t))) (if match-cons (goto-char (car match-cons))) (+ (current-indentation) ada-indent)) ;; ;; for..loop ;; ((save-excursion (setq match-cons (ada-search-ignore-string-comment "\\<loop\\>" nil orgpoint))) (goto-char (car match-cons)) ;; ;; indent according to 'loop', if it's first in the line; ;; otherwise to 'for' ;; (if (not (save-excursion (back-to-indentation) (looking-at "\\<loop\\>"))) (goto-char pos)) (+ (current-indentation) ada-indent)) ;; ;; for-statement is broken ;; (t (+ (current-indentation) ada-broken-indent)))) ;; ;; 'while'-loop ;; ((looking-at "while\\>") ;; ;; while..loop ? ;; (if (save-excursion (setq match-cons (ada-search-ignore-string-comment "\\<loop\\>" nil orgpoint))) (progn (goto-char (car match-cons)) ;; ;; indent according to 'loop', if it's first in the line; ;; otherwise to 'while'. ;; (if (not (save-excursion (back-to-indentation) (looking-at "\\<loop\\>"))) (goto-char pos)) (+ (current-indentation) ada-indent)) (+ (current-indentation) ada-broken-indent)))))) (defun ada-get-indent-type (orgpoint) ;; Returns the indentation (column #) for the new line after ORGPOINT. ;; Assumes point to be at the beginning of a type statement. (let ((match-dat nil)) (cond ;; ;; complete record declaration ;; ((save-excursion (and (setq match-dat (ada-search-ignore-string-comment "\\<end\\>" nil orgpoint)) (ada-goto-next-non-ws) (looking-at "\\<record\\>") (forward-word 1) (ada-goto-next-non-ws) (looking-at ";"))) (goto-char (car match-dat)) (current-indentation)) ;; ;; record type ;; ((save-excursion (setq match-dat (ada-search-ignore-string-comment "\\<record\\>" nil orgpoint))) (goto-char (car match-dat)) (+ (current-indentation) ada-indent)) ;; ;; complete type declaration ;; ((save-excursion (ada-search-ignore-string-comment ";" nil orgpoint)) (current-indentation)) ;; ;; type ... is ;; ((save-excursion (ada-search-ignore-string-comment "\\<is\\>" nil orgpoint)) (+ (current-indentation) ada-indent)) ;; ;; broken statement ;; (t (+ (current-indentation) ada-broken-indent))))) ;;; ---- support-functions for indentation ;;; ---- searching and matching (defun ada-goto-stmt-start (&optional limit) ;; Moves point to the beginning of the statement that point is in or ;; after. Returns the new position of point. Beginnings are found ;; by searching for 'ada-end-stmt-re' and then moving to the ;; following non-ws that is not a comment. LIMIT is actually not ;; used by the indentation functions. (let ((match-dat nil) (orgpoint (point))) (setq match-dat (ada-search-prev-end-stmt limit)) (if match-dat ;; ;; found a previous end-statement => check if anything follows ;; (progn (if (not (save-excursion (goto-char (cdr match-dat)) (ada-search-ignore-string-comment "[^ \t\n]" nil orgpoint))) ;; ;; nothing follows => it's the end-statement directly in ;; front of point => search again ;; (setq match-dat (ada-search-prev-end-stmt limit))) ;; ;; if found the correct end-stetement => goto next non-ws ;; (if match-dat (goto-char (cdr match-dat))) (ada-goto-next-non-ws)) ;; ;; no previous end-statement => we are at the beginning of the ;; accessible part of the buffer ;; (progn (goto-char (point-min)) ;; ;; skip to the very first statement, if there is one ;; (if (setq match-dat (ada-search-ignore-string-comment "[^ \t\n]" nil orgpoint)) (goto-char (car match-dat)) (goto-char orgpoint)))) (point))) (defun ada-search-prev-end-stmt (&optional limit) ;; Moves point to previous end-statement. Returns a cons cell whose ;; car is the beginning and whose cdr the end of the match. ;; End-statements are defined by 'ada-end-stmt-re'. Checks for ;; certain keywords if they follow 'end', which means they are no ;; end-statement there. (let ((match-dat nil) (pos nil) (found nil)) ;; ;; search until found or beginning-of-buffer ;; (while (and (not found) (setq match-dat (ada-search-ignore-string-comment ada-end-stmt-re t limit))) (goto-char (car match-dat)) (if (not (ada-in-open-paren-p)) ;; ;; check if there is an 'end' in front of the match ;; (if (not (and (looking-at "\\<\\(record\\|loop\\|select\\)\\>") (save-excursion (ada-goto-previous-word) (looking-at "\\<end\\>")))) (setq found t) (backward-word 1)))) ; end of loop (if found match-dat nil))) (defun ada-goto-next-non-ws (&optional limit) ;; Skips whitespaces, newlines and comments to next non-ws ;; character. Signals an error if there is no more such character ;; and limit is nil. (let ((match-cons nil)) (setq match-cons (ada-search-ignore-string-comment "[^ \t\n]" nil limit t)) (if match-cons (goto-char (car match-cons)) (if (not limit) (error "no more non-ws") 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. (if (ada-search-ignore-string-comment ada-end-stmt-re nil limit) (point) nil)) (defun 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. (let ((match-cons nil) (orgpoint (point))) (if (setq match-cons (ada-search-ignore-string-comment "[^ \t\n]" t nil t)) ;; ;; move to the beginning of the word found ;; (progn (goto-char (cdr match-cons)) (skip-chars-backward "_a-zA-Z0-9") (point)) ;; ;; if not found, restore old position of point ;; (progn (goto-char orgpoint) 'nil)))) (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) (if (not (looking-at (concat "\\<" keyword "\\>"))) (error (concat "matching start is not '" 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. ;; ;; 'accept' or 'package' ? ;; (if (not (looking-at "\\<\\(accept\\|package\\|task\\)\\>")) (ada-goto-matching-decl-start)) ;; ;; 'begin' of 'procedure'/'function'/'task' or 'declare' ;; (save-excursion ;; ;; a named 'declare'-block ? ;; (if (looking-at "\\<declare\\>") (ada-goto-stmt-start) ;; ;; no, => 'procedure'/'function'/'task' ;; (progn (forward-word 2) (backward-word 1) ;; ;; skip 'body' or 'type' ;; (if (looking-at "\\<\\(body\\|type\\)\\>") (forward-word 1)) (forward-sexp 1) (backward-sexp 1))) ;; ;; should be looking-at the correct name ;; (if (not (looking-at (concat "\\<" defun-name "\\>"))) (error (concat "matching defun has different name: " (buffer-substring (point) (progn (forward-sexp 1) (point)))))))) (defun ada-goto-matching-decl-start (&optional noerror nogeneric) ;; 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) (pos nil) (first t) (flag nil)) ;; ;; search backward for interesting keywords ;; (while (and (not (zerop nest-count)) (ada-search-ignore-string-comment (concat "\\<\\(" "is\\|separate\\|end\\|declare\\|new\\|begin\\|generic" "\\)\\>") t)) ;; ;; calculate nest-depth ;; (cond ;; ((looking-at "end") (ada-goto-matching-start 1 noerror) (if (progn (looking-at "begin")) (setq nest-count (1+ nest-count)))) ;; ((looking-at "declare\\|generic") (setq nest-count (1- nest-count)) (setq first nil)) ;; ((looking-at "is") ;; check if it is only a type definition (if (save-excursion (ada-goto-previous-word) (skip-chars-backward "a-zA-Z0-9_.'") (if (save-excursion (backward-char 1) (looking-at ")")) (progn (forward-char 1) (backward-sexp 1) (skip-chars-backward "a-zA-Z0-9_.'") )) (ada-goto-previous-word) (looking-at "\\<type\\>")) ; end of save-excursion (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) (setq flag t)) ;; (t (setq nest-count (1+ nest-count)) (setq first nil))) ) ;; end of loop ;; check if declaration-start is really found (if (not (and (zerop nest-count) (not flag) (progn (if (looking-at "is") (ada-search-ignore-string-comment "\\<\\(procedure\\|function\\|task\\|package\\)\\>" t) (looking-at "declare\\|generic"))))) (if noerror nil (error "no matching procedure/function/task/declare/package")) t))) (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)) ;; ;; search backward for interesting keywords ;; (while (and (not found) (ada-search-ignore-string-comment (concat "\\<\\(" "end\\|loop\\|select\\|begin\\|case\\|" "if\\|task\\|package\\|record\\|do\\)\\>") t)) ;; ;; calculate nest-depth ;; (cond ;; found block end => increase nest depth ((looking-at "end") (setq nest-count (1+ nest-count))) ;; found loop/select/record/case/if => check if it starts or ;; ends a block ((looking-at "loop\\|select\\|record\\|case\\|if") (setq pos (point)) (save-excursion ;; ;; check if keyword follows 'end' ;; (ada-goto-previous-word) (if (looking-at "\\<end\\>") ;; it ends a block => increase nest depth (progn (setq nest-count (1+ nest-count)) (setq pos (point))) ;; it starts a block => decrease nest depth (setq nest-count (1- nest-count)))) (goto-char pos)) ;; found package start => check if it really is a block ((looking-at "package") (save-excursion (ada-search-ignore-string-comment "\\<is\\>") (ada-goto-next-non-ws) ;; ignore it if it is only a declaration with 'new' (if (not (looking-at "\\<new\\>")) (setq nest-count (1- nest-count))))) ;; found task start => check if it has a body ((looking-at "task") (save-excursion (forward-word 1) (ada-goto-next-non-ws) ;; ignore it if it has no body (if (not (looking-at "\\<body\\>")) (setq nest-count (1- nest-count))))) ;; all the other block starts (t (setq nest-count (1- nest-count)))) ; end of 'cond' ;; match is found, if nest-depth is zero ;; (setq found (zerop nest-count))) ; end of loop (if found ;; ;; match found => is there anything else to do ? ;; (progn (cond ;; ;; found 'if' => skip to 'then', if it's on a separate line ;; and GOTOTHEN is non-nil ;; ((and gotothen (looking-at "if") (save-excursion (ada-search-ignore-string-comment "\\<then\\>" nil nil) (back-to-indentation) (looking-at "\\<then\\>"))) (goto-char (match-beginning 0))) ;; ;; found 'do' => skip back to 'accept' ;; ((looking-at "do") (if (not (ada-search-ignore-string-comment "\\<accept\\>" t nil)) (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)) ;; ;; search forward for interesting keywords ;; (while (and (not found) (ada-search-ignore-string-comment (concat "\\<\\(end\\|loop\\|select\\|begin\\|case\\|" "if\\|task\\|package\\|record\\|do\\)\\>"))) ;; ;; calculate nest-depth ;; (backward-word 1) (cond ;; found block end => decrease nest depth ((looking-at "\\<end\\>") (setq nest-count (1- nest-count)) ;; skip the following keyword (if (progn (skip-chars-forward "end") (ada-goto-next-non-ws) (looking-at "\\<\\(loop\\|select\\|record\\|case\\|if\\)\\>")) (forward-word 1))) ;; found package start => check if it really starts a block ((looking-at "\\<package\\>") (ada-search-ignore-string-comment "\\<is\\>") (ada-goto-next-non-ws) ;; ignore and skip it if it is only a 'new' package (if (not (looking-at "\\<new\\>")) (setq nest-count (1+ nest-count)) (skip-chars-forward "new"))) ;; all the other block starts (t (setq nest-count (1+ nest-count)) (forward-word 1))) ; end of 'cond' ;; match is found, if nest-depth is zero ;; (setq found (zerop nest-count))) ; end of loop (if (not found) (if noerror nil (error "no matching end")) t))) (defun ada-forward-sexp-ignore-comment () ;; Skips one sexp forward, ignoring comments. (while (looking-at "[ \t\n]*--") (skip-chars-forward "[ \t\n]") (end-of-line)) (forward-sexp 1)) (defun ada-search-ignore-string-comment (search-re &optional backward limit paramlists) ;; Regexp-Search for SEARCH-RE, ignoring comments, strings and ;; parameter lists, if PARAMLISTS is nil. Returns a cons cell of ;; begin and end of match data or nil, if not found. (let ((found nil) (begin nil) (end nil) (pos nil) (search-func (if backward 're-search-backward 're-search-forward))) ;; ;; search until found or end-of-buffer ;; (while (and (not found) (funcall search-func search-re limit 1)) (setq begin (match-beginning 0)) (setq end (match-end 0)) (cond ;; ;; found in comment => skip it ;; ((ada-in-comment-p) (if backward (progn (re-search-backward "--" nil 1) (goto-char (match-beginning 0))) (progn (forward-line 1) (beginning-of-line)))) ;; ;; found in string => skip it ;; ((ada-in-string-p) (if backward (progn (re-search-backward "\"\\|#" nil 1) (goto-char (match-beginning 0)))) (re-search-forward "\"\\|#" nil 1)) ;; ;; found character constant => ignore it ;; ((save-excursion (setq pos (- (point) (if backward 1 2))) (and (char-after pos) (= (char-after pos) ?') (= (char-after (+ pos 2)) ?'))) ()) ;; ;; found a parameter-list but should ignore it => skip it ;; ((and (not paramlists) (ada-in-paramlist-p)) (if backward (ada-search-ignore-string-comment "(" t nil t))) ;; ;; directly in front of a comment => skip it, if searching forward ;; ((save-excursion (goto-char begin) (looking-at "--")) (if (not backward) (progn (forward-line 1) (beginning-of-line)))) ;; ;; found what we were looking for ;; (t (setq found t)))) ; end of loop (if found (cons begin end) nil))) (defun ada-search-but-not (search-re not-search-re &optional backward limit) ;; Searches SEARCH-RE, ignoring parts of NOT-SEARCH-RE, strings, ;; comments and parameter-lists. (let ((begin nil) (end nil) (begin-not nil) (begin-end nil) (end-not nil) (ret-cons nil) (found nil)) ;; ;; search until found or end-of-buffer ;; (while (and (not found) (save-excursion (setq ret-cons (ada-search-ignore-string-comment search-re backward limit)) (if (consp ret-cons) (progn (setq begin (car ret-cons)) (setq end (cdr ret-cons)) t) nil))) (if (or ;; ;; if no NO-SEARCH-RE was found ;; (not (save-excursion (setq ret-cons (ada-search-ignore-string-comment not-search-re backward nil)) (if (consp ret-cons) (progn (setq begin-not (car ret-cons)) (setq end-not (cdr ret-cons)) t) nil))) ;; ;; or this NO-SEARCH-RE is not a part of the SEARCH-RE ;; found before. ;; (or (<= end-not begin) (>= begin-not end))) (setq found t) ;; ;; not found the correct match => skip this match ;; (goto-char (if backward begin end)))) ; end of loop (if found (progn (goto-char begin) (cons begin end)) nil))) (defun ada-goto-prev-nonblank-line ( &optional ignore-comment) ;; Moves point to previous non-blank line, ;; ignoring comments if IGNORE-COMMENT is non-nil. ;; It returns t if a matching line was found. (let ((notfound t) (newpoint nil)) (save-excursion ;; ;; backward one line, if there is one ;; (if (zerop (forward-line -1)) ;; ;; there is some kind of previous line ;; (progn (beginning-of-line) (setq newpoint (point)) ;; ;; search until found or beginning-of-buffer ;; (while (and (setq notfound (or (looking-at "[ \t]*$") (and (looking-at "[ \t]*--") ignore-comment))) (not (in-limit-line-p))) (forward-line -1) (beginning-of-line) (setq newpoint (point))) ; end of loop )) ; end of if ) ; end of save-excursion (if notfound nil (progn (goto-char newpoint) t)))) (defun ada-goto-next-nonblank-line ( &optional ignore-comment) ;; Moves point to next non-blank line, ;; ignoring comments if IGNORE-COMMENT is non-nil. ;; It returns t if a matching line was found. (let ((notfound t) (newpoint nil)) (save-excursion ;; ;; forward one line ;; (if (zerop (forward-line 1)) ;; ;; there is some kind of previous line ;; (progn (beginning-of-line) (setq newpoint (point)) ;; ;; search until found or end-of-buffer ;; (while (and (setq notfound (or (looking-at "[ \t]*$") (and (looking-at "[ \t]*--") ignore-comment))) (not (in-limit-line-p))) (forward-line 1) (beginning-of-line) (setq newpoint (point))) ; end of loop )) ; end of if ) ; end of save-excursion (if notfound nil (progn (goto-char newpoint) t)))) ;; ---- boolean functions for indentation (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 an 'private' following a semicolon. (save-excursion (and (looking-at "\\<private\\>") (progn (forward-word 1) (ada-goto-stmt-start) (looking-at "\\<private\\>"))))) (defun in-limit-line-p () ;; Returns t if point is in first or last accessible line. (or (>= 1 (count-lines (point-min) (point))) (>= 1 (count-lines (point) (point-max))))) (defun ada-in-comment-p () ;; Returns t if inside a comment. (save-excursion (and (re-search-backward "\\(--\\|\n\\)" nil 1) (looking-at "-")))) (defun ada-in-string-p () ;; Returns t if point is inside a string ;; (Taken from pascal-mode.el, modified by MH). (save-excursion (and (nth 3 (parse-partial-sexp (save-excursion (beginning-of-line) (point)) (point))) ;; check if 'string quote' is only a character constant (progn (re-search-backward "\"\\|#" nil t) (not (= (char-after (1- (point))) ?')))))) (defun ada-in-string-or-comment-p () ;; Returns t if point is inside a string or a comment. (or (ada-in-comment-p) (ada-in-string-p))) (defun ada-in-paramlist-p () ;; Returns t if point is inside a parameter-list ;; following 'function'/'procedure'/'package'. (save-excursion (and (re-search-backward "(\\|)" nil t) ;; inside parentheses ? (looking-at "(") (backward-word 2) ;; right keyword before paranthesis ? (looking-at (concat "\\<\\(" "procedure\\|function\\|body\\|package\\|" "task\\|entry\\|accept\\)\\>")) (re-search-forward ")\\|:" nil t) ;; at least one ':' inside the parentheses ? (not (backward-char 1)) (looking-at ":")))) ;; not really a boolean function ... (defun ada-in-open-paren-p () ;; If point is somewhere behind an open parenthesis not yet closed, ;; it returns the column # of the first non-ws behind this open ;; parenthesis, otherwise nil." (let ((nest-count 1) (limit nil) (found nil) (pos nil) (col nil) (counter ada-search-paren-line-count-limit)) ;; ;; get search-limit ;; (if ada-search-paren-line-count-limit (setq limit (save-excursion (while (not (zerop counter)) (ada-goto-prev-nonblank-line) (setq counter (1- counter))) (beginning-of-line) (point)))) (save-excursion ;; ;; loop until found or limit ;; (while (and (not found) (ada-search-ignore-string-comment "(\\|)" t limit t)) (setq nest-count (if (looking-at ")") (1+ nest-count) (1- nest-count))) (setq found (zerop nest-count))) ; end of loop (if found ;; if found => return column of first non-ws after the parenthesis (progn (forward-char 1) (if (save-excursion (re-search-forward "[^ \t]" nil 1) (backward-char 1) (and (not (looking-at "\n")) (setq col (current-column)))) col (current-column))) nil)))) ;;;-----------------------------;;; ;;; Simple Completion Functions ;;; ;;;-----------------------------;;; ;; These are my first steps in Emacs-Lisp ... :-) They can be replaced ;; by functions based on the output of the Gnatf Tool that comes with ;; the GNAT Ada compiler. See the file ada-xref.el (MH) But you might ;; use these functions if you don't use GNAT (defun ada-use-last-with () "Inserts the package name of the last 'with' statement after use." (interactive) (let ((pakname nil)) (save-excursion (forward-word -1) (if (looking-at "use") ;; ;; find last 'with' ;; (progn (re-search-backward "\\(\\<with\\s-+\\)\\([a-zA-Z0-9_.]+\\)\\(\\s-*;\\)") ;; ;; get the name of the package ;; (setq pakname (concat (buffer-substring (match-beginning 2) (match-end 2)) ";"))) (setq pakname ""))) (insert pakname))) (defun ada-complete-symbol (symboldef position symalist) ;; Tries to complete a symbol in the buffer. ;; SYMBOLDEF is the regexp to find the definition of the desired symbol. ;; POSITION is the position of the subexpression in SYMBOLDEF to match ;; the symbol itself. ;; SYMALIST is an alist with possibly predefined completions." (let ((sofar nil) (completed nil) (insertpos nil)) (save-excursion ;; ;; get the part of the symbol already typed ;; (re-search-backward "\\([^a-zA-Z0-9_\\.]\\)\\([a-zA-Z0-9_\\.]+\\)") (setq sofar (buffer-substring (match-beginning 2) (match-end 2))) ;; ;; delete it ;; (delete-region (setq insertpos (match-beginning 2)) (match-end 2)) ;; ;; find all possible completions by searching for definitions of ;; this kind of symbol ;; (while (re-search-backward symboldef nil t) ;; ;; build an alist of these possible completions ;; (setq symalist (cons (cons (buffer-substring (match-beginning position) (match-end position)) nil) symalist))) (or ;; ;; symbol gets completed as far as possible ;; (stringp (setq completed (try-completion sofar symalist))) ;; ;; or is already complete ;; (setq completed sofar))) ;; ;; insert the completed symbol ;; (goto-char insertpos) (insert completed))) (defun ada-complete-use () "Tries to complete the package name in an 'use' statement in the buffer. Searches through former 'with' statements for possible completions." (interactive) (ada-complete-symbol "\\(\\<with\\s-+\\)\\([a-zA-Z0-9_.]+\\)\\(\\s-*;\\)" 2 nil) (insert ";")) (defun ada-complete-procedure () "Tries to complete a procedure/function name in the buffer." (interactive) (ada-complete-symbol ada-procedure-start-regexp 2 nil)) (defun ada-complete-variable () "Tries to complete a variable name in the buffer." (interactive) (ada-complete-symbol "\\([^a-zA-Z0-9_]\\)\\([a-zA-Z0-9_]+\\)[ \t\n]+\\(:\\)" 2 nil)) (defun ada-complete-type () "Tries to complete a type name in the buffer." (interactive) (ada-complete-symbol "\\(type\\)[ \t\n]+\\([a-zA-Z0-9_\\.]+\\)" 2 '(("Integer" nil) ("Long_Integer" nil) ("Natural" nil) ("Positive" nil) ("Short_Integer" nil)))) ;;;----------------------;;; ;;; Behaviour Of TAB Key ;;; ;;;----------------------;;; (defun ada-tab () "Do indenting or tabbing according to `ada-tab-policy'." (interactive) (cond ((eq ada-tab-policy 'indent-and-tab) (error "not implemented")) ;; ada-indent-and-tab ((eq ada-tab-policy 'indent-rigidly) (ada-tab-hard)) ((eq ada-tab-policy 'indent-auto) (ada-indent-current)) ((eq ada-tab-policy 'gei) (ada-tab-gei)) ((eq ada-tab-policy 'indent-af) (af-indent-line)) ; GEB ((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-af) (backward-delete-char-untabify ; GEB (prefix-numeric-value arg) ; GEB arg)) ; GEB ((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))) (ada-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-tabsize (s) "changes spacing used for indentation. Reads spacing from minibuffer." (interactive "nnew indentation spacing: ") (setq ada-indent s)) ;;;---------------;;; ;;; Miscellaneous ;;; ;;;---------------;;; (defun ada-remove-trailing-spaces () ;; remove all trailing spaces at the end of lines. "remove trailing spaces in the whole buffer." (interactive) (save-excursion (goto-char (point-min)) (while (re-search-forward "[ \t]+$" nil t) (replace-match "" nil nil)))) (defun ada-untabify-buffer () ;; change all tabs to spaces (save-excursion (untabify (point-min) (point-max)))) (defun ada-uncomment-region (beg end) "delete comment-start at the beginning of a line in the region." (interactive "r") (comment-region beg end -1)) ;; define a function to support find-file.el if loaded (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))) ;;;-------------------------------;;; ;;; Moving To Procedures/Packages ;;; ;;;-------------------------------;;; (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"))) ;;;----------------------- ;;; define keymap for Ada ;;;----------------------- (if (not ada-mode-map) (progn (setq ada-mode-map (make-sparse-keymap)) ;; Indentation and Formatting (define-key ada-mode-map "\C-j" 'ada-indent-newline-indent) (define-key ada-mode-map "\t" 'ada-tab) (define-key ada-mode-map "\C-c\C-l" 'ada-indent-region) ;; How do I write this for working with Lucid Emacs? (define-key ada-mode-map [S-tab] 'ada-untab) (define-key ada-mode-map "\C-c\C-f" 'ada-format-paramlist) (define-key ada-mode-map "\C-c\C-p" 'ada-call-pretty-printer) ;;; We don't want to make meta-characters case-specific. ;;; (define-key ada-mode-map "\M-Q" 'ada-fill-comment-paragraph-justify) (define-key ada-mode-map "\M-\C-q" 'ada-fill-comment-paragraph-postfix) ;; Movement ;;; It isn't good to redefine these. What should be done instead? -- rms. ;;; (define-key ada-mode-map "\M-e" 'ada-next-procedure) ;;; (define-key ada-mode-map "\M-a" 'ada-previous-procedure) (define-key ada-mode-map "\M-\C-e" 'ada-next-package) (define-key ada-mode-map "\M-\C-a" 'ada-previous-package) (define-key ada-mode-map "\C-c\C-a" 'ada-move-to-start) (define-key ada-mode-map "\C-c\C-e" 'ada-move-to-end) ;; Compilation (define-key ada-mode-map "\C-c\C-c" 'compile) ;; Casing (define-key ada-mode-map "\C-c\C-r" 'ada-adjust-case-region) (define-key ada-mode-map "\C-c\C-b" 'ada-adjust-case-buffer) (define-key ada-mode-map "\177" 'backward-delete-char-untabify) ;; Use predefined function of emacs19 for comments (RE) (define-key ada-mode-map "\C-c;" 'comment-region) (define-key ada-mode-map "\C-c:" 'ada-uncomment-region) ;; Change basic functionality (mapcar (lambda (pair) (substitute-key-definition (car pair) (cdr pair) ada-mode-map global-map)) '((beginning-of-line . ada-beginning-of-line) (end-of-line . ada-end-of-line) (forward-to-indentation . ada-forward-to-indentation) )) )) ;;;------------------- ;;; define menu 'Ada' ;;;------------------- (defun ada-add-ada-menu () "Adds the menu 'Ada' to the menu-bar in Ada Mode." (easy-menu-define t ada-mode-map t '("Ada" ["next package" ada-next-package t] ["previous package" ada-previous-package t] ["next procedure" ada-next-procedure t] ["previous procedure" ada-previous-procedure t] ["goto start" ada-move-to-start t] ["goto end" ada-move-to-end t] ["------------------" nil nil] ["indent current line (TAB)" ada-indent-current-function t] ["indent lines in region" ada-indent-region t] ["format parameter list" ada-format-paramlist t] ["pretty print buffer" ada-call-pretty-printer t] ["------------" nil nil] ["fill comment paragraph" ada-fill-comment-paragraph t] ["justify comment paragraph" ada-fill-comment-paragraph-justify t] ["postfix comment paragraph" ada-fill-comment-paragraph-postfix t] ["------------" nil nil] ["adjust case region" ada-adjust-case-region t] ["adjust case buffer" ada-adjust-case-buffer t] ["----------" nil nil] ["comment region" comment-region t] ["uncomment region" ada-uncomment-region t] ["----------------" nil nil] ["compile" compile (fboundp 'compile)] ["next error" next-error (fboundp 'next-error)] ["---------------" nil nil] ["Index" imenu (fboundp 'imenu)] ["--------------" nil nil] ["other file other window" ada-ff-other-window (fboundp 'ff-find-other-file)] ["other file" ff-find-other-file (fboundp 'ff-find-other-file)]))) ;;;------------------------------- ;;; Define Some Support Functions ;;;------------------------------- (defun ada-beginning-of-line (&optional arg) (interactive "P") (cond ((eq ada-tab-policy 'indent-af) (af-beginning-of-line arg)) (t (beginning-of-line arg)) )) (defun ada-end-of-line (&optional arg) (interactive "P") (cond ((eq ada-tab-policy 'indent-af) (af-end-of-line arg)) (t (end-of-line arg)) )) (defun ada-current-column () (cond ((eq ada-tab-policy 'indent-af) (af-current-column)) (t (current-column)) )) (defun ada-forward-to-indentation (&optional arg) (interactive "P") (cond ((eq ada-tab-policy 'indent-af) (af-forward-to-indentation arg)) (t (forward-to-indentation arg)) )) ;;;--------------------------------------------------- ;;; support for find-file ;;;--------------------------------------------------- (defvar ada-krunch-args "8" "*Argument of gnatk8, a string containing the max number of characters. Set to a big number, if you dont use crunched filenames.") (defun ada-make-filename-from-adaname (adaname) "determine the filename of a package/procedure from its own Ada name." ;; this is done simply by calling gkrunch, when we work with GNAT. It ;; must be a more complex function in other compiler environments. (interactive "s") ;; things that should really be done by the external process (let (krunch-buf) (setq krunch-buf (generate-new-buffer "*gkrunch*")) (save-excursion (set-buffer krunch-buf) (insert (downcase adaname)) (goto-char (point-min)) (while (search-forward "." nil t) (replace-match "-" nil t)) (setq adaname (buffer-substring (point-min) (progn (goto-char (point-min)) (end-of-line) (point)))) ;; clean the buffer (delete-region (point-min) (point-max)) ;; send adaname to external process "gnatk8" (call-process "gnatk8" nil krunch-buf nil adaname ada-krunch-args) ;; fetch output of that process (setq adaname (buffer-substring (point-min) (progn (goto-char (point-min)) (end-of-line) (point)))) (kill-buffer krunch-buf))) (setq adaname adaname) ;; can I avoid this statement? ) ;;;--------------------------------------------------- ;;; support for imenu ;;;--------------------------------------------------- (defun imenu-create-ada-index (&optional regexp) "create index alist for Ada files." (let ((index-alist '()) prev-pos char) (goto-char (point-min)) ;(imenu-progress-message prev-pos 0) ;; Search for functions/procedures (save-match-data (while (re-search-forward (or regexp ada-procedure-start-regexp) nil t) ;(imenu-progress-message prev-pos) ;;(backward-up-list 1) ;; needed in Ada ???? ;; do not store forward definitions (save-match-data (if (not (looking-at (concat "[ \t\n]*" ; WS "\([^)]+\)" ; parameterlist "\\([ \n\t]+return[ \n\t]+"; potential return "[a-zA-Z0-9_\\.]+\\)?" "[ \t]*" ; WS ";" ;; THIS is what we really look for ))) ; (push (imenu-example--name-and-position) index-alist) (setq index-alist (cons (imenu-example--name-and-position) index-alist)) )) ;(imenu-progress-message 100) )) (nreverse index-alist))) ;;;--------------------------------------------------- ;;; support for font-lock ;;;--------------------------------------------------- ;; Strings are a real pain in Ada because both ' and " can appear in a ;; non-string quote context (the former as an operator, the latter as ;; a character string). We follow the least losing solution, in which ;; only " is a string quote. Therefore a character string of the form ;; '"' will throw fontification off on the wrong track. (defconst ada-font-lock-keywords-1 (list ;; ;; Function, package (body), pragma, procedure, task (body) plus name. (list (concat "\\<\\(" "function\\|" "p\\(ackage\\(\\|[ \t]+body\\)\\|r\\(agma\\|ocedure\\)\\)\\|" "task\\(\\|[ \t]+body\\)" "\\)\\>[ \t]*\\(\\sw+\\(\\.\\sw*\\)*\\)?") '(1 font-lock-keyword-face) '(6 font-lock-function-name-face nil t))) "For consideration as a value of `ada-font-lock-keywords'. This does fairly subdued highlighting.") (defconst ada-font-lock-keywords-2 (append ada-font-lock-keywords-1 (list ;; ;; Main keywords, except those treated specially below. (concat "\\<\\(" ; ("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" ; "range" "record" "rem" "renames" "requeue" "return" "reverse" ; "select" "separate" "tagged" "task" "terminate" "then" "until" ; "while" "xor") "a\\(b\\(ort\\|s\\(\\|tract\\)\\)\\|cce\\(pt\\|ss\\)\\|" "l\\(iased\\|l\\)\\|nd\\|rray\\|t\\)\\|begin\\|case\\|" "d\\(e\\(clare\\|l\\(ay\\|ta\\)\\)\\|igits\\|o\\)\\|" "e\\(ls\\(e\\|if\\)\\|ntry\\|x\\(ception\\|it\\)\\)\\|for\\|" "generic\\|i[fns]\\|l\\(imited\\|oop\\)\\|mod\\|n\\(ot\\|ull\\)\\|" "o\\(r\\|thers\\|ut\\)\\|pr\\(ivate\\|otected\\)\\|" "r\\(ange\\|e\\(cord\\|m\\|names\\|queue\\|turn\\|verse\\)\\)\\|" "se\\(lect\\|parate\\)\\|" "t\\(a\\(gged\\|sk\\)\\|erminate\\|hen\\)\\|until\\|while\\|xor" "\\)\\>") ;; ;; Anything following end and not already fontified is a body name. '("\\<\\(end\\)\\>[ \t]*\\(\\sw+\\)?" (1 font-lock-keyword-face) (2 font-lock-function-name-face nil t)) ;; ;; Variable name plus optional keywords followed by a type name. Slow. ; (list (concat "\\<\\(\\sw+\\)\\>[ \t]*:?[ \t]*" ; "\\(access\\|constant\\|in\\|in[ \t]+out\\|out\\)?[ \t]*" ; "\\(\\sw+\\)?") ; '(1 font-lock-variable-name-face) ; '(2 font-lock-keyword-face nil t) '(3 font-lock-type-face nil t)) ;; ;; Optional keywords followed by a type name. (list (concat ; ":[ \t]*" "\\<\\(access\\|constant\\|in\\|in[ \t]+out\\|out\\)\\>" "[ \t]*" "\\(\\sw+\\)?") '(1 font-lock-keyword-face nil t) '(2 font-lock-type-face nil t)) ;; ;; Keywords followed by a type or function name. (list (concat "\\<\\(" "new\\|of\\|subtype\\|type" "\\)\\>[ \t]*\\(\\sw+\\)?[ \t]*\\((\\)?") '(1 font-lock-keyword-face) '(2 (if (match-beginning 4) font-lock-function-name-face font-lock-type-face) nil t)) ;; ;; Keywords followed by a (comma separated list of) reference. (list (concat "\\<\\(goto\\|raise\\|use\\|when\\|with\\)\\>" ; "[ \t]*\\(\\sw+\\(\\.\\sw*\\)*\\)?") ; RE "[ \t]*\\([a-zA-Z0-9_\\.\\|, ]+\\)\\W") '(1 font-lock-keyword-face) '(2 font-lock-reference-face nil t)) ;; ;; Goto tags. '("<<\\(\\sw+\\)>>" 1 font-lock-reference-face) )) "For consideration as a value of `ada-font-lock-keywords'. This does a lot more highlighting.") (defvar ada-font-lock-keywords (if font-lock-maximum-decoration ada-font-lock-keywords-2 ada-font-lock-keywords-1) "*Expressions to highlight in Ada mode.") ;;; ;;; ???? ;;; (defun ada-gen-comment-until-proc () ;; comment until spec of a procedure or a function. (forward-line 1) (set-mark-command (point)) (if (re-search-forward ada-procedure-start-regexp nil t) (progn (goto-char (match-beginning 1)) (comment-region (mark) (point))) (error "No more functions/procedures"))) (defun ada-gen-treat-proc nil ;; make dummy body of a procedure/function specification. (goto-char (match-end 0)) (let ((wend (point)) (wstart (progn (re-search-backward "[ ][a-zA-Z0-9_\"]+" nil t) (+ (match-beginning 0) 1)))) ; delete leading WS (copy-region-as-kill wstart wend) ; store proc name in kill-buffer ;; if the next notWS char is '(' ==> parameterlist follows ;; if the next notWS char is ';' ==> no paramterlist ;; if the next notWS char is 'r' ==> paramterless function, search ';' ;; goto end of regex before last (= end of procname) (goto-char (match-end 0)) ;; look for next non WS (backward-char) (re-search-forward "[ ]*.") (if (char-equal (char-after (match-end 0)) ?\;) (delete-char 1) ;; delete the ';' ;; else ;; find ');' or 'return <id> ;' (re-search-forward "\\()[ \t]*;\\)\\|\\(return[ \t]+[a-zA-Z0-9_]+[ \t]*;\\)" nil t) (goto-char (match-end 0)) (delete-backward-char 1) ;; delete the ';' ) (insert " is") ;; if it is a function, we should generate a return variable and a ;; return statement. Sth. like "Result : <return-type>;" and a ;; "return Result;". (ada-indent-newline-indent) (insert "begin -- ") (yank) (newline) (insert "null;") (newline) (insert "end ") (yank) (insert ";") (ada-indent-newline-indent)) (defun ada-gen-make-bodyfile (spec-filename) "Create a new buffer containing the correspondig Ada body to the current specs." (interactive "b") ;;; (let* ( ;;; (file-name (ada-body-filename spec-filename)) ;;; (buf (get-buffer-create file-name))) ;;; (switch-to-buffer buf) ;;; (ada-mode) (ff-find-other-file t t) ;;; (if (= (buffer-size) 0) ;;; (make-header) ;;; ;; make nothing, autoinsert.el had put something in already ;;; ) (end-of-buffer) (let ((hlen (count-lines (point-min) (point-max)))) (insert-buffer spec-filename) ;; hlen lines have already been inserted automatically ) (if (re-search-forward ada-package-start-regexp nil t) (progn (goto-char (match-end 1)) (insert " body")) (error "No package")) ; (comment-until-proc) ; does not work correctly ; must be done by hand (while (re-search-forward ada-procedure-start-regexp nil t) (ada-gen-treat-proc)) ; don't overwrite an eventually ; existing file ; (if (file-exists-p file-name) ; (error "File with this name already exists!") ; (write-file file-name)) )) ;;; provide ourself (provide 'ada-mode) ;;; ada-mode.el ends here