]> git.eshelyaron.com Git - emacs.git/commitdiff
Many doc fixes.
authorRichard M. Stallman <rms@gnu.org>
Tue, 1 Feb 1994 18:14:56 +0000 (18:14 +0000)
committerRichard M. Stallman <rms@gnu.org>
Tue, 1 Feb 1994 18:14:56 +0000 (18:14 +0000)
(pascal-get-beg-of-line, pascal-get-end-of-line):
Use defsubst.  Renamed from get-...
(pascal-within-string): Use defsubst.
(delete-whitespaces): Function deleted;
callers use delete-horizontal-space instead.
(pascal-string-diff): Renamed from string-diff.

Complete rewrite.  Added an outline- minor-mode and completion.

lisp/progmodes/pascal.el

index cf5d25890295842aae5038b5d0b51a492f79084d..469c9c1a9ce7e4ea95d3a8af1f8c47cc1dd239d4 100644 (file)
@@ -1,74 +1,65 @@
 ;;; pascal.el  -  Major mode for editing pascal source in emacs.
 
-;;; Copyright (C) 1993 Free Software Foundation, Inc.
+;;; Copyright (C) 1993, 1994 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.
 
-;; 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 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 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.
+;;; 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.
 
-;; 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.
+;;; 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.
 
 ;;; Commentary:
 
