;; SPP code editing commands for Emacs ;; Copyright (C) 1992, Space Telescope Science Institute. ;; This file is part of GNU Emacs. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY. No author or distributor ;; accepts responsibility to anyone for the consequences of using it ;; or for whether it serves any particular purpose or works at all, ;; unless he says so in writing. Refer to the GNU Emacs General Public ;; License for full details. ;; Everyone is granted permission to copy, modify and redistribute ;; GNU Emacs, but only under the conditions described in the ;; GNU Emacs General Public License. A copy of this license is ;; supposed to have been given to you along with GNU Emacs so you ;; can know your rights and responsibilities. It should be in a ;; file named COPYING. Among other things, the copyright notice ;; and this notice must be preserved on all copies. (defvar spp-mode-map () "Keymap used in Spp mode.") (if spp-mode-map () (setq spp-mode-map (make-sparse-keymap)) (define-key spp-mode-map "\n" 'electric-spp-newline) (define-key spp-mode-map "\r" 'electric-spp-newline) (define-key spp-mode-map "{" 'electric-spp-brace) (define-key spp-mode-map "}" 'electric-spp-brace) (define-key spp-mode-map "(" 'electric-spp-match) (define-key spp-mode-map "[" 'electric-spp-match) (define-key spp-mode-map "\e\C-a" 'begin-of-spp-defun) (define-key spp-mode-map "\e\C-e" 'end-of-spp-defun) (define-key spp-mode-map "\e\C-h" 'mark-spp-function) (define-key spp-mode-map "\177" 'backward-delete-char-untabify) (define-key spp-mode-map "\t" 'spp-indent-command)) (defvar spp-mode-syntax-table nil "Syntax table in use in Spp-mode buffers.") (if spp-mode-syntax-table () (setq spp-mode-syntax-table (make-syntax-table)) (modify-syntax-entry ?\\ "\\" spp-mode-syntax-table) (modify-syntax-entry ?/ "." spp-mode-syntax-table) (modify-syntax-entry ?* "." spp-mode-syntax-table) (modify-syntax-entry ?+ "." spp-mode-syntax-table) (modify-syntax-entry ?- "." spp-mode-syntax-table) (modify-syntax-entry ?= "." spp-mode-syntax-table) (modify-syntax-entry ?% "." spp-mode-syntax-table) (modify-syntax-entry ?< "." spp-mode-syntax-table) (modify-syntax-entry ?> "." spp-mode-syntax-table) (modify-syntax-entry ?& "." spp-mode-syntax-table) (modify-syntax-entry ?| "." spp-mode-syntax-table) (modify-syntax-entry ?_ "w" spp-mode-syntax-table) (modify-syntax-entry ?; "w" spp-mode-syntax-table) (modify-syntax-entry ?\( "()" spp-mode-syntax-table) (modify-syntax-entry ?\) ")(" spp-mode-syntax-table) (modify-syntax-entry ?\[ "(]" spp-mode-syntax-table) (modify-syntax-entry ?\] ")[" spp-mode-syntax-table) (modify-syntax-entry ?{ "(}" spp-mode-syntax-table) (modify-syntax-entry ?} "){" spp-mode-syntax-table) (modify-syntax-entry ?\" "\"" spp-mode-syntax-table) (modify-syntax-entry ?\' "\"" spp-mode-syntax-table) (modify-syntax-entry ?# "<" spp-mode-syntax-table) (modify-syntax-entry ?\n ">" spp-mode-syntax-table) (modify-syntax-entry ?\f ">" spp-mode-syntax-table)) (defvar spp-mode-abbrev-table nil) (if spp-mode-abbrev-table () (define-abbrev-table 'spp-mode-abbrev-table ()) (let ((abbrevs-changed nil)) (define-abbrev spp-mode-abbrev-table ";b" "begin" 'spp-begin-end) (define-abbrev spp-mode-abbrev-table ";bl" "bool" nil) (define-abbrev spp-mode-abbrev-table ";br" "break" nil) (define-abbrev spp-mode-abbrev-table ";c" "call" nil) (define-abbrev spp-mode-abbrev-table ";ch" "char" nil) (define-abbrev spp-mode-abbrev-table ";cm" "common" nil) (define-abbrev spp-mode-abbrev-table ";cx" "complex" nil) (define-abbrev spp-mode-abbrev-table ";de" "define" nil) (define-abbrev spp-mode-abbrev-table ";di" "dimension" nil) (define-abbrev spp-mode-abbrev-table ";do" "double" nil) (define-abbrev spp-mode-abbrev-table ";e" "else" nil) (define-abbrev spp-mode-abbrev-table ";ep" "call eprintf" nil) (define-abbrev spp-mode-abbrev-table ";eq" "equivalence" nil) (define-abbrev spp-mode-abbrev-table ";er" "errchk" nil) (define-abbrev spp-mode-abbrev-table ";ex" "external" nil) (define-abbrev spp-mode-abbrev-table ";ey" "entry" nil) (define-abbrev spp-mode-abbrev-table ";g" "goto" nil) (define-abbrev spp-mode-abbrev-table ";i" "int" nil) (define-abbrev spp-mode-abbrev-table ";ie" "iferr" nil) (define-abbrev spp-mode-abbrev-table ";ine" "ifnoerr" nil) (define-abbrev spp-mode-abbrev-table ";inc" "include" nil) (define-abbrev spp-mode-abbrev-table ";ln" "long" nil) (define-abbrev spp-mode-abbrev-table ";n" "next" nil) (define-abbrev spp-mode-abbrev-table ";p" "pointer" nil) (define-abbrev spp-mode-abbrev-table ";pa" "call parg" nil) (define-abbrev spp-mode-abbrev-table ";pf" "call printf" nil) (define-abbrev spp-mode-abbrev-table ";pr" "procedure" 'spp-procedure) (define-abbrev spp-mode-abbrev-table ";r" "real" nil) (define-abbrev spp-mode-abbrev-table ";rp" "repeat" nil) (define-abbrev spp-mode-abbrev-table ";rt" "return" nil) (define-abbrev spp-mode-abbrev-table ";sh" "short" nil) (define-abbrev spp-mode-abbrev-table ";sm" "call smark (sp)" 'spp-sfree) (define-abbrev spp-mode-abbrev-table ";st" "string") (define-abbrev spp-mode-abbrev-table ";sw" "switch" 'spp-switch) (define-abbrev spp-mode-abbrev-table ";u" "until" nil) (define-abbrev spp-mode-abbrev-table ";w" "while" nil) )) (defconst spp-auto-indent t "*Non-nil means that a newline will always set the justification for the current and next line. Nil means that just a newline is inserted") (defconst spp-auto-newline nil "*Non-nil means automatically newline before and after braces, and after colons and semicolons, inserted in Spp code.") (defconst spp-brace-offset 0 "*Extra indentation for braces, compared with other text in same context.") (defconst spp-continued-statement-offset 0 "*Extra indent for lines not starting new statements.") (defconst spp-indent-case t "*Non-nil means to indent case and default statements spp-indent-level. If nil, then case/default appears at the same level as the enclosing switch.") (defconst spp-indent-level 3 "*Indentation of Spp statements with respect to containing block.") (defconst spp-indent-level-offset 0 "*Extra indentation applied to each line.") (defconst spp-label-offset 0 "*Column that labels should appear in.") (defconst spp-match-brace t "*Non-nil means to automatically insert the matching ], ), or }.") (defconst spp-tab-always-indent t "*Non-nil means TAB in Spp mode should always reindent the current line, regardless of where in the line point is when the TAB command is used.") (defun spp-mode () "Major mode for editing Spp code. Expression and list commands understand all Spp brackets. Tab indents for Spp code. Comments are delimited with #...\\n. Paragraphs are separated by blank lines only. Delete converts tabs to spaces as it moves back. \\{spp-mode-map} Variables controlling indentation style: spp-auto-indent Non-nil means that on every newline, readjust the indentation of current line, and properly indent the next line. If nil, just properly indent the next line. Things will go a bit slower, but the lines will always be correctly adjusted for. spp-auto-newline Non-nil means automatically insert newline before and after braces. spp-brace-offset Extra indentation for line if it starts with an open brace. Used in conjunction with spp-auto-newline. spp-continued-statement-offset Extra indentation given to statements that are continuations of a previous statement. spp-indent-case Non-nil means to indent case and default statements by spp-indent-level amount. If nil, case/defaults will appear at the same indentation level as the enclosing switch statement. spp-indent-level Indentation of Spp statements within surrounding block. Blocks are defined by begin..end pairs, '{' and '}' pairs, and second statements after conditional statements (if's, while's, etc.). spp-indent-level-offset Offset added to each lines indentation. spp-label-offset Extra indentation of labels. spp-match-brace Non-nil means that when one of {, (, or [ is typed, the matching character is inserted. For {, the } is placed on the next line. For the others, the match is placed immediately afterwards. In all cases, point is left between the characters. spp-tab-always-indent Non-nil means TAB in Spp mode should always reindent the current line, regardless of where in the line point is when the TAB command is used. One should also be aware of the variable indent-tabs-mode. If non-nil, tabs are inserted if the tab key is hit (the default). If nil, then spaces are inserted when the tab key is hit. If you want to simulate the IRAF default indentation scheme (or as close as possible), change the following variables to: spp-indent-level 4 spp-indent-level-offset 4 spp-indent-case nil indent-tabs-mode t Using these settings, the only difference between the IRAF convention and spp-mode is the handling of continuations and the indentation of 'call parg*' statements. This mode is slow enough and putting these beasts in would bring the whole system to a halt. Also note that these are NOT the default settings. This is a religious matter and anyone wanting to discuss this should direct their flames to the author who is more than willing to listen. Rest assured, however, that no actions will result. To install SPP mode, add the following lines to your .emacs file and remove the leading '; ;(setq load-path (append '\"(directory where spp-mode.el is\") load-path)) ;(autoload 'spp-mode \"spp-mode\") ;(setq auto-mode-alist ; (append ; '((\"\\.x$\" . spp-mode)) ; auto-mode-alist)) To customize variables and any other aspect of spp-mode, define the following in your .emacs files. The below example will set the defaults for the IRAF way of indenting. Remember, remove the leading ; ;(setq spp-mode-hook ; (function (lambda () ; (setq spp-indent-level 4 ; spp-indent-level-offset 4 ; spp-indent-case nil ; indent-tabs-mode t)))) Turning on Spp mode calls the value of the variable spp-mode-hook with no args, if that value is non-nil." (interactive) (kill-all-local-variables) (use-local-map spp-mode-map) (setq major-mode 'spp-mode) (setq mode-name "SPP") (setq local-abbrev-table spp-mode-abbrev-table) (set-syntax-table spp-mode-syntax-table) (make-local-variable 'paragraph-start) (setq paragraph-start (concat "^$\\|" page-delimiter)) (make-local-variable 'paragraph-separate) (setq paragraph-separate paragraph-start) (make-local-variable 'paragraph-ignore-fill-prefix) (setq paragraph-ignore-fill-prefix t) (make-local-variable 'indent-line-function) (setq indent-line-function 'spp-indent-line) (make-local-variable 'require-final-newline) (setq require-final-newline t) (make-local-variable 'comment-start) (setq comment-start "#") (make-local-variable 'comment-end) (setq comment-end " \r") (make-local-variable 'comment-column) (setq comment-column 32) (make-local-variable 'comment-start-skip) (setq comment-start-skip "/\\*+ *") (make-local-variable 'comment-indent-hook) (setq comment-indent-hook 'spp-comment-indent) (make-local-variable 'parse-sexp-ignore-comments) (setq parse-sexp-ignore-comments t) (make-local-variable 'abbrev-mode) (setq abbrev-mode t) (run-hooks 'spp-mode-hook)) (defun spp-indent-command (&optional whole-exp) (interactive "P") "Indent current line as Spp code, or in some cases insert a tab character. If spp-tab-always-indent is non-nil (the default), always indent current line. Otherwise, indent the current line only if point is at the left margin or in the line's indentation; otherwise insert a tab. A numeric argument, regardless of its value, means indent rigidly all the lines of the expression starting after point so that this line becomes properly indented. The relative indentation among the lines of the expression are preserved." (if whole-exp ;; If arg, always indent this line as C ;; and shift remaining lines of expression the same amount. (let ((shift-amt (spp-indent-line)) beg end) (save-excursion (if spp-tab-always-indent (beginning-of-line)) (setq beg (point)) (forward-sexp 1) (setq end (point)) (goto-char beg) (forward-line 1) (setq beg (point))) (if (> end beg) (indent-code-rigidly beg end shift-amt "#"))) (if (and (not spp-tab-always-indent) (save-excursion (skip-chars-backward " \t") (not (bolp)))) (insert-tab) (spp-indent-line)))) (defun spp-indent-line () "Indent current line as Spp code. Return the amount the indentation changed by." (let ((indent (calculate-spp-indent nil)) beg shift-amt label (case-fold-search nil) (pos (- (point-max) (point)))) (beginning-of-line) (setq beg (point)) (cond ((eq indent nil) (setq indent (current-indentation))) ((eq indent t) (setq indent (if (= ?\t last-command-char) (save-excursion (tab-to-tab-stop) (current-column)) (save-excursion (skip-chars-forward " \t") (current-column))))) (t (setq label (cdr indent)) (setq indent (car indent)) (skip-chars-forward " \t") (cond ((= (following-char) ?}) (setq indent (- indent spp-indent-level))) ((= (following-char) ?{) (setq indent (+ indent spp-brace-offset)))))) (if label (progn (beginning-of-line) (indent-to spp-label-offset) (insert label) (if (save-excursion (skip-chars-forward " \t") (eolp)) (setq indent (current-column)) (if (< indent (current-column)) (newline))) (setq beg (point)))) (skip-chars-forward " \t") (setq shift-amt (- indent (current-column))) (if (zerop shift-amt) (if (> (- (point-max) pos) (point)) (goto-char (- (point-max) pos))) (delete-region beg (point)) (indent-to indent) ;; If initial point was within line's indentation, ;; position after the indentation. Else stay at same point in text. (if (> (- (point-max) pos) (point)) (goto-char (- (point-max) pos)))) shift-amt)) (defun begin-of-spp-defun (&optional arg) "Move backward to next begin-of-spp-defun. A beginning is one of three cases: 1) an SPP BEGIN statement and the point is left at the b of begin, 2) beginning of the buffer, or 3) Point immediately after an SPP END statement. With argument, do this that many times. Returns t if a BEGIN statement is acutally found, nil otherwise" (interactive "p") (or arg (setq arg 1)) (let ((original (point))) (if (not (re-search-backward "^\\s-*begin\\s-*$" nil 'move arg)) nil (let ((begin (point))) (if (and (re-search-forward "^\\s-*end\\s-*$" nil 'move) (> original (point))) (progn (vertical-motion 1) nil) (goto-char begin) t))))) (defun end-of-spp-defun (&optional arg) "Move backward to next begin-of-spp-defun. With argument, do this that many times. Returns t unless search stops due to end of buffer." (interactive "p") (or arg (setq arg 1)) (forward-sexp 1) (let ((result (re-search-forward "^\\s-*end\\s-*$" nil 'move arg))) (beginning-of-line) result)) (defun is-spp-continuation (&optional limit noblock) "Determine whether the current line is a continuation of the previous statement. With LIMIT, limit backwards search to nothing before this point. If NOBLOCK is t, don't include block characters as continuation characters. These are '{' and '('. Returns similar to function memq." (or limit (setq limit (save-excursion (begin-of-spp-defun) (point)))) (save-excursion (let (char) ;; Skip over any comments (spp-backward-to-noncomment limit) ;; Check the last character. If it is one of these then the statement is ;; a continuation. (setq char (if noblock (memq (preceding-char) '(?\, ?\\ ?+ ?- ?* ?/ ?< ?> ?= ?! ?\| ?\&)) (memq (preceding-char) '(?\, ?\\ ?+ ?- ?* ?/ ?< ?> ?= ?! ?\| ?\& ?\()))) (if (not (memq (car char) '(?/ ?>))) char (beginning-of-line) (and (not (looking-at "^\\s-*\\(common\\|data\\|include\\)\\b")) char))))) (defun spp-indent-continuation (&optional limit) "Determine the amount the continuation statement should be indented for top level statements. The possibilities are: If an equation, indent to the first expression after the '='. If nothing on the same line, then indent to just after the '='. If no '=', indent to second sexp on line. If no second sexp, then indent to level of previous line. After all this add spp-continued-statement-offset. With argument, limit backwards searching to point limit" (or limit (save-excursion (begin-of-spp-defun) (point))) ;;Backup to previous statement. (spp-end-last-statement limit) (+ spp-continued-statement-offset (let ((current-point (point)) eol) ;;If this line is a continuation, then just return this indentation. (beginning-of-line) (skip-chars-forward " \t") (if (is-spp-continuation limit) (current-column) (setq eol (save-excursion (end-of-line) (point))) ;;Check for equal sign. (if (and (re-search-forward "=" eol t) (<= (point) current-point)) (if (= (point) current-point) (current-column) (skip-chars-forward " \t") (current-column)) (goto-char current-point) (skip-chars-backward "^ \t") (current-column)))))) (defun spp-backward-to-noncomment (&optional lim) "Skip backwards to the first non-whitespace character. Comment blocks are considered white space. If LIM is specified, point will not move beyond LIM, point can move to the beginning of the buffer." (or lim (save-excursion (begin-of-spp-defun) (point))) (let (eop state (again t)) (skip-chars-backward " \t\n\f" lim) ;; See if in a comment. If so, go to the last complete sexp and search ;; forward for the comment character. Loop to make sure that the ;; comment character is not within the comment itself. (while (and (> (point) lim) again) (setq eop (point)) (beginning-of-line) (if (looking-at "\\s-*\.endhelp") (progn (re-search-backward "^\\s-*\.help" lim 'move) (skip-chars-backward " \t\n\f\r") lim) (setq state (parse-partial-sexp (point) eop)) (if (not (nth 4 state)) (setq again nil) (cond ((nth 2 state) (goto-char (nth 2 state)) (forward-sexp) (setq again nil)) ((nth 1 state) (skip-chars-forward "^ \t") (setq again nil)) (t (beginning-of-line) (skip-chars-backward " \t\n\r\f")))))))) (defun spp-end-last-statement (&optional limit) "Go backwards to end of previous line, skipping comments and labels. With LIMIT, don't go beyond point LIMIT." (or limit (setq limit (save-excursion (begin-of-spp-defun) (point)))) (let ((eoc (progn (spp-backward-to-noncomment limit) (point)))) (beginning-of-line) (if (or (< (point) limit) (not (looking-at "\\s-*\\([0-9]+\\|\\sw+_[ \t\n\r]\\)"))) (goto-char eoc) (skip-chars-forward " \t" eoc) (skip-chars-forward "^ \t" eoc) (if (< (point) eoc) (goto-char eoc) (beginning-of-line) (spp-end-last-statement limit))))) (defun spp-pseudo-continuation (&optional limit) "Determine whether the current statement is the second statement of a multiple statement, i.e. if's etc. Returns a list whose first element is t if this is a second statement, nil otherwise. If the first element is t, the second element is the indentation appropriate for this statement" (save-excursion (or limit (setq limit (save-excursion (begin-of-spp-defun) (point)))) ;; Skip any comments and continuations. (spp-end-last-statement limit) (beginning-of-line) (while (and (> (point) limit) (is-spp-continuation limit)) (progn (spp-end-last-statement limit) (beginning-of-line))) ;;Skip any possible label (if (looking-at "\\([0-9]+\\|\\sw+_\\)\\(\\s-+\\|\n\\)") (skip-chars-forward "^ \t")) (skip-chars-forward " \t") ;; See if we have a double statement. (if (looking-at "\\(\\(if\\(\\(no\\)?err\\)?\\)\\|\ \\(}?\\s-*\\(else\\|then\\)\\)\\|\ while\\|repeat\\|for\\|do\\)\\b") (list t (+ (current-column) spp-indent-level)) '(nil 0)))) (defun calculate-spp-indent (&optional parse-start) "Determine the indentation for the current statement. The containing block is found and the indentation is determine relative to that block. Returned is a cons cell whose car is the indentation amount and whose cdr is the label that appeared on the line. The label is removed during processing. If PARSE-START is specified, the backwards searching will not go beyond it." (save-excursion (beginning-of-line) (let ((indent-point (point)) state bof containing-sexp) (setq bof (cons (begin-of-spp-defun) (point))) (if parse-start (goto-char parse-start)) (setq state (parse-partial-sexp (point) indent-point)) (setq containing-sexp (car (cdr state))) (cond ((or (nth 3 state) (nth 4 state)) ;; return nil or t if should not change this line (nth 4 state)) ((null containing-sexp) ;; Line is at "top level". The only thing to check for now ;; is whether we're in a begin..end. (if (car bof) (spp-indent-statement (cdr bof)) (if (is-in-spp-help (cdr bof)) t (let ((rvalue (spp-indent-statement (cdr bof)))) (cons (+ (car rvalue) (* -1 spp-indent-level)) (cdr rvalue)))))) ((/= (char-after containing-sexp) ?{) ;; line is expression, not statement: ;; indent to just after the surrounding open. (goto-char (1+ containing-sexp)) (skip-chars-forward " \t") (if (or (looking-at "#") (eolp)) (skip-chars-backward " \t")) (cons (current-column) nil)) (t ;; We're in a block. Find the beginning and indent from ;; there. (spp-indent-statement containing-sexp)))))) (defun spp-backward-to-start-of-if (&optional limit) "Move to the start of the last ``unbalanced'' if." (or limit (setq limit (save-excursion (beginning-of-defun) (point)))) (setq parse-sexp-ignore-comments nil) (let ((if-level 1) (case-fold-search nil)) (while (not (zerop if-level)) (backward-sexp 1) (cond ((looking-at "else\\b") (setq if-level (1+ if-level))) ((looking-at "if\\(\\(no\\)?err\\)?\\b") (setq if-level (1- if-level))) ((< (point) limit) (setq if-level 0) (goto-char limit))))) (setq parse-sexp-ignore-comments t) (beginning-of-line) (skip-chars-forward " \t")) (defun is-in-spp-help (&optional limit) "Returns t if in a .help...endhelp block. If LIMIT is specified, search will not proceed beyond limit backwards." (or limit (setq limit (save-excursion (begin-of-spp-defun) (point)))) (let ((current-point (point))) (save-excursion (and (and (re-search-backward "^\\s-*\.help" limit t) (< (point) current-point)) (and (re-search-forward "^\\s-*\.endhelp" nil t) (< current-point (point))))))) (defun spp-indent-statement (containing-sexp) "Return the indentation for a statement. Returns an sexp whose car is the amount of indentation and show cdr is either nil or a string containing the label that was on this line. The label is removed by this routine." ;; Indent continuation lines (if (is-spp-continuation containing-sexp t) (cons (spp-indent-continuation containing-sexp) nil) ;; Else remove any label on this line and determine the indentation. (skip-chars-forward " \t") (if (not (looking-at "\\([0-9]+\\|\\sw+_\\)\\(\\s-\\|\n\\)")) (setq label nil) (let ((beg (point))) (skip-chars-forward "^ \t\n\r") (setq label (buffer-substring beg (point))) (delete-region beg (point)) (skip-chars-forward " \t"))) ;; Now find out how much to indent things. (cons (cond ;; Indent for multiple statement statements (if's, etc.) where ;;there isn't a block indicator {. ((car (setq state (spp-pseudo-continuation containing-sexp))) (car (cdr state))) ;; Check for standalone else/then's. Find the if that they belong ;; to and indent according to the if-statement. ((looking-at "\\s-*\\(else\\|then\\)\\b") (spp-backward-to-start-of-if) (current-column)) ;; If at the end, return 0. ((looking-at "\\s-*end\\b") 0) ;; A standalone statement. Find the containing block and indent ;; relative to that. (t (let ((old-point (point))) (goto-char containing-sexp) (beginning-of-line) (while (is-spp-continuation (point-min)) (spp-end-last-statement (point-min)) (beginning-of-line)) ;;Skip spaces and labels. (skip-chars-forward " \t") (if (looking-at "\\([0-9]+\\|\\sw+_\\)\\s-+") (progn (skip-chars-forward "^ \t") (skip-chars-forward " \t"))) ;; A couple things. If the block introducer is alone on ;; the line, then indent from it. If the statement is ;; first level in a switch block and is not a case ;; double the indentation. (cond ((looking-at "{") (+ (current-column) spp-indent-level)) ((looking-at "switch\\b") (+ (current-column) (progn (goto-char old-point) (if (looking-at "}") spp-indent-level (+ (if spp-indent-case spp-indent-level 0) (progn (goto-char old-point) (if (looking-at "\\s-*\\(\\(case\\|default\\)\\b\\|}\\)") 0 spp-indent-level))))))) ((looking-at "begin\\b") (+ spp-indent-level spp-indent-level-offset)) (t (+ (current-column) spp-indent-level)))))) label))) (defun electric-spp-brace (arg) "Insert character and correct line's indentation." (interactive "P") (let (insertpos) (if (and (not arg) (eolp) (or (save-excursion (skip-chars-backward " \t") (bolp)) (if spp-auto-newline (progn (spp-indent-line) (newline) t) nil))) (progn (insert last-command-char) (spp-indent-line) (if spp-auto-newline (progn (newline) ;; (newline) may have done auto-fill (setq insertpos (- (point) 2)) (spp-indent-line))) (save-excursion (if insertpos (goto-char (1+ insertpos))) (delete-char -1)))) (if insertpos (save-excursion (goto-char insertpos) (self-insert-command (prefix-numeric-value arg))) (self-insert-command (prefix-numeric-value arg))) (if (and spp-match-brace (eq ?\{ last-command-char)) (save-excursion (newline) (insert ?\}) (spp-indent-line))))) (defun electric-spp-newline (arg) "Indent lines as we go." (interactive "P") ;; Insert then delete the newline to get end-of-line abbreviations ;; to expand (newline) (delete-char -1) ;; Now, re-indent according to user's wishes. (if (not spp-auto-indent) (newline) (reindent-then-newline-and-indent))) (defun electric-spp-match (arg) "If spp-match-brace is non-nil, then insert the matching ) or ]." (interactive "P") (insert last-command-char) (if spp-match-brace (save-excursion (cond ((= last-command-char ?\() (insert ?\))) ((= last-command-char ?\[) (insert ?\])) ((= last-command-char ?\{) (insert ?\{)))))) (defun mark-spp-function () "Put mark at end of spp function, point at beginning." (interactive) (push-mark (point)) (end-of-spp-defun) (push-mark (point)) (begin-of-spp-defun)) (defun spp-abbrev-help () "List the currently defined abbrevs in Spp mode." (interactive) (message "Listing abbrev table...") (require 'abbrevlist) (list-one-abbrev-table spp-mode-abbrev-table "*Help*") (message "Listing abbrev table...done")) (defun spp-begin-end () (save-excursion (newline) (insert "end"))) (defun spp-sfree () (save-excursion (newline-and-indent) (insert "call sfree (sp)"))) (defun spp-switch () (insert " (") (save-excursion (insert ") {") (newline) (insert "}") (beginning-of-line) (spp-indent-command))) (defun spp-procedure () (save-excursion (insert " ()") (newline) (insert "begin") (newline) (insert "end")))