Various docstring and commentary fixes, including
[bpt/emacs.git] / lisp / progmodes / pascal.el
index 2e9a759..d2ef2d2 100644 (file)
@@ -1,64 +1,69 @@
-;;; pascal.el  -  Major mode for editing pascal source in emacs.
+;;; pascal.el --- major mode for editing pascal source in Emacs
 
-;;; Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
+;; Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
 
-;;; Author: Espen Skoglund (espensk@stud.cs.uit.no)
-;;; Keywords: languages
+;; Author: Espen Skoglund <espensk@stud.cs.uit.no>
+;; Keywords: languages
 
-;;; This file is part of GNU Emacs.
+;; This file is part of GNU Emacs.
 
-;;; This program 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 of the License, or
-;;; (at your option) any later version.
+;; 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.
 
-;;; This program 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.
+;; 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 this program; if not, write to the Free Software
-;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+;; 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, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
 
 ;;; Commentary:
 
-;;; USAGE
-;;; =====
-
-;;; Emacs should enter Pascal mode when you find a Pascal source file.
-;;; When you have entered Pascal mode, you may get more info by pressing
-;;; C-h m. You may also get online help describing various functions by:
-;;; C-h f <Name of function you want described>
-
-;;; If you want to customize Pascal mode to fit you better, you may add
-;;; these lines (the values of the variables presented here are the defaults):
-;;;
-;;; ;; User customization for Pascal mode
-;;; (setq pascal-indent-level       3
-;;;       pascal-case-indent        2
-;;;       pascal-auto-newline       nil
-;;;       pascal-tab-always-indent  t
-;;;       pascal-auto-endcomments   t
-;;;       pascal-auto-lineup        '(all)
-;;;       pascal-toggle-completions nil
-;;;       pascal-type-keywords      '("array" "file" "packed" "char" 
-;;;                                  "integer" "real" "string" "record")
-;;;       pascal-start-keywords     '("begin" "end" "function" "procedure"
-;;;                                  "repeat" "until" "while" "read" "readln"
-;;;                                  "reset" "rewrite" "write" "writeln")
-;;;       pascal-separator-keywords '("downto" "else" "mod" "div" "then"))
-
-;;; KNOWN BUGS / BUGREPORTS
-;;; =======================
-;;; As far as I know, there are no bugs in the current version of this
-;;; package.  This may not be true however, since I never use this mode
-;;; myself and therefore would never notice them anyway.   If you do
-;;; find any bugs, you may submit them to: espensk@stud.cs.uit.no
-;;; as well as to bug-gnu-emacs@prep.ai.mit.edu.
+;; USAGE
+;; =====
+
+;; Emacs should enter Pascal mode when you find a Pascal source file.
+;; When you have entered Pascal mode, you may get more info by pressing
+;; C-h m. You may also get online help describing various functions by:
+;; C-h f <Name of function you want described>
+
+;; If you want to customize Pascal mode to fit you better, you may add
+;; these lines (the values of the variables presented here are the defaults):
+;;
+;; ;; User customization for Pascal mode
+;; (setq pascal-indent-level       3
+;;       pascal-case-indent        2
+;;       pascal-auto-newline       nil
+;;       pascal-tab-always-indent  t
+;;       pascal-auto-endcomments   t
+;;       pascal-auto-lineup        '(all)
+;;       pascal-toggle-completions nil
+;;       pascal-type-keywords      '("array" "file" "packed" "char" 
+;;                                  "integer" "real" "string" "record")
+;;       pascal-start-keywords     '("begin" "end" "function" "procedure"
+;;                                  "repeat" "until" "while" "read" "readln"
+;;                                  "reset" "rewrite" "write" "writeln")
+;;       pascal-separator-keywords '("downto" "else" "mod" "div" "then"))
+
+;; KNOWN BUGS / BUGREPORTS
+;; =======================
+;; As far as I know, there are no bugs in the current version of this
+;; package.  This may not be true however, since I never use this mode
+;; myself and therefore would never notice them anyway.   If you do
+;; find any bugs, you may submit them to: espensk@stud.cs.uit.no
+;; as well as to bug-gnu-emacs@prep.ai.mit.edu.
 \f
 ;;; Code:
 
