changeset 5723:f5d12c7f056e

Many doc fixes. (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.
author Richard M. Stallman <rms@gnu.org>
date Tue, 01 Feb 1994 18:14:56 +0000
parents b087b24b26ea
children 02a4aeb69cae
files lisp/progmodes/pascal.el
diffstat 1 files changed, 1135 insertions(+), 718 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/progmodes/pascal.el	Tue Feb 01 17:46:53 1994 +0000
+++ b/lisp/progmodes/pascal.el	Tue Feb 01 18:14:56 1994 +0000
@@ -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
+;;; 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.
+
+;;; Code:
 
-;;; 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|
-
-(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.")
@@ -76,37 +67,60 @@
 
 (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)
+;  (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"))
 
-(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.")
@@ -114,82 +128,137 @@
 (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))
+  (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
+(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.
+ 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.
 
-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.
+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 @@
   (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))
 
+
+
 ;;;
 ;;;  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 @@
     (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 @@
       (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)))
+
+
 
 ;;;
 ;;; 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 @@
     (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 @@
 	     (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 @@
 	(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 @@
 	  (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 @@
 	    (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))))))))
+  (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-forward-to-end-of-function ()
-  "Moves the point to the end of the function."
+(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)))))
+
+
 
 ;;;
 ;;; 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 " }")))))))))
 
+
+
 ;;;
-;;; 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))
+  "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))))
+	))))
 
-	  (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-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-lstart-col ()
-  "Return the column of the beginning of the first command on the line."
+(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)))))))))
+(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* ((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))))))
+    
+
 
-;; 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 ()
+;;;
+;;; 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)
+  
+    (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 ((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))))))
+    (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-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)))))))
-  
-(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))
+(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)))))))
+	  ;; 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)))))
+
+
 
-(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)))
+;;;
+;;; 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))))))
+
+(defun pascal-outline-next-defun ()
+  "Move to next function/procedure, hiding all others."
+  (interactive)
+  (pascal-end-of-defun)
+  (pascal-hide-other-defuns))
 
-(provide 'pascal)
+(defun pascal-outline-prev-defun ()
+  "Move to previous function/procedure, hiding all others."
+  (interactive)
+  (pascal-beg-of-defun)
+  (pascal-hide-other-defuns))
 
-;; pascal.el ends here.
+(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