;;; pascal.el --- major mode for editing pascal source in Emacs;; Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.;; Author: Espen Skoglund (espensk@stud.cs.uit.no);; Keywords: languages;; This file is part of XEmacs.;; XEmacs 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.;; XEmacs 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 XEmacs; see the file COPYING. If not, write to;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,;; Boston, MA 02111-1307, USA.;;; Synched up with: FSF 19.34;;; Commentary:;; USAGE;; =====;; Emacs should enter Pascal mode when you find a Pascal source file.;; When you have entered Pascal mode, you may get more info by pressing;; C-h m. You may also get online help describing various functions by:;; C-h f <Name of function you want described>;; If you want to customize Pascal mode to fit you better, you may add;; these lines (the values of the variables presented here are the defaults):;;;; ;; User customization for Pascal mode;; (setq pascal-indent-level 3;; pascal-case-indent 2;; pascal-auto-newline nil;; pascal-tab-always-indent t;; pascal-auto-endcomments t;; pascal-auto-lineup '(all);; pascal-toggle-completions nil;; pascal-type-keywords '("array" "file" "packed" "char" ;; "integer" "real" "string" "record");; pascal-start-keywords '("begin" "end" "function" "procedure";; "repeat" "until" "while" "read" "readln";; "reset" "rewrite" "write" "writeln");; pascal-separator-keywords '("downto" "else" "mod" "div" "then"));; KNOWN BUGS / BUGREPORTS;; =======================;; As far as I know, there are no bugs in the current version of this;; package. This may not be true however, since I never use this mode;; myself and therefore would never notice them anyway. If you do;; find any bugs, you may submit them to: espensk@stud.cs.uit.no;; as well as to bug-gnu-emacs@prep.ai.mit.edu.;;; Code:(defconstpascal-mode-version"2.5""Version of `pascal.el'.")(defgrouppascalnil"Major mode for editing Pascal source in Emacs":group'languages)(defvarpascal-mode-abbrev-tablenil"Abbrev table in use in Pascal-mode buffers.")(define-abbrev-table'pascal-mode-abbrev-table())(defvarpascal-mode-map()"Keymap used in Pascal mode.")(ifpascal-mode-map()(setqpascal-mode-map(make-sparse-keymap))(define-keypascal-mode-map";"'electric-pascal-semi-or-dot)(define-keypascal-mode-map"."'electric-pascal-semi-or-dot)(define-keypascal-mode-map":"'electric-pascal-colon)(define-keypascal-mode-map"="'electric-pascal-equal)(define-keypascal-mode-map"#"'electric-pascal-hash)(define-keypascal-mode-map"\r"'electric-pascal-terminate-line)(define-keypascal-mode-map"\t"'electric-pascal-tab)(define-keypascal-mode-map"\M-\t"'pascal-complete-word)(define-keypascal-mode-map"\M-?"'pascal-show-completions)(define-keypascal-mode-map"\M-\C-h"'pascal-mark-defun)(define-keypascal-mode-map"\C-c\C-b"'pascal-insert-block)(define-keypascal-mode-map"\M-*"'pascal-star-comment)(define-keypascal-mode-map"\C-c\C-c"'pascal-comment-area)(define-keypascal-mode-map"\C-c\C-u"'pascal-uncomment-area)(define-keypascal-mode-map"\M-\C-a"'pascal-beg-of-defun)(define-keypascal-mode-map"\M-\C-e"'pascal-end-of-defun)(define-keypascal-mode-map"\C-c\C-d"'pascal-goto-defun)(define-keypascal-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-cd" 'pascal-downcase-keywords); (define-key pascal-mode-map "\C-cu" 'pascal-upcase-keywords); (define-key pascal-mode-map "\C-cc" 'pascal-capitalize-keywords))(defvarpascal-imenu-generic-expression'("^[ \t]*\\(function\\|procedure\\)[ \t\n]+\\([a-zA-Z0-9_.:]+\\)".(2))"Imenu expression for Pascal-mode. See `imenu-generic-expression'.")(defvarpascal-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.;;;(defconstpascal-symbol-re"\\<[a-zA-Z_][a-zA-Z_0-9.]*\\>")(defconstpascal-beg-block-re"\\<\\(begin\\|case\\|record\\|repeat\\)\\>")(defconstpascal-end-block-re"\\<\\(end\\|until\\)\\>")(defconstpascal-declaration-re"\\<\\(const\\|label\\|type\\|var\\)\\>")(defconstpascal-defun-re"\\<\\(function\\|procedure\\|program\\)\\>")(defconstpascal-sub-block-re"\\<\\(if\\|else\\|for\\|while\\|with\\)\\>")(defconstpascal-noindent-re"\\<\\(begin\\|end\\|until\\|else\\)\\>")(defconstpascal-nosemi-re"\\<\\(begin\\|repeat\\|then\\|do\\|else\\)\\>")(defconstpascal-autoindent-lines-re"\\<\\(label\\|var\\|type\\|const\\|until\\|end\\|begin\\|repeat\\|else\\)\\>");;; Strings used to mark beginning and end of excluded text(defconstpascal-exclude-str-start"{-----\\/----- EXCLUDED -----\\/-----")(defconstpascal-exclude-str-end" -----/\\----- EXCLUDED -----/\\-----}")(defvarpascal-mode-syntax-tablenil"Syntax table in use in Pascal-mode buffers.")(ifpascal-mode-syntax-table()(setqpascal-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?*". 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 ?_ "_" pascal-mode-syntax-table) (modify-syntax-entry ?\' "\"" pascal-mode-syntax-table))(defvar pascal-font-lock-keywords (purecopy (list '("^[ \t]*\\(function\\|pro\\(cedure\\|gram\\)\\)\\>[ \t]*\\(\\[a-z]\\)?" 1 font-lock-keyword-face) '("^[ \t]*\\(function\\|pro\\(cedure\\|gram\\)\\)\\>[ \t]*\\([a-z][a-z0-9_]*\\)" 3 font-lock-function-name-face t); ("type" "const" "real" "integer" "char" "boolean" "var"; "record" "array" "file") (cons (concat "\\<\\(array\\|boolean\\|c\\(har\\|onst\\)\\|file\\|" "integer\\|re\\(al\\|cord\\)\\|type\\|var\\)\\>") 'font-lock-type-face) '("\\<\\(label\\|external\\|forward\\)\\>" . font-lock-reference-face) '("\\<\\([0-9]+\\)[\t]*:" 1 font-lock-function-name-face); ("of" "to" "for" "if" "then" "else" "case" "while"; "do" "until" "and" "or" "not" "in" "with" "repeat" "begin" "end") (concat "\\<\\(" "and\\|begin\\|case\\|do\\|e\\(lse\\|nd\\)\\|for\\|i[fn]\\|" "not\\|o[fr]\\|repeat\\|t\\(hen\\|o\\)\\|until\\|w\\(hile\\|ith\\)" "\\)\\>") '("\\<\\(goto\\)\\>[ \t]*\\([0-9]+\\)?" 1 font-lock-keyword-face) '("\\<\\(goto\\)\\>[ \t]*\\([0-9]+\\)?" 2 font-lock-keyword-face nil t))) "Additional expressions to highlight in Pascal mode.")(put 'pascal-mode 'font-lock-defaults '(pascal-font-lock-keywords nil t))(defcustom pascal-indent-level 3 "*Indentation of Pascal statements with respect to containing block." :type 'integer :group 'pascal)(defcustom pascal-case-indent 2 "*Indentation for case statements." :type 'integer :group 'pascal)(defcustom pascal-auto-newline nil "*Non-nil means automatically newline after semicolons and the punctuationmark after an end." :type 'boolean :group 'pascal)(defcustom pascal-tab-always-indent t "*Non-nil means TAB in Pascal mode should always reindent the current line,regardless of where in the line point is when the TAB command is used." :type 'boolean :group 'pascal)(defcustom pascal-auto-endcomments t "*Non-nil means a comment { ... } is set after the ends which ends cases andfunctions. The name of the function or case will be set between the braces." :type 'boolean :group 'pascal)(defcustom pascal-auto-lineup '(all) "*List of contexts where auto lineup of :'s or ='s should be done.Elements can be of type: 'paramlist', 'declaration' or 'case', which willdo auto lineup in parameterlist, declarations or case-statementsrespectively. The word 'all' will do all lineups. '(case paramlist) forinstance will do lineup in case-statements and parameterlist, while '(all)will do all lineups." :type '(repeat (choice (const all) (const paramlist) (const declaration) (const case))) :group 'pascal)(defcustom pascal-toggle-completions nil "*Non-nil means that repeated use of \\\<pascal-mode-map>\\[pascal-complete-word] will toggle the possiblecompletions in the minibuffer. Normally, when there is more than one possiblecompletion, a buffer will display all completions." :type 'boolean :group 'pascal)(defcustom pascal-type-keywords '("array" "file" "packed" "char" "integer" "real" "string" "record") "*Keywords for types used when completing a word in a declaration or parmlist.\(eg. integer, real, char.) The types defined within the Pascal programwill be completed runtime, and should not be added to this list." :type '(repeat (string :tag "Keyword")) :group 'pascal)(defcustom pascal-start-keywords '("begin" "end" "function" "procedure" "repeat" "until" "while" "read" "readln" "reset" "rewrite" "write" "writeln") "*Keywords to complete when standing at the first word of a statement.\(eg. begin, repeat, until, readln.)The procedures and variables defined within the Pascal programwill be completed runtime and should not be added to this list." :type '(repeat (string :tag "Keyword")) :group 'pascal)(defcustom pascal-separator-keywords '("downto" "else" "mod" "div" "then") "*Keywords to complete when NOT standing at the first word of a statement.\(eg. downto, else, mod, then.) Variables and function names defined within thePascal program are completed runtime and should not be added to this list." :type '(repeat (string :tag "Keyword")) :group 'pascal);;;;;; 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))) ((looking-at "[^(\n]+)") (setq nest 0))))))(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. \\<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 semicolons and the punctuation mark after an end. pascal-tab-always-indent (default t) Non-nil means TAB in Pascal mode should always reindent the current line, regardless of where in the line point is when the TAB command is used. 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. pascal-auto-lineup (default t) List of contexts where auto lineup of :'s or ='s should be done.See also the user variables pascal-type-keywords, pascal-start-keywords andpascal-separator-keywords.Turning on Pascal mode calls the value of the variable pascal-mode-hook withno args, if that value is non-nil." (interactive) (kill-all-local-variables) (use-local-map pascal-mode-map) (setq major-mode 'pascal-mode) (setq mode-name "Pascal") (setq local-abbrev-table pascal-mode-abbrev-table) (set-syntax-table pascal-mode-syntax-table) (make-local-variable 'indent-line-function) (setq indent-line-function 'pascal-indent-line) (setq comment-indent-function 'pascal-indent-comment) (make-local-variable 'parse-sexp-ignore-comments) (setq parse-sexp-ignore-comments nil) (make-local-variable 'case-fold-search) (setq case-fold-search t) (make-local-variable 'comment-start) (setq comment-start "{") (make-local-variable 'comment-start-skip) (setq comment-start-skip "(\\*+ *\\|{*") (make-local-variable 'comment-end) (setq comment-end "}") ;; Font lock support ;(make-local-variable 'font-lock-defaults) ;(setq font-lock-defaults '(pascal-font-lock-keywords nil t)) ;; Imenu support (make-local-variable 'imenu-generic-expression) (setq imenu-generic-expression pascal-imenu-generic-expression) (run-hooks 'pascal-mode-hook));;;;;; Electric functions;;;(defun electric-pascal-terminate-line () "Terminatelineandindentnextline." (interactive) ;; First, check if current line should be indented (save-excursion (beginning-of-line) (skip-chars-forward "\t") (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 (pascal-set-auto-comments)) ;; Check if we shall indent inside comment (let ((setstar nil)) (save-excursion (forward-line -1) (skip-chars-forward "\t") (cond ((looking-at "\\*[\t]+)") ;; Delete region between `*' and `)' if there is only whitespaces. (forward-char 1) (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 (null setstar) (pascal-indent-line) (insert "* "))))(defun electric-pascal-semi-or-dot () "Insert `;' or `.' character and reindent the line." (interactive) (insert last-command-char) (save-excursion (beginning-of-line) (pascal-indent-line)) (if pascal-auto-newline (electric-pascal-terminate-line)))(defun electric-pascal-colon () "Insert `:' and do all indentions except line indent on this line." (interactive) (insert last-command-char) ;; 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." (interactive) (insert last-command-char) (if (eq (car (pascal-calculate-indent)) 'declaration) (let ((pascal-tab-always-indent nil)) (pascal-indent-command))))(defun electric-pascal-hash () "Insert `#', and indent to column 0 if this is a CPP directive." (interactive) (insert last-command-char) (if (save-excursion (beginning-of-line) (looking-at "^[ \t]*#")) (save-excursion (beginning-of-line) (delete-horizontal-space))))(defun electric-pascal-tab () "Function called when TAB is pressed in Pascal mode." (interactive) ;; Do nothing if within a string or in a CPP directive. (if (or (pascal-within-string) (and (not (bolp)) (save-excursion (beginning-of-line) (eq (following-char) ?#)))) (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)) (if (save-excursion (skip-chars-backward " \t") (bolp)) (pascal-indent-line) (insert "\t"))) (pascal-indent-command)));;;;;; Interactive functions;;;(defun pascal-insert-block () "Insert Pascal begin ... end; block in the code with right indentation." (interactive) (pascal-indent-line) (insert "begin") (electric-pascal-terminate-line) (save-excursion (electric-pascal-terminate-line) (insert "end;") (beginning-of-line) (pascal-indent-line)))(defun pascal-star-comment () "Insert Pascal star comment at point." (interactive) (pascal-indent-line) (insert "(*") (electric-pascal-terminate-line) (save-excursion (electric-pascal-terminate-line) (delete-horizontal-space) (insert ")")) (insert " "))(defun pascal-mark-defun () "Mark the current pascal function (or procedure).This puts the mark at the end, and point at the beginning." (interactive) (push-mark (point)) (pascal-end-of-defun) (push-mark (point)) (pascal-beg-of-defun) (if (fboundp 'zmacs-activate-region) (zmacs-activate-region)))(defun pascal-comment-area (start end) "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 (goto-char end) (if (and (save-excursion (skip-chars-forward " \t") (eolp)) (not (save-excursion (skip-chars-backward " \t") (bolp)))) (forward-line 1) (beginning-of-line)) (insert pascal-exclude-str-end) (setq end (point)) (newline) (goto-char start) (beginning-of-line) (insert pascal-exclude-str-start) (newline) ;; Replace end-comments within commented area (goto-char end) (save-excursion (while (re-search-backward "\\*)" start t) (replace-match "!(*" t t))) (save-excursion (while (re-search-backward "}" start t) (replace-match "!{" t t)))))(defun pascal-uncomment-area () "Uncomment a commented area; change deformed comments back to normal.This command does nothing if the pointer is not in a commentedarea. See also `pascal-comment-area'." (interactive) (save-excursion (let ((start (point)) (end (point))) ;; Find the boundaries of the comment (save-excursion (setq start (progn (search-backward pascal-exclude-str-start nil t) (point))) (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))) (message "Not standing within commented area.") (progn ;; Remove endcomment (goto-char end) (beginning-of-line) (let ((pos (point))) (end-of-line) (delete-region pos (1+ (point)))) ;; Change comments back to normal (save-excursion (while (re-search-backward "!{" start t) (replace-match "}" t t))) (save-excursion (while (re-search-backward "!(\\*" start t) (replace-match "*)" t t))) ;; Remove startcomment (goto-char start) (beginning-of-line) (let ((pos (point))) (end-of-line) (delete-region pos (1+ (point)))))))))(defun pascal-beg-of-defun () "Move backward to the beginning of the current function or procedure." (interactive) (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\\>")(>=max0))(setqfunc(1-func)))(setqnest(1+nest)max(maxnestmax)))((match-end2); end|until(if(and(=nestmax)(>=max0))(setqfunc(1+func)))(setqnest(1-nest)))((match-end3); function|procedure(if(=0func)(throw'foundt)(setqfunc(1-func)))))))nil))(defunpascal-end-of-defun()"Move forward to the end of the current function or procedure."(interactive)(if(looking-at"\\s ")(forward-sexp1))(if(not(looking-atpascal-defun-re))(pascal-beg-of-defun))(forward-char1)(let((nest0)(func1)(reg(concatpascal-beg-block-re"\\|"pascal-end-block-re"\\|"pascal-defun-re)))(while(and(/=func0)(re-search-forwardregnil'move))(cond((let((state(save-excursion(parse-partial-sexp(point-min)(point)))))(or(nth3state)(nth4state))); Inside string or comment())((match-end1)(setqnest(1+nest))(if(save-excursion(goto-char(match-beginning0))(looking-at"\\<record\\>"))(setqfunc(1+func))))((match-end2)(setqnest(1-nest))(if(=nest0)(setqfunc(1-func))))((match-end3)(setqfunc(1+func))))))(forward-line1))(defunpascal-end-of-statement()"Move forward to end of current statement."(interactive)(let((parse-sexp-ignore-commentst)(nest0)pos(regexp(concat"\\("pascal-beg-block-re"\\)\\|\\("pascal-end-block-re"\\)")))(if(not(looking-at"[ \t\n]"))(forward-sexp-1))(or(looking-atpascal-beg-block-re);; Skip to end of statement(setqpos(catch'found(whilet(forward-sexp1)(cond((looking-at"[ \t]*;")(skip-chars-forward"^;")(forward-char1)(throw'found(point)))((save-excursion(forward-sexp-1)(looking-atpascal-beg-block-re))(goto-char(match-beginning0))(throw'foundnil))((eobp)(throw'found(point))))))))(if(notpos);; Skip a whole block(catch'found(whilet(re-search-forwardregexpnil'move)(setqnest(if(match-end1)(1+nest)(1-nest)))(cond((eobp)(throw'found(point)))((=0nest)(throw'found(pascal-end-of-statement))))))pos)))(defunpascal-downcase-keywords()"Downcase all Pascal keywords in the buffer."(interactive)(pascal-change-keywords'downcase-word))(defunpascal-upcase-keywords()"Upcase all Pascal keywords in the buffer."(interactive)(pascal-change-keywords'upcase-word))(defunpascal-capitalize-keywords()"Capitalize all Pascal keywords in the buffer."(interactive)(pascal-change-keywords'capitalize-word));; Change the keywords according to argument.(defunpascal-change-keywords(change-word)(save-excursion(let((keyword-re(concat"\\<\\("(mapconcat'identitypascal-keywords"\\|")"\\)\\>")))(goto-char(point-min))(while(re-search-forwardkeyword-renilt)(funcallchange-word-1)))));;;;;; Other functions;;;(defunpascal-set-auto-comments()"Insert `{ case }' or `{ NAME }' on this line if appropriate.Insert `{ case }' if there is an `end' on the line whichends 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;")(not(save-excursion(end-of-line)(search-backward"{"(pascal-get-beg-of-line)t))))(let((type(car(pascal-calculate-indent))))(if(eqtype'declaration)()(if(eqtype'case);; This is a case block(progn(end-of-line)(delete-horizontal-space)(insert" { case }"))(let((nest1));; Check if this is the end of a function(save-excursion(while(not(or(looking-atpascal-defun-re)(bobp)))(backward-sexp1)(cond((looking-atpascal-beg-block-re)(setqnest(1-nest)))((looking-atpascal-end-block-re)(setqnest(1+nest)))))(if(bobp)(setqnest1)))(if(zeropnest)(progn(end-of-line)(delete-horizontal-space)(insert" { ")(let(be)(save-excursion(setqb(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)be))(insert" }"))))))))));;;;;; Indentation;;;(defconstpascal-indent-alist'((block.(+indpascal-indent-level))(case.(+indpascal-case-indent))(caseblock.ind)(cpp.0)(declaration.(+indpascal-indent-level))(paramlist.(pascal-indent-paramlistt))(comment.(pascal-indent-commentt))(defun.ind)(contexp.ind)(unknown.0)(string.0)))(defunpascal-indent-command()"Indent for special part of code."(let*((indent-str(pascal-calculate-indent))(type(carindent-str))(ind(car(cdrindent-str))))(cond((and(eqtype'paramlist)(or(memq'allpascal-auto-lineup)(memq'paramlistpascal-auto-lineup)))(pascal-indent-paramlist)(pascal-indent-paramlist))((and(eqtype'declaration)(or(memq'allpascal-auto-lineup)(memq'declarationpascal-auto-lineup)))(pascal-indent-declaration))((and(eqtype'case)(not(looking-at"^[ \t]*$"))(or(memq'allpascal-auto-lineup)(memq'casepascal-auto-lineup)))(pascal-indent-case)))(if(looking-at"[ \t]+$")(skip-chars-forward" \t"))))(defunpascal-indent-line()"Indent current line as a Pascal statement."(let*((indent-str(pascal-calculate-indent))(type(carindent-str))(ind(car(cdrindent-str))))(if(looking-at"^[0-9a-zA-Z]+[ \t]*:[^=]")(search-forward":"nilt))(delete-horizontal-space);; Some things should not be indented(if(or(and(eqtype'declaration)(looking-atpascal-declaration-re))(eqtype'cpp)(looking-atpascal-defun-re))();; Other things should have no extra indent(if(looking-atpascal-noindent-re)(indent-toind);; But most lines are treated this way:(indent-to(eval(cdr(assoctypepascal-indent-alist))))))))(defunpascal-calculate-indent()"Calculate the indent of the current Pascal line.Return a list of two elements: (INDENT-TYPE INDENT-LEVEL)."(save-excursion(let*((parse-sexp-ignore-commentst)(oldpos(point))(state(save-excursion(parse-partial-sexp(point-min)(point))))(nest0)(par0)(complete(looking-at"[ \t]*end\\>"))(elsed(looking-at"[ \t]*else\\>"))(type(catch'nesting;; Check if inside a string, comment or parenthesis(cond((nth3state)(throw'nesting'string))((nth4state)(throw'nesting'comment))((>(carstate)0)(goto-char(scan-lists(point)-1(carstate)))(setqpar(1+(current-column))))((save-excursion(beginning-of-line)(eq(following-char)?#))(throw'nesting'cpp)));; Loop until correct indent is found(whilet(backward-sexp1)(cond(;--Escape from case statements(and(looking-at"[A-Za-z0-9]+[ \t]*:[^=]")(notcomplete)(save-excursion(skip-chars-backward" \t")(bolp))(=(save-excursion(end-of-line)(backward-sexp)(point))(point))(>(save-excursion(goto-charoldpos)(beginning-of-line)(point))(point)))(throw'nesting'caseblock))(;--Nest block outwards(looking-atpascal-beg-block-re)(if(=nest0)(cond((looking-at"case\\>")(throw'nesting'case))((looking-at"record\\>")(throw'nesting'declaration))(t(throw'nesting'block)))(setqnest(1-nest))))(;--Nest block inwards(looking-atpascal-end-block-re)(if(and(looking-at"end\\s ")elsed(notcomplete))(throw'nesting'block))(setqcompletetnest(1+nest)))(;--Defun (or parameter list)(looking-atpascal-defun-re)(if(=0par)(throw'nesting'defun)(setqpar0)(let((n0))(while(re-search-forward"\\(\\<record\\>\\)\\|\\<end\\>"oldpost)(if(match-end1)(setqn(1+n))(setqn(1-n))))(if(>n0)(throw'nesting'declaration)(throw'nesting'paramlist)))))(;--Declaration part(looking-atpascal-declaration-re)(if(save-excursion(goto-charoldpos)(forward-line-1)(looking-at"^[ \t]*$"))(throw'nesting'unknown)(throw'nesting'declaration)))(;--If, else or while statement(and(notcomplete)(looking-atpascal-sub-block-re))(throw'nesting'block))(;--Found complete statement(save-excursion(forward-sexp1)(=(following-char)?\;))(setqcompletet))(;--No known statements(bobp)(throw'nesting'unknown)))))));; Return type of block and indent level.(if(>par0); Unclosed Parenthesis (list'contexppar)(listtype(pascal-indent-level))))))(defunpascal-indent-level()"Return the indent-level the current statement has.Do not count labels, case-statements or records."(save-excursion(beginning-of-line)(if(looking-at"[ \t]*[0-9a-zA-Z]+[ \t]*:[^=]")(search-forward":"nilt)(if(looking-at".*=[ \t]*record\\>")(search-forward"="nilt)))(skip-chars-forward" \t")(current-column)))(defunpascal-indent-comment(&optionalarg)"Indent current line as comment.If optional arg is non-nil, just return thecolumn number the line should be indented to."(let*((stcol(save-excursion(re-search-backward"(\\*\\|{"nilt)(1+(current-column)))))(ifargstcol(delete-horizontal-space)(indent-tostcol))))(defunpascal-indent-case()"Indent within case statements."(let((savepos(point-marker))(end(prog2(end-of-line)(point-marker)(re-search-backward"\\<case\\>"nilt)))(beg(point))oldpos(ind0));; Get right indent(while(<(point)end)(if(re-search-forward"^[ \t]*[^ \t,:]+[ \t]*\\(,[ \t]*[^ \t,:]+[ \t]*\\)*:"(marker-positionend)'move)(forward-char-1))(if(<(point)end)(progn(delete-horizontal-space)(if(>(current-column)ind)(setqind(current-column)))(pascal-end-of-statement))))(goto-charbeg)(setqoldpos(marker-positionend));; Indent all case statements(while(<(point)end)(if(re-search-forward"^[ \t]*[^][ \t,\\.:]+[ \t]*\\(,[ \t]*[^ \t,:]+[ \t]*\\)*:"(marker-positionend)'move)(forward-char-1))(indent-to(1+ind))(if(/=(following-char)?:)()(forward-char1)(delete-horizontal-space)(insert" "))(setqoldpos(point))(pascal-end-of-statement))(goto-charsavepos)))(defunpascal-indent-paramlist(&optionalarg)"Indent current line in parameterlist.If optional arg is non-nil, just return theindent of the current line in parameterlist."(save-excursion(let*((oldpos(point))(stpos(progn(goto-char(scan-lists(point)-11))(point)))(stcol(1+(current-column)))(edpos(progn(pascal-declaration-end)(search-backward")"(pascal-get-beg-of-line)t)(point)))(usevar(re-search-backward"\\<var\\>"stpost)))(ifarg(progn;; If arg, just return indent(goto-charoldpos)(beginning-of-line)(if(or(notusevar)(looking-at"[ \t]*var\\>"))stcol(+4stcol)))(goto-charstpos)(forward-char1)(delete-horizontal-space)(if(andusevar(not(looking-at"var\\>")))(indent-to(+4stcol)))(pascal-indent-declarationnilstposedpos)))))(defunpascal-indent-declaration(&optionalargstartend)"Indent current lines as declaration, lining up the `:'s or `='s."(let((pos(point-marker)))(if(and(not(orargstart))(not(pascal-declaration-beg)))()(let((lineup(if(or(looking-at"\\<var\\>\\|\\<record\\>")argstart)":""="))(stpos(ifstartstart(forward-word2)(backward-word1)(point)))(edpos(set-marker(make-marker)(ifendend(max(progn(pascal-declaration-end)(point))pos))))ind)(goto-charstpos);; Indent lines in record block(ifarg(while(<=(point)edpos)(beginning-of-line)(delete-horizontal-space)(if(looking-at"end\\>")(indent-toarg)(indent-to(+argpascal-indent-level)))(forward-line1)));; Do lineup(setqind(pascal-get-lineup-indentstposedposlineup))(goto-charstpos)(while(and(<=(point)edpos)(not(eobp)))(if(search-forwardlineup(pascal-get-end-of-line)'move)(forward-char-1))(delete-horizontal-space)(indent-toind)(if(not(looking-atlineup))(forward-line1); No more indent if there is no : or =(forward-char1)(delete-horizontal-space)(insert" ");; Indent record block(if(looking-at"record\\>")(pascal-indent-declaration(current-column)))(forward-line1)))));; If arg - move point(ifarg(forward-line-1)(goto-charpos)))); "Return the indent level that will line up several lines within the region;from b to e nicely. The lineup string is str."(defunpascal-get-lineup-indent(bestr)(save-excursion(let((ind0)(reg(concatstr"\\|\\(\\<record\\>\\)")))(goto-charb);; Get rightmost position(while(<(point)e)(if(re-search-forwardreg(mine(pascal-get-end-of-line2))'move)(progn;; Skip record blocks(if(match-beginning1)(pascal-declaration-end)(progn(goto-char(match-beginning0))(skip-chars-backward" \t")(if(>(current-column)ind)(setqind(current-column)))(goto-char(match-end0))(end-of-line))))));; In case no lineup was found(if(>ind0)(1+ind);; No lineup-string found(goto-charb)(end-of-line)(skip-chars-backward" \t")(1+(current-column))))));;;;;; Completion;;;(defvarpascal-strnil)(defvarpascal-allnil)(defvarpascal-prednil)(defvarpascal-buffer-to-usenil)(defvarpascal-flagnil)(defunpascal-string-diff(str1str2)"Return index of first letter where STR1 and STR2 differs."(catch'done(let((diff0))(whilet(if(or(>(1+diff)(lengthstr1))(>(1+diff)(lengthstr2)))(throw'donediff))(or(equal(arefstr1diff)(arefstr2diff))(throw'donediff))(setqdiff(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.(defunpascal-func-completion(type);; Build regular expression for function/procedure names(if(string=pascal-str"")(setqpascal-str"[a-zA-Z_]"))(let((pascal-str(concat(cond((eqtype'procedure)"\\<\\(procedure\\)\\s +")((eqtype'function)"\\<\\(function\\)\\s +")(t"\\<\\(function\\|procedure\\)\\s +"))"\\<\\("pascal-str"[a-zA-Z0-9_.]*\\)\\>"))match)(if(not(looking-at"\\<\\(function\\|procedure\\)\\>"))(re-search-backward"\\<\\(function\\|procedure\\)\\>"nilt))(forward-char1);; Search through all reachable functions(while(pascal-beg-of-defun)(if(re-search-forwardpascal-str(pascal-get-end-of-line)t)(progn(setqmatch(buffer-substring(match-beginning2)(match-end2)))(if(or(nullpascal-pred)(funcallpascal-predmatch))(setqpascal-all(consmatchpascal-all)))))(goto-char(match-beginning0)))))(defunpascal-get-completion-decl();; Macro for searching through current declaration (var, type or const);; for matches of `str' and adding the occurrence to `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-end1)))(setqmatch(buffer-substring(match-beginning0)(match-end0)))(if(string-match(concat"\\<"pascal-str)match)(if(or(nullpascal-pred)(funcallpascal-predmatch))(setqpascal-all(consmatchpascal-all))))))(if(re-search-forward"\\<record\\>"(pascal-get-end-of-line)t)(pascal-declaration-end)(forward-line1)))))(defunpascal-type-completion()"Calculate all possible completions for types."(let((start(point))goon);; Search for all reachable type declarations(while(or(pascal-beg-of-defun)(setqgoon(notgoon)))(save-excursion(if(and(<start(prog1(save-excursion(pascal-end-of-defun)(point))(forward-char1)))(re-search-forward"\\<type\\>\\|\\<\\(begin\\|function\\|procedure\\)\\>"startt)(not(match-end1)));; Check current type declaration(pascal-get-completion-decl))))))(defunpascal-var-completion()"Calculate all possible completions for variables (or constants)."(let((start(point))goontwice);; Search for all reachable var declarations(while(or(pascal-beg-of-defun)(setqgoon(notgoon)))(save-excursion(if(>start(prog1(save-excursion(pascal-end-of-defun)(point))))(); Declarations not reachable(if(search-forward"("(pascal-get-end-of-line)t);; Check parameterlist(pascal-get-completion-decl))(setqtwice2)(while(>=(setqtwice(1-twice))0)(cond((and(re-search-forward(concat"\\<\\(var\\|const\\)\\>\\|""\\<\\(begin\\|function\\|procedure\\)\\>")startt)(not(match-end2)));; Check var/const declarations(pascal-get-completion-decl))((match-end2)(setqtwice0)))))))))(defunpascal-keyword-completion(keyword-list)"Give list of all possible completions of keywords in KEYWORD-LIST."(mapcar'(lambda(s)(if(string-match(concat"\\<"pascal-str)s)(if(or(nullpascal-pred)(funcallpascal-preds))(setqpascal-all(consspascal-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.(defunpascal-completion(pascal-strpascal-predpascal-flag)(save-excursion(let((pascal-allnil));; Set buffer to use for searching labels. This should be set;; within functions which use pascal-completions(set-bufferpascal-buffer-to-use);; Determine what should be completed(let((state(car(pascal-calculate-indent))))(cond(;--Within a declaration or parameterlist(or(eqstate'declaration)(eqstate'paramlist)(and(eqstate'defun)(save-excursion(re-search-backward")[ \t]*:"(pascal-get-beg-of-line)t))))(if(or(eqstate'paramlist)(eqstate'defun))(pascal-beg-of-defun))(pascal-type-completion)(pascal-keyword-completionpascal-type-keywords))(;--Starting a new statement(and(not(eqstate'contexp))(save-excursion(skip-chars-backward"a-zA-Z0-9_.")(backward-sexp1)(or(looking-atpascal-nosemi-re)(progn(forward-sexp1)(looking-at"\\s *\\(;\\|:[^=]\\)")))))(save-excursion(pascal-var-completion))(pascal-func-completion'procedure)(pascal-keyword-completionpascal-start-keywords))(t;--Anywhere else(save-excursion(pascal-var-completion))(pascal-func-completion'function)(pascal-keyword-completionpascal-separator-keywords))));; Now we have built a list of all matches. Give response to caller(pascal-completion-response))))(defunpascal-completion-response()(cond((or(equalpascal-flag'lambda)(nullpascal-flag));; This was not called by all-completions(if(nullpascal-all);; Return nil if there was no matching labelnil;; Get longest string common in the labels(let*((elm(cdrpascal-all))(match(carpascal-all))(min(lengthmatch))tmp)(if(string=matchpascal-str);; Return t if first match was an exact match(setqmatcht)(while(not(nullelm));; Find longest common string(if(<(setqtmp(pascal-string-diffmatch(carelm)))min)(progn(setqmintmp)(setqmatch(substringmatch0min))));; Terminate with match=t if this is an exact match(if(string=(carelm)pascal-str)(progn(setqmatcht)(setqelmnil))(setqelm(cdrelm)))));; If this is a test just for exact match, return nil ot t(if(and(equalpascal-flag'lambda)(not(equalmatch't)))nilmatch))));; If flag is t, this was called by all-completions. Return;; list of all possible completions(pascal-flagpascal-all)))(defvarpascal-last-word-numb0)(defvarpascal-last-word-shownnil)(defvarpascal-last-completionsnil)(defunpascal-complete-word()"Complete word at current point.\(See also `pascal-toggle-completions', `pascal-type-keywords',`pascal-start-keywords' and `pascal-separator-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)))(pascal-str(buffer-substringbe));; The following variable is used in pascal-completion(pascal-buffer-to-use(current-buffer))(allcomp(if(andpascal-toggle-completions(string=pascal-last-word-shownpascal-str))pascal-last-completions(all-completionspascal-str'pascal-completion)))(match(ifpascal-toggle-completions""(try-completionpascal-str(mapcar'(lambda(elm)(conselm0))allcomp)))));; Delete old string(delete-regionbe);; Toggle-completions inserts whole labels(ifpascal-toggle-completions(progn;; Update entry number in list(setqpascal-last-completionsallcomppascal-last-word-numb(if(>=pascal-last-word-numb(1-(lengthallcomp)))0(1+pascal-last-word-numb)))(setqpascal-last-word-shown(eltallcomppascal-last-word-numb));; Display next match or same string if no match was found(if(not(nullallcomp))(insert""pascal-last-word-shown)(insert""pascal-str)(message"(No match)")));; The other form of completion does not necessarily do that.;; Insert match if found, or the original string if no match(if(or(nullmatch)(equalmatch't))(progn(insert""pascal-str)(message"(No match)"))(insert""match));; Give message about current status of completion(cond((equalmatch't)(if(not(null(cdrallcomp)))(message"(Complete but not unique)")(message"(Sole completion)")));; Display buffer if the current completion didn't help ;; on completing the label.((and(not(null(cdrallcomp)))(=(lengthpascal-str)(lengthmatch)))(with-output-to-temp-buffer"*Completions*"(display-completion-listallcomp));; Wait for a keypress. Then delete *Completion* window(momentary-string-display""(point))(delete-window(get-buffer-window(get-buffer"*Completions*"))))))))(defunpascal-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)))(pascal-str(buffer-substringbe));; The following variable is used in pascal-completion(pascal-buffer-to-use(current-buffer))(allcomp(if(andpascal-toggle-completions(string=pascal-last-word-shownpascal-str))pascal-last-completions(all-completionspascal-str'pascal-completion))));; Show possible completions in a temporary buffer.(with-output-to-temp-buffer"*Completions*"(display-completion-listallcomp));; Wait for a keypress. Then delete *Completion* window(momentary-string-display""(point))(delete-window(get-buffer-window(get-buffer"*Completions*")))))(defunpascal-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)))))(defunpascal-build-defun-re(str&optionalarg)"Return function/procedure starting with STR as regular expression.With optional second arg non-nil, STR is the complete name of the instruction."(ifarg(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.(defunpascal-comp-defun(pascal-strpascal-predpascal-flag)(save-excursion(let((pascal-allnil)match);; Set buffer to use for searching labels. This should be set;; within functions which use pascal-completions(set-bufferpascal-buffer-to-use)(let((pascal-strpascal-str));; Build regular expression for functions(if(string=pascal-str"")(setqpascal-str(pascal-build-defun-re"[a-zA-Z_]"))(setqpascal-str(pascal-build-defun-repascal-str)))(goto-char(point-min));; Build a list of all possible completions(while(re-search-forwardpascal-strnilt)(setqmatch(buffer-substring(match-beginning2)(match-end2)))(if(or(nullpascal-pred)(funcallpascal-predmatch))(setqpascal-all(consmatchpascal-all)))));; Now we have built a list of all matches. Give response to caller(pascal-completion-response))))(defunpascal-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(pascal-buffer-to-use(current-buffer))(default(if(pascal-comp-defundefaultnil'lambda)default""))(label(if(not(string=default""));; Do completion with default(completing-read(concat"Label: (default "default") ")'pascal-comp-defunnilt"");; There is no default value. Complete without it(completing-read"Label: "'pascal-comp-defunnilt""))));; If there was no response on prompt, use default value(if(string=label"")(setqlabeldefault));; 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-relabelt))(beginning-of-line)))));;;;;; Pascal-outline-mode;;;(defvarpascal-outline-mapnil"Keymap used in Pascal Outline mode.")(ifpascal-outline-mapnil(if(boundp'set-keymap-name)(set-keymap-namepascal-outline-map'pascal-outline-map))(if(not(boundp'set-keymap-parent))(setqpascal-outline-map(copy-keymappascal-mode-map))(setqpascal-outline-map(make-sparse-keymap))(set-keymap-parentpascal-outline-mappascal-mode-map))(define-keypascal-outline-map"\M-\C-a"'pascal-outline-prev-defun)(define-keypascal-outline-map"\M-\C-e"'pascal-outline-next-defun)(define-keypascal-outline-map"\C-c\C-d"'pascal-outline-goto-defun)(define-keypascal-outline-map"\C-c\C-s"'pascal-show-all)(define-keypascal-outline-map"\C-c\C-h"'pascal-hide-other-defuns))(defvarpascal-outline-modenil"Non-nil while using Pascal Outline mode.")(make-variable-buffer-local'pascal-outline-mode)(set-default'pascal-outline-modenil)(if(not(assoc'pascal-outline-modeminor-mode-alist))(setqminor-mode-alist(appendminor-mode-alist(list'(pascal-outline-mode" Outl")))))(defunpascal-outline(&optionalarg)"Outline-line minor mode for Pascal mode.When in Pascal Outline mode, portionsof 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")(setqpascal-outline-mode(if(nullarg)(notpascal-outline-mode)t))(if(boundp'redraw-mode-line)(redraw-mode-line))(ifpascal-outline-mode(progn(setqselective-displayt)(use-local-mappascal-outline-map))(progn(setqselective-displaynil)(pascal-show-all)(use-local-mappascal-mode-map))))(defunpascal-outline-change(bepascal-flag)(let((modp(buffer-modified-p)))(unwind-protect(subst-char-in-regionbe(if(=pascal-flag?\n)?\^M?\n)pascal-flag)(set-buffer-modified-pmodp))))(defunpascal-show-all()"Show all of the text in the buffer."(interactive)(pascal-outline-change(point-min)(point-max)?\n))(defunpascal-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-sexp1)(search-forward"\n\\|\^M"nilt)(point)))(opoint(point-min)))(goto-char(point-min));; Hide all functions before current function(while(re-search-forward"^\\(function\\|procedure\\)\\>"beg'move)(pascal-outline-changeopoint(1-(match-beginning0))?\^M)(setqopoint(point));; Functions may be nested(if(>(progn(pascal-end-of-defun)(point))beg)(goto-charopoint)))(if(>begopoint)(pascal-outline-changeopoint(1-beg)?\^M));; Show current function(pascal-outline-changebegend?\n);; Hide nested functions(forward-char1)(while(re-search-forward"^\\(function\\|procedure\\)\\>"end'move)(setqopoint(point))(pascal-end-of-defun)(pascal-outline-changeopoint(point)?\^M))(goto-charend)(setqopointend);; Hide all function after current function(while(re-search-forward"^\\(function\\|procedure\\)\\>"nil'move)(pascal-outline-changeopoint(1-(match-beginning0))?\^M)(setqopoint(point))(pascal-end-of-defun))(pascal-outline-changeopoint(point-max)?\^M);; Hide main program(if(<(progn(forward-line-1)(point))end)(progn(goto-charbeg)(pascal-end-of-defun)(backward-sexp1)(pascal-outline-change(point)(point-max)?\^M))))))(defunpascal-outline-next-defun()"Move to next function/procedure, hiding all others."(interactive)(pascal-end-of-defun)(pascal-hide-other-defuns))(defunpascal-outline-prev-defun()"Move to previous function/procedure, hiding all others."(interactive)(pascal-beg-of-defun)(pascal-hide-other-defuns))(defunpascal-outline-goto-defun()"Move to specified function/procedure, hiding all others."(interactive)(pascal-goto-defun)(pascal-hide-other-defuns));; XEmacs addition;;;###autoload(add-to-list 'auto-mode-alist '("\\.p\\(?:as\\)?\\'" . pascal-mode));;; pascal.el ends here