+(defgroup pascal nil
+  "Major mode for editing Pascal source in Emacs"
+  :group 'languages)
+
 (defvar pascal-mode-abbrev-table nil
   "Abbrev table in use in Pascal-mode buffers.")
 (define-abbrev-table 'pascal-mode-abbrev-table ())
 (defvar pascal-imenu-generic-expression
   '("^[ \t]*\\(function\\|procedure\\)[ \t\n]+\\([a-zA-Z0-9_.:]+\\)" . (2))
   "Imenu expression for Pascal-mode.  See `imenu-generic-expression'.")
-  
+
 (defvar pascal-keywords
   '("and" "array" "begin" "case" "const" "div" "do" "downto" "else" "end" 
     "file" "for" "function" "goto" "if" "in" "label" "mod" "nil" "not" "of" 
   (modify-syntax-entry ?> "."    pascal-mode-syntax-table)
   (modify-syntax-entry ?& "."    pascal-mode-syntax-table)
   (modify-syntax-entry ?| "."    pascal-mode-syntax-table)
-  (modify-syntax-entry ?_ "w"    pascal-mode-syntax-table)
+  (modify-syntax-entry ?_ "_"    pascal-mode-syntax-table)
   (modify-syntax-entry ?\' "\""  pascal-mode-syntax-table))
 
-(defvar pascal-font-lock-keywords
+(defconst pascal-font-lock-keywords (purecopy
   (list
-   '("^[ \t]*\\(function\\|pro\\(cedure\\|gram\\)\\)\\>[ \t]*\\(\\sw+\\)?"
-     (1 font-lock-keyword-face) (3 font-lock-function-name-face nil t))
+   '("^[ \t]*\\(function\\|pro\\(cedure\\|gram\\)\\)\\>[ \t]*\\([a-z]\\)"
+     1 font-lock-keyword-face)
+   '("^[ \t]*\\(function\\|pro\\(cedure\\|gram\\)\\)\\>[ \t]*\\([a-z][a-z0-9_]*\\)"
+     3 font-lock-function-name-face t)
 ;   ("type" "const" "real" "integer" "char" "boolean" "var"
 ;    "record" "array" "file")
    (cons (concat "\\<\\(array\\|boolean\\|c\\(har\\|onst\\)\\|file\\|"
                 "integer\\|re\\(al\\|cord\\)\\|type\\|var\\)\\>")
         'font-lock-type-face)
    '("\\<\\(label\\|external\\|forward\\)\\>" . font-lock-reference-face)
-   '("\\<\\([0-9]+\\)[ \t]*:" 1 font-lock-reference-face)
+   '("\\<\\([0-9]+\\)[ \t]*:" 1 font-lock-function-name-face)
 ;   ("of" "to" "for" "if" "then" "else" "case" "while"
 ;    "do" "until" "and" "or" "not" "in" "with" "repeat" "begin" "end")
    (concat "\\<\\("
           "not\\|o[fr]\\|repeat\\|t\\(hen\\|o\\)\\|until\\|w\\(hile\\|ith\\)"
           "\\)\\>")
    '("\\<\\(goto\\)\\>[ \t]*\\([0-9]+\\)?"
-     (1 font-lock-keyword-face) (2 font-lock-reference-face nil t)))
+     1 font-lock-keyword-face)
+   '("\\<\\(goto\\)\\>[ \t]*\\([0-9]+\\)?"
+     2 font-lock-keyword-face t)))
   "Additional expressions to highlight in Pascal mode.")
