diff options
author | Alexander Sulfrian <alexander@sulfrian.net> | 2009-10-25 01:34:07 +0200 |
---|---|---|
committer | Alexander Sulfrian <alexander@sulfrian.net> | 2009-10-25 01:34:07 +0200 |
commit | 3fb586a7741ae1c66bb74e73a69c140ca89e099d (patch) | |
tree | c0fc99e222893b0126fe48a2e60cb6208a41f591 /emacs | |
parent | c6c70407baf45e21fcbaaa98a3e0b3adb4b3bdae (diff) | |
download | dotfiles-3fb586a7741ae1c66bb74e73a69c140ca89e099d.tar.gz dotfiles-3fb586a7741ae1c66bb74e73a69c140ca89e099d.tar.xz dotfiles-3fb586a7741ae1c66bb74e73a69c140ca89e099d.zip |
added multi-mode and html-php-mode
Diffstat (limited to '')
-rw-r--r-- | emacs | 4 | ||||
-rw-r--r-- | emacs.d/lisp/multi-mode/html-php.el | 91 | ||||
-rw-r--r-- | emacs.d/lisp/multi-mode/multi-mode.el | 524 | ||||
-rw-r--r-- | emacs.elc | bin | 16424 -> 16506 bytes |
4 files changed, 619 insertions, 0 deletions
@@ -361,3 +361,7 @@ (require 'yasnippet) (yas/initialize) (yas/load-directory "~/.emacs.d/snippets") + +; html-php-multi-mode +(require 'html-php) +(setq auto-mode-alist (cons '("\\.php" . html-php-mode) auto-mode-alist)) diff --git a/emacs.d/lisp/multi-mode/html-php.el b/emacs.d/lisp/multi-mode/html-php.el new file mode 100644 index 0000000..22cc210 --- /dev/null +++ b/emacs.d/lisp/multi-mode/html-php.el @@ -0,0 +1,91 @@ +;;; html-php.el --- multi-mode PHP embedded in HTML + +;; Copyright (C) 2008 Dave Love + +;; Author: Dave Love <fx@gnu.org> +;; Keywords: languages +;; $Revision: 2$ +;; URL: http://www.loveshack.ukfsn.org/emacs + +;; This file 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. + +;; This file 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 GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; Multiple-mode editing of PHP embedded in HTML. Subject to the +;; limitations of multi-mode.el. Note that there's no attempt to deal +;; with commented processing instructions markup. Note also that this +;; only works properly with the basic HTML mode -- not PSGML or NXML. +;; Tested with the PHP mode from the hacked CC mode at the above URL. + +;;; Code: + +(require 'multi-mode) + +(defun html-php-mode () + "Mode for editing PHP embedded in HTML, using multi-mode." + (interactive) + (set (make-local-variable 'multi-alist) + '((html-mode) + (php-mode . html-php-chunk-region))) + (multi-mode-install-modes)) + +(defun html-php-chunk-region (pos) + "Mode-selecting function for PHP embedded in HTML. +See `multi-alist'." + (let ((case-fold-search t) + pi-start pi-end next-pi) + (save-excursion + (save-restriction + (widen) + (goto-char pos) + (save-excursion + (let* ((p1 (save-excursion + ;; Check whether we're on the processing + ;; instruction start. Skip definitely clear of + ;; it and then search backwards. + (goto-char (min (point-max) (+ (point) 5))) + (search-backward "<?php" (- (point) 9) t))) + (match-end (if p1 (match-end 0))) + ;; Otherwise search backwards simply. + (p2 (unless p1 (search-backward "<?php" nil t)))) + (if p2 (setq match-end (match-end 0))) + (setq pi-start (or p1 p2)) + ;; Ready to search for matching terminator or next + ;; processing instruction. + (goto-char (or match-end pos))) + (if pi-start + ;; Look forward for the PI terminator. + (let* ((p1 (save-excursion + ;; Check whether we're on the terminator. + (backward-char 1) + (search-backward "?>" (- (point) 2) t))) + (p2 (unless p1 (search-forward "?>" nil t)))) + (setq pi-end (or p1 p2 (point-max)))) + (goto-char pos)) + (if (and pi-start pi-end (< pos pi-end)) + ;; We were between PI start and terminator. + (list 'php-mode pi-start pi-end) + ;; Otherwise, look forward for a PI to delimit the HTML + ;; region. + (setq next-pi (if (search-forward "<?php" nil t) + (match-beginning 0) + (point-max))) + (if pi-start + (list 'html-mode (or pi-end (point-min)) next-pi) + (list 'html-mode (point-min) next-pi)))))))) + +(provide 'html-php) +;;; html-php.el ends here diff --git a/emacs.d/lisp/multi-mode/multi-mode.el b/emacs.d/lisp/multi-mode/multi-mode.el new file mode 100644 index 0000000..2105fda --- /dev/null +++ b/emacs.d/lisp/multi-mode/multi-mode.el @@ -0,0 +1,524 @@ +;;; multi-mode.el --- support for multiple major modes + +;; Copyright (C) 2003, 2004, 2007, 2009 Free Software Foundation, Inc. + +;; Author: Dave Love <fx@gnu.org> +;; Keywords: languages, extensions, files +;; Created: Sept 2003 +;; $Revision: 1.11 $ +;; URL: http://www.loveshack.ukfsn.org/emacs + +;; This file 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 3 of the License, or +;; (at your option) any later version. + +;; This file 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; This is a framework for a sort of meta mode which provides support +;; for multiple major modes in different regions (`chunks') of a +;; buffer -- sort of. Actually, multiple indirect buffers are used, +;; one per mode (apart from the base buffer, which has the default +;; mode). A post-command hook selects the correct buffer for the mode +;; around point. This is done on the basis of calling the elements of +;; `multi-chunk-fns' and taking the value corresponding to a start +;; position closest to point. + +;; [I originally tried maintaining information about the local major +;; mode on a text property maintained by font-lock along with a +;; `point-entered' property to control changing the indirect buffer. +;; This worked less well for reasons I've forgotten, unfortunately. +;; The post-command hook seems to be efficient enough in the simple +;; cases I've tried, and is most general.] + +;; Using indirect buffers ensures that we always have the correct +;; local buffer properties like the keymap and syntax table, including +;; the local variable list. There are other implementations of this +;; sort of thing, e.g. for literate programming, but as far as I know, +;; they all work either by continually re-executing the major mode +;; functions or by swapping things like the keymap in and out +;; explicitly. Using indirect buffers seems to be the right thing and +;; is at least potentially more robust, for instance for things like +;; specific subprocesses associated with the buffer for Ispell or +;; whatever. (However, it has the potential confusion of there +;; actually being multiple buffers, even if they mostly act like one. +;; It also may interact badly with other modes using +;; `post-command-hook', as with Flyspell.) Also, it's fairly simple. + +;; Maybe it won't turn out to be the best approach, but it currently +;; seems to me to be better than the approach used by MMM mode +;; <URL:http://mmm-mode.sourceforge.net/>, and is a lot less code. I +;; suspect doing the job any better would require fairly serious +;; surgery on buffer behaviour. For instance, consider being able +;; programmatically to treat discontinuous buffer regions as +;; continuous according to, say, text properties. That would work +;; rather like having multiple gaps which the most primitive movement +;; functions skip. + +;; The other major difference to MMM mode is that we don't operate on +;; more-or-less static regions in different modes which need to be +;; re-parsed explicitly and/or explicitly inserted. Instead they're +;; dynamically defined, so that random editing DTRT. + +;; Things like font-lock and Imenu need to be done piecewise over the +;; chunks. Some functions, such as indentation, should be executed +;; with the buffer narrowed to the current chunk. This ensures they +;; aren't thrown by syntax in other chunks which could confuse +;; `parse-partial-sexp'. + +;; The intention is that other major modes can be defined with this +;; framework for specific purposes, e.g. literate programming systems, +;; e.g. literate Haskell, mixing Haskell and LaTeX chunks. See the +;; example of haskell-latex.el, which can activate the literate mode +;; just by adding to `haskell-mode-hook'. The multiple modes can also +;; be chosen on the basis of the file contents, e.g. noweb.el. + +;; Problems: +;; * C-x C-v in the indirect buffer just kills both buffers. (Perhaps an +;; Emacs bug.) +;; * Font-locking doesn't always work properly in Emacs 21, due to lack +;; of `font-lock-dont-widen', e.g. see the commentary in +;; haskell-latex.el. +;; * C-x C-w in Emacs 21 may change the mode when it shouldn't. +;; * Flyspell needs modifying so as not to cause trouble with this. +;; For the moment we hack the Flyspell hook functions. +;; * The behaviour of the region can appear odd if point and mark are in +;; regions corresponding to different modes, since they are actually in +;; different buffers. We really want point and marks to be shared among +;; the indirect buffers. +;; * `view-file' doesn't work properly -- only the main buffer gets the +;; minor mode. Probably fixable using `view-mode-hook'. +;; * Doubtless facilities other than Imenu, Font Lock and Flyspell +;; should be supported explicitly or fixed up to work with this, +;; e.g. by narrowing to the chunk around commands. There may be a +;; need for more hooks or other support in base Emacs to help. +;; * Fontification currently doesn't work properly with modes which +;; define their own fontification functions, at least the way nXML mode +;; does it. nXML seems to need hacking to get this right, maybe by +;; converting it to use font-lock. nXML is the only mode I know +;; which defines its own `fontification-functions', although PSGML +;; does its own fontification differently again. Generally, any +;; fontification which doesn't respect the narrowing in force will +;; cause problems. (One might think about `flet'ting `widen' to +;; `ignore' around fontification functions, but that means they can't +;; parse from a previous point, as things like nXML should +;; legitimately be able to do.) + +;; Todo: +;; * Provide a simple way to define multi-chunk functions by a series +;; of delimiting regexps, similarly to MMM mode -- someone asked for +;; that. +;; * Provide a means for code describing `island' chunks, which +;; doesn't know about the base or other modes, to describe a chain +;; of chunks in that mode for mapping over chunks. + +;;; Code: + +(require 'font-lock) +(require 'imenu) +(eval-when-compile (require 'advice)) + +(defvar multi-indirect-buffers-alist nil + "Alist of direct and indirect buffers v. major modes. +Internal use. Buffer local.") +(make-variable-buffer-local 'multi-indirect-buffers-alist) + +(defvar multi-normal-fontify-function nil + "Fontification function normally used by the buffer's major mode. +Internal use. Buffer local.") +(make-variable-buffer-local 'multi-normal-fontify-function) + +(defvar multi-normal-fontify-functions nil + "Fontification functions normally used by the buffer's major mode. +Internal use. Buffer local.") +(make-variable-buffer-local 'multi-normal-fontify-functions) + +(defvar multi-indirect-buffer-hook nil + "Hook run by `multi-install-mode' in each indirect buffer. +It is run after all the indirect buffers have been set up.") + +(defvar multi-select-mode-hook nil + "Hook run after a different mode is selected.") + +(defvar multi-chunk-fns nil + "List of functions to determine the modes of chunks. +Each takes a single arg, the position at which to find the mode. It returns +a list (MODE START END). +Buffer local.") +(make-variable-buffer-local 'multi-chunk-fns) + +(defsubst multi-base-buffer () + "Return base buffer of current buffer, or the current buffer if it's direct." + (or (buffer-base-buffer (current-buffer)) + (current-buffer))) + +(defvar multi-late-index-function nil + "Original value of `imenu-create-index-function' for the buffer's mode.") +(make-variable-buffer-local 'multi-late-index-function) + +;; This isn't called `multi-mode-alist', since that will get treated +;; as risky in file variables. +(defvar multi-alist nil + "Alist of elements (MODE . FUNCTION) specifying a buffer's multiple modes. +MODE is a major mode and FUNCTION is a function used as an element of +`multi-chunk-fns' or nil. Use nil if MODE is detected by another element +of the alist. + +This is intended to be set as a file variable in a file which specifies +`multi-mode' as its major mode.") + +;; See the commentary below. +(defun multi-hack-local-variables () + "Like `hack-local-variables', but ignore `mode' items." + (let ((late-hack (symbol-function 'hack-one-local-variable))) + (fset 'hack-one-local-variable + (lambda (var val) + (unless (eq var 'mode) + (funcall late-hack var val)))) + (unwind-protect + (hack-local-variables) + (fset 'hack-one-local-variable late-hack)))) + +(defun multi-install-mode (mode &optional chunk-fn base) + "Add MODE to the multiple major modes supported by the current buffer. +CHUNK-FN, if non-nil, is a function to select the mode of a chunk, +added to the list `multi-chunk-fns'. BASE non-nil means that this +is the base mode." + (unless (memq mode multi-indirect-buffers-alist) ; be idempotent + ;; This is part of a grim hack for lossage in AUCTeX, which + ;; bogusly advises `hack-one-local-variable'. This loses, due to + ;; the way advice works, when we run `multi-hack-local-variables' + ;; below -- there ought to be a way round this, probably with CL's + ;; flet. Any subsequent use of it then fails because advice has + ;; captured the now-unbound variable `late-hack'... Thus ensure + ;; we've loaded the mode in advance to get any autoloads sorted + ;; out. Do it generally in case other modes have similar + ;; problems. [The AUCTeX stuff is in support of an undocumented + ;; feature which is unnecessary and, anyway, wouldn't need advice + ;; to implement. Unfortunately the maintainer seems not to + ;; understand the local variables mechanism and wouldn't remove + ;; this. To invoke minor modes, you should just use `mode:' in + ;; `local variables'.] + (if (eq 'autoload (car-safe (indirect-function mode))) + (with-temp-buffer + (insert "Local Variables:\nmode: fundamental\nEnd:\n") + (funcall mode) + (hack-local-variables))) + (let ((new-buffer (if base + (current-buffer) + ;; Perhaps the name uniquification should use + ;; the mode name somehow (without getting long). + (make-indirect-buffer (current-buffer) + (generate-new-buffer-name + (buffer-name)))))) + (with-current-buffer (multi-base-buffer) + (push (cons mode new-buffer) multi-indirect-buffers-alist) + (let ((alist multi-indirect-buffers-alist) + (hook multi-indirect-buffer-hook) + (fns (if chunk-fn + (add-to-list 'multi-chunk-fns chunk-fn) + multi-chunk-fns)) + (alist2 multi-alist) + (file (buffer-file-name)) + (base-name (buffer-name)) + (coding buffer-file-coding-system) + (multi-mode t)) ; The modes might examine this. + (with-current-buffer new-buffer + (unless (and base (eq mode major-mode)) + (funcall mode)) + ;; Now we can make it local: + (set (make-local-variable 'multi-mode) t) + ;; Use file's local variables section to set variables in + ;; this buffer. (Don't just copy local variables from the + ;; base buffer because it may have set things locally that + ;; we don't want in the other modes.) We need to prevent + ;; `mode' being processed and re-setting the major mode. + ;; It all goes badly wrong if `hack-one-local-variable' is + ;; advised. The appropriate mechanism to get round this + ;; appears to be `ad-with-originals', but we don't want to + ;; pull in the advice package unnecessarily. `flet'-like + ;; mechanisms lose with advice because `fset' acts on the + ;; advice anyway. + (if (featurep 'advice) + (ad-with-originals (hack-one-local-variable) + (multi-hack-local-variables)) + (multi-hack-local-variables)) + ;; Indentation should first narrow to the chunk. Modes + ;; should normally just bind `indent-line-function' to + ;; handle indentation. + (when indent-line-function ; not that it should ever be nil... + (set (make-local-variable 'indent-line-function) + `(lambda () + (save-restriction + (multi-narrow-to-chunk) + (,indent-line-function))))) + ;; Now handle the case where the mode binds TAB directly. + ;; Bind it in an overriding map to use the local definition, + ;; but narrowed to the chunk. + (let ((tab (local-key-binding "\t"))) + (when tab + (make-local-variable 'minor-mode-map-alist) + (push (cons multi-mode + (let ((map (make-sparse-keymap))) + (define-key map "\t" + `(lambda () + (interactive) + (save-restriction + (multi-narrow-to-chunk) + (call-interactively ',tab)))) + map)) + minor-mode-map-alist))) + (setq multi-normal-fontify-function + font-lock-fontify-region-function) + (set (make-local-variable 'font-lock-fontify-region-function) + #'multi-fontify-region) + (setq multi-normal-fontify-functions fontification-functions) + (setq fontification-functions '(multi-fontify)) + ;; Don't let parse-partial-sexp get fooled by syntax outside + ;; the chunk being fontified. (Not in Emacs 21.) + (set (make-local-variable 'font-lock-dont-widen) t) + (setq multi-late-index-function imenu-create-index-function) + (setq imenu-create-index-function #'multi-create-index + multi-indirect-buffer-hook hook) + ;; Kill the base buffer along with the indirect one; careful not + ;; to infloop. + (add-hook 'kill-buffer-hook + '(lambda () + (setq kill-buffer-hook nil) + (kill-buffer (buffer-base-buffer (current-buffer)))) + t t) + ;; This should probably be at the front of the hook list, so + ;; that other hook functions get run in the (perhaps) + ;; newly-selected buffer. + (add-hook 'post-command-hook 'multi-select-buffer nil t) + ;; Avoid the uniqified name for the indirect buffer in the + ;; mode line. + (setq mode-line-buffer-identification + (propertized-buffer-identification base-name)) + ;; Fixme: Are there other things to copy? + (setq buffer-file-coding-system coding) + ;; For benefit of things like VC + (setq buffer-file-name file) + (vc-find-file-hook)) + ;; Propagate updated values of the relevant buffer-local + ;; variables to the indirect buffers. + (dolist (x alist) + (if (car x) + (with-current-buffer (cdr x) + (setq multi-chunk-fns fns) + (setq multi-indirect-buffers-alist alist) + (setq multi-alist alist2) + (run-hooks 'multi-indirect-buffer-hook))))))))) + +(defun multi-map-over-chunks (beg end thunk) + "For all chunks between BEG and END, execute THUNK. +THUNK is a function of no args. It is executed with point at the +beginning of the chunk and with the buffer narrowed to the chunk." + (save-excursion + (save-window-excursion + (goto-char beg) + (while (< (point) end) + (multi-select-buffer) + (save-restriction + (multi-narrow-to-chunk) + (funcall thunk) + (goto-char (point-max))) + (unless (multi-next-chunk-start) + (goto-char (point-max))))))) + +;; We need this for asynchronous fontification by jit-lock, even +;; though we're redefining `fontification-functions'. +(defun multi-fontify-region (beg end loudly) + "Multi-mode font-lock fontification function. +Fontifies chunk-by chunk within the region. +Assigned to `font-lock-fontify-region-function'." + (let* ((modified (buffer-modified-p)) + (buffer-undo-list t) + (inhibit-read-only t) + (inhibit-point-motion-hooks t) + (inhibit-modification-hooks t) + deactivate-mark) + (font-lock-unfontify-region beg end) + (save-restriction + (widen) + (multi-map-over-chunks + beg end (lambda () + (if (and font-lock-mode font-lock-keywords) + (funcall multi-normal-fontify-function + (point-min) (point-max) loudly))))) + ;; In case font-lock isn't done for some mode: + (put-text-property beg end 'fontified t) + (when (and (not modified) (buffer-modified-p)) + (set-buffer-modified-p nil)))) + +;; I'm not sure it's worth trying to support non-font-lock +;; fontification functions like this (see this file's commentary). +(defun multi-fontify (start) + "Multi-mode fontification function. +Fontifies chunk-by-chunk within the region from START for up to +`multi-fontification-chunk-size' characters." + (save-restriction + (multi-narrow-to-chunk) + (run-hook-with-args 'multi-normal-fontify-functions start))) + +(defun multi-create-index () + "Create Imenu index alist for the currently-selected buffer. +Works piece-wise in all the chunks with the same major mode. +Assigned to `imenu-create-index-function'." + (let ((selected-mode major-mode) + imenu-alist ; accumulator + last mode) + (multi-map-over-chunks + (point-min) (point-max) + (lambda () + (if (eq major-mode selected-mode) + ;; Index this chunk and merge results with accumulator. + (dolist (elt (funcall multi-late-index-function)) + (if (not (listp (cdr elt))) + (push elt imenu-alist) ; normal element + (let ((elt2 (assoc (car elt) imenu-alist))) ; submenu + ;; Fixme: Assumes only a single level of submenu. + (if elt2 + (setcdr elt2 (append (cdr elt) (cdr elt2))) + (push elt imenu-alist)))))))) + imenu-alist)) + +(defun multi-next-chunk-start () + "Move to the start of the next chunk." + (widen) + (goto-char (nth 2 (multi-find-mode-at))) + (unless (eobp) + (forward-char) + t)) + +(defun multi-narrow-to-chunk () + "Narrow to the current chunk." + (interactive) + (unless (= (point-min) (point-max)) + (apply #'narrow-to-region (cdr (multi-find-mode-at))))) + +(defun multi-select-buffer () + "Select the appropriate (indirect) buffer corresponding to point's context." + ;; It may help to catch errors here. If there are context-dependent + ;; errors, it may well work correctly when point changes, but if it + ;; gets an error, it will be removed from post-command-hook and there + ;; won't be useful debugging context anyway. + (condition-case () + (let ((buffer (cdr (assoc (car (multi-find-mode-at)) + multi-indirect-buffers-alist)))) + (unless (eq buffer (current-buffer)) + (let* ((point (point)) + (window-start (window-start)) + (visible (pos-visible-in-window-p)) + (oldbuf (current-buffer))) + (when (buffer-live-p buffer) + (switch-to-buffer buffer) + (bury-buffer oldbuf) + (goto-char point) + ;; Avoid the display jumping around. + (when visible + (set-window-start (get-buffer-window buffer t) window-start)) + (unless (eq buffer oldbuf) + (run-hooks 'multi-select-mode-hook)))))) + (error nil))) + +(defvar multi-mode-list (list t t t)) + +(defsubst multi-make-list (mode start end) + "Constructor for lists returned by elements of `multi-chunk-fns' &c. +Destructively modifies `multi-mode-list' to avoid consing in +`post-command-hook'." + (setcar multi-mode-list mode) + (setcar (cdr multi-mode-list) start) + (setcar (cddr multi-mode-list) end) + multi-mode-list) + +;; It would be nice to cache the results of this on text properties, +;; but that probably won't work well if chunks can be nested. In that +;; case, you can't just mark everything between delimiters -- you have +;; to consider other possible regions between them. For now, we do +;; the calculation each time, scanning outwards from point. +(defun multi-find-mode-at (&optional pos) + "Apply elements of `multi-chunk-fns' to determine major mode at POS. +Return a list (MODE START END), the value returned by the function in the +list for which START is closest to POS (and before it); i.e. the innermost +mode is selected. POS defaults to point." + (let ((fns multi-chunk-fns) + (start (point-min)) + (mode (with-current-buffer (multi-base-buffer) + major-mode)) + (end (point-max)) + (pos (or pos (point))) + val) + (save-restriction + (widen) + (dolist (fn multi-chunk-fns) + (setq val (funcall fn pos)) + (if (and val (or (not mode) + (>= (nth 1 val) start))) + (setq mode (nth 0 val) + start (nth 1 val) + end (nth 2 val))))) + (unless (and (<= start end) (<= pos end) (>= pos start)) + (error "Bad multi-mode selection: %s, %s" + (multi-make-list mode start end) pos)) + (if (= start end) + (setq end (1+ end))) + (multi-make-list mode start end))) + +;; This was basically for testing, and isn't a reasonable thing to use +;; otherwise. + +;; (define-derived-mode multi-mode fundamental-mode "" +;; "Pseudo major mode controlling multiple major modes apparently in a buffer. +;; Actually maintains multiple views of the data in indirect buffers and +;; switches between them according to the context of point with a post-command +;; hook. Depends on a specification of `multi-alist' in file variables." +;; ;; We need to do the work after file variables have been processed so +;; ;; that we can use a specification of `multi-alist'. +;; (set (make-local-variable 'hack-local-variables-hook) +;; #'multi-mode-install-modes)) + +(defun multi-mode-install-modes () + "Process `multi-alist' and create the appropriate buffers." + (if multi-alist + (let ((elt (pop multi-alist))) + (multi-install-mode (car elt) (cdr elt) t) + (dolist (elt multi-alist) + (multi-install-mode (car elt) (cdr elt)))) + (fundamental-mode) + (error "`multi-alist' not defined for multi-mode"))) + +;; In 21.3, Flyspell breaks things, apparently by getting an error in +;; post-command-hook and thus clobbering it. In development code it +;; doesn't do that, but does check indirect buffers it shouldn't. I'm +;; not sure exactly how this happens, but checking flyspell-mode in +;; the hook functions cures this. For the moment, we'll hack this up. +;; (Let's not bring advice into it...) +(eval-after-load "flyspell" + '(progn + (defalias 'flyspell-post-command-hook + `(lambda () + ,(concat (documentation 'flyspell-post-command-hook) + "\n\n[Wrapped by multi-mode.]") + (if flyspell-mode + (funcall ,(symbol-function 'flyspell-post-command-hook))))) + + (defalias 'flyspell-pre-command-hook + `(lambda () + (concat (documentation 'flyspell-pre-command-hook) + "\n\n[Wrapped by multi-mode.]") + (if 'flyspell-mode + (funcall ,(symbol-function 'flyspell-pre-command-hook))))))) + +(provide 'multi-mode) + +;;; multi-mode.el ends here Binary files differ |