home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 8
/
FreshFishVol8-CD1.bin
/
new
/
util
/
edit
/
jade
/
lisp
/
modes.jl
< prev
next >
Wrap
Lisp/Scheme
|
1994-10-03
|
10KB
|
281 lines
;;;; modes.jl -- Code for handling editing modes.
;;; Copyright (C) 1993, 1994 John Harper <jsh@ukc.ac.uk>
;;; This file is part of Jade.
;;; Jade 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.
;;; Jade 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 Jade; see the file COPYING. If not, write to
;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
;;; Notes:
;;; Major Modes:
;;;
;;; Each major mode has a function which is called to install the mode,
;;; the first thing such a function should do is check if a mode is
;;; already installed and if so remove it:
;;;
;;; (when major-mode-kill
;;; (funcall major-mode-kill))
;;;
;;; Now the new mode is free to install itself; generally this entails
;;; setting at least the `mode-name' and `major-mode-kill' variables
;;; and installing a local keymap. For example `lisp-mode' does this:
;;;
;;; (setq mode-name "Lisp"
;;; major-mode 'lisp-mode
;;; major-mode-kill 'lisp-mode-kill
;;; mode-comment-fun 'lisp-mode-insert-comment
;;; keymap-path (cons 'lisp-mode-keymap keymap-path))
;;; (eval-hook 'lisp-mode-hook)
;;;
;;; The function to be called when the mode is removed should remove the
;;; effects of the above, for example:
;;;
;;; (setq keymap-path (delq 'lisp-mode-keymap keymap-path)
;;; major-mode nil
;;; major-mode-kill nil
;;; mode-comment-fun nil
;;; mode-name nil)
;;; Minor Modes:
;;;
;;; These are usually harder to implement than major modes since they
;;; have to coexist with all other modes which are installed.
;;;
;;; Generally each minor mode maintains a buffer-local variable saying
;;; whether or not it's installed in the buffer. The minor mode's
;;; function usually toggles the mode on or off depending on the state of
;;; this variable.
;;;
;;; There are two functions which *must* be used to install/remove a
;;; minor mode -- `add-minor-mode' and `remove-minor-mode', see there
;;; documentation for details.
;;;
;;; Each buffer has a keymap for the bindings of all the minor modes
;;; active in the buffer (called `minor-mode-keymap'). These bindings
;;; have to be added when the mode is enabled and removed when it
;;; is disabled.
(defvar mode-alist '(
;;; ::mode-alist-start::
("\\.(c|h)$|^c(|-mode)$" . c-mode)
("\\.jl$|^lisp(|-mode)$" . lisp-mode)
("\\.(text|doc|txt|article|letter)$" . text-mode)
("^(text(|-mode)|(.*/|)draft)$" . text-mode)
("^indented-text(|-mode)$" . indented-text-mode)
("\\.[s]$|^asm(|-mode)$" . asm-mode)
("\\.[S]$|^asm-cpp(|-mode)$" . asm-cpp-mode)
("\\.texi(|nfo)|^texinfo(|-mode)$" . texinfo-mode)
;;; ::mode-alist-end::
) "List of all major modes which can be enabled by loading a file into
a buffer. List is made of `(REGEXP . MODE)' cells; the REGEXP is matched
against the mode specification (i.e. the filename), if it matches the
function MODE is called to install the mode.")
;; Variables
(defvar major-mode nil
"The function which was used to initialise the buffer's major mode.")
(make-variable-buffer-local 'major-mode)
(defvar major-mode-kill nil
"The function which should be called to remove the buffer's major mode.")
(make-variable-buffer-local 'major-mode-kill)
(defvar comment-column 41
"Buffer-local variable containing the canonical column number which
comments should begin at. If the line extends past this column the next
tab stop after the end of the line is used instead.")
(make-variable-buffer-local 'comment-column)
(make-variable-buffer-local 'mode-comment-fun)
(defvar mode-indent-line nil
"A function called to indent a specified line in the current buffer.")
(make-variable-buffer-local 'mode-indent-line)
(defvar mode-forward-exp nil
"Function like `lisp-forward-sexp'.")
(make-variable-buffer-local 'mode-forward-exp)
(defvar mode-backward-exp nil
"Function like `lisp-backward-sexp'.")
(make-variable-buffer-local 'mode-backward-exp)
;; Major mode handling
(defun get-mode (name)
"Scan the alist `mode-alist' for a mode whose regexp matches NAME,
returning the initialisation function of that mode (a symbol) or nil."
(let*
((list mode-alist)
(elt nil))
(while (setq elt (car list))
(when (regexp-match (car elt) name t)
(return (cdr elt)))
(setq list (cdr list)))))
(defun init-mode (buf &optional name)
"Initialise an edit-mode for buffer BUF, either calls the function named
in the buffer-local variable `major-mode' or finds a mode in `mode-alist'
using one of the following to match against:
1. NAME
2. The word specified on the first line of the buffer surrounded by
`-*-...-*-' (ie, -*-texinfo-*-)
3. The value of the variable `mode-name'
4. The name of the file being edited in the buffer"
(with-buffer (unless buf (current-buffer))
(unless major-mode
(setq name (or name
(regexp-expand-line "-\\*- *([^ ]+) *-\\*-" "\\1"
(buffer-start))
mode-name
(buffer-file-name buf)))
(setq major-mode (get-mode name)))
(when (functionp major-mode)
(funcall major-mode name))))
(defun kill-mode (&optional buf)
"Destroy the mode being used to edit buffer BUF with."
(unless buf
(setq buf (current-buffer)))
(with-buffer buf
(when major-mode-kill
(funcall major-mode-kill buf))))
;; Minor-mode handling
(defvar minor-mode-list ()
"List of all minor-modes enabled in this buffer.")
(make-variable-buffer-local 'minor-mode-list)
(defvar minor-mode-keymap nil
"Buffer-local keymap to be used by minor-modes. This is only created
the first time a minor mode calls `add-minor-mode' in the buffer.")
(make-variable-buffer-local 'minor-mode-keymap)
(defun add-minor-mode (mode name &optional no-keymap)
"For use by minor-modes. MODE is the mode's function symbol. This sets up the
current buffer. All minor-modes should call this before doing anything drastic.
NAME is the string to be displayed in the status-line to show that the mode
is enabled."
(when (memq mode minor-mode-list)
(error "Minor mode already installed" mode))
(setq minor-mode-list (cons mode minor-mode-list)
minor-mode-names (cons name minor-mode-names))
(unless (or minor-mode-keymap no-keymap)
(setq minor-mode-keymap (make-keylist)
keymap-path (cons 'minor-mode-keymap keymap-path)))
t)
(defun remove-minor-mode (mode name)
"For use by minor-modes. MODE is the mode's function symbol. Removes MODE
from the current buffer."
(setq minor-mode-list (delq mode minor-mode-list)
minor-mode-names (delete name minor-mode-names))
t)
;; Comment handling
(defun insert-comment ()
"Insert comment delimeters on the current line, place the cursor where the
comment should be written. This may or not be defined by each major mode."
(interactive)
(if (and (boundp 'mode-comment-fun) mode-comment-fun)
(funcall mode-comment-fun)
(error "No defined method for inserting comments in this buffer")))
(defun find-comment-pos ()
(let
((pos (glyph-to-char-pos (pos (1- comment-column) nil))))
(goto-line-end)
(if (>= (line-end) pos)
(insert "\t")
(indent-to (1- comment-column)))))
;; Indentation
(defun indent-area (start end)
"Use the `mode-indent-line' function to indent each line between START and
END."
(interactive "-m\nM")
(setq start (line-start start)
end (line-start end))
(unless mode-indent-line
(error "No method for indenting lines in this buffer"))
(while (< start end)
(funcall mode-indent-line start)
(next-line 1 start)))
(defvar newline-and-indent ()
"(newline-and-indent)
Insert a newline then either call this buffer's `mode-indent-line' function
or insert a tab."
(interactive)
(if (null mode-indent-line)
(insert "\n\t")
(insert "\n")
(funcall mode-