diff options
Diffstat (limited to 'contrib/mmm/mmm-region.el')
-rw-r--r-- | contrib/mmm/mmm-region.el | 818 |
1 files changed, 0 insertions, 818 deletions
diff --git a/contrib/mmm/mmm-region.el b/contrib/mmm/mmm-region.el deleted file mode 100644 index 1b4975df..00000000 --- a/contrib/mmm/mmm-region.el +++ /dev/null @@ -1,818 +0,0 @@ -;;; mmm-region.el --- Manipulating and behavior of MMM submode regions - -;; Copyright (C) 2000 by Michael Abraham Shulman - -;; Author: Michael Abraham Shulman <viritrilbia@users.sourceforge.net> -;; Version: $Id$ - -;;{{{ GPL - -;; 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: - -;; This file provides the functions and variables to create, delete, -;; and inspect submode regions, as well as functions that make them -;; behave like the submode with respect to syntax tables, local maps, -;; font lock, etc. - -;; See mmm-class.el for functions which scan the buffer and decide -;; where to create regions. - -;;; Code: - -(require 'cl) -(require 'font-lock) -(require 'mmm-compat) -(require 'mmm-utils) -(require 'mmm-auto) -(require 'mmm-vars) - -;; INSPECTION -;;{{{ Current Overlays - -;; Emacs counts an overlay starting at POS as "at" POS, but not an -;; overlay ending at POS. XEmacs is more sensible and uses beg- and -;; end-stickiness to determine whether an endpoint is within an -;; extent. Here we want to act like XEmacs does. - -(defsubst mmm-overlay-at (&optional pos type) - "Return the highest-priority MMM Mode overlay at POS. -See `mmm-included-p' for the values of TYPE." - (car (mmm-overlays-at pos type))) - -(defun mmm-overlays-at (&optional pos type) - "Return a list of the MMM overlays at POS, in decreasing priority. -See `mmm-included-p' for the values of TYPE." - (or pos (setq pos (point))) - (mmm-sort-overlays - (remove-if-not - #'(lambda (ovl) - (and (overlay-get ovl 'mmm) - (mmm-included-p ovl pos type))) - ;; XEmacs complains about positions outside the buffer - (overlays-in (max (1- pos) (point-min)) - (min (1+ pos) (point-max)))))) - -(defun mmm-included-p (ovl pos &optional type) - "Return true if the overlay OVL contains POS. - -If OVL strictly contains POS, always return true. If OVL starts or -ends at POS, return true or false based on the value of TYPE, which -should be one of nil, `beg', `end', `none', or `all'. -* If TYPE is nil, return true for an overlay starting at POS only if - it is beg-sticky, and for one ending at POS only if it is end-sticky. -* If TYPE is `beg', return true for any overlay starting at POS but - false for any ending at POS. -* If TYPE is `end', return true for any overlay ending at POS but - false for any starting at POS. -* If TYPE is `all', return true for any overlay starting or ending at POS. -* If TYPE is `none' \(or any other value), return false for any - overlay starting or ending at POS." - (let ((beg (overlay-start ovl)) - (end (overlay-end ovl))) - (cond ((and (= beg pos) (= end pos)) - ;; Do the Right Thing for zero-width overlays - (case type - ((nil) (and (overlay-get ovl 'beg-sticky) - (overlay-get ovl 'end-sticky))) - ((none) nil) - (t t))) - ((= beg pos) - (case type - ((nil) (overlay-get ovl 'beg-sticky)) - ((beg all) t) - (t nil))) - ((= end pos) - (case type - ((nil) (overlay-get ovl 'end-sticky)) - ((end all) t) - (t nil))) - ((and (> end pos) (< beg pos)) - t)))) - -;;; `mmm-overlays-in' has been retired as altogether too confusing a -;;; name, when what is really meant is one of the following three: - -(defun mmm-overlays-containing (start stop) - "Return all MMM overlays containing the region START to STOP. -The overlays are returned in order of decreasing priority. No -attention is paid to stickiness." - (mmm-sort-overlays - (remove-if-not - #'(lambda (ovl) - (and (overlay-get ovl 'mmm) - (<= (overlay-start ovl) start) - (>= (overlay-end ovl) stop))) - (overlays-in (max start (point-min)) - (min stop (point-max)))))) - -(defun mmm-overlays-contained-in (start stop) - "Return all MMM overlays entirely contained in START to STOP. -The overlays are returned in order of decreasing priority. No -attention is paid to stickiness." - (mmm-sort-overlays - (remove-if-not - #'(lambda (ovl) - (and (overlay-get ovl 'mmm) - (>= (overlay-start ovl) start) - (<= (overlay-end ovl) stop))) - (overlays-in (max start (point-min)) - (min stop (point-max)))))) - -(defun mmm-overlays-overlapping (start stop) - "Return all MMM overlays overlapping the region START to STOP. -The overlays are returned in order of decreasing priority. No -attention is paid to stickiness." - (mmm-sort-overlays - (remove-if-not - #'(lambda (ovl) - (overlay-get ovl 'mmm)) - (overlays-in (max start (point-min)) - (min stop (point-max)))))) - -(defun mmm-sort-overlays (overlays) - "Sort OVERLAYS in order of decreasing priority." - (sort (copy-list overlays) - #'(lambda (x y) (> (or (overlay-get x 'priority) 0) - (or (overlay-get y 'priority) 0))))) - -;;}}} -;;{{{ Current Submode - -(defvar mmm-current-overlay nil - "What submode region overlay we think we are currently in. -May be out of date; call `mmm-update-current-submode' to correct it.") -(make-variable-buffer-local 'mmm-current-overlay) - -(defvar mmm-previous-overlay nil - "What submode region overlay we were in just before this one. -Set by `mmm-update-current-submode'.") -(make-variable-buffer-local 'mmm-previous-overlay) - -(defvar mmm-current-submode nil - "What submode we think we are currently in. -May be out of date; call `mmm-update-current-submode' to correct it.") -(make-variable-buffer-local 'mmm-current-submode) - -(defvar mmm-previous-submode nil - "What submode we were in just before this one. -Set by `mmm-update-current-submode'.") -(make-variable-buffer-local 'mmm-previous-submode) - -(defun mmm-update-current-submode (&optional pos) - "Update current and previous position variables to POS, or point. -Return non-nil if the current region changed. - -Also deletes overlays that ought to evaporate because their delimiters -have disappeared." - (mapc #'delete-overlay - (remove-if #'(lambda (ovl) - (or (not (eq (overlay-get ovl 'mmm-evap) 'front)) - (overlay-buffer (overlay-get ovl 'front)))) - (mmm-overlays-at pos))) - (let ((ovl (mmm-overlay-at pos))) - (if (eq ovl mmm-current-overlay) - nil - (setq mmm-previous-overlay mmm-current-overlay - mmm-previous-submode mmm-current-submode) - (setq mmm-current-overlay ovl - mmm-current-submode (if ovl (overlay-get ovl 'mmm-mode))) - t))) - -;; This function is, I think, mostly for hacking font-lock. -(defun mmm-set-current-submode (mode &optional pos) - "Set the current submode to MODE and the current region to whatever -region of that mode is present at POS, or nil if none." - (setq mmm-previous-overlay mmm-current-overlay - mmm-previous-submode mmm-current-submode) - (setq mmm-current-submode mode - mmm-current-overlay - (find-if #'(lambda (ovl) - (eq (overlay-get ovl 'mmm-mode) mode)) - (mmm-overlays-at (or pos (point)) 'all)))) - -(defun mmm-submode-at (&optional pos type) - "Return the submode at POS \(or point), or NIL if none. -See `mmm-included-p' for values of TYPE." - (let ((ovl (mmm-overlay-at pos type))) - (if ovl (overlay-get ovl 'mmm-mode)))) - -;;}}} -;;{{{ Delimiter Matching and Boundaries - -(defun mmm-match-front (ovl) - "Return non-nil if the front delimiter of OVL matches as it should. -Sets the match data to the front delimiter, if it is a regexp. -Otherwise, calls it as a function with point at the beginning of the -front delimiter overlay \(i.e. where the front delimiter ought to -start) and one argument being the region overlay. The function should -return non-nil if the front delimiter matches correctly, and set the -match data appropriately." - (let* ((front-ovl (overlay-get ovl 'front)) - (front (if front-ovl (overlay-get front-ovl 'match)))) - (when front - (save-excursion - (goto-char (overlay-start front-ovl)) - (if (stringp front) - ;; It's a regexp - (looking-at front) - ;; It's a function - (funcall front ovl)))))) - -(defun mmm-match-back (ovl) - "Return non-nil if the back delimiter of OVL matches as it should. -Sets the match data to the back delimiter, if it is a regexp. -Otherwise, calls it as a function with point at the beginning of the -back delimiter overlay \(i.e. where the back delimiter ought to start) -and one argument being the region overlay. The function should return -non-nil if the back delimiter matches correctly, and set the match -data appropriately." - (let* ((back-ovl (overlay-get ovl 'back)) - (back (if back-ovl (overlay-get back-ovl 'match)))) - (when back - (save-excursion - (goto-char (overlay-start back-ovl)) - (if (stringp back) - ;; It's a regexp - (looking-at back) - ;; It's a function - (funcall back ovl)))))) - -(defun mmm-front-start (ovl) - "Return the position at which the front delimiter of OVL starts." - (let ((front (overlay-get ovl 'front))) - ;; Overlays which have evaporated become "overlays in no buffer" - (if (and front (overlay-buffer front)) - (overlay-start front) - (overlay-start ovl)))) - -(defun mmm-back-end (ovl) - "Return the position at which the back delimiter of OVL ends." - (let ((back (overlay-get ovl 'back))) - ;; Overlays which have evaporated become "overlays in no buffer" - (if (and back (overlay-buffer back)) - (overlay-end back) - (overlay-end ovl)))) - -;;}}} - -;; CREATION & DELETION -;;{{{ Make Submode Regions - -(defun mmm-valid-submode-region (submode beg end) - "Check if the region between BEG and END is valid for SUBMODE. -This region must be entirely contained within zero or more existing -submode regions, none of which start or end inside it, and it must be -a valid child of the highest-priority of those regions, if any. -Signals errors, returns `t' if no error." - ;; First check if the placement is valid. Every existing region - ;; that overlaps this one must contain it in its entirety. - (let ((violators (set-difference - (mmm-overlays-overlapping beg end) - (mmm-overlays-containing beg end)))) - (if violators - (signal 'mmm-subregion-invalid-placement - violators))) - ;; Now check if it is inside a valid parent - (let ((parent-mode (mmm-submode-at beg 'beg))) - (and parent-mode - ;; TODO: Actually check parents here. For present purposes, - ;; we just make sure we aren't putting a submode inside one - ;; of the same type. Actually, what we should really be - ;; doing is checking classes/names of regions, not just the - ;; submodes. - (eq submode parent-mode) - (signal 'mmm-subregion-invalid-parent - (list parent-mode)))) - t) - -(defun* mmm-make-region - (submode beg end &key face - front back (evaporation 'front) - delimiter-mode front-face back-face - display-name - (match-front "") (match-back "") - (beg-sticky t) (end-sticky t) - name creation-hook - ) - "Make a submode region from BEG to END of SUBMODE. - -BEG and END are buffer positions or markers with BEG <= END \(although -see EVAPORATION below). SUBMODE is a major mode function or a valid -argument to `mmm-modename->function'. FACE is a valid display face. - -FRONT and BACK specify the positions of the front and back delimiters -for this region, if any. If FRONT is a buffer position or marker, the -front delimiter runs from it to BEG. FRONT can also be a two-element -list \(FRONT-BEG FRONT-END) specifying the exact position of the front -delimiter. One must have FRONT-BEG < FRONT-END <= BEG. - -Similarly, BACK may be a buffer position or marker, in which case the -back delimiter runs from END to BACK. BACK can also be a two-element -list \(BACK-BEG BACK-END) specifying the exact position, in which case -we must have END <= BACK-BEG < BACK-END. - -EVAPORATION specifies under what conditions this submode region should -disappear. -* If `nil', the region never disappears. This can cause serious - problems when using cut-and-paste and is not recommended. -* If the value is t, the region disappears whenever it has zero - length. This is recommended for manually created regions used for - temporary editing convenience. -* If the value is `front', the region will disappear whenever the text - in its front delimiter disappears, that is, whenever the overlay - which marks its front delimiter has zero width. -The default value is `front'. However, if the parameter FRONT is nil, -then this makes no sense, so the default becomes `t'. Note that if -EVAPORATION is `t', then an error is signalled if BEG = END. - -MATCH-FRONT \(resp. MATCH-BACK) is a regexp or function to match the -correct delimiters, see `mmm-match-front' \(resp. `mmm-match-back'). -It is ignored if FRONT \(resp. BACK) is nil. At present these are not -used much. - -DELIMITER-MODE specifies the major mode to use for delimiter regions. -A `nil' value means they remain in the primary mode. - -FACE, FRONT-FACE, and BACK-FACE, are faces to use for the region, the -front delimiter, and the back delimiter, respectively, under high -decoration \(see `mmm-submode-decoration-level'). - -BEG-STICKY and END-STICKY determine whether the front and back of the -region, respectively, are sticky with respect to new insertion. The -default is yes. - -NAME is a string giving the \"name\" of this submode region. Submode -regions with the same name are considered part of the same code -fragment and formatted accordingly. - -DISPLAY-NAME is a string to display in the mode line when point is in -this submode region. If nil or not given, the name associated with -SUBMODE is used. In delimiter regions, \"--\" is shown. - -CREATION-HOOK should be a function to run after the region is created, -with point at the start of the new region." - ;; Check placement of region and delimiters - (unless (if (eq evaporation t) - (< beg end) - (<= beg end)) - (signal 'mmm-subregion-invalid-placement (list beg end))) - (when front - (unless (listp front) - (setq front (list front beg))) - (unless (and (< (car front) (cadr front)) - (<= (cadr front) beg)) - (signal 'mmm-subregion-invalid-placement front))) - (when back - (unless (listp back) - (setq back (list end back))) - (unless (and (< (car back) (cadr back)) - (<= end (car back))) - (signal 'mmm-subregion-invalid-placement back))) - (setq submode (mmm-modename->function submode)) - ;; Check embedding in existing regions - (mmm-valid-submode-region submode beg end) - (mmm-mode-on) - (when submode - (mmm-update-mode-info submode)) - (and (not front) (eq evaporation 'front) (setq evaporation t)) - (let ((region-ovl - (mmm-make-overlay submode beg end name face beg-sticky end-sticky - (or (eq evaporation t) nil) display-name))) - ;; Save evaporation type for checking later - (overlay-put region-ovl 'mmm-evap evaporation) - ;; Calculate priority to supersede anything already there. - (overlay-put region-ovl 'priority (length (mmm-overlays-at beg))) - ;; Make overlays for the delimiters, with appropriate pointers. - (when front - (let ((front-ovl - (mmm-make-overlay delimiter-mode (car front) (cadr front) - nil front-face nil nil t "--" t))) - (overlay-put region-ovl 'front front-ovl) - (overlay-put front-ovl 'region region-ovl) - (overlay-put front-ovl 'match match-front))) - (when back - (let ((back-ovl - (mmm-make-overlay delimiter-mode (car back) (cadr back) - nil back-face nil nil t "--" t))) - (overlay-put region-ovl 'back back-ovl) - (overlay-put back-ovl 'region region-ovl) - (overlay-put back-ovl 'match match-back))) - ;; Update everything and run all the hooks - (mmm-save-all - (goto-char (overlay-start region-ovl)) - (mmm-set-current-submode submode) - (mmm-set-local-variables submode) - (mmm-run-submode-hook submode) - (when creation-hook - (funcall creation-hook)) - (mmm-save-changed-local-variables region-ovl submode)) - (setq mmm-previous-submode submode - mmm-previous-overlay region-ovl) - (mmm-update-submode-region) - region-ovl)) - -(defun mmm-make-overlay (submode beg end name face beg-sticky end-sticky evap - &optional display-name delim) - "Internal function to make submode overlays. -Does not handle delimiters. Use `mmm-make-region'." - (let ((ovl (make-overlay beg end nil (not beg-sticky) end-sticky))) - (mapc - #'(lambda (pair) (overlay-put ovl (car pair) (cadr pair))) - `((mmm t) ; Mark all submode overlays - (mmm-mode ,submode) - ,@(if delim '((delim t)) nil) - (mmm-local-variables - ;; Have to be careful to make new list structure here - ,(list* (list 'font-lock-cache-state nil) - (list 'font-lock-cache-position (make-marker)) - (copy-tree - (cdr (assq submode mmm-region-saved-locals-defaults))))) - (name ,name) - (display-name ,display-name) - ;; Need to save these, because there's no way of accessing an - ;; overlay's official "front-advance" parameter once it's created. - (beg-sticky ,beg-sticky) - (end-sticky ,end-sticky) - ;; These have special meaning to Emacs - (,mmm-evaporate-property ,evap) - (face ,(mmm-get-face face submode delim)) - )) - ovl)) - -(defun mmm-get-face (face submode &optional delim) - (cond ((= mmm-submode-decoration-level 0) nil) - ((and (= mmm-submode-decoration-level 2) face) face) - (delim 'mmm-delimiter-face) - (submode 'mmm-default-submode-face))) - -;;}}} -;;{{{ Clear Overlays - -;; See also `mmm-clear-current-region'. - -(defun mmm-clear-overlays (&optional start stop strict) - "Clears all MMM overlays overlapping START and STOP. -If STRICT, only clear those entirely included in that region." - (mapc #'delete-overlay - (if strict - (mmm-overlays-contained-in (or start (point-min)) - (or stop (point-max))) - (mmm-overlays-overlapping (or start (point-min)) - (or stop (point-max))))) - (mmm-update-submode-region)) - -;;}}} - -;; BASIC UPDATING -;;{{{ Submode Info - -(defun mmm-update-mode-info (mode &optional force) - "Save the global-saved and buffer-saved variables for MODE. -Global saving is done on properties of the symbol MODE and buffer -saving in `mmm-buffer-saved-locals'. This function must be called for -both the dominant mode and all submodes, in each file. Region-saved -variables are initialized from `mmm-region-saved-locals-defaults', -which is set here as well. See `mmm-save-local-variables'. If FORCE -is non-nil, don't quit if the info is already there." - (let ((buffer-entry (assq mode mmm-buffer-saved-locals)) - (region-entry (assq mode mmm-region-saved-locals-defaults)) - global-vars buffer-vars region-vars - ;; kludge for XEmacs 20 - (html-helper-build-new-buffer nil)) - (unless (and (not force) - (get mode 'mmm-local-variables) - buffer-entry - region-entry) - (save-excursion - (let ((filename (buffer-file-name))) - ;; On errors, the temporary buffers don't get deleted, so here - ;; we get rid of any old ones that may be hanging around. - (when (buffer-live-p (get-buffer mmm-temp-buffer-name)) - (with-current-buffer (get-buffer mmm-temp-buffer-name) - (set-buffer-modified-p nil) - (kill-buffer (current-buffer)))) - ;; Now make a new temporary buffer. - (set-buffer (mmm-make-temp-buffer (current-buffer) - mmm-temp-buffer-name)) - ;; Handle stupid modes that need the file name set - (if (memq mode mmm-set-file-name-for-modes) - (setq buffer-file-name filename))) - (funcall mode) - (when (featurep 'font-lock) - ;; XEmacs doesn't have global-font-lock-mode (or rather, it - ;; has nothing but global-font-lock-mode). - (when (or mmm-xemacs - ;; Code copied from font-lock.el to detect when font-lock - ;; should be on via global-font-lock-mode. - (and (or font-lock-defaults - (with-no-warnings - (assq major-mode font-lock-defaults-alist)) - (assq major-mode font-lock-keywords-alist)) - (or (eq font-lock-global-modes t) - (if (eq (car-safe font-lock-global-modes) 'not) - (not (memq major-mode - (cdr font-lock-global-modes))) - (memq major-mode font-lock-global-modes))))) - ;; Don't actually fontify in the temp buffer, but note - ;; that we should fontify when we use this mode. - (put mode 'mmm-font-lock-mode t)) - ;; Get the font-lock variables - (when mmm-font-lock-available-p - ;; To fool `font-lock-add-keywords' - (let ((font-lock-mode t)) - (mmm-set-font-lock-defaults))) - ;; These can't be in the local variables list, because we - ;; replace their actual values, but we want to use their - ;; original values elsewhere. - (unless (and mmm-xemacs (= emacs-major-version 20)) - ;; XEmacs 20 doesn't have this variable. This effectively - ;; prevents the MMM font-lock support from working, but we - ;; just ignore it and go on, to prevent an error message. - (put mode 'mmm-fontify-region-function - font-lock-fontify-region-function)) - (put mode 'mmm-beginning-of-syntax-function - ;font-lock-beginning-of-syntax-function)) - syntax-begin-function)) - ;; Get variables - (setq global-vars (mmm-get-locals 'global) - buffer-vars (mmm-get-locals 'buffer) - region-vars (mmm-get-locals 'region)) - (put mode 'mmm-mode-name mode-name) - (set-buffer-modified-p nil) - (kill-buffer (current-buffer))) - (put mode 'mmm-local-variables global-vars) - (if buffer-entry - (setcdr buffer-entry buffer-vars) - (push (cons mode buffer-vars) mmm-buffer-saved-locals)) - (if region-entry - (setcdr region-entry region-vars) - (push (cons mode region-vars) - mmm-region-saved-locals-defaults))))) - -;;}}} -;;{{{ Updating Hooks - -(defun mmm-update-submode-region () - "Update all MMM properties correctly for the current position. -This function and those it calls do the actual work of setting the -different keymaps, syntax tables, local variables, etc. for submodes." - (when (mmm-update-current-submode) - (mmm-save-changed-local-variables mmm-previous-overlay - mmm-previous-submode) - (let ((mode (or mmm-current-submode mmm-primary-mode))) - (mmm-update-mode-info mode) - (mmm-set-local-variables mode) - (mmm-enable-font-lock mode)) - (mmm-set-mode-line) - (dolist (func (if mmm-current-overlay - (overlay-get mmm-current-overlay 'entry-hook) - mmm-primary-mode-entry-hook)) - (ignore-errors (funcall func))))) - -(defun mmm-add-hooks () - (add-hook 'post-command-hook 'mmm-update-submode-region nil 'local)) - -(defun mmm-remove-hooks () - (remove-hook 'post-command-hook 'mmm-update-submode-region 'local)) - -;;}}} -;;{{{ Local Variables - -(defun mmm-get-local-variables-list (type mode) - "Filter `mmm-save-local-variables' to match TYPE and MODE. -Return a list \(VAR ...). In some cases, VAR will be a cons cell -\(GETTER . SETTER) -- see `mmm-save-local-variables'." - (mapcan #'(lambda (element) - (and (if (and (consp element) - (cdr element) - (cadr element)) - (eq (cadr element) type) - (eq type 'global)) - (if (and (consp element) - (cddr element) - (not (eq (caddr element) t))) - (if (functionp (caddr element)) - (funcall (caddr element)) - (member mode (caddr element))) - t) - (list (if (consp element) (car element) element)))) - mmm-save-local-variables)) - -(defun mmm-get-locals (type) - "Get the local variables and values for TYPE from this buffer. -Return \((VAR VALUE) ...). In some cases, VAR will be of the form -\(GETTER . SETTER) -- see `mmm-save-local-variables'." - (mapcan #'(lambda (var) - (if (consp var) - `((,var ,(funcall (car var)))) - (and (boundp var) - ;; This seems logical, but screws things up. - ;;(local-variable-p var) - `((,var ,(symbol-value var)))))) - (mmm-get-local-variables-list type major-mode))) - -(defun mmm-get-saved-local (mode var) - "Get the value of the local variable VAR saved for MODE, if any." - (cadr (assq var (mmm-get-saved-local-variables mode)))) - -(defun mmm-set-local-variables (mode) - "Set all the local variables saved for MODE. -Looks up both global, buffer, and region saves." - (mapcar #'(lambda (var) - ;; (car VAR) may be (GETTER . SETTER) - (if (consp (car var)) - (funcall (cdar var) (cadr var)) - (make-local-variable (car var)) - (set (car var) (cadr var)))) - (mmm-get-saved-local-variables mode))) - -(defun mmm-get-saved-local-variables (mode) - (append (get mode 'mmm-local-variables) - (cdr (assq mode mmm-buffer-saved-locals)) - (let ((ovl (mmm-overlay-at (point)))) - (if ovl - (overlay-get ovl 'mmm-local-variables) - mmm-region-saved-locals-for-dominant)))) - -(defun mmm-save-changed-local-variables (ovl mode) - "Save by-buffer and by-region variables for OVL and MODE. -Called when we move to a new submode region, with OVL and MODE the -region and mode for the previous position." - (let ((buffer-vars (cdr (assq (or mode mmm-primary-mode) - mmm-buffer-saved-locals))) - (region-vars (if ovl - (overlay-get ovl 'mmm-local-variables) - mmm-region-saved-locals-for-dominant)) - (set-local-value - #'(lambda (var) - (setcar (cdr var) - ;; (car VAR) may be (GETTER . SETTER) - (if (consp (car var)) - (funcall (caar var)) - (symbol-value (car var))))))) - (mapc set-local-value buffer-vars) - (mapc set-local-value region-vars))) - -(defun mmm-clear-local-variables () - "Clear all buffer- and region-saved variables for current buffer." - (setq mmm-buffer-saved-locals () - mmm-region-saved-locals-defaults () - mmm-region-saved-locals-for-dominant ())) - -;;}}} - -;; FONT LOCK -;;{{{ Enable Font Lock - -(defun mmm-enable-font-lock (mode) - "Turn on font lock if it is not already on and MODE enables it." - (mmm-update-mode-info mode) - (and mmm-font-lock-available-p - (not font-lock-mode) - (get mode 'mmm-font-lock-mode) - (font-lock-mode 1))) - -(defun mmm-update-font-lock-buffer () - "Turn on font lock iff any mode in the buffer enables it." - (when mmm-font-lock-available-p - (if (some #'(lambda (mode) - (get mode 'mmm-font-lock-mode)) - (cons mmm-primary-mode - (mapcar #'(lambda (ovl) - (overlay-get ovl 'mmm-mode)) - (mmm-overlays-overlapping - (point-min) (point-max))))) - (font-lock-mode 1) - (font-lock-mode 0)))) - -(defun mmm-refontify-maybe (&optional start stop) - "Re-fontify from START to STOP, or entire buffer, if enabled." - (and font-lock-mode - (if (or start stop) - (font-lock-fontify-region (or start (point-min)) - (or stop (point-max))) - (font-lock-fontify-buffer)))) - -;;}}} -;;{{{ Get Submode Regions - -;;; In theory, these are general functions that have nothing to do -;;; with font-lock, but they aren't used anywhere else, so we might as -;;; well have them close. - -(defun mmm-submode-changes-in (start stop) - "Return a list of all submode-change positions from START to STOP. -The list is sorted in order of increasing buffer position." - (sort (remove-duplicates - (list* start stop - (mapcan #'(lambda (ovl) - `(,(overlay-start ovl) - ,(overlay-end ovl))) - (mmm-overlays-overlapping start stop)))) - #'<)) - -(defun mmm-regions-in (start stop &optional flag delim) - "Return a list of regions of the form (MODE BEG END) whose disjoint -union covers the region from START to STOP, including delimiters." - (let ((regions - (maplist #'(lambda (pos-list) - (if (cdr pos-list) - (list (or (mmm-submode-at (car pos-list) 'beg) - mmm-primary-mode) - (car pos-list) (cadr pos-list)))) - (mmm-submode-changes-in start stop)))) - (setcdr (last regions 2) nil) - regions)) - - -(defun mmm-regions-alist (start stop) - "Return a list of lists of the form \(MODE . REGIONS) where REGIONS -is a list of elements of the form \(BEG END). The disjoint union all -of the REGIONS covers START to STOP." - (let ((regions (mmm-regions-in start stop))) - (mapcar #'(lambda (mode) - (cons mode - (mapcan #'(lambda (region) - (if (eq mode (car region)) - (list (cdr region)))) - regions))) - ;; All the modes - (remove-duplicates (mapcar #'car regions))))) - -;;}}} -;;{{{ Fontify Regions - -(defun mmm-fontify-region (start stop &optional loudly) - "Fontify from START to STOP keeping track of submodes correctly." - (when loudly - (message "Fontifying %s with submode regions..." (buffer-name))) - ;; Necessary to catch changes in font-lock cache state and position. - (mmm-save-changed-local-variables - mmm-current-overlay mmm-current-submode) - ;; For some reason `font-lock-fontify-block' binds this to nil, thus - ;; preventing `mmm-beginning-of-syntax' from doing The Right Thing. - ;; I don't know why it does this, but let's undo it here. - (let ((;font-lock-beginning-of-syntax-function - syntax-begin-function 'mmm-beginning-of-syntax)) - (mapc #'(lambda (elt) - (when (get (car elt) 'mmm-font-lock-mode) - (mmm-fontify-region-list (car elt) (cdr elt)))) - (mmm-regions-alist start stop))) - ;; With jit-lock, this causes blips in the mode line and menus. - ;; Shouldn't be necessary here, since it's in post-command-hook too. - ;;(mmm-update-submode-region) - (when loudly (message nil))) - -(defun mmm-fontify-region-list (mode regions) - "Fontify REGIONS, each like \(BEG END), in mode MODE." - (save-excursion - (let (;(major-mode mode) - (func (get mode 'mmm-fontify-region-function))) - (mapc #'(lambda (reg) - (goto-char (car reg)) - ;; Here we do the same sort of thing that - ;; `mmm-update-submode-region' does, but we force it - ;; to use a specific mode, and don't save anything, - ;; fontify, or change the mode line. - (mmm-set-current-submode mode) - (mmm-set-local-variables mode) - (funcall func (car reg) (cadr reg) nil) - ;; Catch changes in font-lock cache. - (mmm-save-changed-local-variables - mmm-current-overlay mmm-current-submode)) - regions)))) - -;;}}} -;;{{{ Beginning of Syntax - -(defun mmm-beginning-of-syntax () - (goto-char - (let ((ovl (mmm-overlay-at (point))) - (func (get (or mmm-current-submode mmm-primary-mode) - 'mmm-beginning-of-syntax-function))) - (max (if ovl (overlay-start ovl) (point-min)) - (if func (progn (funcall func) (point)) (point-min)) - (point-min))))) - -;;}}} - -(provide 'mmm-region) - -;;; mmm-region.el ends here
\ No newline at end of file |