home *** CD-ROM | disk | FTP | other *** search
- ;; Self mode editing commands for Emacs, a first cut...
- ;; Mar 11, 1992 Stuart Williams, williams@cs.washington.edu
- ;; Let me know if you fix stuff.
-
- ;; Extended by Craig Chambers, Jan 30, 1993.
- ;; Indent statement continuation lines
- ;; Indent comments and multi-line comments (sort of)
-
- ;; Extended by Urs Hoelzle, March 21, 1993.
- ;; Added Lucid emacs highlighting (thanks to Lars Bak)
-
- ;;
- ;; Hacked by Michael Richardson <mcr@physics.carleton.ca> to interact
- ;; with self.el, an inferior self mode.
- ;; - Added M-C-x to do send-self-object.
- ;; - Added beginning-of-object/end-of-object for above.
- ;; - Also added backward-object/forward-object (not currently bound
- ;; to any specific key. I tend to bind them to function keys..)
- ;; - Stuff it into RCS.
-
- ;; To do:
- ;; - Parsing for indentation is currently done starting at the top of the
- ;; whole file (yuck)! It should start parsing somewhere closer.
- ;; - Indentation is absolute from parsing the whole file and the left margin,
- ;; it should be relative to the enclosing block of code.
- ;; - right bracket and parethesis should only call self-indent if they're
- ;; at the beginning of a line, not at the end.
- ;; - A second tab in a row could be smarter and insert a tab
-
- ;
- ; $Id: self-mode.el,v 1.1 1993/05/14 21:11:48 richards Rel $
- ;
- ; $Log: self-mode.el,v $
- ; Revision 1.1 1993/05/14 21:11:48 richards
- ; Initial revision
- ;
- ;
-
- (provide 'self-mode)
-
- (defvar self-mode-abbrev-table nil
- "Abbrev table for use in self-mode buffers.")
- (define-abbrev-table 'self-mode-abbrev-table ())
-
- (defvar self-mode-map ()
- "Keymap used in Self mode.")
-
- (defun self-mode-commands (map)
- "Adds the self commands to a keymap."
- (define-key map "\177" 'backward-delete-char-untabify)
- (define-key map "\t" 'self-tab-indent)
- (define-key map "\C-j" 'newline-and-indent)
- (define-key map "\M-\C-x" 'self-send-object)
- ;; uncomment the next 4 lines to turn off automatic indentation
- (define-key map "(" 'electric-self-brace)
- (define-key map ")" 'electric-self-brace)
- (define-key map "[" 'electric-self-brace)
- (define-key map "]" 'electric-self-brace))
-
- (if self-mode-map
- ()
- (progn
- (setq self-mode-map (make-sparse-keymap))
- (self-mode-commands self-mode-map)))
-
- (defvar self-mode-syntax-table nil
- "Syntax table in use in Self-mode buffers.")
-
- (if self-mode-syntax-table
- ()
- (setq self-mode-syntax-table (make-syntax-table))
- (modify-syntax-entry ?\( "() " self-mode-syntax-table)
- (modify-syntax-entry ?\) ")( " self-mode-syntax-table)
- (modify-syntax-entry ?\[ "(] " self-mode-syntax-table)
- (modify-syntax-entry ?\] ")[ " self-mode-syntax-table)
- (modify-syntax-entry ?\| "$| " self-mode-syntax-table)
-
- ;; treat double quote as string,
- ;; since it can't be both comment start and end
- (modify-syntax-entry ?\" "\" " self-mode-syntax-table)
-
- ;; apostrophe is used for strings
- (modify-syntax-entry ?\' "\" " self-mode-syntax-table)
-
- ;; space, tab, newline, and formfeed are whitespace:
- (modify-syntax-entry ? " " self-mode-syntax-table)
- (modify-syntax-entry ?\t " " self-mode-syntax-table)
- (modify-syntax-entry ?\n " " self-mode-syntax-table)
- (modify-syntax-entry ?\f " " self-mode-syntax-table)
-
- (modify-syntax-entry ?\\ "\\ " self-mode-syntax-table)
-
- (modify-syntax-entry ?+ "." self-mode-syntax-table)
- (modify-syntax-entry ?- "." self-mode-syntax-table)
- (modify-syntax-entry ?= "." self-mode-syntax-table)
- (modify-syntax-entry ?% "." self-mode-syntax-table)
- (modify-syntax-entry ?< "." self-mode-syntax-table)
- (modify-syntax-entry ?> "." self-mode-syntax-table)
- (modify-syntax-entry ?& "." self-mode-syntax-table))
-
- (defconst self-indent-level 4
- "*Indentation of Self statements with respect to containing block.")
-
- (defconst self-continuation-indent-level 4
- "*Indentation of Self statement continuations with respect to statement start.")
-
- (defun self-mode ()
- "Major mode for editing Self code."
- (interactive)
- (kill-all-local-variables)
- (use-local-map self-mode-map)
- (setq major-mode 'self-mode)
- (setq mode-name "Self")
- (self-mode-variables)
- (run-hooks 'self-mode-hook))
-
- (defun self-mode-variables ()
- (setq local-abbrev-table self-mode-abbrev-table)
- (set-syntax-table self-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 'self-tab-indent)
- (make-local-variable 'require-final-newline)
- (setq require-final-newline t))
-
-
- (defun self-tab-indent ()
- "Indent current line as Self code, even if an empty line."
- (interactive)
- (let ((indent-column (self-indent-line))) ; how far should we indent
- (if (and (numberp indent-column)
- (< (current-column) indent-column)) ; move cursor to right only
- (move-to-column indent-column))))
-
- (defun self-indent-line ()
- "Indent current line as Self code."
- (interactive)
- (let ((indent-size (calculate-self-indent)))
- (if (numberp indent-size) ; else don't indent
- (save-excursion
- (beginning-of-line)
- (skip-chars-forward " \t")
- (if (/= (current-column) indent-size)
- (progn ; don't change unless we have to
- (delete-horizontal-space)
- (indent-to-column indent-size)))))
- indent-size))
-
- (defun self-indent-region (start end)
- "Indent the current region as Self code."
- (interactive "r")
- (save-excursion
- (let ((end-marker (copy-marker end)))
- (goto-char start)
- (while (< (point) (marker-position end-marker))
- (forward-line)
- (self-indent-line)))))
-
- (defun self-indent-buffer ()
- "Indent the current buffer as Self code."
- (interactive)
- (save-excursion
- (self-indent-region (point-min) (point-max))))
-
- (defun calculate-self-indent ()
- "Calculate correct indentation for a line of Self code.
- Returns an integer or nil if inside a string."
- (save-excursion
- (beginning-of-line)
- (skip-chars-forward " \t")
- (let (state paren-depth containing-sexp in-comment in-string)
- (setq state (parse-partial-sexp 1 (point))) ;; this should *not* be 1
-
- (setq paren-depth (nth 0 state))
- (setq containing-sexp (nth 1 state))
- (setq in-comment (nth 3 state)) ;; documentation has these two backwards
- (setq in-string (nth 4 state))
-
- (cond
- (in-string
- ;; If inside string return nil (don't indent);
- nil)
-
- (in-comment
- ;; If inside comment indent equal to enclosing statement, plus 1 to
- ;; skip the enclosing quote char
- ;; (really should indent equal to the first char after the quote,
- ;; to line up text nicely)
- (1+ (* self-indent-level paren-depth)))
-
- ((null containing-sexp)
- ;; Line is at top level.
- ;; Because of paren-counting at top-level, never have a continuation
- ;; line at the top-level.
- ;; No indentation at top-level.
- 0)
-
- ((or
- (looking-at ")")
- (looking-at "]")
- (looking-at "|[ \t]*)")
- (looking-at "|[ \t]*]"))
- ;; line starts a statement, and should back up indentation, too
- (* self-indent-level (1- paren-depth)))
-
- (t
- ;; a nested line; check whether it starts a statement or continues one
- (cond ((self-starts-statement containing-sexp)
- ;; starts statement
- (* self-indent-level paren-depth))
- (t
- ;; continues statement; indent some more
- (+ (* self-indent-level paren-depth)
- self-continuation-indent-level))))))))
-
- (defun self-starts-statement (lim)
- (save-excursion
- (catch 'done
- (while t
- (skip-chars-backward " \t\n\f" lim)
- (if (<= (point) lim) (throw 'done t))
- (backward-char)
- (cond ((looking-at "\"")
- (progn
- (search-backward "\"" lim 'move-if-fail)
- (if (<= (point) lim) (throw 'done t))))
- (t (throw 'done
- (or
- (looking-at "\\.")
- (looking-at "(")
- (looking-at "\\[")
- (looking-at "|")))))))))
-
- (defun electric-self-brace (arg)
- "Insert character and correct line's indentation."
- (interactive "P")
- (insert last-command-char) ; insert arg, in a way that won't blink
- (self-indent-line) ; indent it
- (delete-char -1) ; delete and reinsert arg so it blinks
- (self-insert-command (prefix-numeric-value arg)))
-
- (defun end-of-object ()
- "Move the point to the spot where the object ends."
- ; I assume that with normal formatting, this is a line that has
- ; just a (|) on it.
- (interactive)
- (beginning-of-line)
- (while (and (< (point) (point-max))
- (not (looking-at ")"))
- (not (looking-at "]"))
- (not (looking-at "|[ \t]*)"))
- (not (looking-at "|[ \t]*]")))
- (forward-line)
- (beginning-of-line))
- (if (< (point) (point-max)) (forward-line)))
-
- (defun beginning-of-object ()
- "Move the point to the spot where the object begins."
- ; We do this by going upwards, looking for the end of previous object.
- ; An alternative way is to look for a line that doesn't start with a space.
- ; Time will tell what the better method is.
- (interactive)
- (beginning-of-line)
- (while (and (> (point) (point-min))
- (not (looking-at ")"))
- (not (looking-at "]"))
- (not (looking-at "|[ \t]*)"))
- (not (looking-at "|[ \t]*]")))
- (forward-line -1)
- (beginning-of-line))
- ; don't go forward at the top.
- (if (> (point) (point-min)) (forward-line)))
-
- (defun forward-object (&optional num)
- "moves forward in the file by arg objects"
- (interactive "p")
- (if (not num) (setq num 1))
- (while (> num 0)
- (end-of-object)
- (setq num (- num 1))))
-
- (defun backward-object (&optional num)
- "moves backward in the file by arg objects"
- (interactive "p")
- (if (not num) (setq num 1))
- (forward-line -1)
- (while (> num 0)
- (beginning-of-line)
- (while (or (looking-at ")")
- (looking-at "]")
- (looking-at "|[ \t]*)")
- (looking-at "|[ \t]*]"))
- (forward-line -1))
- (beginning-of-object)
- (setq num (- num 1))))
-
-