-
-(defvar pascal-indent-level 3
-  "*Indentation of Pascal statements with respect to containing block.")
-
-(defvar pascal-case-indent 2
-  "*Indentation for case statements.")
-
-(defvar pascal-auto-newline nil
-  "*Non-nil means automatically newline after simcolons and the punctation mark
-after an end.")
-
-(defvar pascal-tab-always-indent t
-  "*Non-nil means TAB in Pascal mode should always reindent the current line,
-regardless of where in the line point is when the TAB command is used.")
-
-(defvar pascal-auto-endcomments t
-  "*Non-nil means a comment { ... } is set after the ends which ends cases and
-functions. The name of the function or case will be set between the braces.")
-
-(defvar pascal-auto-lineup '(all)
+(put 'pascal-mode 'font-lock-defaults '(pascal-font-lock-keywords nil t))
+
+(defcustom pascal-indent-level 3
+  "*Indentation of Pascal statements with respect to containing block."
+  :type 'integer
+  :group 'pascal)
+
+(defcustom pascal-case-indent 2
+  "*Indentation for case statements."
+  :type 'integer
+  :group 'pascal)
+
+(defcustom pascal-auto-newline nil
+  "*Non-nil means automatically insert newlines in certain cases.
+These include after semicolons and after the punctuation mark after an `end'."
+  :type 'boolean
+  :group 'pascal)
+
+(defcustom pascal-tab-always-indent t
+  "*Non-nil means TAB in Pascal mode should always reindent the current line.
+If this is nil, TAB inserts a tab if it is at the end of the line
+and follows non-whitespace text."
+  :type 'boolean
+  :group 'pascal)
+
+(defcustom pascal-auto-endcomments t
+  "*Non-nil means automatically insert comments after certain `end's.
+Specifically, this is done after the ends of cases statements and functions.
+The name of the function or case is included between the braces."
+  :type 'boolean
+  :group 'pascal)
+
+(defcustom pascal-auto-lineup '(all)
   "*List of contexts where auto lineup of :'s or ='s should be done.
 Elements can be of type: 'paramlist', 'declaration' or 'case', which will
 do auto lineup in parameterlist, declarations or case-statements
 respectively. The word 'all' will do all lineups. '(case paramlist) for
 instance will do lineup in case-statements and parameterlist, while '(all)
-will do all lineups.")
-
-(defvar pascal-toggle-completions nil
+will do all lineups."
+  :type '(repeat (choice (const all)
+                        (const paramlist)
+                        (const declaration)
+                        (const case)))
+  :group 'pascal)
+
+(defcustom pascal-toggle-completions nil
   "*Non-nil means \\<pascal-mode-map>\\[pascal-complete-word] should try all possible completions one by one.
 Repeated use of \\[pascal-complete-word] will show you all of them.
 Normally, when there is more than one possible completion,
-it displays a list of all possible completions.")
+it displays a list of all possible completions."
+  :type 'boolean
+  :group 'pascal)
 
-(defvar pascal-type-keywords
+(defcustom pascal-type-keywords
   '("array" "file" "packed" "char" "integer" "real" "string" "record")
   "*Keywords for types used when completing a word in a declaration or parmlist.
-\(eg. integer, real, char.)  The types defined within the Pascal program
-will be completed runtime, and should not be added to this list.")
+These include integer, real, char, etc.
+The types defined within the Pascal program
+are handled in another way, and should not be added to this list."
+  :type '(repeat (string :tag "Keyword"))
+  :group 'pascal)
 
-(defvar pascal-start-keywords
+(defcustom pascal-start-keywords
   '("begin" "end" "function" "procedure" "repeat" "until" "while"
     "read" "readln" "reset" "rewrite" "write" "writeln")
   "*Keywords to complete when standing at the first word of a statement.
-\(eg. begin, repeat, until, readln.)
+These are keywords such as begin, repeat, until, readln.
 The procedures and variables defined within the Pascal program
-will be completed runtime and should not be added to this list.")
+are handled in another way,  and should not be added to this list."
+  :type '(repeat (string :tag "Keyword"))
+  :group 'pascal)
 
-(defvar pascal-separator-keywords
+(defcustom pascal-separator-keywords
   '("downto" "else" "mod" "div" "then")
   "*Keywords to complete when NOT standing at the first word of a statement.
-\(eg. downto, else, mod, then.) 
-Variables and function names defined within the
-Pascal program are completed runtime and should not be added to this list.")
+These are keywords such as downto, else, mod, then.
+Variables and function names defined within the Pascal program
+are handled in another way, and should not be added to this list."
+  :type '(repeat (string :tag "Keyword"))
+  :group 'pascal)
+
 
 ;;;
 ;;;  Macros
@@ -243,7 +280,8 @@ Pascal program are completed runtime and should not be added to this list.")
                 "[:=]\\|\\(\\<record\\>\\)\\|\\(\\<end\\>\\)" 
                 (save-excursion (end-of-line 2) (point)) t))
       (cond ((match-beginning 1) (setq nest (1+ nest)))
-           ((match-beginning 2) (setq nest (1- nest)))))))
+           ((match-beginning 2) (setq nest (1- nest)))
+           ((looking-at "[^(\n]+)") (setq nest 0))))))
 
 
 (defun pascal-declaration-beg ()
@@ -290,8 +328,8 @@ Variables controlling indentation/edit style:
  pascal-case-indent       (default 2)
     Indentation for case statements.
  pascal-auto-newline      (default nil)
-    Non-nil means automatically newline after simcolons and the punctation mark
-    after an end.
+    Non-nil means automatically newline after semicolons and the punctuation
+    mark after an end.
  pascal-tab-always-indent (default t)
     Non-nil means TAB in Pascal mode should always reindent the current line,
     regardless of where in the line point is when the TAB command is used.
@@ -299,7 +337,7 @@ Variables controlling indentation/edit style:
     Non-nil means a comment { ... } is set after the ends which ends cases and
     functions. The name of the function or case will be set between the braces.
  pascal-auto-lineup       (default t)
-    List of contexts where auto lineup of :'s or ='s hould be done.
+    List of contexts where auto lineup of :'s or ='s should be done.
 
 See also the user variables pascal-type-keywords, pascal-start-keywords and
 pascal-separator-keywords.
@@ -315,6 +353,7 @@ no args, if that value is non-nil."
   (set-syntax-table pascal-mode-syntax-table)
   (make-local-variable 'indent-line-function)
   (setq indent-line-function 'pascal-indent-line)
+  (make-local-variable 'comment-indent-function)
   (setq comment-indent-function 'pascal-indent-comment)
   (make-local-variable 'parse-sexp-ignore-comments)
   (setq parse-sexp-ignore-comments nil)
@@ -332,6 +371,7 @@ no args, if that value is non-nil."
   ;; Imenu support
   (make-local-variable 'imenu-generic-expression)
   (setq imenu-generic-expression pascal-imenu-generic-expression)
+  (setq imenu-case-fold-search t)
   (run-hooks 'pascal-mode-hook))
 
 \f
@@ -406,7 +446,7 @@ no args, if that value is non-nil."
        (pascal-indent-command))))
 
 (defun electric-pascal-hash ()
-  "Insert `#', and indent to coulmn 0 if this is a CPP directive."
+  "Insert `#', and indent to column 0 if this is a CPP directive."
   (interactive)
   (insert last-command-char)
   (if (save-excursion (beginning-of-line) (looking-at "^[ \t]*#"))
@@ -426,7 +466,11 @@ no args, if that value is non-nil."
        (save-excursion
          (beginning-of-line)
          (pascal-indent-line))
-      (insert "\t"))
+      (if (save-excursion
+           (skip-chars-backward " \t")
+           (bolp))
+         (pascal-indent-line)
+       (insert "\t")))
     (pascal-indent-command)))
 
 \f
@@ -606,7 +650,8 @@ area.  See also `pascal-comment-area'."
 (defun pascal-end-of-statement ()
   "Move forward to end of current statement."
   (interactive)
-  (let ((nest 0) pos
+  (let ((parse-sexp-ignore-comments t)
+       (nest 0) pos
        (regexp (concat "\\(" pascal-beg-block-re "\\)\\|\\("
                        pascal-end-block-re "\\)")))
     (if (not (looking-at "[ \t\n]")) (forward-sexp -1))
@@ -778,7 +823,8 @@ on the line which ends a function or procedure named NAME."
   "Calculate the indent of the current Pascal line.
 Return a list of two elements: (INDENT-TYPE INDENT-LEVEL)."
   (save-excursion
-    (let* ((oldpos (point))
+    (let* ((parse-sexp-ignore-comments t)
+          (oldpos (point))
           (state (save-excursion (parse-partial-sexp (point-min) (point))))
           (nest 0) (par 0) (complete (looking-at "[ \t]*end\\>"))
           (elsed (looking-at "[ \t]*else\\>"))
@@ -880,36 +926,38 @@ Do not count labels, case-statements or records."
   "Indent current line as comment.
 If optional arg is non-nil, just return the
 column number the line should be indented to."
-    (let* ((stcol (save-excursion
-                   (re-search-backward "(\\*\\|{" nil t)
-                   (1+ (current-column)))))
-      (if arg stcol
-       (delete-horizontal-space)
-       (indent-to stcol))))
+  (let* ((stcol (save-excursion
+                 (re-search-backward "(\\*\\|{" nil t)
+                 (1+ (current-column)))))
+    (if arg stcol
+      (delete-horizontal-space)
+      (indent-to stcol))))
 
 (defun pascal-indent-case ()
   "Indent within case statements."
-  (skip-chars-forward ": \t")
-  (let ((end (prog2
+  (let ((savepos (point-marker))
+       (end (prog2
                 (end-of-line)
                 (point-marker)
               (re-search-backward "\\<case\\>" nil t)))
        (beg (point)) oldpos
        (ind 0))
     ;; Get right indent
-    (while (< (point) (marker-position end))
+    (while (< (point) end)
       (if (re-search-forward 
           "^[ \t]*[^ \t,:]+[ \t]*\\(,[ \t]*[^ \t,:]+[ \t]*\\)*:"
           (marker-position end) 'move)
          (forward-char -1))
-      (delete-horizontal-space)
-      (if (> (current-column) ind)
-         (setq ind (current-column)))
-      (pascal-end-of-statement))
+      (if (< (point) end)
+         (progn
+           (delete-horizontal-space)
+           (if (> (current-column) ind)
+               (setq ind (current-column)))
+           (pascal-end-of-statement))))
     (goto-char beg)
     (setq oldpos (marker-position end))
     ;; Indent all case statements
-    (while (< (point) (marker-position end))
+    (while (< (point) end)
       (if (re-search-forward
           "^[ \t]*[^][ \t,\\.:]+[ \t]*\\(,[ \t]*[^ \t,:]+[ \t]*\\)*:"
           (marker-position end) 'move)
@@ -922,7 +970,7 @@ column number the line should be indented to."
        (insert " "))
       (setq oldpos (point))
       (pascal-end-of-statement))
-    (goto-char oldpos)))
+    (goto-char savepos)))
 
 (defun pascal-indent-paramlist (&optional arg)
   "Indent current line in parameterlist.
@@ -968,7 +1016,7 @@ indent of the current line in parameterlist."
        (goto-char stpos)
        ;; Indent lines in record block
        (if arg
-           (while (<= (point) (marker-position edpos))
+           (while (<= (point) edpos)
              (beginning-of-line)
              (delete-horizontal-space)
              (if (looking-at "end\\>")
@@ -979,7 +1027,7 @@ indent of the current line in parameterlist."
        ;; Do lineup
        (setq ind (pascal-get-lineup-indent stpos edpos lineup))
        (goto-char stpos)
-       (while (<= (point) (marker-position edpos))
+       (while (and (<= (point) edpos) (not (eobp)))
          (if (search-forward lineup (pascal-get-end-of-line) 'move)
              (forward-char -1))
          (delete-horizontal-space)
@@ -996,19 +1044,17 @@ indent of the current line in parameterlist."
 
     ;; If arg - move point
     (if arg (forward-line -1)
-      (goto-char (marker-position pos)))))
+      (goto-char pos))))
 
 ;  "Return the indent level that will line up several lines within the region
 ;from b to e nicely. The lineup string is str."
 (defun pascal-get-lineup-indent (b e str)
   (save-excursion
     (let ((ind 0)
-         (reg (concat str "\\|\\(\\<record\\>\\)"))
-         nest)
+         (reg (concat str "\\|\\(\\<record\\>\\)")))
       (goto-char b)
       ;; Get rightmost position
       (while (< (point) e)
-       (setq nest 1)
        (if (re-search-forward reg (min e (pascal-get-end-of-line 2)) 'move)
            (progn
              ;; Skip record blocks
@@ -1019,7 +1065,9 @@ indent of the current line in parameterlist."
                  (skip-chars-backward " \t")
                  (if (> (current-column) ind)
                      (setq ind (current-column)))
-                 (goto-char (match-end 0)))))))
+                 (goto-char (match-end 0))
+                 (end-of-line)
+                 )))))
       ;; In case no lineup was found
       (if (> ind 0)
          (1+ ind)
@@ -1083,7 +1131,7 @@ indent of the current line in parameterlist."
 
 (defun pascal-get-completion-decl ()
   ;; Macro for searching through current declaration (var, type or const)
-  ;; for matches of `str' and adding the occurence tp `all'
+  ;; for matches of `str' and adding the occurrence to `all'
   (let ((end (save-excursion (pascal-declaration-end)
                             (point)))
        match)
@@ -1133,7 +1181,7 @@ indent of the current line in parameterlist."
       (save-excursion
        (if (> start (prog1 (save-excursion (pascal-end-of-defun)
                                            (point))))
-           () ; Declarations not reacable
+           () ; Declarations not reachable
          (if (search-forward "(" (pascal-get-end-of-line) t)
              ;; Check parameterlist
                (pascal-get-completion-decl))
@@ -1172,7 +1220,7 @@ indent of the current line in parameterlist."
   (save-excursion
     (let ((pascal-all nil))
       ;; Set buffer to use for searching labels. This should be set
-      ;; within functins which use pascal-completions
+      ;; within functions which use pascal-completions
       (set-buffer pascal-buffer-to-use)
 
       ;; Determine what should be completed
@@ -1217,7 +1265,7 @@ indent of the current line in parameterlist."
           (let* ((elm (cdr pascal-all))
                  (match (car pascal-all))
                  (min (length match))
-                 exact tmp)
+                 tmp)
             (if (string= match pascal-str)
                 ;; Return t if first match was an exact match
                 (setq match t)
@@ -1282,7 +1330,7 @@ indent of the current line in parameterlist."
              (insert "" pascal-last-word-shown)
            (insert "" pascal-str)
            (message "(No match)")))
-      ;; The other form of completion does not necessarly do that.
+      ;; The other form of completion does not necessarily do that.
 
       ;; Insert match if found, or the original string if no match
       (if (or (null match) (equal match 't))
@@ -1358,7 +1406,7 @@ With optional second arg non-nil, STR is the complete name of the instruction."
          match)
 
       ;; Set buffer to use for searching labels. This should be set
-      ;; within functins which use pascal-completions
+      ;; within functions which use pascal-completions
       (set-buffer pascal-buffer-to-use)
 
       (let ((pascal-str pascal-str))
@@ -1545,4 +1593,6 @@ Pascal Outline mode provides some additional commands.
   (pascal-goto-defun)
   (pascal-hide-other-defuns))
 
+(provide 'pascal)
+
 ;;; pascal.el ends here