-;;; If you want to customize the pascal mode in your startup file, you
-;;; can add these lines to your .emacs file (and remove the ;s at the
-;;; beginning of the line):
-;;;
-;;; ;;; Pascal-mode custumization.
-;;; (autoload 'pascal-mode "pascal-mode" nil t)
-;;; (setq auto-mode-alist (append (list (cons "\\.p$" 'pascal-mode)
-;;;                                     (cons "\\.pas$" 'pascal-mode))
-;;;                       auto-mode-alist))
-;;; (setq pascal-mode-hook '(lambda ()
-;;;                          ;; User specifications
-;;;                          (setq pascal-tab-always-indent t
-;;;                               pascal-auto-newline nil
-;;;                               pascal-auto-endcomments t
-;;;                               pascal-indent-level 3
-;;;                                pascal-continued-expr 1
-;;;                               pascal-label-offset -2
-;;;                               pascal-case-offset 2
-;;;                               pascal-typedecl-indent 10
-;;;                               pascal-vardecl-indent 20)))
-
 ;;; USAGE
 ;;; =====
-;;; If you have modified your startup file as described above, emacs
-;;; should enter pascal-mode when you load a pascal source into emacs.
-;;; If not, you will have to start pascal-mode manually:
-;;;    M-x load-library pascal-mode
-;;;    M-x pascal-mode
-;;; When you have entered pascal-mode, you may get more info by pressing
+
+;;; 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 d <Name of function you want described>
+;;; 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-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-seperator-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. But if you DO
-;;; find any bugd, you may submitt them to: espensk@stud.cs.uit.no
-
-;;; LCD Archive Entry:
-;;; pascal-mode|Espen Skoglund|espensk@stud.cs.uit.no|
-;;; Major mode for editing Pascal code|
-;;; 14-Sep-93|$Revision: 1.3 $|~/modes/pascal-mode.el.Z|
+;;; 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:
 
-(defconst pascal-mode-version "1.3"
-  "Version of this pascal mode.")
+(defconst pascal-mode-version "2.1a"
+  "Version of `pascal-mode.el'.")
 
 (defvar pascal-mode-abbrev-table nil
   "Abbrev table in use in Pascal-mode buffers.")
 
 (defvar pascal-mode-map ()
   "Keymap used in Pascal mode.")
-(if (null pascal-mode-map)
-    (setq pascal-mode-map (make-sparse-keymap)))
-
-(define-key pascal-mode-map ";" 'electric-pascal-semi)
-(define-key pascal-mode-map "." 'electric-pascal-dot)
-(define-key pascal-mode-map ":" 'electric-pascal-colon)
-(define-key pascal-mode-map "=" 'electric-pascal-equal)
-(define-key pascal-mode-map "\r" 'electric-pascal-terminate-line)
-(define-key pascal-mode-map "\t" 'electric-pascal-tab)
-(define-key pascal-mode-map "\177" 'backward-delete-char-untabify)
-(define-key pascal-mode-map "\C-\M-a" 'pascal-backward-to-beginning-of-function)
-(define-key pascal-mode-map "\C-\M-e" 'pascal-forward-to-end-of-function)
-(define-key pascal-mode-map "\C-\M-h" 'pascal-mark-function)
-(define-key pascal-mode-map "\C-c\C-b" 'pascal-insert-block)
-(define-key pascal-mode-map "\C-c\C-c" 'pascal-comment-area)
-(define-key pascal-mode-map "\C-c\C-u" 'pascal-uncomment-area)
-(define-key pascal-mode-map "\M-*" 'pascal-star-comment)
-
+(if pascal-mode-map
+    ()
+  (setq pascal-mode-map (make-sparse-keymap))
+  (define-key pascal-mode-map ";"        'electric-pascal-semi-or-dot)
+  (define-key pascal-mode-map "."        'electric-pascal-semi-or-dot)
+  (define-key pascal-mode-map ":"        'electric-pascal-colon)
+  (define-key pascal-mode-map "="        'electric-pascal-equal)
+  (define-key pascal-mode-map "\r"       'electric-pascal-terminate-line)
+  (define-key pascal-mode-map "\t"       'electric-pascal-tab)
+  (define-key pascal-mode-map "\e\t"     'pascal-complete-word)
+  (define-key pascal-mode-map "\e?"      'pascal-show-completions)
+  (define-key pascal-mode-map "\177"     'backward-delete-char-untabify)
+  (define-key pascal-mode-map "\e\C-h"   'pascal-mark-defun)
+  (define-key pascal-mode-map "\C-cb"    'pascal-insert-block)
+  (define-key pascal-mode-map "\M-*"     'pascal-star-comment)
+  (define-key pascal-mode-map "\C-c\C-c" 'pascal-comment-area)
+  (define-key pascal-mode-map "\C-c\C-u" 'pascal-uncomment-area)
+  (define-key pascal-mode-map "\e\C-a"   'pascal-beg-of-defun)
+  (define-key pascal-mode-map "\e\C-e"   'pascal-end-of-defun)
+  (define-key pascal-mode-map "\C-cg"    'pascal-goto-defun)
+  (define-key pascal-mode-map "\C-c\C-o"  'pascal-outline)
 ;;; A command to change the whole buffer won't be used terribly
 ;;; often, so no need for a key binding.
-;;;(define-key pascal-mode-map "\C-c\C-l" 'pascal-downcase-keywords)
-;;;(define-key pascal-mode-map "\C-c\C-u" 'pascal-upcase-keywords)
-;;;(define-key pascal-mode-map "\C-c\C-c" 'pascal-capitalize-keywords)
-
-(defvar pascal-keywords '("and" "array" "begin" "case" "const" "div" "do" 
-"downto" "else" "end" "file" "for" "function" "goto" "if" "in" "label" "mod" 
-"nil" "not" "of" "or" "packed" "procedure" "program" "record" "repeat" "set" 
-"then" "to" "type" "until" "var" "while" "with"
-;; The following are not standard in pascal, but widely used.
-"get" "put" "input" "output" "read" "readln" "reset" "rewrite" "write"
-"writeln"))
+;  (define-key pascal-mode-map "\C-cd"    'pascal-downcase-keywords)
+;  (define-key pascal-mode-map "\C-cu"    'pascal-upcase-keywords)
+;  (define-key pascal-mode-map "\C-cc"    'pascal-capitalize-keywords)
+  )
+  
+(defvar pascal-keywords
+  '("and" "array" "begin" "case" "const" "div" "do" "downto" "else" "end" 
+    "file" "for" "function" "goto" "if" "in" "label" "mod" "nil" "not" "of" 
+    "or" "packed" "procedure" "program" "record" "repeat" "set" "then" "to" 
+    "type" "until" "var" "while" "with"
+    ;; The following are not standard in pascal, but widely used.
+    "get" "put" "input" "output" "read" "readln" "reset" "rewrite" "write"
+    "writeln"))
+
+;;;
+;;; Regular expressions used to calculate indent, etc.
+;;;
+(defconst pascal-symbol-re      "\\<[a-zA-Z_][a-zA-Z_0-9.]*\\>")
+(defconst pascal-beg-block-re   "\\<\\(begin\\|case\\|record\\|repeat\\)\\>")
+(defconst pascal-end-block-re   "\\<\\(end\\|until\\)\\>")
+(defconst pascal-declaration-re "\\<\\(const\\|label\\|type\\|var\\)\\>")
+(defconst pascal-defun-re       "\\<\\(function\\|procedure\\|program\\)\\>")
+(defconst pascal-sub-block-re   "\\<\\(if\\|else\\|while\\)\\>")
+(defconst pascal-noindent-re    "\\<\\(begin\\|end\\|until\\)\\>")
+(defconst pascal-nosemi-re      "\\<\\(begin\\|repeat\\|then\\|do\\|else\\)\\>")
+(defconst pascal-autoindent-lines-re
+  "\\<\\(label\\|var\\|type\\|const\\|until\\|end\\|begin\\|repeat\\|else\\)\\>")
+
+;;; Strings used to mark beginning and end of excluded text
+(defconst pascal-exclude-str-start "{-----\\/----- EXCLUDED -----\\/-----")
+(defconst pascal-exclude-str-end " -----/\\----- EXCLUDED -----/\\-----}")
 
 (defvar pascal-mode-syntax-table nil
   "Syntax table in use in Pascal-mode buffers.")
 (if pascal-mode-syntax-table
     ()
   (setq pascal-mode-syntax-table (make-syntax-table))
-  (modify-syntax-entry ?\\ "\\" pascal-mode-syntax-table)
-  (modify-syntax-entry ?( ". 1" pascal-mode-syntax-table)  
-  (modify-syntax-entry ?) ". 4" pascal-mode-syntax-table)
+  (modify-syntax-entry ?\\ "\\"  pascal-mode-syntax-table)
+  (modify-syntax-entry ?( "()1"  pascal-mode-syntax-table)  
+  (modify-syntax-entry ?) ")(4"  pascal-mode-syntax-table)
   (modify-syntax-entry ?* ". 23" pascal-mode-syntax-table)
-  (modify-syntax-entry ?{ "<" pascal-mode-syntax-table)
-  (modify-syntax-entry ?} ">" pascal-mode-syntax-table)
-  (modify-syntax-entry ?+ "." pascal-mode-syntax-table)
-  (modify-syntax-entry ?- "." pascal-mode-syntax-table)
-  (modify-syntax-entry ?= "." pascal-mode-syntax-table)
-  (modify-syntax-entry ?% "." pascal-mode-syntax-table)
-  (modify-syntax-entry ?< "." pascal-mode-syntax-table)
-  (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))
-
-(defconst pascal-indent-level 3
+  (modify-syntax-entry ?{ "<"    pascal-mode-syntax-table)
+  (modify-syntax-entry ?} ">"    pascal-mode-syntax-table)
+  (modify-syntax-entry ?+ "."    pascal-mode-syntax-table)
+  (modify-syntax-entry ?- "."    pascal-mode-syntax-table)
+  (modify-syntax-entry ?= "."    pascal-mode-syntax-table)
+  (modify-syntax-entry ?% "."    pascal-mode-syntax-table)
+  (modify-syntax-entry ?< "."    pascal-mode-syntax-table)
+  (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))
+
+(defvar pascal-indent-level 3
   "*Indentation of Pascal statements with respect to containing block.")
-(defconst pascal-continued-expr 1
-  "*Indentation of line that is a continued expression.")
-(defconst pascal-label-offset -1
-  "*Offset of Pascal label lines, case statements and record lines.
-This is relative to usual indentation.")
-(defconst pascal-case-offset 2
-  "*Indentation after case statements.")
-(defconst pascal-vardecl-indent 15
-  "*Indentation (from the beginning of line to `:' of the declaration.")
-(defconst pascal-typedecl-indent 10
-  "*Indentation (from the beginning of line to `=' of the declaration.")
-(defconst pascal-auto-newline nil
-  "*Non-nil means automatically newline after semicolons and `end'.")
-(defconst pascal-tab-always-indent t
-  "*Non-nil means TAB in Pascal mode should always reindent the current line.
-It does so regardless of where in the line point is
-when the TAB command is used.")
-(defconst pascal-auto-endcomments t
-  "*Non-nil means make a comment { ... } after the end for a case or function.
-The name of the function or case is put between the braces.")
+(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-toggle-completions nil
+  "*Non-nil means that \\<pascal-mode-map>\\[pascal-complete-label] should \
+not display a completion buffer when
+the label couldn't be completed, but instead toggle the possible completions
+with repeated \\[pascal-complete-label]'s.")
+(defvar 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.")
+(defvar 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.)
+The procedures and variables defined within the Pascal program
+will be completed runtime and should not be added to this list.")
+(defvar pascal-seperator-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.")
+
+;;;
+;;;  Macros
+;;;
+
+(defsubst pascal-get-beg-of-line (&optional arg)
+  (save-excursion
+    (beginning-of-line arg)
+    (point)))
+
+(defsubst pascal-get-end-of-line (&optional arg)
+  (save-excursion
+    (end-of-line arg)
+    (point)))
+
+(defun pascal-declaration-end ()
+  (let ((nest 1))
+    (while (and (> nest 0)
+               (re-search-forward 
+                "[:=]\\|\\(\\<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)))))))
+
+(defun pascal-declaration-beg ()
+  (let ((nest 1))
+    (while (and (> nest 0)
+               (re-search-backward "[:=]\\|\\<\\(type\\|var\\|label\\|const\\)\\>\\|\\(\\<record\\>\\)\\|\\(\\<end\\>\\)" (pascal-get-beg-of-line -0) t))
+      (cond ((match-beginning 1) (setq nest 0))
+           ((match-beginning 2) (setq nest (1- nest)))
+           ((match-beginning 3) (setq nest (1+ nest)))))
+    (= nest 0)))
+  
+(defsubst pascal-within-string ()
+  (save-excursion
+    (nth 3 (parse-partial-sexp (pascal-get-beg-of-line) (point)))))
+
 
 ;;;###autoload
 (defun pascal-mode ()
-  "Major mode for editing Pascal code.
-Tab indents for Pascal code.
-Delete converts tabs to spaces as it moves back.
-\\{pascal-mode-map}
-Variables controlling indentation style:
- pascal-tab-always-indent (default t)
+  "Major mode for editing Pascal code. \\<pascal-mode-map>
+TAB indents for Pascal code.  Delete converts tabs to spaces as it moves back.
+
+\\[pascal-complete-word] completes the word around current point with respect \
+to position in code
+\\[pascal-show-completions] shows all possible completions at this point.
+
+Other useful functions are:
+
+\\[pascal-mark-defun]\t- Mark function.
+\\[pascal-insert-block]\t- insert begin ... end;
+\\[pascal-star-comment]\t- insert (* ... *)
+\\[pascal-comment-area]\t- Put marked area in a comment, fixing nested comments.
+\\[pascal-uncomment-area]\t- Uncomment an area commented with \
+\\[pascal-comment-area].
+\\[pascal-beg-of-defun]\t- Move to beginning of current function.
+\\[pascal-end-of-defun]\t- Move to end of current function.
+\\[pascal-goto-defun]\t- Goto function prompted for in the minibuffer.
+\\[pascal-outline]\t- Enter pascal-outline-mode (see also pascal-outline).
+
+Variables controlling indentation/edit style:
+
+ pascal-indent-level      (default 3)
+    Indentation of Pascal statements with respect to containing block.
+ 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.
+ pascal-tab-always-indent (defualt 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.
- pascal-auto-newline (default nil)
-    Non-nil means automatically newline after semicolons and the punctation
-    mark after an end.
- pascal-auto-endcomments (default t)
-    Non-nil means automatically set name of function or `case' in braces after
-    after the `end' if this end ends a function or a case block.
- pascal-indent-level (default 3)
-    Indentation of Pascal statements within surrounding block.
- pascal-continued-expr (default 1)
-    Indentation of a line that is a continued expression.
- pascal-typedecl-indent (default 10)
-    Indentation to the `=' in type declarations. (Or constant declarations.)
- pascal-vardecl-indent (default 20)
-    Indentation to the `:' in var declarations.
- pascal-label-offset (default -1)
-    Extra indentation for line that is a label, case statement or part of
-    a record block.
- pascal-case-offset (default 2)
-    Extra indent to the `:' in case statements.
-
-The only auto indention this mode doesn't fully support is if there is a
-case within a type declaration.  However, this is seldom used.
-
-When typing text, you should not worry about to get right indentions, they
-will be set when you hit return. The mode will also automatically delete the
-whitespaces between `*' and `)' when ending a starcomment.
+ pascal-auto-endcomments  (default 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.
+
+See also the user variables pascal-type-keywords, pascal-start-keywords and
+pascal-seperator-keywords.
 
 Turning on Pascal mode calls the value of the variable pascal-mode-hook with
 no args, if that value is non-nil."
@@ -202,26 +271,30 @@ 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)
-  (setq comment-indent-hook 'pascal-indent-within-comment)
+  (setq comment-indent-function 'pascal-indent-comment)
   (make-local-variable 'parse-sexp-ignore-comments)
   (setq parse-sexp-ignore-comments t)
   (make-local-variable 'case-fold-search)
   (setq case-fold-search t)
   (run-hooks 'pascal-mode-hook))
 
+\f
+
 ;;;
 ;;;  Electric functions
 ;;;
-
 (defun electric-pascal-terminate-line ()
   "Terminate line and indent next line."
   (interactive)
+  ;; First, check if current line should be indented
   (save-excursion
     (beginning-of-line)
     (skip-chars-forward " \t")
-    (if (looking-at "until\\b\\|end\\(\\b\\|;\\|\\.\\)\\|begin\\b\\|repeat\\b\\|else\\b")
+    (if (looking-at pascal-autoindent-lines-re)
        (pascal-indent-line)))
+  (delete-horizontal-space) ; Removes trailing whitespaces
   (newline)
+  ;; Indent next line
   (pascal-indent-line)
   ;; Maybe we should set some endcomments
   (if pascal-auto-endcomments
@@ -231,33 +304,22 @@ no args, if that value is non-nil."
     (save-excursion
       (forward-line -1)
       (skip-chars-forward " \t")
-      (cond ((looking-at "\\*[ \t]*)")
+      (cond ((looking-at "\\*[ \t]+)")
             ;; Delete region between `*' and `)' if there is only whitespaces.
             (forward-char 1)
-            (pascal-delete-whitespaces))
+            (delete-horizontal-space))
            ((and (looking-at "(\\*\\|\\*[^)]")
                  (not (save-excursion
                         (search-forward "*)" (pascal-get-end-of-line) t))))
             (setq setstar t))))
     ;; If last line was a star comment line then this one shall be too.
-    (if setstar
-       (progn
-         (insert "*")
-         (pascal-indent-command))
-      (pascal-indent-line))))
+    (if (null setstar) 
+       (pascal-indent-line)
+      (insert "*  "))))
 
-(defun electric-pascal-semi ()
-  "Insert ; character and correct this line's indention."
-  (interactive)
-  (insert last-command-char)
-  (save-excursion
-    (beginning-of-line)
-    (pascal-indent-line))
-  (if pascal-auto-newline
-      (electric-pascal-terminate-line)))
 
-(defun electric-pascal-dot ()
-  "Insert a period and correct this line's indention."
+(defun electric-pascal-semi-or-dot ()
+  "Insert `;' or `.' character and reindent the line."
   (interactive)
   (insert last-command-char)
   (save-excursion
@@ -267,48 +329,47 @@ no args, if that value is non-nil."
       (electric-pascal-terminate-line)))
 
 (defun electric-pascal-colon ()
-  "Insert : and do all indentions except line indent on this line."
+  "Insert `:' and do all indentions except line indent on this line."
   (interactive)
   (insert last-command-char)
-  ;; Do nothing of within string.
-  (if (not (pascal-within-string))
-      (progn
-       (if (save-excursion
-             (backward-char 2)
-             (looking-at "[0-9]"))
-           (save-excursion
-             (beginning-of-line)
-             (pascal-indent-line)))
-       (let ((pascal-tab-always-indent nil))
-         (pascal-indent-command)))))
-  
+  ;; Do nothing if within string.
+  (if (pascal-within-string)
+      ()
+    (save-excursion
+      (beginning-of-line)
+      (pascal-indent-line))
+    (let ((pascal-tab-always-indent nil))
+      (pascal-indent-command))))
+
 (defun electric-pascal-equal ()
-  "Insert = and do indention if within type declaration."
+  "Insert `=', and do indention if within type declaration."
   (interactive)
   (insert last-command-char)
-  (if (eq (nth 1 (pascal-calculate-indent t)) 'decl)
+  (if (eq (car (pascal-calculate-indent)) 'declaration)
       (let ((pascal-tab-always-indent nil))
        (pascal-indent-command))))
 
 (defun electric-pascal-tab ()
-  "Function called when tab is pressed."
+  "Function called when TAB is pressed in Pascal mode."
   (interactive)
   ;; Do nothing if within a string.
-  (if (not (pascal-within-string))
-      ;; If pascal-tab-always-indent is set then indent the beginning of
-      ;; the line.
-      (progn
-       (if pascal-tab-always-indent
-           (save-excursion
-             (beginning-of-line)
-             (pascal-indent-line)))
-       (pascal-indent-command))))
+  (if (pascal-within-string)
+      (insert "\t")
+    ;; If pascal-tab-always-indent, indent the beginning of the line.
+    (if pascal-tab-always-indent
+       (save-excursion
+         (beginning-of-line)
+         (pascal-indent-line))
+      (insert "\t"))
+    (pascal-indent-command)))
+
+\f
 
 ;;;
 ;;; Interactive functions
 ;;;
 (defun pascal-insert-block ()
-  "Insert begin ... end; block in the code with right indents."
+  "Insert Pascal begin ... end; block in the code with right indentation."
   (interactive)
   (pascal-indent-line)
   (insert "begin")
@@ -320,35 +381,38 @@ no args, if that value is non-nil."
     (pascal-indent-line)))
 
 (defun pascal-star-comment ()
-  "Insert star comment in the code."
+  "Insert Pascal star comment at point."
   (interactive)
   (pascal-indent-line)
   (insert "(*")
   (electric-pascal-terminate-line)
   (save-excursion
     (electric-pascal-terminate-line)
-    (pascal-delete-whitespaces)
-    (insert ")")))
+    (delete-horizontal-space)
+    (insert ")"))
+  (insert "  "))
 
-(defun pascal-mark-function ()
+(defun pascal-mark-defun ()
   "Mark the current pascal function (or procedure).
-Put the mark at the end of the function, and point at the beginning."
+This puts the mark at the end, and point at the beginning."
   (interactive)
   (push-mark (point))
-  (pascal-forward-to-end-of-function)
+  (pascal-end-of-defun)
   (push-mark (point))
-  (pascal-backward-to-beginning-of-function)
-  (zmacs-activate-region))
+  (pascal-beg-of-defun)
+  (if (fboundp 'zmacs-activate-region)
+      (zmacs-activate-region)))
 
 (defun pascal-comment-area (start end)
-  "Put the current region in a comment.
-The comments that are in this area are
-be changed so that `*)' becomes `!(*' and `}' becomes `!{'. These will
-however be turned back to normal when the area is uncommented by pressing
-\\[pascal-uncomment-area].
-The commented area starts with: `{---\\/---EXCLUDED---\\/---' , and ends with:
-` ---/\\---EXCLUDED---/\\---}'. If these texts are changed, uncomment-area
-will not be able to recognize them."
+  "Put the region into a Pascal comment.
+The comments that are in this area are \"deformed\":
+`*)' becomes `!(*' and `}' becomes `!{'.
+These deformed comments are returned to normal if you use
+\\[pascal-uncomment-area] to undo the commenting.
+
+The commented area starts with `pascal-exclude-str-start', and ends with
+`pascal-include-str-end'.  But if you change these variables,
+\\[pascal-uncomment-area] won't recognize the comments."
   (interactive "r")
   (save-excursion
     ;; Insert start and endcomments
@@ -357,12 +421,12 @@ will not be able to recognize them."
             (not (save-excursion (skip-chars-backward " \t") (bolp))))
        (forward-line 1)
       (beginning-of-line))
-    (insert " ---/\\---EXCLUDED---/\\---}")
+    (insert pascal-exclude-str-end)
     (setq end (point))
     (newline)
     (goto-char start)
     (beginning-of-line)
-    (insert "{---\\/---EXCLUDED---\\/--- ")
+    (insert pascal-exclude-str-start)
     (newline)
     ;; Replace end-comments within commented area
     (goto-char end)
@@ -374,9 +438,8 @@ will not be able to recognize them."
        (replace-match "!{" t t)))))
 
 (defun pascal-uncomment-area ()
-  "Uncomment a commented area.
-Change all deformed comments in this area back to normal.
-This function does nothing if the pointer is not in a commented
+  "Uncomment a commented area; change deformed comments back to normal.
+This command does nothing if the pointer is not in a commented
 area.  See also `pascal-comment-area'."
   (interactive)
   (save-excursion
@@ -384,9 +447,9 @@ area.  See also `pascal-comment-area'."
          (end (point)))
       ;; Find the boundaries of the comment
       (save-excursion
-       (setq start (progn (search-backward "{---\\/---EXCLUDED---\\/--" nil t)
+       (setq start (progn (search-backward pascal-exclude-str-start nil t)
                           (point)))
-       (setq end (progn (search-forward "---/\\---EXCLUDED---/\\---}" nil t)
+       (setq end (progn (search-forward pascal-exclude-str-end nil t)
                         (point))))
       ;; Check if we're really inside a comment
       (if (or (equal start (point)) (<= end (point)))
@@ -412,569 +475,923 @@ area.  See also `pascal-comment-area'."
            (end-of-line)
            (delete-region pos (1+ (point)))))))))
 
-(defun pascal-backward-to-beginning-of-function ()
-  "Move backwards to the beginning of this function or procedure."
+(defun pascal-beg-of-defun ()
+  "Move backward to the beginning of the current function or procedure."
   (interactive)
-  ;; Check if this is a 
-  (if (save-excursion
-       (re-search-backward "\\<end" nil t)
-       (looking-at "end\\."))
-      (beginning-of-buffer)
-    (let ((nest-depth 0) (nest-max 0)
-         (nest-noexit 1))
-      (beginning-of-line)
-      ;; First we find the max depth of the nesting
-      (save-excursion
-       (while (not (or (bobp) (looking-at "function\\b\\|procedure\\b")))
-         (backward-sexp 1)
-         (cond ((looking-at "begin\\b\\|\\case\\b\\|record\\b")
-                (setq nest-depth (1+ nest-depth)))
-               ((looking-at "end\\(\\b\\|;\\|\\.\\)")
-                (setq nest-depth (1- nest-depth))))
-         (setq nest-max (max nest-depth nest-max))))
-      ;; Then we can start searching
-      (setq nest-depth 0)
-      (while (not (or (bobp) (and (looking-at "function\\b\\|procedure\\b")
-                                 (zerop nest-noexit))))
-       (backward-sexp 1)
-       (cond ((looking-at "begin\\b\\|\\case\\b\\|record\\b")
-              (setq nest-depth (1+ nest-depth)))
-             ((looking-at "end\\(\\b\\|;\\|\\.\\)")
-              (if (equal nest-depth nest-max)
-                  (setq nest-noexit (1+ nest-noexit)))
-              (setq nest-depth (1- nest-depth)))
-             ((looking-at "function\\b\\|procedure\\b")
-              (setq nest-noexit (1- nest-noexit))))))))
-
-(defun pascal-forward-to-end-of-function ()
-  "Moves the point to the end of the function."
+  (catch 'found
+    (if (not (looking-at (concat "\\s \\|\\s)\\|" pascal-defun-re)))
+       (forward-sexp 1))
+    (let ((nest 0) (max -1) (func 0)
+         (reg (concat pascal-beg-block-re "\\|" 
+                      pascal-end-block-re "\\|"
+                      pascal-defun-re)))
+      (while (re-search-backward reg nil 'move)
+       (cond ((let ((state (save-excursion
+                             (parse-partial-sexp (point-min) (point)))))
+                (or (nth 3 state) (nth 4 state))) ; Inside string or comment
+              ())
+             ((match-end 1)                       ; begin|case|record|repeat
+              (if (and (looking-at "\\<record\\>") (>= max 0))
+                  (setq func (1- func)))
+              (setq nest (1+ nest)
+                    max (max nest max)))
+             ((match-end 2)                       ; end|until
+              (if (and (= nest max) (>= max 0))
+                  (setq func (1+ func)))
+              (setq nest (1- nest)))
+             ((match-end 3)                       ; function|procedure
+              (if (= 0 func)
+                  (throw 'found t)
+                (setq func (1- func)))))))
+    nil))
+
+(defun pascal-end-of-defun ()
+  "Move forward to the end of the current function or procedure."
   (interactive)
-  (if (not (looking-at "function\\b\\|procedure\\b"))
-      (pascal-backward-to-beginning-of-function))
-  (if (bobp)
-      (end-of-buffer)
-    (progn
-      (let ((nest-depth 0)
-           (func-depth 1))
-       (while (not (or (and (zerop nest-depth) (zerop func-depth)) (eobp)))
-         (forward-sexp 2)
-         (if (not (eobp))
-             (progn
-               (backward-sexp 1) ; Move to the beginning of the next sexp
-               (cond ((looking-at "begin\\b\\|case\\b\\|record\\b")
-                      (setq nest-depth (1+ nest-depth)))
-                     ((looking-at "end\\(\\b\\|;\\|\\.\\)")
-                      (setq nest-depth (1- nest-depth))
-                      (if (zerop nest-depth)
-                          (setq func-depth (1- func-depth))))
-                     ((looking-at "function\\b\\|procedure\\b")
-                      (setq func-depth (1+ func-depth)))))))
-       (end-of-line)))))
+  (if (looking-at "\\s ")
+      (forward-sexp 1))
+  (if (not (looking-at pascal-defun-re))
+      (pascal-beg-of-defun))
+  (forward-char 1)
+  (let ((nest 0) (func 1)
+       (reg (concat pascal-beg-block-re "\\|" 
+                    pascal-end-block-re "\\|"
+                    pascal-defun-re)))
+    (while (and (/= func 0)
+               (re-search-forward reg nil 'move))
+      (cond ((let ((state (save-excursion
+                             (parse-partial-sexp (point-min) (point)))))
+                (or (nth 3 state) (nth 4 state))) ; Inside string or comment
+              ())
+           ((match-end 1)
+            (setq nest (1+ nest))
+            (if (save-excursion
+                  (goto-char (match-beginning 0))
+                  (looking-at "\\<record\\>"))
+                (setq func (1+ func))))
+           ((match-end 2)
+            (setq nest (1- nest))
+            (if (= nest 0)
+                (setq func (1- func))))
+           ((match-end 3)
+            (setq func (1+ func))))))
+  (forward-line 1))
 
 (defun pascal-downcase-keywords ()
-  "Makes all Pascal keywords in the buffer lowercase."
+  "Downcase all Pascal keywords in the buffer."
   (interactive)
   (pascal-change-keywords 'downcase-word))
 
 (defun pascal-upcase-keywords ()
-  "Makes all Pascal keywords in the buffer uppercase."
+  "Upcase all Pascal keywords in the buffer."
   (interactive)
   (pascal-change-keywords 'upcase-word))
 
 (defun pascal-capitalize-keywords ()
-  "Makes all Pascal keywords in the buffer uppercase."
+  "Capitalize all Pascal keywords in the buffer."
   (interactive)
   (pascal-change-keywords 'capitalize-word))
 
+;; Change the keywords according to argument.
 (defun pascal-change-keywords (change-word)
-  "Change the keywords according to argument."
   (save-excursion
-    (beginning-of-buffer)
-    (while (re-search-forward (mapconcat
-                              'downcase pascal-keywords "\\>\\|\\<") nil t)
-      (funcall change-word -1))))
+    (let ((keyword-re (concat "\\<\\("
+                             (mapconcat 'identity pascal-keywords "\\|")
+                             "\\)\\>")))
+      (goto-char (point-min))
+      (while (re-search-forward keyword-re nil t)
+       (funcall change-word -1)))))
+
+\f
 
 ;;;
 ;;; Other functions
 ;;;
-(defun pascal-delete-whitespaces ()
-  "Deletes the whitespaces around the current point."
-  (interactive)
-  (let ((pos (progn (skip-chars-backward " \t") (point))))
-    (skip-chars-forward " \t")
-    (delete-region pos (point))))
-
-(defun pascal-get-beg-of-line ()
-  (save-excursion
-    (beginning-of-line)
-    (point)))
-
-(defun pascal-get-end-of-line ()
-  (save-excursion
-    (end-of-line)
-    (point)))
-  
-(defun pascal-within-string ()
-  "Return t if within string; nil otherwise."
-  (and (save-excursion (search-backward "\"" (pascal-get-beg-of-line) t))
-       (save-excursion (not (search-backward "\"" (pascal-get-beg-of-line) t 2)))))
-
-(defun pascal-check-if-within-comment ()
-  "If within a comment, return the correct indent.  Return nil otherwise."
-  (let ((comstart (point))
-       (comend (point)))
-    (save-excursion
-      (if (re-search-backward "(\\*\\|{" nil t)
-         (setq comstart (point))
-       (setq comstart 0)))
-    (save-excursion
-      (if (re-search-backward "\\*)\\|}" nil t)
-         (setq comend (point))
-       (setq comend 0)))
-    (if (< comend comstart)
-       (save-excursion
-         (goto-char comstart)
-         ;; Add 1 to indent if this is a starcomment
-         (if (looking-at "(\\*")
-             (1+ (current-column))
-           (current-column)))
-      nil)))
 
 (defun pascal-set-auto-comments ()
-  "Put { case } or { FUNNAME } on this line if appropriate after `end'."
+  "Insert `{ case }' or `{ NAME }' on this line if appropriate.
+Insert `{ case }' if there is an `end' on the line which
+ends a case block.  Insert `{ NAME }' if there is an `end'
+on the line which ends a function or procedure named NAME."
   (save-excursion
     (forward-line -1)
     (skip-chars-forward " \t")
-    (if (and (looking-at "end\\(\>\\|;\\)")
+    (if (and (looking-at "\\<end;")
             (not (save-excursion
                    (end-of-line)
-                   (search-backward "}" (pascal-get-beg-of-line) t))))
+                   (search-backward "{" (pascal-get-beg-of-line) t))))
        (progn
-         (if (eq (nth 1 (pascal-calculate-indent)) 'case)
+         (if (eq (car (pascal-calculate-indent)) 'case)
              ;; This is a case block
              (progn
                (end-of-line)
-               (pascal-delete-whitespaces)
+               (delete-horizontal-space)
                (insert " { case }"))
            (let ((nest 1))
              ;; Check if this is the end of a function
              (save-excursion
-               (while (not (or (looking-at "function\\b\\|\\procedure\\b")
-                               (bobp)))
+               (while (not (or (looking-at pascal-defun-re) (bobp)))
                  (backward-sexp 1)
-                 (cond ((looking-at "begin\\b\\|case\\b")
+                 (cond ((looking-at pascal-beg-block-re)
                         (setq nest (1- nest)))
-                       ((looking-at "end\\(\\b\\|;\\|\\.\\)")
+                       ((looking-at pascal-end-block-re)
                         (setq nest (1+ nest)))))
                (if (bobp)
                    (setq nest 1)))
              (if (zerop nest)
-                 (let ((last-command nil))
-                   ;; Find the function name and put it in braces
-                   (save-excursion
-                     (pascal-backward-to-beginning-of-function)
-                     (skip-chars-forward "^ \t")
-                     (skip-chars-forward " \t")
-                     (copy-region-as-kill (point)
-                                          (save-excursion
-                                            (skip-chars-forward "a-zA-Z0-9_")
-                                            (point))))
+                 (progn
                    (end-of-line)
-                   (pascal-delete-whitespaces)
+                   (delete-horizontal-space)
                    (insert " { ")
-                   ;; We've filled up the kill ring, but hey, who cares?
-                   (yank) (rotate-yank-pointer 1)
+                   (let (b e)
+                     (save-excursion
+                       (setq b (progn (pascal-beg-of-defun)
+                                      (skip-chars-forward "^ \t")
+                                      (skip-chars-forward " \t")
+                                      (point))
+                             e (progn (skip-chars-forward "a-zA-Z0-9_")
+                                      (point))))
+                     (insert-buffer-substring (current-buffer) b e))
                    (insert " }")))))))))
 
+\f
+
 ;;;
-;;; Indent functions and calculation of indent
-;;;    
+;;; Indentation
+;;;
+(defconst pascal-indent-alist
+  '((block . (+ ind pascal-indent-level))
+    (case . (+ ind pascal-case-indent))
+    (declaration . (+ ind pascal-indent-level))
+    (paramlist . (pascal-indent-paramlist t))
+    (comment . (pascal-indent-comment t))
+    (defun . ind) (contexp . ind)
+    (unknown . 0) (string . 0)))
+
 (defun pascal-indent-command ()
-  "Indent current line as Pascal code and/or indent within line."
-  ;; Call pascal-indent-line. This does nothing if we're not at the
-  ;; beginning of the line.
-  (pascal-indent-line)
-  (let ((indent (pascal-calculate-indent t))
-       (pos 0))
-    (save-excursion
-      (cond ((or (eq (nth 1 indent) 'case)
-                (eq (nth 1 indent) 'record))
-            ;; Indent for case and record blocks
-            (beginning-of-line)
-            (if (search-forward ":" (pascal-get-end-of-line) t)
-                (progn
-                  ;; Indent before colon
-                  (backward-char 1)
-                  (pascal-delete-whitespaces)
-                  (indent-to (max (pascal-find-leading-case-colon)
-                                  (1+ (current-column))))
-                  ;; Indent after colon
-                  (forward-char 1)
-                  (pascal-delete-whitespaces)
-                  (indent-to (1+ (current-column))))
-              ;; Indent if there is no colon
-              (progn
-                (beginning-of-line)
-                (skip-chars-forward " \t")
-                (if (not (eolp))
-                    (progn
-                      (skip-chars-forward "0-9a-zA-Z\"\'_;")
-                      (pascal-delete-whitespaces)
-                      (indent-to (max (pascal-find-leading-case-colon)
-                                      (1+ (current-column)))))))))
-           ((eq (nth 1 indent) 'decl)
-            ;; Indent for declarations
-            (let ((posii (pascal-get-beg-of-line)))
-              (re-search-backward "\\<\\(var\\|type\\|const\\|label\\)\\>"
-                                  nil t)
-              (cond ((looking-at "var\\b")
-                     (pascal-declindent-middle-of-line
-                      ":" posii pascal-vardecl-indent))
-                    ((looking-at "type\\b\\|const\\b")
-                     (pascal-declindent-middle-of-line
-                      "=" posii pascal-typedecl-indent)))))
-           ((eq (nth 1 indent) 'function)
-            ;; Indent for parameterlist
-            ;; Done twice in case something has changed
-            (pascal-indent-parameter-list)
-            (pascal-indent-parameter-list))))       
-    ;; Go to the end of a line if rest of line contains only whitespaces
-    (if (save-excursion (skip-chars-forward " \t") (eolp))
-       (end-of-line))))
+  "Indent for special part of code."
+  (let* ((indent-str (pascal-calculate-indent))
+        (type (car indent-str))
+        (ind (car (cdr indent-str))))
+    (cond ((eq type 'paramlist)
+          (pascal-indent-paramlist)
+          (pascal-indent-paramlist))
+         ((eq type 'declaration)
+          (pascal-indent-declaration))
+         ((and (eq type 'case) (not (looking-at "^[ \t]*$")))
+          (pascal-indent-case)))
+    (if (looking-at "[ \t]+$")
+       (skip-chars-forward " \t"))))
 
 (defun pascal-indent-line ()
-  "Indent current line as Pascal code."
-  (let ((indent (list 0 nil))
-       (comindent 0)
-       beg (point))
-    (save-excursion
-      (beginning-of-line)
-      (setq indent (pascal-calculate-indent)))
-    ;; If we are inside a comment, do special indent.
-    (if (setq comindent (pascal-check-if-within-comment))
-       (pascal-indent-within-comment comindent)
-      ;; Skip the rest if we're not standing on the beginning of a line.
-      (if (save-excursion (skip-chars-backward " \t") (bolp))
-         (progn
-           (beginning-of-line)
-           (pascal-delete-whitespaces)
-           ;; When to skip the ekstra indent:
-           ;; If we are standing at end or until.
-           ;; If we are in an if statement and standing at else,
-           ;;  begin or repeat
-           ;; If we are in a with, while or for statement and standing
-           ;;  at begin or end.
-           (cond ((or (or (looking-at "end\\b\\|until\\b")
-                          (not (nth 1 indent)))
-                      (and (eq (nth 1 indent) 'if)
-                           (looking-at "begin\\b\\|\\repeat\\b\\|else\\b"))
-                      (and (eq (nth 1 indent) 'whilewith)
-                           (looking-at "begin\\b\\|\\repeat\\b")))
-                  (indent-to (car indent)))
-                 ;; Continued expression
-                 ((eq (nth 1 indent) 'contexp)
-                  (indent-to (+ (car indent) pascal-continued-expr)))
-                 ;; If this is a part of a case or record block,
-                 ;; then modify the indent level.
-                 ((or (eq (nth 1 indent) 'case)
-                      (eq (nth 1 indent) 'record))
-                  (indent-to (+ (car indent) pascal-indent-level
-                                pascal-label-offset)))
-                 ;; If this is a label - don't indent.
-                 ((looking-at "[0-9]*:")
-                  (skip-chars-forward "0-9:")
-                  (pascal-delete-whitespaces)
-                  (indent-to (+ (car indent) pascal-indent-level)))
-                 ;; If this is insde a parameter list, do special indent
-                 ((eq (nth 1 indent) 'function)
-                  (pascal-indent-parameter-list))
-                 ;; All other indents are set normaly.
-                 (t
-                  (indent-to (+ (car indent) pascal-indent-level)))))))))
-    
-(defun pascal-calculate-indent (&optional arg)
-  "Search backward in code to find the right indent level.
-Return a list containing:
-1. Indent level
-2. The indent keyword (begin, case etc.), or nil if backtracking failed.
-If arg is non-nil, we do not search for continued expressions."
-  (let ((pascal-nest-depth 1)
-       (oldpos (save-excursion (forward-line -1) (end-of-line) (point)))
-       (samepos (point)) (if-is-set t)
-       (return-struct (list 0 nil)) (pos 0)
-       (contexpr nil) (after-contexpr (not arg))
-       (case-fold-search t))
-    (save-excursion
-      (while (and (not (zerop pascal-nest-depth))
-                 (not (bobp)))
-       (progn
-         (backward-sexp 1)
-         (if (save-excursion
-               (setq pos (point))
-               (end-of-line)
-               (search-backward ";" pos t))
-             (setq if-is-set nil
-                   after-contexpr nil))
-         (if (looking-at "then\\b\\|end\\b\\|else\\b\\|do\\b")
-             (setq after-contexpr nil))
-
-         (cond ((looking-at "begin\\b\\|case\\b\\|record\\b\\|repeat\\b")
-                (setq pascal-nest-depth (1- pascal-nest-depth)))
-               ;;
-               ;; END | UNTIL
-               ((looking-at "end\\(\\b\\|;\\|\\.\\)\\|until\\b")
-                (setq if-is-set nil)
-                (if after-contexpr
-                    (setq pascal-nest-depth 0
-                          contexpr t)
-                  (setq pascal-nest-depth (1+ pascal-nest-depth))))
-               ;;
-               ;; IF | ELSE | WITH | WHILE | FOR
-               ;; LABEL |  CONST | TYPE | FUNCTION | PROCEDURE
-               ((or (and (looking-at "if\\b\\|else\\b\\|with\\b\\|while\\b\\|for\\b")
-                         if-is-set)
-                    (looking-at "label\\b\\|const\\b\\|type\\b\\|function\\b\\|procedure\\b"))
-                (setq pascal-nest-depth 0))
-               ;;
-               ;; VAR
-               ((looking-at "var\\b")
-                ;; A `var' can be in a declaration part or parameter part
-                (let ((stpos 0) (edpos 0))
-                  (save-excursion
-                    (if (not (re-search-backward
-                              "\\<\\(function\\|procedure\\)\\>" nil t))
-                        (beginning-of-buffer))
-                    (setq stpos (save-excursion
-                                  (search-forward "(" nil t) (point)))
-                    (setq edpos (save-excursion
-                                  (search-forward ")" nil t) (point))))
-                  (cond ((or (= stpos edpos) (< samepos stpos)
-                             (and (> (point) edpos) (> edpos stpos)))
-                         ;; This is really a declaration block!!
-                         nil)
-                        ((and (>= samepos stpos) (or (< samepos edpos)
-                                                     (> stpos edpos)))
-                         ;; Hmm... part of a parameter
-                         (re-search-backward
-                          "\\<\\(function\\|procedure\\)\\>" nil t))
-                        (t
-                         ;; This is just after a parameter declaration
-                         (forward-char 1)))
-                  ;; We'll quit anyway
-                  (setq pascal-nest-depth 0)))
-               ;;
-               ;; CONTINUED EXPRESSIONS
-               (after-contexpr
-                (save-excursion
-                  ;; First, we have to be at the begining of a line
-                  (if (and (progn (skip-chars-backward " \t") (bolp))
-                           ;; Blank lines don't count
-                           (not (progn (skip-chars-forward " \t") (eolp)))
-                           ;; But nonblank without ';' do
-                           (not (search-forward ";" (pascal-get-end-of-line) t)))
-                      (save-excursion
-                        (forward-line -1)
-                        (end-of-line)
-                        (backward-sexp 1)
-                        (if (or (looking-at "\\(do\\|then\\|of\\\|begin\\|repeat\\|else\\)\\>")
-                                (progn
-                                  (skip-chars-forward "^; " (pascal-get-end-of-line))
-                                  (equal (char-to-string (following-char))
-                                         ";")))
-                            (setq pascal-nest-depth 0))
-                        (setq contexpr t)))))
-               )))
-      (cond (contexpr
-            (setq return-struct (list (pascal-lstart-col) 'contexp)))
-           ((looking-at "begin\\b")
-            (setq return-struct (list (pascal-lstart-col) 'begin)))
-           ((looking-at "else\\b")
-            (setq return-struct (list (save-excursion
-                                        (re-search-backward "if\\b" nil t)
-                                        (pascal-lstart-col)) 'if))
-            ;; Indent line in case this is a multiple if
-            (beginning-of-line)
-            (pascal-delete-whitespaces)
-            (indent-to (car return-struct)))
-           ((looking-at "if\\b")
-            (if (save-excursion
-                  (narrow-to-region (pascal-get-beg-of-line) (point))
-                  (backward-sexp 1)
-                  (widen)
-                  (looking-at "else\\b"))
-                ;; Indent line if this is a multiple if
-                (progn
-                  (beginning-of-line)
-                  (pascal-delete-whitespaces)
-                  (indent-to (save-excursion
-                               (re-search-backward "if\\b" nil t)
-                               (pascal-lstart-col)))))
-            ;; This could be a continued expression
-            (if (and after-contexpr
-                     (not (save-excursion (re-search-forward
-                                           "then\\b" (pascal-get-end-of-line) t))))
-                (setq return-struct (list (pascal-lstart-col) 'contexp))
-              (setq return-struct (list (pascal-lstart-col) 'if))))
-           ((looking-at "repeat\\b")
-            (setq return-struct (list (pascal-lstart-col) 'repeat)))
-           ((looking-at "case\\b")
-            (setq return-struct (list (current-column) 'case)))
-           ((looking-at "record\\b")
-            (setq return-struct (list (current-column) 'record)))
-           ((looking-at "while\\b\\|with\\b\\|for\\b")
-            ;; This could ba a continued expression
-            (if (and after-contexpr
-                     (not (save-excursion (re-search-forward
-                                           "do\\b" (pascal-get-end-of-line) t))))
-                (setq return-struct (list (pascal-lstart-col) 'contexp))
-              (setq return-struct (list (current-column) 'whilewith))))
-           ((looking-at "procedure\\b\\|function\\b")
-            ;; Make sure that this is a function with parameters, and
-            ;; that we are actually standing inside the paranthesis.
-            (let ((spos (save-excursion
-                          (search-forward "(" samepos t) (point)))
-                  (epos (save-excursion
-                          (search-forward ")" samepos t) (point))))
-              (if (and (>= samepos spos) (or (< samepos epos)
-                                             (> spos epos)))
-                  (setq return-struct (list 0 'function))
-                (setq return-struct (list 0 nil)))))
-           ((looking-at "var\\b\\|label\\b\\|const\\b\\|type\\b")
-            ;; Are we really in the declaration part?(Check for blank lines)
-            (if (< oldpos (point))
-                (setq return-struct (list 0 'decl))
-              (if (save-excursion
-                    (not (re-search-forward "^[ \t]*$" oldpos t)))
-                  (setq return-struct (list 0 'decl))
-                (setq return-struct (list 0 nil)))))
-           (t
-            (setq return-struct (list 0 nil))))
-      return-struct)))
-
-(defun pascal-lstart-col ()
-  "Return the column of the beginning of the first command on the line."
+  "Indent current line as a Pascal statement."
+  (let* ((indent-str (pascal-calculate-indent))
+        (type (car indent-str))
+        (ind (car (cdr indent-str))))
+    (if (looking-at "^[0-9a-zA-Z]+[ \t]*:[^=]")
+       (search-forward ":" nil t))
+    (delete-horizontal-space)
+    ;; Some thing should not be indented
+    (if (or (and (eq type 'declaration) (looking-at pascal-declaration-re))
+           (looking-at pascal-defun-re))
+       ()
+      ;; Other things should have no extra indent
+      (if (looking-at pascal-noindent-re)
+         (indent-to ind)
+       ;; But most lines are treated this way:
+       (indent-to (eval (cdr (assoc type pascal-indent-alist))))
+       ))))
+
+(defun pascal-calculate-indent ()
+  "Calculate the indent of the current Pascal line.
+Return a list of two elements: (INDENT-TYPE INDENT-LEVEL)."
+  (save-excursion
+    (let* ((oldpos (point))
+          (state (save-excursion (parse-partial-sexp (point-min) (point))))
+          (nest 0) (par 0) (complete nil) (blocked nil)
+          (type (catch 'nesting
+                  ;; Check if inside a string, comment or parenthesis
+                  (cond ((nth 3 state) (throw 'nesting 'string))
+                        ((nth 4 state) (throw 'nesting 'comment))
+                        ((> (car state) 0)
+                         (goto-char (scan-lists (point) -1 (car state)))
+                         (setq par (1+ (current-column)))))
+                  ;; Loop until correct indent is found
+                  (while t
+                    (backward-sexp 1)
+                    (cond (;--Nest block outwards
+                           (looking-at pascal-beg-block-re)
+                           (if (= nest 0)
+                               (cond ((looking-at "case\\>")
+                                      (setq blocked t)
+                                      (throw 'nesting 'case))
+                                     ((looking-at "record\\>")
+                                      (throw 'nesting 'declaration))
+                                     (t (setq blocked t)
+                                        (throw 'nesting 'block)))
+                             (setq nest (1- nest))))
+                          (;--Nest block inwards
+                           (looking-at pascal-end-block-re)
+                           (setq complete t
+                                 nest (1+ nest)))
+                          (;--Defun (or parameter list)
+                           (looking-at pascal-defun-re)
+                           (if (= 0 par)
+                               (throw 'nesting 'defun)
+                             (setq par 0)
+                             (let ((n 0))
+                               (while (re-search-forward
+                                       "\\(\\<record\\>\\)\\|\\<end\\>"
+                                       oldpos t)
+                                 (if (match-end 1)
+                                     (setq n (1+ n)) (setq n (1- n))))
+                               (if (> n 0)
+                                   (throw 'nesting 'declaration)
+                                 (throw 'nesting 'paramlist)))))
+                          (;--Declaration part
+                           (looking-at pascal-declaration-re)
+                           (if (or blocked
+                                   (save-excursion
+                                     (goto-char oldpos)
+                                     (forward-line -1)
+                                     (looking-at "^[ \t]*$")))
+                               (throw 'nesting 'unknown)
+                             (throw 'nesting 'declaration)))
+                          (;--If, else or while statement
+                           (and (not complete)
+                                (looking-at pascal-sub-block-re))
+                           (throw 'nesting 'block))
+                          (;--Found complete statement
+                           (save-excursion (forward-sexp 1)
+                                           (= (following-char) ?\;))
+                           (setq complete t))
+                          (;--No known statements
+                           (bobp)
+                           (throw 'nesting 'unknown))
+                          )))))
+      ;; Return type of block and indent level.
+      (if (> par 0)                               ; Unclosed Parenthesis 
+         (list 'contexp par)
+       (list type (pascal-indent-level))))))
+
+(defun pascal-indent-level ()
+  "Return the indent-level the current statement has.
+Do not count labels, case-statements or records."
   (save-excursion
     (beginning-of-line)
-    (skip-chars-forward ":0-9")
+    (if (looking-at "[ \t]*[0-9a-zA-Z]+[ \t]*:[^=]")
+       (search-forward ":" nil t)
+      (if (looking-at ".*=[ \t]*record\\>")
+         (search-forward "=" nil t)))
     (skip-chars-forward " \t")
     (current-column)))
 
-(defun pascal-indent-parameter-list ()
-  "Indent this line as part of a parameter list in a function."
-  (let ((indents (pascal-get-highest-indents-in-parameterlist))
-       (pos 0))
-    (if (not (progn (beginning-of-line)
-                   (search-forward "(" (pascal-get-end-of-line) t)))
-       (progn (beginning-of-line)
-              (skip-chars-forward " \t")))
-    ;; Indent region in front of var
-    (skip-chars-forward " \t")
-    (pascal-delete-whitespaces)
-    (indent-to (nth 0 indents))
-    (if (looking-at "var\\b")
-       (forward-char 3))
-    ;; Indent parameternames
-    (pascal-delete-whitespaces)
-    (indent-to (nth 1 indents))
-    (if (not (save-excursion (skip-chars-forward " \t") (eolp)))
-       (progn
-         ;; Indent colon
-         (if (search-forward ":" (pascal-get-end-of-line) t)
-             (backward-char 1)
-           (end-of-line))
-         (pascal-delete-whitespaces)
-         (indent-to (nth 2 indents))
-         ;; Indent after colon
-         (if (equal (following-char) ?:)
-             (progn
-               (forward-char 1)
-               (pascal-delete-whitespaces)
-               (indent-to (+ 2 (nth 2 indents)))))))))
-
-;; Get the indents to use in a parameterlist.
-;; Returns:
-;; 1. Indent to the beginning of the line.
-;; 2. Indent to the beginning of the parameter names.
-;; 3. Indent to the right colon position."
-(defun pascal-get-highest-indents-in-parameterlist ()
+(defun pascal-indent-comment (&optional arg)
+  "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))))
+
+(defun pascal-indent-case ()
+  "Indent within case statements."
+  (skip-chars-forward ": \t")
+  (let ((end (prog1 (point-marker)
+              (re-search-backward "\\<case\\>" nil t)))
+       (beg (point))
+       (ind 0))
+    ;; Get right indent
+    (while (< (point) (marker-position end))
+      (if (re-search-forward "^[ \t]*\\([^ \t]+\\)[ \t]*:"
+                        (marker-position end) 'move)
+         (goto-char (match-end 1)))
+      (delete-horizontal-space)
+      (if (> (current-column) ind)
+         (setq ind (current-column)))
+      (beginning-of-line 2))
+    (goto-char beg)
+    ;; Indent all case statements
+    (while (< (point) (marker-position end))
+      (if (re-search-forward "^[ \t]*[^ \t]+[ \t]*:"
+                            (marker-position end) 'move)
+         (forward-char -1))
+      (indent-to (1+ ind))
+      (if (/= (following-char) ?:)
+         ()
+       (forward-char 1)
+       (delete-horizontal-space)
+       (insert " ")))))
+
+(defun pascal-indent-paramlist (&optional arg)
+  "Indent current line in parameterlist.
+If optional arg is non-nil, just return the
+indent of the current line in parameterlist."
   (save-excursion
-    (let ((start (progn
-                  (re-search-backward
-                   "\\<\\(function\\|procedure\\)\\>" nil t)
-                  (search-forward "(")
-                  (current-column)))
-         (arglength 0) (vardecl nil) (done nil))
-      (while (not (or done (eobp)))
-       (beginning-of-line)
-       (if (save-excursion
-             (re-search-forward "\\<var\\>" (pascal-get-end-of-line) t))
-             (setq vardecl t))
-       (if (not (re-search-forward ":" (pascal-get-end-of-line) t))
-           (setq done t))
-       (skip-chars-backward ": \t")
-       (setq arglength (max arglength (current-column)))
-       (forward-line 1))
-      (if vardecl
-         (list start (+ start 4) (1+ arglength))
-       (list start start (1+ arglength))))))
-
-(defun pascal-declindent-middle-of-line (declkey endpos defaultindent)
-  "Indent declaration line."
-  (let ((decindent 0))
-    (if (search-forward declkey endpos t)
-       (setq decindent (1- (current-column)))
-      (setq decindent defaultindent))
-    (goto-char endpos)
-    (end-of-line)
-    (if (save-excursion (search-backward declkey endpos t))
-       (progn (search-backward declkey) (skip-chars-backward " \t"))
-      (skip-chars-backward " \t"))
-    (pascal-delete-whitespaces)
-    (indent-to (max decindent (1+ (current-column))))
-    ;; Indent after `declkey'
-    (if (looking-at declkey)
-       (progn
-         (forward-char 1)
-         (pascal-delete-whitespaces)
-         (indent-to (1+ (current-column)))))))
+    (let* ((oldpos (point))
+          (stpos (progn (goto-char (scan-lists (point) -1 1)) (point)))
+          (stcol (1+ (current-column)))
+          (edpos (progn (pascal-declaration-end) 
+                        (search-backward ")" (pascal-get-beg-of-line) t)
+                        (point)))
+          (usevar (re-search-backward "\\<var\\>" stpos t)))
+      (if arg (progn
+               ;; If arg, just return indent
+               (goto-char oldpos)
+               (beginning-of-line)
+               (if (or (not usevar) (looking-at "[ \t]*var\\>"))
+                   stcol (+ 4 stcol)))
+       (goto-char stpos)
+       (forward-char 1)
+       (delete-horizontal-space)
+       (if (and usevar (not (looking-at "var\\>")))
+           (indent-to (+ 4 stcol)))
+       (pascal-indent-declaration nil stpos edpos)))))
+
+(defun pascal-indent-declaration (&optional arg start end)
+  "Indent current lines as declaration, lining up the `:'s or `='s."
+  (let ((pos (point-marker)))
+    (if (and (not (or arg start)) (not (pascal-declaration-beg)))
+       ()
+      (let ((lineup (if (or (looking-at "\\<var\\>\\|\\<record\\>") arg start) 
+                       ":" "="))
+           (stpos (if start start
+                      (forward-word 2) (backward-word 1) (point)))
+           (edpos (set-marker (make-marker)
+                              (if end end
+                                (max (progn (pascal-declaration-end)
+                                            (point))
+                                     pos))))
+           ind)
+
+       (goto-char stpos)
+       ;; Indent lines in record block
+       (if arg
+           (while (<= (point) (marker-position edpos))
+             (beginning-of-line)
+             (delete-horizontal-space)
+             (if (looking-at "end\\>")
+                 (indent-to arg)
+               (indent-to (+ arg pascal-indent-level)))
+             (forward-line 1)))
+
+       ;; Do lineup
+       (setq ind (pascal-get-lineup-indent stpos edpos lineup))
+       (goto-char stpos)
+       (while (<= (point) (marker-position edpos))
+         (if (search-forward lineup (pascal-get-end-of-line) 'move)
+             (forward-char -1))
+         (delete-horizontal-space)
+         (indent-to ind)
+         (if (not (looking-at lineup))
+             (forward-line 1) ; No more indent if there is no : or =
+           (forward-char 1)
+           (delete-horizontal-space)
+           (insert " ")
+           ;; Indent record block
+           (if (looking-at "record\\>")
+               (pascal-indent-declaration (current-column)))
+           (forward-line 1)))))
+
+    ;; If arg - move point
+    (if arg (forward-line -1)
+      (goto-char (marker-position 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)
+      (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)
+           ;; Skip record blocks
+           (if (match-beginning 1)
+               (pascal-declaration-end)
+             (save-excursion
+               (goto-char (match-beginning 0))
+               (skip-chars-backward " \t")
+               (if (> (current-column) ind)
+                   (setq ind (current-column)))))))
+      ;; In case no lineup was found
+      (if (> ind 0)
+         (1+ ind)
+       ;; No lineup-string found
+       (goto-char b)
+       (end-of-line)
+       (skip-chars-backward " \t")
+       (1+ (current-column))))))
+    
+\f
+
+;;;
+;;; Completion
+;;;
+(defun pascal-string-diff (str1 str2)
+  "Return index of first letter where STR1 and STR2 differs."
+  (catch 'done
+    (let ((diff 0))
+      (while t
+       (if (or (> (1+ diff) (length str1))
+               (> (1+ diff) (length str2)))
+           (throw 'done diff))
+       (or (equal (aref str1 diff) (aref str2 diff))
+           (throw 'done diff))
+       (setq diff (1+ diff))))))
+
+;; Calculate all possible completions for functions if argument is `function',
+;; completions for procedures if argument is `procedure' or both functions and
+;; procedures otherwise.
+
+(defun pascal-func-completion (type)
+  ;; Build regular expression for function/procedure names
+  (if (string= str "")
+      (setq str "[a-zA-Z_]"))
+  (let ((str (concat (cond ((eq type 'procedure) "\\<\\(procedure\\)\\s +")
+                          ((eq type 'function) "\\<\\(function\\)\\s +")
+                          (t "\\<\\(function\\|procedure\\)\\s +"))
+                    "\\<\\(" str "[a-zA-Z0-9_.]*\\)\\>"))
+       match)
   
-(defun pascal-indent-within-comment (indent)
-  "Indent comments and/or indent text within comment."
-  (progn
-    ;; If we are at the beginning of the line, then we indent this line.
-    (if (save-excursion (skip-chars-backward " \t") (bolp))
+    (if (not (looking-at "\\<\\(function\\|procedure\\)\\>"))
+       (re-search-backward "\\<\\(function\\|procedure\\)\\>" nil t))
+    (forward-char 1)
+
+    ;; Search through all reachable functions
+    (while (pascal-beg-of-defun)
+      (if (re-search-forward str (pascal-get-end-of-line) t)
+         (progn (setq match (buffer-substring (match-beginning 2)
+                                              (match-end 2)))
+                (if (or (null predicate)
+                        (funcall prdicate match))
+                    (setq all (cons match all)))))
+      (goto-char (match-beginning 0)))))
+
+(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'
+  (let ((end (save-excursion (pascal-declaration-end)
+                            (point)))
+       match)
+    ;; Traverse lines
+    (while (< (point) end)
+      (if (re-search-forward "[:=]" (pascal-get-end-of-line) t)
+         ;; Traverse current line
+         (while (and (re-search-backward 
+                      (concat "\\((\\|\\<\\(var\\|type\\|const\\)\\>\\)\\|" 
+                              pascal-symbol-re)
+                      (pascal-get-beg-of-line) t)
+                     (not (match-end 1)))
+           (setq match (buffer-substring (match-beginning 0) (match-end 0)))
+           (if (string-match (concat "\\<" str) match)
+               (if (or (null predicate)
+                       (funcall predicate match))
+                   (setq all (cons match all))))))
+      (if (re-search-forward "\\<record\\>" (pascal-get-end-of-line) t)
+         (pascal-declaration-end)
+       (forward-line 1)))))
+
+(defun pascal-type-completion ()
+  "Calculate all possible completions for types."
+  (let ((start (point))
+       goon)
+    ;; Search for all reachable type declarations
+    (while (or (pascal-beg-of-defun)
+              (setq goon (not goon)))
+      (save-excursion
+       (if (and (< start (prog1 (save-excursion (pascal-end-of-defun)
+                                                (point))
+                           (forward-char 1)))
+                (re-search-forward
+                 "\\<type\\>\\|\\<\\(begin\\|function\\|proceudre\\)\\>"
+                 start t)
+                (not (match-end 1)))
+           ;; Check current type declaration
+           (pascal-get-completion-decl))))))
+
+(defun pascal-var-completion ()
+  "Calculate all possible completions for variables (or constants)."
+  (let ((start (point))
+       goon twice)
+    ;; Search for all reachable var declarations
+    (while (or (pascal-beg-of-defun)
+              (setq goon (not goon)))
+      (save-excursion
+       (if (> start (prog1 (save-excursion (pascal-end-of-defun)
+                                           (point))))
+           () ; Declarations not reacable
+         (if (search-forward "(" (pascal-get-end-of-line) t)
+             ;; Check parameterlist
+               (pascal-get-completion-decl))
+         (setq twice 2)
+         (while (>= (setq twice (1- twice)) 0)
+           (cond ((and (re-search-forward
+                        (concat "\\<\\(var\\|const\\)\\>\\|"
+                                "\\<\\(begin\\|function\\|procedure\\)\\>")
+                        start t)
+                       (not (match-end 2)))
+                  ;; Check var/const declarations
+                  (pascal-get-completion-decl))
+                 ((match-end 2)
+                  (setq twice 0)))))))))
+
+
+(defun pascal-keyword-completion (keyword-list)
+  "Give list of all possible completions of keywords in KEYWORD-LIST."
+  (mapcar '(lambda (s) 
+            (if (string-match (concat "\\<" str) s)
+                (if (or (null predicate)
+                        (funcall predicate s))
+                    (setq all (cons s all)))))
+         keyword-list))
+
+;; Function passed to completing-read, try-completion or
+;; all-completions to get completion on STR. If predicate is non-nil,
+;; it must be a function to be called for every match to check if this
+;; should really be a match. If flag is t, the function returns a list
+;; of all possible completions. If it is nil it returns a string, the
+;; longest possible completion, or t if STR is an exact match. If flag
+;; is 'lambda, the function returns t if STR is an exact match, nil
+;; otherwise.
+
+(defun pascal-completion (str predicate flag)
+  (save-excursion
+    (let ((all nil))
+      ;; Set buffer to use for searching labels. This should be set
+      ;; within functins which use pascal-completions
+      (set-buffer buffer-to-use)
+
+      ;; Determine what should be completed
+      (let ((state (car (pascal-calculate-indent))))
+       (cond (;--Within a declaration or parameterlist
+              (or (eq state 'declaration) (eq state 'paramlist)
+                  (and (eq state 'defun)
+                       (save-excursion
+                         (re-search-backward ")[ \t]*:" (pascal-get-beg-of-line) t))))
+              (if (or (eq state 'paramlist) (eq state 'defun))
+                  (pascal-beg-of-defun))
+              (pascal-type-completion)
+              (pascal-keyword-completion pascal-type-keywords))
+             (;--Starting a new statement
+                           (and (not (eq state 'contexp))
+                                (save-excursion
+                                  (skip-chars-backward "a-zA-Z0-9_.")
+                                  (backward-sexp 1)
+                                  (or (looking-at pascal-nosemi-re)
+                                      (progn
+                                        (forward-sexp 1)
+                                        (looking-at "\\s *\\(;\\|:[^=]\\)")))))
+                           (save-excursion (pascal-var-completion))
+                           (pascal-func-completion 'procedure)
+                           (pascal-keyword-completion pascal-start-keywords))
+             (t;--Anywhere else
+              (save-excursion (pascal-var-completion))
+              (pascal-func-completion 'function)
+              (pascal-keyword-completion pascal-seperator-keywords))))
+
+      ;; Now we have built a list of all matches. Give response to caller
+      (pascal-completion-response))))
+
+(defun pascal-completion-response ()
+  (cond ((or (equal flag 'lambda) (null flag))
+        ;; This was not called by all-completions
+        (if (null all)
+            ;; Return nil if there was no matching label
+            nil
+          ;; Get longest string common in the labels
+          (let* ((elm (cdr all))
+                 (match (car all))
+                 (min (length match))
+                 exact tmp)
+            (if (string= match str)
+                ;; Return t if first match was an exact match
+                (setq match t)
+              (while (not (null elm))
+                ;; Find longest common string
+                (if (< (setq tmp (pascal-string-diff match (car elm))) min)
+                    (progn
+                      (setq min tmp)
+                      (setq match (substring match 0 min))))
+                ;; Terminate with match=t if this is an exact match
+                (if (string= (car elm) str)
+                    (progn
+                      (setq match t)
+                      (setq elm nil))
+                  (setq elm (cdr elm)))))
+            ;; If this is a test just for exact match, return nil ot t
+            (if (and (equal flag 'lambda) (not (equal match 't)))
+                nil
+              match))))
+       ;; If flag is t, this was called by all-completions. Return
+       ;; list of all possible completions
+       (flag
+        all)))
+
+(defvar pascal-last-word-numb 0)
+(defvar pascal-last-word-shown nil)
+(defvar pascal-last-completions nil)
+
+(defun pascal-complete-word ()
+  "Complete word at current point.
+\(See also `pascal-toggle-completions', `pascal-type-keywords',
+`pascal-start-keywords' and `pascal-seperator-keywords'.)"
+  (interactive)
+  (let* ((b (save-excursion (skip-chars-backward "a-zA-Z0-9_") (point)))
+        (e (save-excursion (skip-chars-forward "a-zA-Z0-9_") (point)))
+        (str (buffer-substring b e))
+        ;; The following variable is used in pascal-completion
+        (buffer-to-use (current-buffer))
+        (allcomp (if (and pascal-toggle-completions
+                          (string= pascal-last-word-shown str))
+                     pascal-last-completions
+                   (all-completions str 'pascal-completion)))
+        (match (if pascal-toggle-completions
+                   "" (try-completion
+                       str (mapcar '(lambda (elm) (cons elm 0)) allcomp)))))
+    ;; Delete old string
+    (delete-region b e)
+
+    ;; Toggle-completions inserts whole labels
+    (if pascal-toggle-completions
        (progn
-         (beginning-of-line)
-         (pascal-delete-whitespaces)
-         (indent-to indent))
-      ;; Do nothing if we're not in a star comment.
-      (if (save-excursion
-           (beginning-of-line)
-           (skip-chars-forward " \t")
-           (looking-at "\\*\\|(\\*"))
-         (save-excursion
-           (beginning-of-line)
-           (search-forward "*")
-           (pascal-delete-whitespaces)
-           (indent-to (+ (current-column) 2)))))))
-
-(defun pascal-find-leading-case-colon ()
-  "Return hpos of first colon after the case-of or record line.
-If there's no such line, use the place where it ought to be."
-  (let ((pos (save-excursion
-              (beginning-of-line)
-              (skip-chars-forward " \t")
-              (point))))
-    (save-excursion
-      (re-search-backward "\\<\\(case\\|record\\)\\>")
-      (forward-line 1)
-      (skip-chars-forward " \t")
-      (if (not (eq pos (point)))
+         ;; Update entry number in list
+         (setq pascal-last-completions allcomp
+               pascal-last-word-numb 
+               (if (>= pascal-last-word-numb (1- (length allcomp)))
+                   0
+                 (1+ pascal-last-word-numb)))
+         (setq pascal-last-word-shown (elt allcomp pascal-last-word-numb))
+         ;; Display next match or same string if no match was found
+         (if (not (null allcomp))
+             (insert "" pascal-last-word-shown)
+           (insert "" str)
+           (message "(No match)")))
+      ;; The other form of completion does not necessarly do that.
+
+      ;; Insert match if found, or the original string if no match
+      (if (or (null match) (equal match 't))
+         (progn (insert "" str)
+                (message "(No match)"))
+       (insert "" match))
+      ;; Give message about current status of completion
+      (cond ((equal match 't)
+            (if (not (null (cdr allcomp)))
+                (message "(Complete but not unique)")
+              (message "(Sole completion)")))
+           ;; Display buffer if the current completion didn't help 
+           ;; on completing the label.
+           ((and (not (null (cdr allcomp))) (= (length str) (length match)))
+            (with-output-to-temp-buffer "*Completions*"
+              (display-completion-list allcomp))
+            ;; Wait for a keypress. Then delete *Completion*  window
+            (momentary-string-display "" (point))
+            (delete-window (get-buffer-window (get-buffer "*Completions*")))
+            )))))
+
+(defun pascal-show-completions ()
+  "Show all possible completions at current point."
+  (interactive)
+  (let* ((b (save-excursion (skip-chars-backward "a-zA-Z0-9_") (point)))
+        (e (save-excursion (skip-chars-forward "a-zA-Z0-9_") (point)))
+        (str (buffer-substring b e))
+        ;; The following variable is used in pascal-completion
+        (buffer-to-use (current-buffer))
+        (allcomp (if (and pascal-toggle-completions
+                          (string= pascal-last-word-shown str))
+                     pascal-last-completions
+                   (all-completions str 'pascal-completion))))
+    ;; Show possible completions in a temporary buffer.
+    (with-output-to-temp-buffer "*Completions*"
+      (display-completion-list allcomp))
+    ;; Wait for a keypress. Then delete *Completion*  window
+    (momentary-string-display "" (point))
+    (delete-window (get-buffer-window (get-buffer "*Completions*")))))
+
+
+(defun pascal-get-default-symbol ()
+  "Return symbol around current point as a string."
+  (save-excursion
+    (buffer-substring (progn
+                       (skip-chars-backward " \t")
+                       (skip-chars-backward "a-zA-Z0-9_")
+                       (point))
+                     (progn
+                       (skip-chars-forward "a-zA-Z0-9_")
+                       (point)))))
+
+(defun pascal-build-defun-re (str &optional arg)
+  "Return function/procedure starting with STR as regular expression.
+With optional second arg non-nil, STR is the complete name of the instruction."
+  (if arg
+      (concat "^\\(function\\|procedure\\)[ \t]+\\(" str "\\)\\>")
+    (concat "^\\(function\\|procedure\\)[ \t]+\\(" str "[a-zA-Z0-9_]*\\)\\>")))
+
+;; Function passed to completing-read, try-completion or
+;; all-completions to get completion on any function name. If
+;; predicate is non-nil, it must be a function to be called for every
+;; match to check if this should really be a match. If flag is t, the
+;; function returns a list of all possible completions. If it is nil
+;; it returns a string, the longest possible completion, or t if STR
+;; is an exact match. If flag is 'lambda, the function returns t if
+;; STR is an exact match, nil otherwise.
+
+(defun pascal-comp-defun (str predicate flag)
+  (save-excursion
+    (let ((all nil)
+         match)
+
+      ;; Set buffer to use for searching labels. This should be set
+      ;; within functins which use pascal-completions
+      (set-buffer buffer-to-use)
+
+      (let ((str str))
+       ;; Build regular expression for functions
+       (if (string= str "")
+           (setq str (pascal-build-defun-re "[a-zA-Z_]"))
+         (setq str (pascal-build-defun-re str)))
+       (goto-char (point-min))
+      
+       ;; Build a list of all possible completions
+       (while (re-search-forward str nil t)
+         (setq match (buffer-substring (match-beginning 2) (match-end 2)))
+         (if (or (null predicate)
+                 (funcall predicate match))
+             (setq all (cons match all)))))
+
+      ;; Now we have built a list of all matches. Give response to caller
+      (pascal-completion-response))))
+
+(defun pascal-goto-defun ()
+  "Move to specified Pascal function/procedure.
+The default is a name found in the buffer around point."
+  (interactive)
+  (let* ((default (pascal-get-default-symbol))
+        ;; The following variable is used in pascal-comp-function
+        (buffer-to-use (current-buffer))
+        (default (if (pascal-comp-defun default nil 'lambda)
+                     default ""))
+        (label (if (not (string= default ""))
+                   ;; Do completion with default
+                   (completing-read (concat "Label: (default " default ") ")
+                                    'pascal-comp-defun nil t "")
+                 ;; There is no default value. Complete without it
+                 (completing-read "Label: "
+                                  'pascal-comp-defun nil t ""))))
+    ;; If there was no response on prompt, use default value
+    (if (string= label "")
+       (setq label default))
+    ;; Goto right place in buffer if label is not an empty string
+    (or (string= label "")
+       (progn
+         (goto-char (point-min))
+         (re-search-forward (pascal-build-defun-re label t))
+         (beginning-of-line)))))
+
+\f
+
+;;;
+;;; Pascal-outline-mode
+;;;
+(defvar pascal-outline-map nil "Keymap used in Pascal Outline mode.")
+
+(if pascal-outline-map
+    nil
+  (if (boundp 'set-keymap-name)
+      (set-keymap-name pascal-outline-map 'pascal-outline-map))
+  (if (not (boundp 'set-keymap-parent))
+      (setq pascal-outline-map (copy-keymap pascal-mode-map))
+    (setq pascal-outline-map (make-sparse-keymap))
+    (set-keymap-parent pascal-outline-map pascal-mode-map))
+  (define-key pascal-outline-map "\e\C-a"   'pascal-outline-prev-defun)
+  (define-key pascal-outline-map "\e\C-e"   'pascal-outline-next-defun)
+  (define-key pascal-outline-map "\C-cg"    'pascal-outline-goto-defun)
+  (define-key pascal-outline-map "\C-c\C-s" 'pascal-show-all)
+  (define-key pascal-outline-map "\C-c\C-h" 'pascal-hide-other-defuns))
+
+(defvar pascal-outline-mode nil "Non-nil while using Pascal Outline mode.")
+(make-variable-buffer-local 'pascal-outline-mode)
+(set-default 'pascal-outline-mode nil)
+(if (not (assoc 'pascal-outline-mode minor-mode-alist))
+    (setq minor-mode-alist (append minor-mode-alist
+                                  (list '(pascal-outline-mode " Outl")))))
+
+(defun pascal-outline (&optional arg)
+  "Outline-line minor mode for Pascal mode.
+When in Pascal Outline mode, portions
+of the text being edited may be made invisible. \\<pascal-outline-map>
+
+Pascal Outline mode provides some additional commands.
+
+\\[pascal-outline-prev-defun]\
+\t- Move to previous function/procedure, hiding everything else.
+\\[pascal-outline-next-defun]\
+\t- Move to next function/procedure, hiding everything else.
+\\[pascal-outline-goto-defun]\
+\t- Goto function/procedure prompted for in minibuffer,
+\t  hide all other functions.
+\\[pascal-show-all]\t- Show the whole buffer.
+\\[pascal-hide-other-defuns]\
+\t- Hide everything but the current function (function under the cursor).
+\\[pascal-outline]\t- Leave pascal-outline-mode."
+  (interactive "P")
+  (setq pascal-outline-mode
+       (if (null arg) (not pascal-outline-mode) t))
+  (if (boundp 'redraw-mode-line)
+      (redraw-mode-line))
+  (if pascal-outline-mode
+      (progn
+       (setq selective-display t)
+       (use-local-map pascal-outline-map))
+    (progn
+      (setq selective-display nil)
+      (pascal-show-all)
+      (use-local-map pascal-mode-map))))
+
+(defun pascal-outline-change (b e flag)
+  (let ((modp (buffer-modified-p)))
+    (unwind-protect
+       (subst-char-in-region b e (if (= flag ?\n) ?\^M ?\n) flag)
+      (set-buffer-modified-p modp))))
+
+(defun pascal-show-all ()
+  "Show all of the text in the buffer."
+  (interactive)
+  (pascal-outline-change (point-min) (point-max) ?\n))
+
+(defun pascal-hide-other-defuns ()
+  "Show only the current defun."
+  (interactive)
+  (save-excursion
+    (let ((beg (progn (if (not (looking-at "\\(function\\|procedure\\)\\>"))
+                         (pascal-beg-of-defun))
+                     (point)))
+         (end (progn (pascal-end-of-defun)
+                     (backward-sexp 1)
+                     (search-forward "\n\\|\^M" nil t)
+                     (point)))
+         (opoint (point-min)))
+      (goto-char (point-min))
+
+      ;; Hide all functions before current function
+      (while (re-search-forward "^\\(function\\|procedure\\)\\>" beg 'move)
+       (pascal-outline-change opoint (1- (match-beginning 0)) ?\^M)
+       (setq opoint (point))
+       ;; Functions may be nested
+       (if (> (progn (pascal-end-of-defun) (point)) beg)
+           (goto-char opoint)))
+      (if (> beg opoint)
+         (pascal-outline-change opoint (1- beg) ?\^M))
+
+      ;; Show current function
+      (pascal-outline-change beg end ?\n)
+      ;; Hide nested functions
+      (forward-char 1)
+      (while (re-search-forward "^\\(function\\|procedure\\)\\>" end 'move)
+       (setq opoint (point))
+       (pascal-end-of-defun)
+       (pascal-outline-change opoint (point) ?\^M))
+
+      (goto-char end)
+      (setq opoint end)
+
+      ;; Hide all function after current function
+      (while (re-search-forward "^\\(function\\|procedure\\)\\>" nil 'move)
+       (pascal-outline-change opoint (1- (match-beginning 0)) ?\^M)
+       (setq opoint (point))
+       (pascal-end-of-defun))
+      (pascal-outline-change opoint (point-max) ?\^M)
+
+      ;; Hide main program
+      (if (< (progn (forward-line -1) (point)) end)
          (progn
-           (search-forward ":" (pascal-get-end-of-line) t)
-           (1- (current-column)))
-       (+ (current-column) pascal-case-offset)))))
+           (goto-char beg)
+           (pascal-end-of-defun)
+           (backward-sexp 1)
+           (pascal-outline-change (point) (point-max) ?\^M))))))
 
-(provide 'pascal)
+(defun pascal-outline-next-defun ()
+  "Move to next function/procedure, hiding all others."
+  (interactive)
+  (pascal-end-of-defun)
+  (pascal-hide-other-defuns))
+
+(defun pascal-outline-prev-defun ()
+  "Move to previous function/procedure, hiding all others."
+  (interactive)
+  (pascal-beg-of-defun)
+  (pascal-hide-other-defuns))
+
+(defun pascal-outline-goto-defun ()
+  "Move to specified function/procedure, hiding all others."
+  (interactive)
+  (pascal-goto-defun)
+  (pascal-hide-other-defuns))
 
-;; pascal.el ends here.
+;;; pascal.el ends here