diff options
| author | Stefan Monnier | 2000-03-10 01:17:04 +0000 |
|---|---|---|
| committer | Stefan Monnier | 2000-03-10 01:17:04 +0000 |
| commit | 5a7a545cc5e6d09cb39bb1aaf87b48ac10d1f91e (patch) | |
| tree | fb92b99261cdd4b2da3818a5a1608f153168d93c | |
| parent | 445b0666d6143c345042155a086c6157156abaef (diff) | |
| download | emacs-5a7a545cc5e6d09cb39bb1aaf87b48ac10d1f91e.tar.gz emacs-5a7a545cc5e6d09cb39bb1aaf87b48ac10d1f91e.zip | |
(easy-mmode-define-keymap): Extend to allow more flexibility.
(easy-mmode-set-keymap-parents, easy-mmode-define-syntax): New functions.
(easy-mmode-defmap, easy-mmode-defsyntax, easy-mmode-define-derived-mode):
New macros.
| -rw-r--r-- | lisp/ChangeLog | 8 | ||||
| -rw-r--r-- | lisp/emacs-lisp/easy-mmode.el | 193 |
2 files changed, 187 insertions, 14 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 6512731114f..36a12c6c28f 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,11 @@ | |||
| 1 | 2000-03-09 Stefan Monnier <monnier@cs.yale.edu> | ||
| 2 | |||
| 3 | * emacs-lisp/easy-mmode.el (easy-mmode-define-keymap): Extend to allow | ||
| 4 | more flexibility. | ||
| 5 | (easy-mmode-set-keymap-parents, easy-mmode-define-syntax): New functions. | ||
| 6 | (easy-mmode-defmap, easy-mmode-defsyntax, easy-mmode-define-derived-mode): | ||
| 7 | New macros. | ||
| 8 | |||
| 1 | 2000-09-01 Didier Verna <didier@xemacs.org> | 9 | 2000-09-01 Didier Verna <didier@xemacs.org> |
| 2 | 10 | ||
| 3 | * rect.el (replace-rectangle): New function. | 11 | * rect.el (replace-rectangle): New function. |
diff --git a/lisp/emacs-lisp/easy-mmode.el b/lisp/emacs-lisp/easy-mmode.el index c39e6b96424..98ee96bdac9 100644 --- a/lisp/emacs-lisp/easy-mmode.el +++ b/lisp/emacs-lisp/easy-mmode.el | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | ;;; easy-mmode.el --- easy definition of minor modes. | 1 | ;;; easy-mmode.el --- easy definition for major and minor modes. |
| 2 | 2 | ||
| 3 | ;; Copyright (C) 1997 Free Software Foundation, Inc. | 3 | ;; Copyright (C) 1997 Free Software Foundation, Inc. |
| 4 | 4 | ||
| @@ -46,20 +46,10 @@ | |||
| 46 | ;; installed. Perhaps there should be a feature to let you specify | 46 | ;; installed. Perhaps there should be a feature to let you specify |
| 47 | ;; orderings. | 47 | ;; orderings. |
| 48 | 48 | ||
| 49 | ;;; Code: | 49 | ;; Additionally to `define-minor-mode', the package provides convenient |
| 50 | ;; ways to define keymaps, and other helper functions for major and minor modes. | ||
| 50 | 51 | ||
| 51 | (defun easy-mmode-define-keymap (keymap-alist &optional menu-name) | 52 | ;;; Code: |
| 52 | "Return a keymap built from KEYMAP-ALIST. | ||
| 53 | KEYMAP-ALIST must be a list of (KEYBINDING . BINDING) where | ||
| 54 | KEYBINDING and BINDINGS are suited as for define-key. | ||
| 55 | optional MENU-NAME is passed to `make-sparse-keymap'." | ||
| 56 | (let ((keymap (make-sparse-keymap menu-name))) | ||
| 57 | (mapcar | ||
| 58 | (function (lambda (bind) | ||
| 59 | (define-key keymap | ||
| 60 | (car bind) (cdr bind)))) | ||
| 61 | keymap-alist) | ||
| 62 | keymap)) | ||
| 63 | 53 | ||
| 64 | (defmacro easy-mmode-define-toggle (mode &optional doc &rest body) | 54 | (defmacro easy-mmode-define-toggle (mode &optional doc &rest body) |
| 65 | "Define a one arg toggle mode MODE function and associated hooks. | 55 | "Define a one arg toggle mode MODE function and associated hooks. |
| @@ -161,6 +151,181 @@ Use the function `%s' to change this variable." mode-name)) | |||
| 161 | (setcdr (assq ',mode minor-mode-map-alist) | 151 | (setcdr (assq ',mode minor-mode-map-alist) |
| 162 | ,keymap-sym)) )) | 152 | ,keymap-sym)) )) |
| 163 | 153 | ||
| 154 | |||
| 155 | ;;; | ||
| 156 | ;;; easy-mmode-defmap | ||
| 157 | ;;; | ||
| 158 | |||
| 159 | (if (fboundp 'set-keymap-parents) | ||
| 160 | (defalias 'easy-mmode-set-keymap-parents 'set-keymap-parents) | ||
| 161 | (defun easy-mmode-set-keymap-parents (m parents) | ||
| 162 | (set-keymap-parent | ||
| 163 | m | ||
| 164 | (cond | ||
| 165 | ((not (consp parents)) parents) | ||
| 166 | ((not (cdr parents)) (car parents)) | ||
| 167 | (t (let ((m (copy-keymap (pop parents)))) | ||
| 168 | (easy-mmode-set-keymap-parents m parents) | ||
| 169 | m)))))) | ||
| 170 | |||
| 171 | (defun easy-mmode-define-keymap (bs &optional name m args) | ||
| 172 | "Return a keymap built from bindings BS. | ||
| 173 | BS must be a list of (KEY . BINDING) where | ||
| 174 | KEY and BINDINGS are suited as for define-key. | ||
| 175 | optional NAME is passed to `make-sparse-keymap'. | ||
| 176 | optional map M can be used to modify an existing map. | ||
| 177 | ARGS is a list of additional arguments." | ||
| 178 | (let (inherit dense suppress) | ||
| 179 | (while args | ||
| 180 | (let ((key (pop args)) | ||
| 181 | (val (pop args))) | ||
| 182 | (cond | ||
| 183 | ((eq key :dense) (setq dense val)) | ||
| 184 | ((eq key :inherit) (setq inherit val)) | ||
| 185 | ((eq key :group) ) | ||
| 186 | ;;((eq key :suppress) (setq suppress val)) | ||
| 187 | (t (message "Unknown argument %s in defmap" key))))) | ||
| 188 | (unless (keymapp m) | ||
| 189 | (setq bs (append m bs)) | ||
| 190 | (setq m (if dense (make-keymap name) (make-sparse-keymap name)))) | ||
| 191 | (dolist (b bs) | ||
| 192 | (let ((keys (car b)) | ||
| 193 | (binding (cdr b))) | ||
| 194 | (dolist (key (if (consp keys) keys (list keys))) | ||
| 195 | (cond | ||
| 196 | ((symbolp key) | ||
| 197 | (substitute-key-definition key binding m global-map)) | ||
| 198 | ((null binding) | ||
| 199 | (unless (keymapp (lookup-key m key)) (define-key m key binding))) | ||
| 200 | ((let ((o (lookup-key m key))) | ||
| 201 | (or (null o) (numberp o) (eq o 'undefined))) | ||
| 202 | (define-key m key binding)))))) | ||
| 203 | (cond | ||
| 204 | ((keymapp inherit) (set-keymap-parent m inherit)) | ||
| 205 | ((consp inherit) (easy-mmode-set-keymap-parents m inherit))) | ||
| 206 | m)) | ||
| 207 | |||
| 208 | ;;;###autoload | ||
| 209 | (defmacro easy-mmode-defmap (m bs doc &rest args) | ||
| 210 | `(defconst ,m | ||
| 211 | (easy-mmode-define-keymap ,bs nil (if (boundp ',m) ,m) ,(cons 'list args)) | ||
| 212 | ,doc)) | ||
| 213 | |||
| 214 | |||
| 215 | ;;; | ||
| 216 | ;;; easy-mmode-defsyntax | ||
| 217 | ;;; | ||
| 218 | |||
| 219 | (defun easy-mmode-define-syntax (css args) | ||
| 220 | (let ((st (make-syntax-table (cadr (memq :copy args))))) | ||
| 221 | (dolist (cs css) | ||
| 222 | (let ((char (car cs)) | ||
| 223 | (syntax (cdr cs))) | ||
| 224 | (if (sequencep char) | ||
| 225 | (mapcar* (lambda (c) (modify-syntax-entry c syntax st)) char) | ||
| 226 | (modify-syntax-entry char syntax st)))) | ||
| 227 | st)) | ||
| 228 | |||
| 229 | ;;;###autoload | ||
| 230 | (defmacro easy-mmode-defsyntax (st css doc &rest args) | ||
| 231 | `(defconst ,st (custom-create-syntax ,css ,(cons 'list args)) doc)) | ||
| 232 | |||
| 233 | |||
| 234 | |||
| 235 | ;;; A "macro-only" reimplementation of define-derived-mode. | ||
| 236 | |||
| 237 | (defmacro easy-mmode-define-derived-mode (child parent name &optional docstring &rest body) | ||
| 238 | "Create a new mode as a variant of an existing mode. | ||
| 239 | |||
| 240 | The arguments to this command are as follow: | ||
| 241 | |||
| 242 | CHILD: the name of the command for the derived mode. | ||
| 243 | PARENT: the name of the command for the parent mode (e.g. `text-mode'). | ||
| 244 | NAME: a string which will appear in the status line (e.g. \"Hypertext\") | ||
| 245 | DOCSTRING: an optional documentation string--if you do not supply one, | ||
| 246 | the function will attempt to invent something useful. | ||
| 247 | BODY: forms to execute just before running the | ||
| 248 | hooks for the new mode. | ||
| 249 | |||
| 250 | Here is how you could define LaTeX-Thesis mode as a variant of LaTeX mode: | ||
| 251 | |||
| 252 | (define-derived-mode LaTeX-thesis-mode LaTeX-mode \"LaTeX-Thesis\") | ||
| 253 | |||
| 254 | You could then make new key bindings for `LaTeX-thesis-mode-map' | ||
| 255 | without changing regular LaTeX mode. In this example, BODY is empty, | ||
| 256 | and DOCSTRING is generated by default. | ||
| 257 | |||
| 258 | On a more complicated level, the following command uses `sgml-mode' as | ||
| 259 | the parent, and then sets the variable `case-fold-search' to nil: | ||
| 260 | |||
| 261 | (define-derived-mode article-mode sgml-mode \"Article\" | ||
| 262 | \"Major mode for editing technical articles.\" | ||
| 263 | (setq case-fold-search nil)) | ||
| 264 | |||
| 265 | Note that if the documentation string had been left out, it would have | ||
| 266 | been generated automatically, with a reference to the keymap." | ||
| 267 | |||
| 268 | ; Some trickiness, since what | ||
| 269 | ; appears to be the docstring | ||
| 270 | ; may really be the first | ||
| 271 | ; element of the body. | ||
| 272 | (if (and docstring (not (stringp docstring))) | ||
| 273 | (progn (setq body (cons docstring body)) | ||
| 274 | (setq docstring nil))) | ||
| 275 | (let* ((child-name (symbol-name child)) | ||
| 276 | (map (intern (concat child-name "-map"))) | ||
| 277 | (syntax (intern (concat child-name "-syntax-table"))) | ||
| 278 | (abbrev (intern (concat child-name "-abbrev-table"))) | ||
| 279 | (hook (intern (concat child-name "-hook")))) | ||
| 280 | |||
| 281 | `(progn | ||
| 282 | (defvar ,map (make-sparse-keymap)) | ||
| 283 | (defvar ,syntax (make-char-table 'syntax-table nil)) | ||
| 284 | (defvar ,abbrev (progn (define-abbrev-table ',abbrev nil) ,abbrev)) | ||
| 285 | |||
| 286 | (defun ,child () | ||
| 287 | ,(or docstring | ||
| 288 | (format "Major mode derived from `%s' by `define-derived-mode'. | ||
| 289 | Inherits all of the parent's attributes, but has its own keymap, | ||
| 290 | abbrev table and syntax table: | ||
| 291 | |||
| 292 | `%s', `%s' and `%s' | ||
| 293 | |||
| 294 | which more-or-less shadow %s's corresponding tables. | ||
| 295 | It also runs its own `%s' after its parent's. | ||
| 296 | |||
| 297 | \\{%s}" parent map syntax abbrev parent hook map)) | ||
| 298 | (interactive) | ||
| 299 | ; Run the parent. | ||
| 300 | (,parent) | ||
| 301 | ; Identify special modes. | ||
| 302 | (put ',child 'special (get ',parent 'special)) | ||
| 303 | ; Identify the child mode. | ||
| 304 | (setq major-mode ',child) | ||
| 305 | (setq mode-name ,name) | ||
| 306 | ; Set up maps and tables. | ||
| 307 | (unless (keymap-parent ,map) | ||
| 308 | (set-keymap-parent ,map (current-local-map))) | ||
| 309 | (let ((parent (char-table-parent ,syntax))) | ||
| 310 | (unless (and parent (not (eq parent (standard-syntax-table)))) | ||
| 311 | (set-char-table-parent ,syntax (syntax-table)))) | ||
| 312 | (when local-abbrev-table | ||
| 313 | (mapatoms | ||
| 314 | (lambda (symbol) | ||
| 315 | (or (intern-soft (symbol-name symbol) ,abbrev) | ||
| 316 | (define-abbrev ,abbrev (symbol-name symbol) | ||
| 317 | (symbol-value symbol) (symbol-function symbol)))) | ||
| 318 | local-abbrev-table)) | ||
| 319 | |||
| 320 | (use-local-map ,map) | ||
| 321 | (set-syntax-table ,syntax) | ||
| 322 | (setq local-abbrev-table ,abbrev) | ||
| 323 | ; Splice in the body (if any). | ||
| 324 | ,@body | ||
| 325 | ; Run the hooks, if any. | ||
| 326 | (run-hooks ',hook))))) | ||
| 327 | |||
| 328 | |||
| 164 | (provide 'easy-mmode) | 329 | (provide 'easy-mmode) |
| 165 | 330 | ||
| 166 | ;;; easy-mmode.el ends here | 331 | ;;; easy-mmode.el ends here |