From 3c5b50aa498a7434a100ca7c22d87cb3e1bb4cb2 Mon Sep 17 00:00:00 2001 From: "Toby S. Cubitt" Date: Sat, 7 Feb 2015 01:09:35 +0000 Subject: [PATCH] Add auto-overlays package. --- packages/auto-overlays/README | 391 +++ packages/auto-overlays/auto-overlay-common.el | 228 ++ packages/auto-overlays/auto-overlay-flat.el | 193 ++ packages/auto-overlays/auto-overlay-line.el | 106 + .../auto-overlays/auto-overlay-manual.info | 2246 +++++++++++++++++ packages/auto-overlays/auto-overlay-nested.el | 219 ++ packages/auto-overlays/auto-overlay-self.el | 321 +++ packages/auto-overlays/auto-overlay-word.el | 70 + .../auto-overlays/auto-overlays-compat.el | 51 + packages/auto-overlays/auto-overlays.el | 1710 +++++++++++++ packages/auto-overlays/dir | 19 + 11 files changed, 5554 insertions(+) create mode 100644 packages/auto-overlays/README create mode 100644 packages/auto-overlays/auto-overlay-common.el create mode 100644 packages/auto-overlays/auto-overlay-flat.el create mode 100644 packages/auto-overlays/auto-overlay-line.el create mode 100644 packages/auto-overlays/auto-overlay-manual.info create mode 100644 packages/auto-overlays/auto-overlay-nested.el create mode 100644 packages/auto-overlays/auto-overlay-self.el create mode 100644 packages/auto-overlays/auto-overlay-word.el create mode 100644 packages/auto-overlays/auto-overlays-compat.el create mode 100644 packages/auto-overlays/auto-overlays.el create mode 100644 packages/auto-overlays/dir diff --git a/packages/auto-overlays/README b/packages/auto-overlays/README new file mode 100644 index 000000000..120b9016a --- /dev/null +++ b/packages/auto-overlays/README @@ -0,0 +1,391 @@ + + An Emacs overlay demarcates a region of text in a buffer, often +giving it a different face or changing other properties for that +region. There are many circumstance in which it might be useful to +create, update, and delete overlays automatically when text matches +some criterion, specified for example by regular expressions. This is +what the auto-overlays package addresses. It is intended as an Elisp +library, providing functions to be used by other Elisp packages, so +does not itself define any new interactive commands or minor modes. + +This documentation is an extract from the extensive Auto Overlays +Manual that comes with the package. For more detailed information and +examples, please read the manual. + + +1 Overview +********** + +The auto-overlays package automatically creates, updates and destroys +overlays based on regular expression matches in the buffer text. The +overlay is created when text is typed that matches an auto-overlay +regexp, and is destroyed if and when the matching text is changed so +that it no longer matches. + + The regexps are grouped into sets, and any number of different sets +of regexps can be active in the same buffer simultaneously. Regexps in +different sets are completely independent, and each set can be activated +and deactivated independently (*note Defining Regexps::). This allows +different Emacs modes to simultaneously make use of auto-overlays in the +same buffer. + + There are different "classes" of auto-overlay, used to define +different kinds of overlay behaviour. Some classes only require a single +regexp, others require separate regexps to define the start and end of +the overlay (*note Defining Regexps::). Any additional regexps, beyond +the minimum requirements, act as alternatives; if more than one of the +regexps matches overlapping regions of text, the one that appears +earlier in the list will take precedence. The predefined regexp classes +are: `word', `line', `self', `nested' and `flat', but the auto-overlay +package can easily be extended with new classes. + +`word' + These are used to define overlays that cover the text matched by + the regexp itself, so require a single regexp. An example use + would be to create overlays covering single words. + +`line' + These are used to define overlays that stretch from the text + matching the regexp to the end of the line, and require a single + regexp to define the start of the overlay. An example use would be + to create overlays covering single-line comments in programming + languages such as c. + +`self' + These are used to define overlays that stretch from one regexp + match to the next match for the same regexp, so naturally require + a single regexp. An example use would be to create overlays + covering strings delimited by `""'. + + Note that for efficiency reasons, `self' overlays are _not_ fully + updated when a new match is found. Instead, when a modification is + subsequently made at any position in the buffer after the new + match, the overlays are updated _up to_ that position. The update + occurs just _before_ the modification is made. Therefore, the + overlays at a given buffer position will not necessarily be + correct until a modification is made at or after that position + (*note To-Do::). + +`nested' + These are used to define overlays that start and end at different + regexp matches, and that can be nested one inside another. This + class requires separate start and end regexps. An example use + would be to create overlays between matching braces `{}'. + +`flat' + These are used to define overlays that start and end at different + regexp matches, but that can not be nested. Extra start matches + within one of these overlays are ignored. This class requires + separate start and end regexps. An example use would be to create + overlays covering multi-line comments in code, e.g. c++ block + comments delimited by `/*' and `*/'. + + By default, the entire text matching a regexp acts as the +"delimeter". For example, a `word' overlay will cover all the text +matching its regexp, and a `nested' overlay will start at the end of +the text matching its start regexp. Sometimes it is useful to be able +to have only part of the regexp match act as the delimeter. This can be +done by grouping that part of the regexp (*note Defining Regexps::). +Overlays will then start and end at the text matching the group, +instead of the text matching the entire regexp. + + Of course, automatically creating overlays isn't much use without +some way of setting their properties too. Overlay properties can be +defined along with the regexp, and are applied to any overlays created +by a match to that regexp. Certain properties have implications for +auto-overlay behaviour. + +`priority' + This is a standard Emacs overlay property (*note Overlay + Properties: (elisp)Overlay Properties.), but it is also used to + determine which regexp takes precedence when two or more regexps + in the same auto-overlay definition match overlapping regions of + text. It is also used to determine which regexp's properties take + precedence for overlays that are defined by separate start and end + matches. + +`exclusive' + Normally, different auto-overlay regexps coexist, and act + completely independently of one-another. However, if an + auto-overlay has non-nil `exclusive' and `priority' properties, + regexp matches within the overlay are ignored if they have lower + priority. An example use is ignoring other regexp matches within + comments in code. + + +2 Auto-Overlay Functions +************************ + +To use auto-overlays in an Elisp package, you must load the overlay +classes that you require by including lines of the form + (require 'auto-overlay-CLASS) + near the beginning of your package, where CLASS is the class name. +The standard classes are: `word', `line', `self', `nested' and `flat' +(*note Overview::), though new classes can easily be added (*note +Extending the Auto-Overlays Package::). + + Sometimes it is useful for a package to make use of auto-overlays if +any are defined, without necessarily requiring them. To facilitate +this, the relevant functions can be loaded separately from the rest of +the auto-overlays package with the line + (require 'auto-overlay-common) + This provides all the functions related to searching for overlays and +retrieving overlay properties. *Note Searching for Overlays::. Note that +there is no need to include this line if any auto-overlay classes are +`require'd, though it will do no harm. + + This section describes the functions that are needed in order to make +use of auto-overlays in an Elisp package. It does _not_ describe +functions related to extending the auto-overlays package. *Note +Extending the Auto-Overlays Package::. + +2.1 Defining Regexps +==================== + +An auto-overlay definition is a list of the form: + (CLASS &optional :id ENTRY-ID REGEXP1 REGEXP2 ...) + CLASS is one of the regexp classes described in the previous section +(*note Overview::). The optional `:id' property should be a symbol that +can be used to uniquely identify the auto-overlay definition. + + Each REGEXP defines one of the regexps that make up the auto-overlay +definition. It should be a list of the form + (RGXP &optional :edge EDGE :id SUBENTRY-ID @rest PROPERTY1 PROPERTY2 ...) + The `:edge' property should be one of the symbols `'start' or +`'end', and determines which edge of the auto-overlay this regexp +corresponds to. If `:edge' is not specified, it is assumed to be +`'start'. Auto-overlay classes that do not require separate `start' and +`end' regexps ignore this property. The `:id' property should be a +symbol that can be used to uniquely identify the regexp. Any further +elements in the list are cons cells of the form `(property . value)', +where PROPERTY is an overlay property name (a symbol) and VALUE its +value. In its simplest form, RGXP is a single regular expression. + + If only part of the regexp should act as the delimeter (*note +Overview::), RGXP should instead be a cons cell: + (RX . GROUP) + where RX is a regexp that contains at least one group (*note Regular +Expressions: (elisp)Regular Expressions.), and GROUP is an integer +identifying which group should act as the delimeter. + + If the overlay class requires additional groups to be specified, +RGXP should instead be a list: + (RX GROUP0 GROUP1 ...) + where RX is a regexp. The first GROUP0 still specifies the part that +acts as the delimeter, as before. If the entire regexp should act as +the delimeter, GROUP0 must still be supplied but should be set to 0 +(meaning the entire regexp). None of the standard classes make use of +any additional groups, but extensions to the auto-overlays package that +define new classes may. *Note Extending the Auto-Overlays Package::. + + The following functions are used to load and unload regexp +definitions: + +`(auto-overlay-load-definition SET-ID DEFINITION &optional POS)' + Load a new auto-overlay DEFINITION, which should be a list of the + form described above, into the set identified by the symbol + SET-ID. The optional parameter POS determines where in the set's + regexp list the new regexp is inserted. If it is `nil', the regexp + is added at the end. If it is `t', the regexp is added at the + beginning. If it is an integer, the regexp is added at that + position in the list. Whilst the position in the list has no + effect on overlay behaviour, it does determine the order in which + regexps are checked, so can affect efficiency. + +`(auto-overlay-load-regexp SET-ID ENTRY-ID REGEXP &optional POS)' + Load a new REGEXP, which should be a list of the form described + above, into the auto-overlay definition identified by the symbol + ENTRY-ID, in the set identified by the symbol SET-ID. REGEXP + should be a list of the form described above. The optional POS + determines the position of the regexp in the list of regexps + defining the auto-overlay, which can be significant for overlay + behaviour since it determines which regexp takes precedence when + two match the same text. + +`(auto-overlay-unload-set SET-ID)' + Unload the entire regexp set identified by the symbol SET-ID. + +`(auto-overlay-unload-definition SET-ID ENTRY-ID)' + Unload the auto-overlay definition identified by the symbol + ENTRY-ID from the set identified by the symbol SET-ID. + +`(auto-overlay-unload-regexp SET-ID ENTRY-ID SUBENTRY-ID)' + Unload the auto-overlay regexp identified by the symbol + SUBENTRY-ID from the auto-overlay definition identified by the + symbol ENTRY-ID in the set identified by the symbol SET-ID. + +`(auto-overlay-share-regexp-set SET-ID FROM-BUFFER @optional TO-BUFFER)' + Share the set of regexp definitions identified by the symbol + SET-ID in buffer `from-buffer' with the buffer TO-BUFFER, or the + current buffer if TO-BUFFER is null. The regexp set becomes common + to both buffers, and any changes made to it in one buffer, such as + loading and unloading regexp definitions, are also reflected in + the other buffer. However, the regexp set can still be enabled and + disabled independently in both buffers. The same regexp set can be + shared between any number of buffers. To remove a shared regexp + set from one of the buffers, simply unload the entire set from that + buffer using `auto-overlay-unload-regexp'. The regexp set will + remain defined in all the other buffers it was shared with. + +2.2 Starting and Stopping Auto-Overlays +======================================= + +A set of regexps is not active until it has been "started", and can be +deactivated by "stopping" it. When a regexp set is activated, the +entire buffer is scanned for regexp matches, and the corresponding +overlays created. Similarly, when a set is deactivated, all the overlays +are deleted. Note that regexp definitions can be loaded and unloaded +whether the regexp set is active or inactive, and that deactivating a +regexp set does _not_ delete its regexp definitions. + + Since scanning the whole buffer for regexp matches can take some +time, especially for large buffers, auto-overlay data can be saved to an +auxiliary file so that the overlays can be restored more quickly if the +same regexp set is subsequently re-activated. Of course, if the text in +the buffer is modified whilst the regexp set is disabled, or the regexp +definitions differ from those that were active when the overlay data was +saved, the saved data will be out of date. Auto-overlays automatically +checks if the text has been modified and, if it has, ignores the saved +data and re-scans the buffer. However, no check is made to ensure the +regexp definitions used in the buffer and saved data are consistent +(*note To-Do::); the saved data will be used even if the definitions +have changed. + + The usual time to save and restore overlay data is when a regexp set +is deactivated or activated. The auxilliary file name is then +constructed automatically from the buffer name and the set-id. However, +auto-overlays can also be saved and restored manually. + +`(auto-overlay-start SET-ID @optional BUFFER SAVE-FILE NO-REGEXP-CHECK)' + Activate the auto-overlay regexp set identified by the symbol + SET-ID in BUFFER, or the current buffer if the latter is `nil'. If + there is an file called `auto-overlay-'BUFFER-NAME`-'SET-ID in the + containing up-to-date overlay data, it will be used to restore the + auto-overlays (BUFFER-NAME is the name of the file visited by the + buffer, or the buffer name itself if there is none). Otherwise, the + entire buffer will be scanned for regexp matches. + + The string SAVE-FILE specifies the where to look for the file of + saved overlay data. If it is nil, it defaults to the current + directory. If it is a string specifying a relative path, then it is + relative to the current directory, whereas an absolute path + specifies exactly where to look. If it is a string specifying a + file name (with or without a full path, relative or absolute), + then it overrides the default file name and/or location. Any other + value of SAVE-FILE will cause the file of overlay data to be + ignored, even if it exists. + + If the overlays are being loaded from a file, but optional argument + no-regexp-check is non-nil, the file of saved overlays will be + used, but no check will be made to ensure regexp refinitions are + the same as when the overlays were saved. + +`(auto-overlay-stop SET-ID @optional BUFFER SAVE-FILE LEAVE-OVERLAYS)' + Deactivate the auto-overlay regexp set identified by the symbol + SET-ID in BUFFER, or the current buffer if the latter is `nil'. + All corresponding overlays will be deleted (unless the + LEAVE-OVERLAYS option is non-nil, which should only be used if the + buffer is about to be killed), but the regexp definitions are + preserved and can be reactivated later. + + If SAVE-FILE is non-nil, overlay data will be saved in an + auxilliary file called `auto-overlay-'BUFFER-NAME`-'SET-ID in the + current directory, to speed up subsequent reactivation of the + regexp set in the same buffer (BUFFER-NAME is the name of the file + visited by the buffer, or the buffer name itself if there is + none). If SAVE-FILE is a string, it overrides the default save + location, overriding either the directory if it only specifies a + path (relative paths are relative to the current directory), or + the file name if it only specifies a file name, or both. + +`(auto-overlay-save-overlays SET-ID @optional BUFFER FILE)' + Save auto-overlay data for the regexp set identified by the symbol + SET-ID in BUFFER, or the current buffer if `nil', to an auxilliary + file called FILE. If FILE is nil, the overlay data are saved to a + file called `auto-overlay-'BUFFER-NAME`-'SET-ID in the current + directory (BUFFER-NAME is the name of the file visited by the + buffer, or the buffer name itself if there is none). Note that + this is the only name that will be recognized by + `auto-overlay-start'. + +`(auto-overlay-load-overlays SET-ID @optional BUFFER FILE NO-REGEXP-CHECK)' + Load auto-overlay data for the regexp set identified by the symbol + SET-ID into BUFFER, or the current buffer if `nil', from an + auxilliary file called FILE. If FILE is nil, it attempts to load + the overlay data from a file called + `auto-overlay-'BUFFER-NAME`-'SET-ID in the current directory + (BUFFER-NAME is the name of the file visited by the buffer, or the + buffer name itself if there is none). If NO-REGEXP-CHECK is + no-nil, the saved overlays will be loaded even if different regexp + definitions were active when the overlays were saved. Returns `t' + if the overlays were successfully loaded, `nil' otherwise. + +2.3 Searching for Overlays +========================== + +Auto-overlays are just normal Emacs overlays, so any of the standard +Emacs functions can be used to search for overlays and retrieve overlay +properties. The auto-overlays package provides some additional +functions. + +`(auto-overlays-at-point @optional POINT PROP-TEST INACTIVE)' + Return a list of overlays overlapping POINT, or the point if POINT + is null. The list includes _all_ overlays, not just auto-overlays + (but see below). The list can be filtered to only return overlays + with properties matching criteria specified by PROP-TEST. This + should be a list defining a property test, with one of the + following forms (or a list of such lists, if more than one + property test is required): + (FUNCTION PROPERTY) + (FUNCTION PROPERTY VALUE) + (FUNCTION (PROPERTY1 PROPERTY2 ...) (VALUE1 VALUE2 ...)) + where FUNCTION is a function, PROPERTY is an overlay property name + (a symbol), and VALUE can be any value or lisp expression. For + each overlay, first the values corresponding to the PROPERTY names + are retrieved from the overlay and any VALUEs that are lisp + expressions are evaluated. Then FUNCTION is called with the + property values followed by the other values as its arguments. The + test is satisfied if the result is non-nil, otherwise it fails. + Tests are evaluated in order, but only up to the first failure. + Only overlays that satisfy all property tests are returned. + + All auto-overlays are given a non-nil `auto-overlay' property, so + to restrict the list to auto-overlays, PROP-TEST should include + the following property test: + ('identity 'auto-overlay) + For efficiency reasons, the auto-overlays package sometimes leaves + overlays hanging around in the buffer even when they should have + been deleted. These are marked with a non-nil `inactive' property. + By default, `auto-overlays-at-point' ignores these. A non-nil + INACTIVE will override this, causing inactive overlays to be + included in the returned list (assuming they pass all property + tests). + +`(auto-overlays-in START END @optional PROP-TEST WITHIN INACTIVE)' + Return a list of overlays overlapping the region between START and + END. The PROP-TEST and INACTIVE arguments have the same behaviour + as in `auto-overlays-at-point', above. If WITHIN is non-nil, only + overlays that are entirely within the region from START to END + will be returned, not overlays that extend outside that region. + +`(auto-overlay-highest-priority-at-point @optional POINT PROP-TEST)' + Return the highest priority overlay at POINT (or the point, of + POINT is null). The PROP-TEST argument has the same behaviour as + in `auto-overlays-at-point', above. An overlay's priority is + determined by the value of its `priority' property (*note Overlay + Properties: (elisp)Overlay Properties.). If two overlays have the + same priority, the innermost one takes precedence (i.e. the one + that begins later in the buffer, or if they begin at the same + point the one that ends earlier; if two overlays have the same + priority and extend over the same region, there is no way to + predict which will be returned). + +`(auto-overlay-local-binding SYMBOL @optional POINT)' + Return the "overlay-local" binding of SYMBOL at POINT (or the + point if POINT is null), or the current local binding if there is + no overlay binding. An "overlay-local" binding for SYMBOL is the + value of the overlay property called SYMBOL. If more than one + overlay at POINT has a non-nil SYMBOL property, the value from the + highest priority overlay is returned (see + `auto-overlay-highest-priority-at-point', above, for an + explanation of "highest priority"). diff --git a/packages/auto-overlays/auto-overlay-common.el b/packages/auto-overlays/auto-overlay-common.el new file mode 100644 index 000000000..19ddd346c --- /dev/null +++ b/packages/auto-overlays/auto-overlay-common.el @@ -0,0 +1,228 @@ +;;; auto-overlay-common.el --- general overlay functions + + +;; Copyright (C) 2005-2015 Free Software Foundation, Inc + +;; Author: Toby Cubitt +;; Maintainer: Toby Cubitt +;; URL: http://www.dr-qubit.org/emacs.php +;; Repository: http://www.dr-qubit.org/git/predictive.git + +;; This file is part of the 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 program 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 this program. If not, see . + + +;;; Code: + +(provide 'auto-overlay-common) + + +(defun auto-overlays-at-point (&optional point prop-test inactive) + "Return overlays overlapping POINT +(or the point, if POINT is null). If PROP-TEST is supplied, it +should be a list which specifies a property test with one of the +following forms (or a list of such lists if more than one +property test is required): + + (FUNCTION PROPERTY) + + (FUNCTION PROPERTY VALUE) + + (FUNCTION (PROPERTY1 PROPERTY2 ...) (VALUE1 VALUE2 ...)) + +where PROPERTY indicates an overlay property name (a symbol), and +VALUE indicates an arbitrary value or lisp expression. + +For each overlay overlapping POINT, first the values +corresponding to the property names are retrieved from the +overlay, then FUNCTION is called with the properties values +followed by the other values as its arguments. The test is +satisfied if the result is non-nil, otherwise it fails. Tests are +evaluated in order, but only up to the first failure. Only +overlays that satisfy all property tests are returned. + +If INACTIVE is non-nil, both active and inactive overlays are +returned (usually inactive ones are ignored). + +Note that this function returns any overlay. If you want to +restrict it to auto overlays, include '(identity auto-overlay) in +PROP-TEST." + (when (null point) (setq point (point))) + + (let (overlay-list) + ;; get overlays overlapping POINT and zero-length overlays at POINT + (setq overlay-list + (auto-overlays-in point point prop-test nil inactive)) + ;; get overlays that end at POINT + (dolist (o (auto-overlays-in (1- point) point prop-test nil inactive)) + (when (and (< (overlay-start o) point) + (= (overlay-end o) point)) + (push o overlay-list))) + ;; get overlays that start at POINT + (dolist (o (auto-overlays-in point (1+ point) prop-test nil inactive)) + (when (and (> (overlay-end o) point) + (= (overlay-start o) point)) + (push o overlay-list))) + + overlay-list) +) + + + +;; FIXME: get rid of INACTIVE argument +(defun auto-overlays-in (start end &optional prop-test within inactive) + "Return auto overlays overlapping region between START and END. + +If PROP-TEST is supplied, it should be a list which specifies a +property test with one of the following forms (or a list of such +lists if more than one property test is required): + + (FUNCTION PROPERTY) + + (FUNCTION PROPERTY VALUE) + + (FUNCTION (PROPERTY1 PROPERTY2 ...) (VALUE1 VALUE2 ...)) + +where PROPERTY indicates an overlay property name (a symbol), and +VALUE indicates an arbitrary value or lisp expression. + +For each overlay between START and END, first the values +corresponding to the property names are retrieved from the +overlay, then FUNCTION is called with the properties values +followed by the other values as its arguments. The test is +satisfied if the result is non-nil, otherwise it fails. Tests are +evaluated in order, but only up to the first failure. Only +overlays that satisfy all property tests are returned. + +If WITHIN is non-nil, only overlays entirely within START and END +are returned. If INACTIVE is non-nil, both active and inactive +overlays are returned (usually inactive ones are ignored). + +Note that this function returns any overlay. If you want to +restrict it to auto overlays, include '(identity auto-overlay) in +PROP-TEST." + + ;; make sure prop-test is a list of lists, even if there's only one, and + ;; exclude inactive overlays unless told not to + (cond + ((null prop-test) + (unless inactive (setq prop-test '((null inactive))))) + ((functionp (car prop-test)) + (if inactive + (setq prop-test (list prop-test)) + (setq prop-test (list '(null inactive) prop-test)))) + (t + (unless inactive (setq prop-test (push '(null inactive) prop-test))))) + + (let (overlay-list function prop-list value-list result) + ;; check properties of each overlay in region + (dolist (o (overlays-in start end)) + ;; check overlay is entirely within region + (if (and within + (or (< (overlay-start o) start) (> (overlay-end o) end))) + (setq result nil) + + ;; if it is, or we don't care + (setq result t) + (catch 'failed + ;; check if properties match + (dolist (test prop-test) + ;; (Note: the whole thing would be neater with something like + ;; (apply 'and (map ...)) but 'and is a special form, not a + ;; function, so can't be applied) + (setq function (nth 0 test)) + (unless (listp (setq prop-list (nth 1 test))) + (setq prop-list (list prop-list))) + (setq value-list nil) + (unless (or (< (length test) 3) + (and (setq value-list (nth 2 test)) ; nil isn't list + (listp value-list))) + (setq value-list (list value-list))) + + ;; apply the test + (setq result + (and result + (apply function + (append (mapcar (lambda (p) (overlay-get o p)) + prop-list) + value-list)))) + (when (null result) (throw 'failed nil))))) + + ;; add overlay to result list if its properties matched + (when result (push o overlay-list))) + ;; return result list + overlay-list) +) + + + +(defun auto-overlay-highest-priority-at-point (&optional point proptest) + "Return highest priority overlay at POINT (defaults to the point). + +If two overlays have the same priority, the innermost one takes +precedence (i.e. the one that begins later, or if they begin at +the same point the one that ends earlier). + +See `auto-overlays-at' for ane explanation of the PROPTEST argument." + + (unless point (setq point (point))) + + ;; get all overlays at point with a non-nil SYMBOL property + (let* ((overlay-list (auto-overlays-at-point point proptest)) + (overlay (pop overlay-list)) + p p1) + + ;; find the highest priority, innermost overlay + (dolist (o1 overlay-list) + (setq p (overlay-get overlay 'priority)) + (setq p1 (overlay-get o1 'priority)) + (when (or (and (null p) p1) + (and p p1 (> p1 p)) + (and (equal p1 p) + (or (> (overlay-start o1) (overlay-start overlay)) + (and (= (overlay-start o1) (overlay-start overlay)) + (< (overlay-end o1) (overlay-end o1)))))) + (setq overlay o1))) + + ;; return the overlay + overlay) +) + + + +(defun auto-overlay-local-binding (symbol &optional point only-overlay) + "Return \"overlay local \" binding of SYMBOL at POINT, +or the current local binding if there is no overlay binding. If +there is no overlay binding and SYMBOL is not bound, return +nil. POINT defaults to the point. + +If ONLY-OVERLAY is non-nil, only overlay bindings are +returned. If none exists at POINT, nil is returned + +An \"overlay local\" binding is created by giving an overlay a +non-nil value for a property named SYMBOL. If more than one +overlay at POINT has a non-nil SYMBOL property, the value from +the highest priority overlay is returned. + +See `auto-overlay-highest-priority-at-point' for a definition of +\"highest priority\"." + + (let ((overlay (auto-overlay-highest-priority-at-point + point `(identity ,symbol)))) + (if overlay + (overlay-get overlay symbol) + (and (not only-overlay) (boundp symbol) (symbol-value symbol))))) + +;; auto-overlay-common.el ends here diff --git a/packages/auto-overlays/auto-overlay-flat.el b/packages/auto-overlays/auto-overlay-flat.el new file mode 100644 index 000000000..c790059ff --- /dev/null +++ b/packages/auto-overlays/auto-overlay-flat.el @@ -0,0 +1,193 @@ +;;; auto-overlay-flat.el --- flat start/end-delimited automatic overlays + + +;; Copyright (C) 2005-2015 Free Software Foundation, Inc + +;; Author: Toby Cubitt +;; Maintainer: Toby Cubitt +;; URL: http://www.dr-qubit.org/emacs.php +;; Repository: http://www.dr-qubit.org/git/predictive.git + +;; This file is part of the 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 program 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 this program. If not, see . + + +;;; Code: + +(require 'auto-overlays) +(provide 'auto-overlay-flat) + + +;; set flat overlay parsing and suicide functions, and indicate class requires +;; separate start and end regexps +(put 'flat 'auto-overlay-parse-function 'auto-o-parse-flat-match) +(put 'flat 'auto-overlay-suicide-function 'auto-o-flat-suicide) +(put 'flat 'auto-overlay-complex-class t) + + + +(defun auto-o-parse-flat-match (o-match) + ;; Perform any necessary updates of auto overlays due to a match for a flat + ;; regexp. + + (let (o-parent) + (cond + + ;; if match is for a start regexp... + ((eq (auto-o-edge o-match) 'start) + ;; if match is within an existing overlay, ignore match + (unless (auto-overlays-at-point + (overlay-get o-match 'delim-end) ; FIXME: is this right? + `((identity auto-overlay) + (eq set-id ,(overlay-get o-match 'set-id)) + (eq definition-id ,(overlay-get o-match 'definition-id)))) + + ;; otherwise, look for next end-match... + (let ((o-end (auto-o-next-flat-match o-match 'end))) + (cond + ;; if there is one that has a parent, steal start of the parent + ;; overlay + ((and o-end (overlay-get o-end 'parent)) + (auto-o-match-overlay (overlay-get o-end 'parent) o-match) + nil) ; return nil since haven't created any overlays + + ;; if there is one but it's parentless, make a new overlay, match + ;; it with O-MATCH and the next end-match, and return it + (o-end + (let ((pos (overlay-get o-match 'delim-end))) + (setq o-parent (make-overlay pos pos nil nil 'rear-advance))) + (overlay-put o-parent 'auto-overlay t) + (overlay-put o-parent 'set-id (overlay-get o-match 'set-id)) + (overlay-put o-parent 'definition-id + (overlay-get o-match 'definition-id)) + (auto-o-match-overlay o-parent o-match o-end) + o-parent) + + (t ;; otherwise, make a new, end-unmatched overlay and return it + (let ((pos (overlay-get o-match 'delim-end))) + (setq o-parent (make-overlay pos pos nil nil 'read-advance)) + (overlay-put o-parent 'auto-overlay t) + (overlay-put o-parent 'set-id (overlay-get o-match 'set-id)) + (overlay-put o-parent 'definition-id + (overlay-get o-match 'definition-id)) + (auto-o-match-overlay o-parent o-match 'unmatched) + o-parent)) + )))) + + + (t ;; if match is for an end regexp... + ;; if match is within existing overlay with same set-d and definition-id... + (when (setq o-parent + (car ; FIXME: is this right? + (auto-overlays-at-point + (overlay-get o-match 'delim-start) ; FIXME: is this right? + `((identity auto-overlay) + (eq set-id ,(overlay-get o-match 'set-id)) + (eq definition-id ,(overlay-get o-match 'definition-id)))))) + + ;; if overlay can simply be re-matched with new end-match, do so + (let ((o-end (overlay-get o-parent 'end)) + (o-start (auto-o-next-flat-match o-match 'start))) + (if (not (and o-end o-start + (<= (overlay-get o-start 'delim-end) + (overlay-get o-end 'delim-start)))) + (progn (auto-o-match-overlay o-parent nil o-match) nil) + + ;; if overlay was end-matched, and there's a start match within + ;; existing overlay that will be "unmasked" when end is stolen, + ;; create a new overlay between that start match and the end match + ;; we're stealing from + (auto-o-match-overlay o-parent nil o-match) + (let ((pos (overlay-get o-start 'delim-end))) + (setq o-parent (make-overlay pos pos nil nil 'read-advance)) + (overlay-put o-parent 'auto-overlay t) + (overlay-put o-parent 'set-id (overlay-get o-match 'set-id)) + (overlay-put o-parent 'definition-id + (overlay-get o-match 'definition-id)) + (auto-o-match-overlay o-parent o-start o-end)) + o-parent)) ; return newly created overlay + )))) +) + + + +(defun auto-o-flat-suicide (o-self) + ;; Called when match no longer matches. Unmatch the match overlay O-SELF, + ;; re-matching or deleting its parent overlay as necessary. + + (let ((o-parent (overlay-get o-self 'parent))) + (cond + ;; if we have no parent, don't need to do anything + ((null o-parent)) + + ;; if we're a start-match... + ((eq (auto-o-edge o-self) 'start) + ;; if parent is end-unmatched, delete parent + (if (null (overlay-get o-parent 'end)) + (auto-o-delete-overlay o-parent) + + ;; otherwise, look for next start match... + (let ((o-start (auto-o-next-flat-match o-self 'start))) + ;; if there is one, match parent with it + (if o-start + (auto-o-match-overlay o-parent o-start) + ;; otherwise, delete parent + (auto-o-delete-overlay o-parent))))) + + + (t ;; if we're an end-match, look for next end-match... + (let ((o-start (overlay-get o-parent 'start)) + (o-end (auto-o-next-flat-match o-self 'end))) + (cond + ;; if there is one, match parent with it + (o-end + ;; if end-match already has a parent, delete it as its now + ;; superfluous (note: no need to parse, since parent overlay will be + ;; extended to cover same region anyway) + (when (overlay-get o-end 'parent) + (auto-o-delete-overlay (overlay-get o-end 'parent) 'no-parse)) + (auto-o-match-overlay o-parent nil o-end)) + + (t ;; otherwise, make parent end-unmatched + (auto-o-match-overlay o-parent nil 'unmatched))))) + )) +) + + + +(defun auto-o-next-flat-match (o-match edge) + ;; Find first match overlay for EDGE ('start of 'end) after match overlay + ;; O-MATCH in buffer, with same set-id and definition-id as O-MATCH. + + ;; get sorted list of matching overlays after O-MATCH + (let ((o-list + (sort (auto-overlays-in + (overlay-start o-match) (point-max) ; FIXME: is start right? + `((identity auto-overlay-match) + (eq set-id ,(overlay-get o-match 'set-id)) + (eq definition-id ,(overlay-get o-match 'definition-id)) + (,(lambda (set-id definition-id regexp-id edge) + (eq (auto-o-entry-edge set-id definition-id regexp-id) + edge)) + (set-id definition-id regexp-id) (,edge)))) + (lambda (a b) (<= (overlay-start a) (overlay-start b)))))) + ;; if searching for same EDGE as O-MATCH, first overlay in list is always + ;; O-MATCH itself, so we drop it + (if (eq (auto-o-edge o-match) edge) (nth 1 o-list) (car o-list))) +) + + + +;;; auto-overlay-flat.el ends here diff --git a/packages/auto-overlays/auto-overlay-line.el b/packages/auto-overlays/auto-overlay-line.el new file mode 100644 index 000000000..0241e978f --- /dev/null +++ b/packages/auto-overlays/auto-overlay-line.el @@ -0,0 +1,106 @@ +;;; auto-overlay-line.el --- automatic overlays for single lines + + +;; Copyright (C) 2005-2015 Free Software Foundation, Inc + +;; Author: Toby Cubitt +;; Maintainer: Toby Cubitt +;; URL: http://www.dr-qubit.org/emacs.php +;; Repository: http://www.dr-qubit.org/git/predictive.git + +;; This file is part of the 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 program 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 this program. If not, see . + + +;;; Code: + +(require 'auto-overlays) +(provide 'auto-overlay-line) + + +;; set line overlay parsing and suicide funtions +(put 'line 'auto-overlay-parse-function 'auto-o-parse-line-match) +(put 'line 'auto-overlay-suicide-function + (lambda (o) (auto-o-delete-overlay (overlay-get o 'parent)))) + + + +(defun auto-o-parse-line-match (o-match) + ;; Create overlay for a new line match. + (let ((o-new (make-overlay (overlay-get o-match 'delim-end) + (save-excursion + (goto-char (overlay-get o-match 'delim-end)) + (1+ (line-end-position)))))) + + ;; give new overlay some basic properties + (overlay-put o-new 'auto-overlay t) + (overlay-put o-new 'set-id (overlay-get o-match 'set-id)) + (overlay-put o-new 'definition-id (overlay-get o-match 'definition-id)) + ;; match start of new overlay with match + (auto-o-match-overlay o-new o-match nil) + ;; set overlay's modification hooks to ensure that it always extends to + ;; end of line + (overlay-put o-new 'modification-hooks + (cons 'auto-o-schedule-extend-line + (overlay-get o-new 'modification-hooks))) + ;; return new overlay + o-new)) + + +(defun auto-o-schedule-extend-line (o-self modified &rest unused) + ;; All line overlay modification hooks are set to this function, which + ;; schedules `auto-o-extend-line' to run after any suicide functions have + ;; been called, but before the overlays are updated. + (unless modified + (push (list 'auto-o-extend-line o-self) auto-o-pending-post-suicide))) + + + +(defun auto-o-extend-line (o-self) + ;; Checks if overlay still extends to end of line, and update the necessary + ;; if not. + + ;; if we haven't been deleted by a suicide function... + (when (overlay-buffer o-self) + (save-match-data + (let ((start (overlay-start o-self)) + (end (overlay-end o-self))) + (cond + ;; if we no longer extend to end of line... + ((null (string-match "\n" (buffer-substring-no-properties + (overlay-start o-self) + (overlay-end o-self)))) + ;; grow ourselves so we extend till end of line + (move-overlay o-self start (save-excursion + (goto-char (overlay-end o-self)) + (1+ (line-end-position)))) + ;; if we're exclusive, delete lower priority overlays in newly + ;; covered region + (auto-o-update-exclusive (overlay-get o-self 'set-id) + end (overlay-end o-self) + nil (overlay-get o-self 'priority))) + + ;; if we extend beyond end of line... + ((/= (overlay-end o-self) (+ start (match-end 0))) + ;; shrink ourselves so we extend till end of line + (move-overlay o-self start (+ start (match-end 0))) + ;; if we're exclusive, re-parse region that is no longer covered + (auto-o-update-exclusive (overlay-get o-self 'set-id) + (overlay-end o-self) end + (overlay-get o-self 'priority) nil)) + ))))) + + +;; auto-overlay-line.el ends here diff --git a/packages/auto-overlays/auto-overlay-manual.info b/packages/auto-overlays/auto-overlay-manual.info new file mode 100644 index 000000000..84c8fd244 --- /dev/null +++ b/packages/auto-overlays/auto-overlay-manual.info @@ -0,0 +1,2246 @@ +This is auto-overlay-manual/auto-overlay-manual.info, produced by +makeinfo version 4.13 from +auto-overlay-manual/auto-overlay-manual.texinfo. + +INFO-DIR-SECTION Emacs +START-INFO-DIR-ENTRY +* auto-overlays (auto-overlay-manual). Automatic regexp-delimited overlays +END-INFO-DIR-ENTRY + + This manual describes the Emacs Auto-Overlays package, version 0.10 + + Copyright (C) 2007, 2008 Toby Cubitt + + Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU Free Documentation License, + Version 1.2 or any later version published by the Free Software + Foundation; with no Invariant Sections, no Front-Cover Texts, and + no Back-Cover Texts. A copy of the license is included in the + section entitled "GNU Free Documentation License". + + +File: auto-overlay-manual.info, Node: Top, Next: Overview, Up: (dir) + +Emacs Auto-Overlays Manual +************************** + +This manual describes the Emacs Auto-Overlays package, version 0.10 + + Copyright (C) 2007, 2008 Toby Cubitt + + Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU Free Documentation License, + Version 1.2 or any later version published by the Free Software + Foundation; with no Invariant Sections, no Front-Cover Texts, and + no Back-Cover Texts. A copy of the license is included in the + section entitled "GNU Free Documentation License". + + An Emacs overlay demarcates a region of text in a buffer, often +giving it a different face or changing other properties for that +region. There are many circumstance in which it might be useful to +create, update, and delete overlays automatically when text matches +some criterion, specified for example by regular expressions. This is +what the auto-overlays package addresses. It is intended as an Elisp +library, providing functions to be used by other Elisp packages, so +does not itself define any new interactive commands or minor modes. + +* Menu: + +* Overview:: +* Auto-Overlay Functions:: +* Worked Example:: +* Extending the Auto-Overlays Package:: +* To-Do:: +* Function Index:: +* Variable Index:: +* Concept Index:: +* Copying this Manual:: + + --- The Detailed Node Listing --- + +Emacs Auto-Overlays Manual + +* Overview:: +* Auto-Overlay Functions:: +* Worked Example:: +* Extending the Auto-Overlays Package:: +* To-Do:: + +Auto-Overlay Functions + +* Defining Regexps:: +* Starting and Stopping Auto-Overlays:: +* Searching for Overlays:: + +Extending the Auto-Overlays Package + +* Auto-Overlays in Depth:: +* Integrating New Overlay Classes:: +* Functions for Writing New Overlay Classes:: +* Auto-Overlay Hooks:: +* Auto-Overlay Modification Pseudo-Hooks:: + +Functions for Writing New Overlay Classes + +* Functions for Modifying Overlays:: +* Functions for Querying Overlays:: + +Copying this Manual + +* GNU Free Documentation License:: + + +File: auto-overlay-manual.info, Node: Overview, Next: Auto-Overlay Functions, Prev: Top, Up: Top + +1 Overview +********** + +The auto-overlays package automatically creates, updates and destroys +overlays based on regular expression matches in the buffer text. The +overlay is created when text is typed that matches an auto-overlay +regexp, and is destroyed if and when the matching text is changed so +that it no longer matches. + + The regexps are grouped into sets, and any number of different sets +of regexps can be active in the same buffer simultaneously. Regexps in +different sets are completely independent, and each set can be activated +and deactivated independently (*note Defining Regexps::). This allows +different Emacs modes to simultaneously make use of auto-overlays in the +same buffer. + + There are different "classes" of auto-overlay, used to define +different kinds of overlay behaviour. Some classes only require a single +regexp, others require separate regexps to define the start and end of +the overlay (*note Defining Regexps::). Any additional regexps, beyond +the minimum requirements, act as alternatives; if more than one of the +regexps matches overlapping regions of text, the one that appears +earlier in the list will take precedence. The predefined regexp classes +are: `word', `line', `self', `nested' and `flat', but the auto-overlay +package can easily be extended with new classes. + +`word' + These are used to define overlays that cover the text matched by + the regexp itself, so require a single regexp. An example use + would be to create overlays covering single words. + +`line' + These are used to define overlays that stretch from the text + matching the regexp to the end of the line, and require a single + regexp to define the start of the overlay. An example use would be + to create overlays covering single-line comments in programming + languages such as c. + +`self' + These are used to define overlays that stretch from one regexp + match to the next match for the same regexp, so naturally require + a single regexp. An example use would be to create overlays + covering strings delimited by `""'. + + Note that for efficiency reasons, `self' overlays are _not_ fully + updated when a new match is found. Instead, when a modification is + subsequently made at any position in the buffer after the new + match, the overlays are updated _up to_ that position. The update + occurs just _before_ the modification is made. Therefore, the + overlays at a given buffer position will not necessarily be + correct until a modification is made at or after that position + (*note To-Do::). + +`nested' + These are used to define overlays that start and end at different + regexp matches, and that can be nested one inside another. This + class requires separate start and end regexps. An example use + would be to create overlays between matching braces `{}'. + +`flat' + These are used to define overlays that start and end at different + regexp matches, but that can not be nested. Extra start matches + within one of these overlays are ignored. This class requires + separate start and end regexps. An example use would be to create + overlays covering multi-line comments in code, e.g. c++ block + comments delimited by `/*' and `*/'. + + By default, the entire text matching a regexp acts as the +"delimeter". For example, a `word' overlay will cover all the text +matching its regexp, and a `nested' overlay will start at the end of +the text matching its start regexp. Sometimes it is useful to be able +to have only part of the regexp match act as the delimeter. This can be +done by grouping that part of the regexp (*note Defining Regexps::). +Overlays will then start and end at the text matching the group, +instead of the text matching the entire regexp. + + Of course, automatically creating overlays isn't much use without +some way of setting their properties too. Overlay properties can be +defined along with the regexp, and are applied to any overlays created +by a match to that regexp. Certain properties have implications for +auto-overlay behaviour. + +`priority' + This is a standard Emacs overlay property (*note Overlay + Properties: (elisp)Overlay Properties.), but it is also used to + determine which regexp takes precedence when two or more regexps + in the same auto-overlay definition match overlapping regions of + text. It is also used to determine which regexp's properties take + precedence for overlays that are defined by separate start and end + matches. + +`exclusive' + Normally, different auto-overlay regexps coexist, and act + completely independently of one-another. However, if an + auto-overlay has non-nil `exclusive' and `priority' properties, + regexp matches within the overlay are ignored if they have lower + priority. An example use is ignoring other regexp matches within + comments in code. + + +File: auto-overlay-manual.info, Node: Auto-Overlay Functions, Next: Worked Example, Prev: Overview, Up: Top + +2 Auto-Overlay Functions +************************ + +To use auto-overlays in an Elisp package, you must load the overlay +classes that you require by including lines of the form + (require 'auto-overlay-CLASS) + near the beginning of your package, where CLASS is the class name. +The standard classes are: `word', `line', `self', `nested' and `flat' +(*note Overview::), though new classes can easily be added (*note +Extending the Auto-Overlays Package::). + + Sometimes it is useful for a package to make use of auto-overlays if +any are defined, without necessarily requiring them. To facilitate +this, the relevant functions can be loaded separately from the rest of +the auto-overlays package with the line + (require 'auto-overlay-common) + This provides all the functions related to searching for overlays and +retrieving overlay properties. *Note Searching for Overlays::. Note that +there is no need to include this line if any auto-overlay classes are +`require'd, though it will do no harm. + + This section describes the functions that are needed in order to make +use of auto-overlays in an Elisp package. It does _not_ describe +functions related to extending the auto-overlays package. *Note +Extending the Auto-Overlays Package::. + +* Menu: + +* Defining Regexps:: +* Starting and Stopping Auto-Overlays:: +* Searching for Overlays:: + + +File: auto-overlay-manual.info, Node: Defining Regexps, Next: Starting and Stopping Auto-Overlays, Up: Auto-Overlay Functions + +2.1 Defining Regexps +==================== + +An auto-overlay definition is a list of the form: + (CLASS &optional :id ENTRY-ID REGEXP1 REGEXP2 ...) + CLASS is one of the regexp classes described in the previous section +(*note Overview::). The optional `:id' property should be a symbol that +can be used to uniquely identify the auto-overlay definition. + + Each REGEXP defines one of the regexps that make up the auto-overlay +definition. It should be a list of the form + (RGXP &optional :edge EDGE :id SUBENTRY-ID @rest PROPERTY1 PROPERTY2 ...) + The `:edge' property should be one of the symbols `'start' or +`'end', and determines which edge of the auto-overlay this regexp +corresponds to. If `:edge' is not specified, it is assumed to be +`'start'. Auto-overlay classes that do not require separate `start' and +`end' regexps ignore this property. The `:id' property should be a +symbol that can be used to uniquely identify the regexp. Any further +elements in the list are cons cells of the form `(property . value)', +where PROPERTY is an overlay property name (a symbol) and VALUE its +value. In its simplest form, RGXP is a single regular expression. + + If only part of the regexp should act as the delimeter (*note +Overview::), RGXP should instead be a cons cell: + (RX . GROUP) + where RX is a regexp that contains at least one group (*note Regular +Expressions: (elisp)Regular Expressions.), and GROUP is an integer +identifying which group should act as the delimeter. + + If the overlay class requires additional groups to be specified, +RGXP should instead be a list: + (RX GROUP0 GROUP1 ...) + where RX is a regexp. The first GROUP0 still specifies the part that +acts as the delimeter, as before. If the entire regexp should act as +the delimeter, GROUP0 must still be supplied but should be set to 0 +(meaning the entire regexp). None of the standard classes make use of +any additional groups, but extensions to the auto-overlays package that +define new classes may. *Note Extending the Auto-Overlays Package::. + + The following functions are used to load and unload regexp +definitions: + +`(auto-overlay-load-definition SET-ID DEFINITION &optional POS)' + Load a new auto-overlay DEFINITION, which should be a list of the + form described above, into the set identified by the symbol + SET-ID. The optional parameter POS determines where in the set's + regexp list the new regexp is inserted. If it is `nil', the regexp + is added at the end. If it is `t', the regexp is added at the + beginning. If it is an integer, the regexp is added at that + position in the list. Whilst the position in the list has no + effect on overlay behaviour, it does determine the order in which + regexps are checked, so can affect efficiency. + +`(auto-overlay-load-regexp SET-ID ENTRY-ID REGEXP &optional POS)' + Load a new REGEXP, which should be a list of the form described + above, into the auto-overlay definition identified by the symbol + ENTRY-ID, in the set identified by the symbol SET-ID. REGEXP + should be a list of the form described above. The optional POS + determines the position of the regexp in the list of regexps + defining the auto-overlay, which can be significant for overlay + behaviour since it determines which regexp takes precedence when + two match the same text. + +`(auto-overlay-unload-set SET-ID)' + Unload the entire regexp set identified by the symbol SET-ID. + +`(auto-overlay-unload-definition SET-ID ENTRY-ID)' + Unload the auto-overlay definition identified by the symbol + ENTRY-ID from the set identified by the symbol SET-ID. + +`(auto-overlay-unload-regexp SET-ID ENTRY-ID SUBENTRY-ID)' + Unload the auto-overlay regexp identified by the symbol + SUBENTRY-ID from the auto-overlay definition identified by the + symbol ENTRY-ID in the set identified by the symbol SET-ID. + +`(auto-overlay-share-regexp-set SET-ID FROM-BUFFER @optional TO-BUFFER)' + Share the set of regexp definitions identified by the symbol + SET-ID in buffer `from-buffer' with the buffer TO-BUFFER, or the + current buffer if TO-BUFFER is null. The regexp set becomes common + to both buffers, and any changes made to it in one buffer, such as + loading and unloading regexp definitions, are also reflected in + the other buffer. However, the regexp set can still be enabled and + disabled independently in both buffers. The same regexp set can be + shared between any number of buffers. To remove a shared regexp + set from one of the buffers, simply unload the entire set from that + buffer using `auto-overlay-unload-regexp'. The regexp set will + remain defined in all the other buffers it was shared with. + + +File: auto-overlay-manual.info, Node: Starting and Stopping Auto-Overlays, Next: Searching for Overlays, Prev: Defining Regexps, Up: Auto-Overlay Functions + +2.2 Starting and Stopping Auto-Overlays +======================================= + +A set of regexps is not active until it has been "started", and can be +deactivated by "stopping" it. When a regexp set is activated, the +entire buffer is scanned for regexp matches, and the corresponding +overlays created. Similarly, when a set is deactivated, all the overlays +are deleted. Note that regexp definitions can be loaded and unloaded +whether the regexp set is active or inactive, and that deactivating a +regexp set does _not_ delete its regexp definitions. + + Since scanning the whole buffer for regexp matches can take some +time, especially for large buffers, auto-overlay data can be saved to an +auxiliary file so that the overlays can be restored more quickly if the +same regexp set is subsequently re-activated. Of course, if the text in +the buffer is modified whilst the regexp set is disabled, or the regexp +definitions differ from those that were active when the overlay data was +saved, the saved data will be out of date. Auto-overlays automatically +checks if the text has been modified and, if it has, ignores the saved +data and re-scans the buffer. However, no check is made to ensure the +regexp definitions used in the buffer and saved data are consistent +(*note To-Do::); the saved data will be used even if the definitions +have changed. + + The usual time to save and restore overlay data is when a regexp set +is deactivated or activated. The auxilliary file name is then +constructed automatically from the buffer name and the set-id. However, +auto-overlays can also be saved and restored manually. + +`(auto-overlay-start SET-ID @optional BUFFER SAVE-FILE NO-REGEXP-CHECK)' + Activate the auto-overlay regexp set identified by the symbol + SET-ID in BUFFER, or the current buffer if the latter is `nil'. If + there is an file called `auto-overlay-'BUFFER-NAME`-'SET-ID in the + containing up-to-date overlay data, it will be used to restore the + auto-overlays (BUFFER-NAME is the name of the file visited by the + buffer, or the buffer name itself if there is none). Otherwise, the + entire buffer will be scanned for regexp matches. + + The string SAVE-FILE specifies the where to look for the file of + saved overlay data. If it is nil, it defaults to the current + directory. If it is a string specifying a relative path, then it is + relative to the current directory, whereas an absolute path + specifies exactly where to look. If it is a string specifying a + file name (with or without a full path, relative or absolute), + then it overrides the default file name and/or location. Any other + value of SAVE-FILE will cause the file of overlay data to be + ignored, even if it exists. + + If the overlays are being loaded from a file, but optional argument + no-regexp-check is non-nil, the file of saved overlays will be + used, but no check will be made to ensure regexp refinitions are + the same as when the overlays were saved. + +`(auto-overlay-stop SET-ID @optional BUFFER SAVE-FILE LEAVE-OVERLAYS)' + Deactivate the auto-overlay regexp set identified by the symbol + SET-ID in BUFFER, or the current buffer if the latter is `nil'. + All corresponding overlays will be deleted (unless the + LEAVE-OVERLAYS option is non-nil, which should only be used if the + buffer is about to be killed), but the regexp definitions are + preserved and can be reactivated later. + + If SAVE-FILE is non-nil, overlay data will be saved in an + auxilliary file called `auto-overlay-'BUFFER-NAME`-'SET-ID in the + current directory, to speed up subsequent reactivation of the + regexp set in the same buffer (BUFFER-NAME is the name of the file + visited by the buffer, or the buffer name itself if there is + none). If SAVE-FILE is a string, it overrides the default save + location, overriding either the directory if it only specifies a + path (relative paths are relative to the current directory), or + the file name if it only specifies a file name, or both. + +`(auto-overlay-save-overlays SET-ID @optional BUFFER FILE)' + Save auto-overlay data for the regexp set identified by the symbol + SET-ID in BUFFER, or the current buffer if `nil', to an auxilliary + file called FILE. If FILE is nil, the overlay data are saved to a + file called `auto-overlay-'BUFFER-NAME`-'SET-ID in the current + directory (BUFFER-NAME is the name of the file visited by the + buffer, or the buffer name itself if there is none). Note that + this is the only name that will be recognized by + `auto-overlay-start'. + +`(auto-overlay-load-overlays SET-ID @optional BUFFER FILE NO-REGEXP-CHECK)' + Load auto-overlay data for the regexp set identified by the symbol + SET-ID into BUFFER, or the current buffer if `nil', from an + auxilliary file called FILE. If FILE is nil, it attempts to load + the overlay data from a file called + `auto-overlay-'BUFFER-NAME`-'SET-ID in the current directory + (BUFFER-NAME is the name of the file visited by the buffer, or the + buffer name itself if there is none). If NO-REGEXP-CHECK is + no-nil, the saved overlays will be loaded even if different regexp + definitions were active when the overlays were saved. Returns `t' + if the overlays were successfully loaded, `nil' otherwise. + + +File: auto-overlay-manual.info, Node: Searching for Overlays, Prev: Starting and Stopping Auto-Overlays, Up: Auto-Overlay Functions + +2.3 Searching for Overlays +========================== + +Auto-overlays are just normal Emacs overlays, so any of the standard +Emacs functions can be used to search for overlays and retrieve overlay +properties. The auto-overlays package provides some additional +functions. + +`(auto-overlays-at-point @optional POINT PROP-TEST INACTIVE)' + Return a list of overlays overlapping POINT, or the point if POINT + is null. The list includes _all_ overlays, not just auto-overlays + (but see below). The list can be filtered to only return overlays + with properties matching criteria specified by PROP-TEST. This + should be a list defining a property test, with one of the + following forms (or a list of such lists, if more than one + property test is required): + (FUNCTION PROPERTY) + (FUNCTION PROPERTY VALUE) + (FUNCTION (PROPERTY1 PROPERTY2 ...) (VALUE1 VALUE2 ...)) + where FUNCTION is a function, PROPERTY is an overlay property name + (a symbol), and VALUE can be any value or lisp expression. For + each overlay, first the values corresponding to the PROPERTY names + are retrieved from the overlay and any VALUEs that are lisp + expressions are evaluated. Then FUNCTION is called with the + property values followed by the other values as its arguments. The + test is satisfied if the result is non-nil, otherwise it fails. + Tests are evaluated in order, but only up to the first failure. + Only overlays that satisfy all property tests are returned. + + All auto-overlays are given a non-nil `auto-overlay' property, so + to restrict the list to auto-overlays, PROP-TEST should include + the following property test: + ('identity 'auto-overlay) + For efficiency reasons, the auto-overlays package sometimes leaves + overlays hanging around in the buffer even when they should have + been deleted. These are marked with a non-nil `inactive' property. + By default, `auto-overlays-at-point' ignores these. A non-nil + INACTIVE will override this, causing inactive overlays to be + included in the returned list (assuming they pass all property + tests). + +`(auto-overlays-in START END @optional PROP-TEST WITHIN INACTIVE)' + Return a list of overlays overlapping the region between START and + END. The PROP-TEST and INACTIVE arguments have the same behaviour + as in `auto-overlays-at-point', above. If WITHIN is non-nil, only + overlays that are entirely within the region from START to END + will be returned, not overlays that extend outside that region. + +`(auto-overlay-highest-priority-at-point @optional POINT PROP-TEST)' + Return the highest priority overlay at POINT (or the point, of + POINT is null). The PROP-TEST argument has the same behaviour as + in `auto-overlays-at-point', above. An overlay's priority is + determined by the value of its `priority' property (*note Overlay + Properties: (elisp)Overlay Properties.). If two overlays have the + same priority, the innermost one takes precedence (i.e. the one + that begins later in the buffer, or if they begin at the same + point the one that ends earlier; if two overlays have the same + priority and extend over the same region, there is no way to + predict which will be returned). + +`(auto-overlay-local-binding SYMBOL @optional POINT)' + Return the "overlay-local" binding of SYMBOL at POINT (or the + point if POINT is null), or the current local binding if there is + no overlay binding. An "overlay-local" binding for SYMBOL is the + value of the overlay property called SYMBOL. If more than one + overlay at POINT has a non-nil SYMBOL property, the value from the + highest priority overlay is returned (see + `auto-overlay-highest-priority-at-point', above, for an + explanation of "highest priority"). + + +File: auto-overlay-manual.info, Node: Worked Example, Next: Extending the Auto-Overlays Package, Prev: Auto-Overlay Functions, Up: Top + +3 Worked Example +**************** + +The interaction of all the different regexp definitions, overlay +properties and auto-overlay classes provided by the auto-overlay package +can be a little daunting. This section will go through an example of how +the auto-overlay regexps could be defined to create overlays for a +subset of LaTeX, which is complex enough to demonstrate most of the +features. + + LaTeX is a markup language, so a LaTeX document combines markup +commands with normal text. Commands start with `\', and end at the +first non-word-constituent character. We want to highlight all LaTeX +commands in blue. Two commands that will particularly interest us are +`\begin' and `\end', which begin and end a LaTeX environment. The +environment name is enclosed in braces: `\begin{ENVIRONMENT-NAME}', and +we want it to be highlighted in pink. LaTeX provides many environments, +used to create lists, tables, titles, etc. We will take the example of +an `equation' environment, used to typeset mathematical equations. Thus +equations are enclosed by `\begin{equation}' and `\end{equation}', and +we would like to highlight these equations in yellow. Another example +we will use is the `$' delimiter. Pairs of `$'s delimit mathematical +expressions that appear in the middle of a paragraph of normal text +(whereas `equation' environments appear on their own, slightly +separated from surrounding text). Again, we want to highlight these +mathematical expressions, this time in green. The final piece of LaTeX +markup we will need to consider is the `%' character, which creates a +comment that lasts till the end of the line (i.e. text after the `%' is +ignored by the LaTeX processor up to the end of the line). + + LaTeX commands are a good example of when to use `word' regular +expressions (*note Overview::). The appropriate regexp definition is +loaded by + + (auto-overlay-load-definition + 'latex + '(word ("\\\\[[:alpha:]]*?\\([^[:alpha:]]\\|$\\)" + (face . (background-color . "blue"))))) + +We have called the regexp set `latex'. The `face' property is a +standard Emacs overlay property that sets font properties within the +overlay. *Note Overlay Properties: (elisp)Overlay Properties. `"\\\\"' +is the string defining the regexp that matches a _single_ `\'. (Note +that the `\' character has a special meaning in regular expressions, so +to include a literal one it must be escaped: `\\'. However, `\' also +has a special meaning in lisp strings, so both `\' characters must be +escaped there too, giving `\\\\'.) `[[:alpha:]]*?' matches a sequence +of zero or more letter characters. The `?' ensures that it matches the +_shortest_ sequence of letters consistent with matching the regexp, +since we want the region to end at the first non-letter character, +matched by `[^[:alpha:]]'. The `\|' defines an alternative, to allow +the LaTeX command to be terminated either by a non-letter character or +by the end of the line (`$'). *Note Regular Expressions: (elisp)Regular +Expressions, for more details on Emacs regular expressions. + + However, there's a small problem. We only want the blue background to +cover the characters making up a LaTeX command. But as we've defined +things so far, it will cover all the text matched by the regexp, which +includes the leading `\' and the trailing non-letter character. To +rectify this, we need to group the part of the regexp that matches the +command (i.e. by surround it with `\(' and `\)'), and put the regexp +inside a cons cell containing the regexp in its `car' and a number +indicating which subgroup to use in its `cdr': + + (auto-overlay-load-definition + 'latex + '(word (("\\\\[[:alpha:]]*?\\([^[:alpha:]]\\|$\\)" . 1) + (face . (background-color . "blue"))))) + + The `$' delimiter is an obvious example of when to use a `self' +regexp (*note Overview::). We can update our example to include this +(note that `$' also has a special meaning in regular expressions, so it +must be escaped with `\' which itself must be escaped in lisp strings): + + (auto-overlay-load-definition + 'latex + '(word (("\\\\[[:alpha:]]*?\\([^[:alpha:]]\\|$\\)" . 1) + (face . (background-color . "blue"))))) + + (auto-overlay-load-definition + 'latex + '(self ("\\$" (face . (background-color . "green"))))) + +This won't quite work though. LaTeX maths commands also start with a +`\' character, which will match the `word' regexp. For the sake of +example we want the entire equation highlighted in green, without +highlighting any LaTeX maths commands it contains in blue. Since the +`word' overlay will be within the `self' overlay, the blue highlighting +will take precedence. We can change this by giving the `self' overlay a +higher priority (any priority is higher than a non-existent one; we use +3 here for later convenience). For efficiency reasons, it's a good idea +to put higher priority regexp definitions before lower priority ones, +so we get: + + (auto-overlay-load-definition + 'latex + '(self ("\\$" (priority . 3) (face . (background-color . "green"))))) + + (auto-overlay-load-definition + 'latex + '(word (("\\\\[[:alpha:]]*?\\([^[:alpha:]]\\|$\\)" . 1) + (face . (background-color . "blue"))))) + + The `\begin{equation}' and `\end{equation}' commands also enclose +maths regions, which we would like to highlight in yellow. Since the +opening and closing delimiters are different in this case, we must use +`nested' overlays (*note Overview::). Our example now looks like: + + (auto-overlay-load-definition + 'latex + '(self ("\\$" (priority . 3) (face . (background-color . "green"))))) + + (auto-overlay-load-definition + 'latex + '(nested + ("\\begin{equation}" + :edge start + (priority . 1) + (face . (background-color . "yellow"))) + ("\\end{equation}" + :edge end + (priority . 1) + (face . (background-color . "yellow"))))) + + (auto-overlay-load-definition + 'latex + '(word (("\\\\[[:alpha:]]*?\\([^[:alpha:]]\\|$\\)" . 1) + (face . (background-color . "blue"))))) + +Notice how we've used separate `start' and `end' regexps to define the +auto-overlay. Once again, we have had to escape the `\' characters, and +increase the priority of the new regexp definition to avoid any LaTeX +commands within the maths region being highlighted in blue. + + LaTeX comments start with `%' and last till the end of the line: a +perfect demonstration of a `line' regexp. Here's a first attempt: + + (auto-overlay-load-definition + 'latex + '(self ("\\$" (priority . 3) (face . (background-color . "green"))))) + + (auto-overlay-load-definition + 'latex + '(nested + ("\\begin{equation}" + :edge start + (priority . 1) + (face . (background-color . "yellow"))) + ("\\end{equation}" + :edge end + (priority . 1) + (face . (background-color . "yellow"))))) + + (auto-overlay-load-definition + 'latex + '(word (("\\\\[[:alpha:]]*?\\([^[:alpha:]]\\|$\\)" . 1) + (face . (background-color . "blue"))))) + + (auto-overlay-load-definition + 'latex + `(line ("%" (face . (background-color + . ,(face-attribute 'default :background)))))) + +We use the standard Emacs `face-attribute' function to retrieve the +default background colour, which is evaluated before the regexp +definition is loaded. (This will of course go wrong if the default +background colour is subsequently changed, but it's sufficient for this +example). Let's think about this a bit. We probably don't want anything +within a comment to be highlighted at all, even if it matches one of the +other regexps. In fact, creating overlays for `\begin' and `\end' +commands which are within a comment could cause havoc! If they don't +occur in pairs within the commented region, they will erroneously pair +up with ones outside the comment. We need comments to take precedence +over everything else, and we need them to block other regexp matches, +so we boost the overlay's priority and set the exclusive property: + + (auto-overlay-load-definition + 'latex + `(line ("%" (priority . 4) (exclusive . t) + (face . (background-color + . ,(face-attribute 'default :background)))))) + + (auto-overlay-load-definition + 'latex + '(self ("\\$" (priority . 3) (face . (background-color . "green"))))) + + (auto-overlay-load-definition + 'latex + '(nested + ("\\begin{equation}" + :edge start + (priority . 1) + (face . (background-color . "yellow"))) + ("\\end{equation}" + :edge end + (priority . 1) + (face . (background-color . "yellow"))))) + + (auto-overlay-load-definition + 'latex + '(word (("\\\\[[:alpha:]]*?\\([^[:alpha:]]\\|$\\)" . 1) + (face . (background-color . "blue"))))) + + We're well on our way to creating a useful setup, at least for the +LaTeX commands we're considering in this example. There is one last +type of overlay to create, but it is the most complicated. We want +environment names to be highlighted in pink, i.e. the region between +`\begin{' and `}'. A first attempt at this might result in: + + (auto-overlay-load-definition + 'latex + `(line ("%" (priority . 4) (exclusive . t) + (face . (background-color + . ,(face-attribute 'default :background)))))) + + (auto-overlay-load-definition + 'latex + '(self ("\\$" (priority . 3) (face . (background-color . "green"))))) + + (auto-overlay-load-definition + 'latex + '(nested + ("\\begin{" + :edge start + (priority . 2) + (face . (background-color . "pink"))) + ("}" + :edge end + (priority . 2) + (face . (background-color . "pink"))))) + + (auto-overlay-load-definition + 'latex + '(nested + ("\\begin{equation}" + :edge start + (priority . 1) + (face . (background-color . "yellow"))) + ("\\end{equation}" + :edge end + (priority . 1) + (face . (background-color . "yellow"))))) + + (auto-overlay-load-definition + 'latex + '(word (("\\\\[[:alpha:]]*?\\([^[:alpha:]]\\|$\\)" . 1) + (face . (background-color . "blue"))))) + +However, we'll hit a problem with this. The `}' character also closes +the `\end{' command. Since we haven't told auto-overlays about `\end{', +every `}' that should close an `\end{' command will instead be +interpreted as the end of a `\start{' command, probably resulting in +lots of unmatched `}' characters, creating pink splodges everywhere! +Clearly, since we also want environment names between `\end{' and `}' +to be pink, we need something more along the lines of: + + (auto-overlay-load-definition + 'latex + `(line ("%" (priority . 4) (exclusive . t) + (face . (background-color + . ,(face-attribute 'default :background)))))) + + (auto-overlay-load-definition + 'latex + '(self ("\\$" (priority . 3) (face . (background-color . "green"))))) + + (auto-overlay-load-definition + 'latex + '(nested + ("\\begin{" + :edge start + (priority . 2) + (face . (background-color . "pink"))) + ("\\end{" + :edge start + (priority . 2) + (face . (background-color . "pink"))) + ("}" + :edge end + (priority . 2) + (face . (background-color . "pink"))))) + + (auto-overlay-load-definition + 'latex + '(nested + ("\\begin{equation}" + :edge start + (priority . 1) + (face . (background-color . "yellow"))) + ("\\end{equation}" + :edge end + (priority . 1) + (face . (background-color . "yellow"))))) + + (auto-overlay-load-definition + 'latex + '(word (("\\\\[[:alpha:]]*?\\([^[:alpha:]]\\|$\\)" . 1) + (face . (background-color . "blue"))))) + +We still haven't solved the problem though. The `}' character doesn't +only close `\begin{' and `\end{' commands in LaTeX. _All_ arguments to +LaTeX commands are surrounded by `{' and `}'. We could add all the +commands that take arguments, but we don't really want to bother about +any other commands (at least in this example). All we want to do is +prevent predictive mode incorrectly pairing the `}' characters used for +other commands. Instead, we can just add `{' to the list: + + (auto-overlay-load-definition + 'latex + `(line ("%" (priority . 4) (exclusive . t) + (face . (background-color + . ,(face-attribute 'default :background)))))) + + (auto-overlay-load-definition + 'latex + '(self ("\\$" (priority . 3) (face . (background-color . "green"))))) + + (auto-overlay-load-definition + 'latex + '(nested + ("{" + :edge start + (priority . 2)) + ("\\begin{" + :edge start + (priority . 2) + (face . (background-color . "pink"))) + ("\\end{" + :edge start + (priority . 2) + (face . (background-color . "pink"))) + ("}" + :edge end + (priority . 2)))) + + (auto-overlay-load-definition + 'latex + '(nested + ("\\begin{equation}" + :edge start + (priority . 1) + (face . (background-color . "yellow"))) + ("\\end{equation}" + :edge end + (priority . 1) + (face . (background-color . "yellow"))))) + + (auto-overlay-load-definition + 'latex + '(word (("\\\\[[:alpha:]]*?\\([^[:alpha:]]\\|$\\)" . 1) + (face . (background-color . "blue"))))) + +Notice how the `{' and `}' regexps do not define a background colour +(or indeed any other properties), so that any overlays they create will +have no effect other than making sure all `{' and `}' characters are +correctly paired. + + We've made one mistake though: by putting the `{' regexp at the +beginning of the list, it will take priority over any other regexp in +the list that could match the same text. And since `{' will match +whenever `\begin{' or `\end{' matches, environments will never be +highlighted! The `{' regexp must come _after_ the `\begin{' and `\end{' +regexps, to ensure it is only used if neither of them match (it doesn't +matter whether it appears before or after the `{' regexp, since the +latter will never match the same text): + + (auto-overlay-load-definition + 'latex + `(line ("%" (priority . 4) (exclusive . t) + (face . (background-color + . ,(face-attribute 'default :background)))))) + + (auto-overlay-load-definition + 'latex + '(self ("\\$" (priority . 3) (face . (background-color . "green"))))) + + (auto-overlay-load-definition + 'latex + '(nested + ("\\begin{" + :edge start + (priority . 2) + (face . (background-color . "pink"))) + ("\\end{" + :edge start + (priority . 2) + (face . (background-color . "pink"))) + ("{" + :edge start + (priority . 2)) + ("}" + :edge end + (priority . 2)))) + + (auto-overlay-load-definition + 'latex + '(nested + ("\\begin{equation}" + :edge start + (priority . 1) + (face . (background-color . "yellow"))) + ("\\end{equation}" + :edge end + (priority . 1) + (face . (background-color . "yellow"))))) + + (auto-overlay-load-definition + 'latex + '(word (("\\\\[[:alpha:]]*?\\([^[:alpha:]]\\|$\\)" . 1) + (face . (background-color . "blue"))))) + + There is one last issue. A literal `{' or `}' character can be +included in a LaTeX document by escaping it with `\': `\{' and `\}'. In +this situation, the characters do not match anything and should not be +treated as delimiters. We can modify the `{' and `}' regexps to exclude +these cases: + + (auto-overlay-load-definition + 'latex + `(line ("%" (priority . 4) (exclusive . t) + (face . (background-color + . ,(face-attribute 'default :background)))))) + + (auto-overlay-load-definition + 'latex + '(self ("\\$" (priority . 3) (face . (background-color . "green"))))) + + (auto-overlay-load-definition + 'latex + '(nested + ("\\begin{" + :edge start + (priority . 2) + (face . (background-color . "pink"))) + ("\\end{" + :edge start + (priority . 2) + (face . (background-color . "pink"))) + ("\\([^\\]\\|^\\){" + :edge start + (priority . 2)) + ("\\([^\\]\\|^\\)}" + :edge end + (priority . 2)))) + + (auto-overlay-load-definition + 'latex + '(nested + ("\\begin{equation}" + :edge start + (priority . 1) + (face . (background-color . "yellow"))) + ("\\end{equation}" + :edge end + (priority . 1) + (face . (background-color . "yellow"))))) + + (auto-overlay-load-definition + 'latex + '(word (("\\\\[[:alpha:]]*?\\([^[:alpha:]]\\|$\\)" . 1) + (face . (background-color . "blue"))))) + +The new, complicated-looking regexps will only match `{' and `}' +characters if they are _not_ preceded by a `\' character (*note Regular +Expressions: (elisp)Regular Expressions.). Note that the character +alternative `[^\]\|^' can match any character that isn't a `\' _or_ the +start of a line. This is required because macthes to auto-overlay +regexps are not allowed to span more than one line. If `{' or `}' +appear at the beginning of a line, there will be no character in front +(the newline character doesn't count, since it isn't on the same line), +so the `[^\]' will not match. + + However, when it does match, the `}' regexp will now match an +additional character before the `}', causing the overlay to end one +character early. (The `{' regexp will also match one additional +character before the `{', but since the beginning of the overlay starts +from the _end_ of the `start' delimiter, this poses less of a problem.) +We need to group the part of the regexp that should define the +delimiter, i.e. the `}', by surrounding it with `\(' and `\)', and put +the regexp in the `car' of a cons cell whose `cdr' specifies the new +subgroup (i.e. the 2nd subgroup, since the regexp already included a +group for other reasons; we could alternatively replace the original +group by a shy-group, since we don't actually need to capture match +data for that group). Our final version looks like this: + + (auto-overlay-load-definition + 'latex + `(line ("%" (priority . 4) (exclusive . t) + (face . (background-color + . ,(face-attribute 'default :background)))))) + + (auto-overlay-load-definition + 'latex + '(self ("\\$" (priority . 3) (face . (background-color . "green"))))) + + (auto-overlay-load-definition + 'latex + '(nested + ("\\begin{" + :edge start + (priority . 2) + (face . (background-color . "pink"))) + ("\\end{" + :edge start + (priority . 2) + (face . (background-color . "pink"))) + ("\\([^\\]\\|^\\){" + :edge start + (priority . 2)) + (("\\([^\\]\\|^\\)\\(}\\)" . 2) + :edge end + (priority . 2)))) + + (auto-overlay-load-definition + 'latex + '(nested + ("\\begin{equation}" + :edge start + (priority . 1) + (face . (background-color . "yellow"))) + ("\\end{equation}" + :edge end + (priority . 1) + (face . (background-color . "yellow"))))) + + (auto-overlay-load-definition + 'latex + '(word (("\\\\[[:alpha:]]*?\\([^[:alpha:]]\\|$\\)" . 1) + (face . (background-color . "blue"))))) + + With these regexp definitions, LaTeX commands will automatically be +highlighted in blue, equation environments in yellow, inline maths +commands in green, and environment names in pink. LaTeX markup within +comments will be ignored. And `{' and `}' characters from other +commands will be correctly taken into account. All this is done in +"real-time"; it doesn't wait until Emacs is idle to update the +overlays. Not bad for a bundle of regexps! + + Of course, this could all be done more easily using Emacs' built-in +syntax highlighting features, but the highlighting was only an example +to show the location of the overlays. The main point is that the +overlays are automatically created and kept up to date, and can be given +any properties you like and used for whatever purpose is required by +your Elisp package. + + +File: auto-overlay-manual.info, Node: Extending the Auto-Overlays Package, Next: To-Do, Prev: Worked Example, Up: Top + +4 Extending the Auto-Overlays Package +************************************* + +The auto-overlay package can easily be extended by adding new overlay +classes(1). The next sections document the functions and interfaces +provided by the auto-overlays package for this purpose. + + Often, a new class is a minor modification of one of the standard +classes. For example, it may work exactly like one of the standard +classes, but in addition call some function whenever an overlay is +created or destroyed. In this case, it is far better to build the new +class on top of the existing class, using functions from the +class-specific Elisp files, rather than starting from scratch. *Note +Standard Parse and Suicide Functions::. + +* Menu: + +* Auto-Overlays in Depth:: +* Integrating New Overlay Classes:: +* Functions for Writing New Overlay Classes:: +* Auto-Overlay Hooks:: +* Auto-Overlay Modification Pseudo-Hooks:: + + ---------- Footnotes ---------- + + (1) Or rather, it is easy to integrate new overlay classes into the +package. Whether writing a new overlay class is easy or not depends on +what you're trying to do, and how good your coding skills are ;-) + + +File: auto-overlay-manual.info, Node: Auto-Overlays in Depth, Next: Integrating New Overlay Classes, Up: Extending the Auto-Overlays Package + +4.1 Auto-Overlays in Depth +========================== + +In order to write new classes, a deeper understanding is required of how +the auto-overlay package works. In fact, two kinds of overlays are +automatically created, updated and destroyed when auto-overlays are +active: the auto-overlays themselves, and "match" overlays, used to +mark text that matches an auto-overlay regexp. + + For overlay classes that only require one regexp to fully define an +overlay (the `word' and `line' classes are the only standard classes +like this(1)), the auto-overlays are always matched with the +corresponding match overlay. For classes that require two regexp +matches to define the start and end of an overlay (all other standard +classes), each edge of an auto-overlay can be matched with a match +overlay. The match overlays define where the edge of the auto-overlay +is located. There will always be at least one matched edge, since an +auto-overlay is only created when a regexp match is found, but it is +possible for the second edge to not yet be matched (for many classes, +the unmatched edge will be located at the beginning or end of the +buffer). + + If a match overlay delimits the start of an auto-overlay, the match +overlay is stored in the auto-overlay's `start' property. The match +overlay is also stored in the `start' property for auto-overlays that +only require a single match. If a match overlay delimits the end of an +auto-overlay, the match overlay is stored in the auto-overlay's `end' +property. Conversely, a "link" to the auto-overlay is always stored in +the match overlay's `parent' property(2). + + Whenever a buffer is modified, the lines containing the modifications +are scanned for new regexp matches. If one is found, a new match overlay +is created covering the matching text, and then passed as an argument to +the appropriate "parse" function(3) for its class. This deals with +creating or updating the auto-overlays as appropriate. If the text +within a match overlay is modified, the match overlay checks whether +the text it covers still matches the regexp. If it no longer matches, +the match overlay is passed as an argument to the appropriate "suicide" +function for its class, which deals with updating or deleting its +parent auto-overlay (and possibly more besides). + + To summarise, the core of the auto-overlays package deals with +searching for regexp matches, and creating or deleting the +corresponding match overlays. It then hands over the task of creating, +updating or deleting the auto-overlays themselves to class-specific +functions, which implement the correct behaviour for that class. + + ---------- Footnotes ---------- + + (1) Although the `self' class only requires one regexp definition, +the auto-overlays themselves require two matches to that same regexp to +set the start and end of the overlay. + + (2) The "parent" terminology is admittedly very poor, and is a relic +of a previous incarnation of the auto-overlays package, when it made +more sense. + + (3) More bad terminology. + + +File: auto-overlay-manual.info, Node: Integrating New Overlay Classes, Next: Functions for Writing New Overlay Classes, Prev: Auto-Overlays in Depth, Up: Extending the Auto-Overlays Package + +4.2 Integrating New Overlay Classes +=================================== + +To add a new overlay class, all that is required is to write new +"parse" and "suicide" functions, and inform the auto-overlays package +of their existence. A "match" function can also optionally be defined. +It is called whenever a match overlay in the class becomes matched with +the edge of an auto-overlay (*note Functions for Modifying Overlays::). +The parse, suicide and match functions are conventionally called +`auto-o-parse-'CLASS`-match', `auto-o-'CLASS`-suicide' and +`auto-o-match-'CLASS, where CLASS is the name of the class, though the +convention is not enforced in any way. + +parse function + A parse function is passed a single argument containing a match + overlay. It should return a list containing any new auto-overlays + it creates, or `nil' if none were created. + O-LIST = (auto-o-parse-CLASS-match O-MATCH) + Note that the parse function itself is responsible for calling the + `auto-o-update-exclusive' function if a new exclusive overlay is + created. *Note Functions for Modifying Overlays::. + +suicide function + A suicide function is passed a single argument containing a match + overlay. Its return value is ignored. + (auto-o-CLASS-suicide O-MATCH) + The text covered by the match overlay should be considered to no + longer match its regexp, although in certain cases matches are + ignored for other reasons and this may not really be the case (for + example if a new, higher-priority, exclusive overlay overlaps the + match, *note Overview::). + +match function + A match function is passed a single argument containing a match + overlay that has just been matched with an edge of an auto-overlay + (*note Functions for Modifying Overlays::). Its return value is + ignored. + (auto-o-match-CLASS O-MATCH) + The auto-overlay it is matched with is stored in the match + overlay's `parent' property. + + To integrate the new class into the auto-overlays package, the parse +and suicide functions must be added to the property list of the symbol +used to refer to the new class, denoted here by CLASS: + (put 'CLASS 'auto-overlay-parse-function + 'auto-o-parse-CLASS-match) + (put 'CLASS 'auto-overlay-suicide-function + 'auto-o-CLASS-suicide) + If the optional match function is defined, it should similarly be +added to the symbol's property list: + (put 'CLASS 'auto-overlay-match-function + 'auto-o-match-CLASS) + + +File: auto-overlay-manual.info, Node: Functions for Writing New Overlay Classes, Next: Auto-Overlay Hooks, Prev: Integrating New Overlay Classes, Up: Extending the Auto-Overlays Package + +4.3 Functions for Writing New Overlay Classes +============================================= + +Some functions are provided by the auto-overlays package for use in new +parse and suicide functions. The functions that modify overlays carry +out tasks that require interaction with the core of the auto-overlays +package, and provide the only reliable way of carrying out those tasks. +The other functions are used to query various things about +auto-overlays and match overlays. Again, they are the only reliable +interface for this, since the internal implementation may change between +releases of the auto-overlays package. + +* Menu: + +* Standard Parse and Suicide Functions:: +* Functions for Modifying Overlays:: +* Functions for Querying Overlays:: + + +File: auto-overlay-manual.info, Node: Standard Parse and Suicide Functions, Next: Functions for Modifying Overlays, Up: Functions for Writing New Overlay Classes + +4.3.1 Standard Parse and Suicide Functions +------------------------------------------ + +All the standard overlay classes define their own parse and suicide +functions (none of them require a match function), which can be used to +create new "derived" classes based on the standard ones. This is the +easiest and most common way to create a new class. For example, the new +class may behave exactly like one of the standard classes, but perform +some additional processing whenever an overlay is created, destroyed, or +matched. The parse and suicide functions for the new class should +perform whatever additional processing is required, and call the +standard class functions to deal with creating and destroying the +overlay. + + All the standard parse and suicide functions follow the same naming +convention (*note Integrating New Overlay Classes::), where CLASS is +the name of the overlay class (one of `word', `line', `self', `nested' +or `flat', *note Overview::): + +`(auto-o-parse-CLASS-match O-MATCH)' + Parse a new match overlay O-MATCH whose class is CLASS. This will + create or update auto-overlays, as appropriate for the class. + +`(auto-o-CLASS-suicide O-MATCH)' + Delete or update auto-overlays as appropriate for overlay class + CLASS, due to the match overlay O-MATCH no longer matching. + + +File: auto-overlay-manual.info, Node: Functions for Modifying Overlays, Next: Functions for Querying Overlays, Prev: Standard Parse and Suicide Functions, Up: Functions for Writing New Overlay Classes + +4.3.2 Functions for Modifying Overlays +-------------------------------------- + +These functions modify auto-overlays and match overlays as necessary to +perform a particular update. They should _always_ be used to carry out +their corresponding tasks, rather than doing it separately, since these +tasks require interaction with the core of the auto-overlays package. + +`(auto-o-update-exclusive SET-ID BEG END OLD-PRIORITY NEW-PRIORITY)' + Update the region between BEG and END in the current buffer as + necessary due to the priority of an exclusive overlay overlapping + the region changing from OLD-PRIORITY to NEW-PRIORITY. If the + exclusive overlay did not previously overlap the region, + OLD-PRIORITY should be null. If it no longer overlaps the region, + NEW-PRIORITY should be null. (If both are null, nothing will + happen!) The return value is meaningless. + +`(auto-o-match-overlay OVERLAY START @optional END NO-PROPS NO-PARSE PROTECT-MATCH)' + Match or unmatch the start and end of the auto-overlay OVERLAY, + update all appropriate properties (such as `parent', `start' and + `end' properties, and any properties specified in regexp + definitions), and update other auto-overlays in the region covered + by OVERLAY if required because the `exclusive' or `priority' + properties of OVERLAY have changed. + + If START or END are match overlays, match the corresponding edge + of OVERLAY. The edge is moved to the location defined by the match + overlay, and the `parent' property of the match overlay and the + `start' and `end' properties of OVERLAY are updated accordingly. + The START argument should be a match overlay corresponding either + to the unique regexp if only one is needed for that overlay class, + or to a start regexp if the overlay class uses separate start and + end regexps. The END argument should then be a match overlay + corresponding to an end regexp in the same class (*note + Overview::). You're responsible for enforcing this; no check is + made. + + If START or END are numbers or markers, move the corresponding + edge of OVERLAY to that location and set it as unmatched. The + `start' or `end' property of OVERLAY and the `parent' property of + any corresponding match overlay are set to `nil'). If START or END + are non-nil but neither of the above, leave the corresponding edge + of OVERLAY where it is, but set it unmatched (as described above). + If START or END are null, don't change the corresponding edge. + However, for convenience, if END is null but START is a match + overlay corresponding to a match for an end-regexp, match the end + of OVERLAY rather than the start. + + The remaining arguments disable some of the tasks normally carried + out by `auto-o-match-overlay'. If NO-PROPS is non-nil, overlay + properties specified in regexp definitions are ignored and not + updated. If NO-PARSE is non-nil, auto-overlays in the region + covered by OVERLAY are not updated, even if the `exclusive' or + `priority' properties of OVERLAY have changed. If PROTECT-MATCH is + non-nil, the `parent' properties of the START and END match + overlays are left alone. + +`(auto-o-delete-overlay OVERLAY @optional NO-PARSE PROTECT-MATCH)' + Delete auto-overlay OVERLAY from the buffer, and update overlays + and overlay properties as necessary. The optional arguments disable + parts of the updating process, as for `auto-o-match-overlay', + above. + + +File: auto-overlay-manual.info, Node: Functions for Querying Overlays, Prev: Functions for Modifying Overlays, Up: Functions for Writing New Overlay Classes + +4.3.3 Functions for Querying Overlays +------------------------------------- + +These functions query certain things about auto-overlays or match +overlays, or retrieve certain values associated with them. A few are +merely convenience functions, but most depend on the internal +implementation details of the auto-overlays package, and provide the +only reliable interface for whatever they return. + +`(auto-o-class O-MATCH)' + Return the class of match overlay O-MATCH. + +`(auto-o-regexp O-MATCH)' + Return the regular expression matched by the text covered by match + overlay O-MATCH. + +`(auto-o-regexp-group O-MATCH)' + Return the regexp group defined in the regexp definition + corresponding to match overlay O-MATCH (*note Defining Regexps::). + +`(auto-o-props O-MATCH)' + Return the list of overlay properties defined in the regexp + definition corresponding to match overlay O-MATCH (*note Defining + Regexps::). + +`(auto-o-edge O-MATCH)' + Return edge (the symbol `start' or `end') of match overlay O-MATCH. + +`(auto-o-parse-function O-MATCH)' + Return appropriate parse function for match overlay O-MATCH. + +`(auto-o-suicide-function O-MATCH)' + Return appropriate suicide function for match overlay O-MATCH. + +`(auto-o-match-function O-MATCH)' + Return match function for match overlay O-MATCH, if any. + +`(auto-o-edge-matched-p OVERLAY EDGE)' + Return non-nil if EDGE (the symbol `start' or `end') of + auto-overlay `overlay' is matched. + +`(auto-o-start-matched-p OVERLAY)' + Return non-nil if auto-overlay OVERLAY is start-matched. + +`(auto-o-end-matched-p OVERLAY)' + Return non-nil if auto-overlay OVERLAY is end-matched. + + +File: auto-overlay-manual.info, Node: Auto-Overlay Hooks, Next: Auto-Overlay Modification Pseudo-Hooks, Prev: Functions for Writing New Overlay Classes, Up: Extending the Auto-Overlays Package + +4.4 Auto-Overlay Hooks +====================== + +The auto-overlays package defines two hooks, that are called when +auto-overlays are enabled and disabled in a buffer. These are intended +to be used by overlay classes to set up any extra buffer-local variables +and settings they require, and clean them up afterwards. (There is no +point leaving auto-overlay variables and settings hanging around in a +buffer when auto-overlays are not in use.) + +`auto-overlay-load-hook' + This hook is run when the first auto-overlay regexp set in a + buffer is started, using the `auto-overlay-start' function. *Note + Starting and Stopping Auto-Overlays::. + +`auto-overlay-unload-hook' + This hook is run when the last auto-overlay regexp set in a buffer + is stopped, using the `auto-overlay-stop' function. *Note Starting + and Stopping Auto-Overlays::. + + +File: auto-overlay-manual.info, Node: Auto-Overlay Modification Pseudo-Hooks, Prev: Auto-Overlay Hooks, Up: Extending the Auto-Overlays Package + +4.5 Auto-Overlay Modification Pseudo-Hooks +========================================== + +The auto-overlays package adds functions to buffer and overlay +modification hooks in order to update the overlays as the buffer text is +modified (*note Modification Hooks: (elisp)Modification Hooks.). The +order in which all these modification hooks are called is undefined in +Emacs(1). Therefore, the auto-overlays package provides a mechanism to +schedule functions to run at particular points during the overlay +update process. + + There are two stages to the overlay update process: first, any match +overlay suicide functions are called, then modified buffer lines are +scanned for new regexp matches. Three pseudo-hooks are defined that are +called before, after and in between these stages. Their values are lists +containing elements of the form: + (FUNCTION ARG1 ARG2 ...) + where FUNCTION is the function to be called by the hook, and the +ARG's are the arguments to be passed to that function. The list +elements are evaluated in order. The pseudo-hooks are cleared each time +after they have been called. + +`auto-o-pending-pre-suicide' + Pseudo-hook called before any suicide functions. + +`auto-o-pending-post-suicide' + Pseudo-hook called after any suicide functions but before scanning + for regexp matches. + +`auto-o-pending-post-update' + Pseudo-hook called after scanning for regexp matches. + + These pseudo-hooks can be used to ensure that a function that would +normally be added to a modification hook will be called at a particular +point in the auto-overlay update process. To achieve this, a helper +function must be added to the modification hook instead. The helper +function should add the function itself to the appropriate pseudo-hook +by adding a list element with the form described above. The `push' and +`add-to-list' Elisp functions are the most useful ways to add elements +to the list. + + ---------- Footnotes ---------- + + (1) Or at least undocumented, and therefore unreliable. + + +File: auto-overlay-manual.info, Node: To-Do, Next: Function Index, Prev: Extending the Auto-Overlays Package, Up: Top + +5 To-Do +******* + +Things that still need to be implemented (in no particular order): + + 1. There needs to be an `eager-self' overlay class, similar to the + existing `self' class but updated immediately, rather than waiting + for buffer modifications. This will be significantly less + efficient, but is necessary for applications that require overlays + to be up to date all the time, not just when the buffer is being + modified. + + 2. Currently, it's difficult to deal with `nested' class regexps for + which the `end' regexps match some `start' regexps of interest but + also others that are irrelevant. E.g. `{' and `}' in LaTeX when + you're only interested in `\somecommand{' `start' regexps. Or + matching parens in LISP, when you're only interested in function + bodies, say. The only solution is to include all `start' regexps, + but not set any of their properties. This can end up creating a + lot of overlays! A variant of the `nested' class that avoids this + problem is needed. + + +File: auto-overlay-manual.info, Node: Function Index, Next: Variable Index, Prev: To-Do, Up: Top + +Appendix A Function Index +************************* + +[index] +* Menu: + +* auto-o-class: Functions for Querying Overlays. + (line 13) +* auto-o-delete-overlay: Functions for Modifying Overlays. + (line 61) +* auto-o-edge: Functions for Querying Overlays. + (line 29) +* auto-o-edge-matched-p: Functions for Querying Overlays. + (line 41) +* auto-o-end-matched-p: Functions for Querying Overlays. + (line 48) +* auto-o-match-function: Functions for Querying Overlays. + (line 38) +* auto-o-match-overlays: Functions for Modifying Overlays. + (line 21) +* auto-o-match-{class}: Integrating New Overlay Classes. + (line 36) +* auto-o-parse-function: Functions for Querying Overlays. + (line 32) +* auto-o-parse-{class}-match <1>: Standard Parse and Suicide Functions. + (line 23) +* auto-o-parse-{class}-match: Integrating New Overlay Classes. + (line 17) +* auto-o-props: Functions for Querying Overlays. + (line 24) +* auto-o-regexp: Functions for Querying Overlays. + (line 16) +* auto-o-regexp-group: Functions for Querying Overlays. + (line 20) +* auto-o-start-matched-p: Functions for Querying Overlays. + (line 45) +* auto-o-suicide-function: Functions for Querying Overlays. + (line 35) +* auto-o-update-exclusive: Functions for Modifying Overlays. + (line 12) +* auto-o-{class}-suicide <1>: Standard Parse and Suicide Functions. + (line 27) +* auto-o-{class}-suicide: Integrating New Overlay Classes. + (line 26) +* auto-overlay-highest-priority-at-point: Searching for Overlays. + (line 52) +* auto-overlay-load-definition: Defining Regexps. (line 46) +* auto-overlay-load-overlays: Starting and Stopping Auto-Overlays. + (line 85) +* auto-overlay-load-regexp: Defining Regexps. (line 57) +* auto-overlay-local-binding: Searching for Overlays. + (line 64) +* auto-overlay-save-overlays: Starting and Stopping Auto-Overlays. + (line 75) +* auto-overlay-share-regexp-set: Defining Regexps. (line 79) +* auto-overlay-start: Starting and Stopping Auto-Overlays. + (line 33) +* auto-overlay-stop: Starting and Stopping Auto-Overlays. + (line 57) +* auto-overlay-unload-definition: Defining Regexps. (line 70) +* auto-overlay-unload-regexp: Defining Regexps. (line 74) +* auto-overlay-unload-set: Defining Regexps. (line 67) +* auto-overlays-at-point: Searching for Overlays. + (line 12) +* auto-overlays-in: Searching for Overlays. + (line 45) + + +File: auto-overlay-manual.info, Node: Variable Index, Next: Concept Index, Prev: Function Index, Up: Top + +Appendix B Variable Index +************************* + +[index] +* Menu: + +* auto-o-pending-post-suicide: Auto-Overlay Modification Pseudo-Hooks. + (line 28) +* auto-o-pending-post-update: Auto-Overlay Modification Pseudo-Hooks. + (line 32) +* auto-o-pending-pre-suicide: Auto-Overlay Modification Pseudo-Hooks. + (line 25) +* auto-overlay-load-hook: Auto-Overlay Hooks. (line 13) +* auto-overlay-unload-hook: Auto-Overlay Hooks. (line 18) + + +File: auto-overlay-manual.info, Node: Concept Index, Next: Copying this Manual, Prev: Variable Index, Up: Top + +Appendix C Concept Index +************************ + +[index] +* Menu: + +* adding new overlay classes: Extending the Auto-Overlays Package. + (line 6) +* auto-overlay definitions: Defining Regexps. (line 46) +* auto-overlay definitions, unloading: Defining Regexps. (line 67) +* auto-overlays in depth: Auto-Overlays in Depth. + (line 6) +* auto-overlays, defining: Defining Regexps. (line 46) +* auto-overlays, loading: Defining Regexps. (line 46) +* buffers, sharing regexp sets between: Defining Regexps. (line 79) +* class, flat: Overview. (line 63) +* class, line: Overview. (line 35) +* class, line example: Worked Example. (line 137) +* class, nested: Overview. (line 57) +* class, nested example: Worked Example. (line 106) +* class, self: Overview. (line 47) +* class, self example: Worked Example. (line 72) +* class, standard parse functions: Standard Parse and Suicide Functions. + (line 6) +* class, standard suicide functions: Standard Parse and Suicide Functions. + (line 6) +* class, word: Overview. (line 30) +* class, word example: Worked Example. (line 33) +* classes of overlay: Overview. (line 19) +* classes, adding new: Extending the Auto-Overlays Package. + (line 6) +* classes, integrating new: Integrating New Overlay Classes. + (line 6) +* defining auto-overlays: Defining Regexps. (line 46) +* defining regexps: Defining Regexps. (line 6) +* deleting overlays: Functions for Modifying Overlays. + (line 61) +* delimeter: Overview. (line 70) +* example: Worked Example. (line 6) +* example, line class: Worked Example. (line 137) +* example, nested class: Worked Example. (line 106) +* example, self class: Worked Example. (line 72) +* example, word class: Worked Example. (line 33) +* exclusive property <1>: Functions for Modifying Overlays. + (line 12) +* exclusive property: Overview. (line 95) +* extending the auto-overlays package: Extending the Auto-Overlays Package. + (line 6) +* extending, deleting overlays: Functions for Modifying Overlays. + (line 61) +* extending, functions: Functions for Writing New Overlay Classes. + (line 6) +* extending, functions for modifying overlays: Functions for Modifying Overlays. + (line 6) +* extending, functions for querying overlays: Functions for Querying Overlays. + (line 6) +* extending, integrating new overlay classes: Integrating New Overlay Classes. + (line 6) +* extending, matching overlays: Functions for Modifying Overlays. + (line 21) +* extending, standard parse functions: Standard Parse and Suicide Functions. + (line 6) +* extending, standard suicide functions: Standard Parse and Suicide Functions. + (line 6) +* extending, updating exclusive: Functions for Modifying Overlays. + (line 12) +* FDL, GNU Free Documentation License: GNU Free Documentation License. + (line 6) +* finding overlays: Searching for Overlays. + (line 6) +* flat overlay class: Overview. (line 63) +* functions: Auto-Overlay Functions. + (line 6) +* functions, defining regexps: Defining Regexps. (line 6) +* functions, loading and saving overlays: Starting and Stopping Auto-Overlays. + (line 6) +* functions, loading and unloading regexps: Defining Regexps. (line 6) +* functions, match function: Integrating New Overlay Classes. + (line 36) +* functions, modifying overlays: Functions for Modifying Overlays. + (line 6) +* functions, parse function: Integrating New Overlay Classes. + (line 17) +* functions, querying overlays: Functions for Querying Overlays. + (line 6) +* functions, scheduling: Auto-Overlay Modification Pseudo-Hooks. + (line 6) +* functions, searching for overlays: Searching for Overlays. + (line 6) +* functions, starting and stopping overlays: Starting and Stopping Auto-Overlays. + (line 6) +* functions, suicide function: Integrating New Overlay Classes. + (line 26) +* functions, writing new overlay classes: Functions for Writing New Overlay Classes. + (line 6) +* grouping in regexps: Overview. (line 70) +* highest priority overlay: Searching for Overlays. + (line 52) +* hooks: Auto-Overlay Hooks. (line 6) +* hooks, loading and unloading: Auto-Overlay Hooks. (line 6) +* hooks, modification: Auto-Overlay Modification Pseudo-Hooks. + (line 6) +* integrating new classes, match function: Integrating New Overlay Classes. + (line 36) +* integrating new classes, parse function: Integrating New Overlay Classes. + (line 17) +* integrating new classes, suicide function: Integrating New Overlay Classes. + (line 26) +* integrating new overlay classes: Integrating New Overlay Classes. + (line 6) +* LaTeX: Worked Example. (line 6) +* line overlay class: Overview. (line 35) +* line overlay class example: Worked Example. (line 137) +* loading auto-overlay definitions: Defining Regexps. (line 46) +* loading overlays: Starting and Stopping Auto-Overlays. + (line 6) +* loading regexps: Defining Regexps. (line 57) +* loading the package: Auto-Overlay Functions. + (line 6) +* local-binding: Searching for Overlays. + (line 64) +* match function: Integrating New Overlay Classes. + (line 36) +* matching overlays: Functions for Modifying Overlays. + (line 21) +* modification pseudo-hooks: Auto-Overlay Modification Pseudo-Hooks. + (line 6) +* nested overlay class: Overview. (line 57) +* nested overlay class example: Worked Example. (line 106) +* overlay class, flat: Overview. (line 63) +* overlay class, line: Overview. (line 35) +* overlay class, line example: Worked Example. (line 137) +* overlay class, nested: Overview. (line 57) +* overlay class, nested example: Worked Example. (line 106) +* overlay class, self: Overview. (line 47) +* overlay class, self example: Worked Example. (line 72) +* overlay class, word: Overview. (line 30) +* overlay class, word example: Worked Example. (line 33) +* overlay classes: Overview. (line 19) +* overlay classes, functions for writing new: Functions for Writing New Overlay Classes. + (line 6) +* overlay classes, integrating new: Integrating New Overlay Classes. + (line 6) +* overlay classes, match function: Integrating New Overlay Classes. + (line 36) +* overlay classes, parse function: Integrating New Overlay Classes. + (line 17) +* overlay classes, standard parse functions: Standard Parse and Suicide Functions. + (line 6) +* overlay classes, standard suicide functions: Standard Parse and Suicide Functions. + (line 6) +* overlay classes, suicide function: Integrating New Overlay Classes. + (line 26) +* overlay properties <1>: Searching for Overlays. + (line 6) +* overlay properties: Overview. (line 101) +* overlay property, exclusive <1>: Functions for Modifying Overlays. + (line 12) +* overlay property, exclusive: Overview. (line 95) +* overlay property, priority: Overview. (line 86) +* overlay-local binding: Searching for Overlays. + (line 64) +* overlays, deleting: Functions for Modifying Overlays. + (line 61) +* overlays, finding: Searching for Overlays. + (line 6) +* overlays, functions for modifying: Functions for Modifying Overlays. + (line 6) +* overlays, functions for querying: Functions for Querying Overlays. + (line 6) +* overlays, local-binding: Searching for Overlays. + (line 64) +* overlays, matching: Functions for Modifying Overlays. + (line 21) +* overlays, priority: Searching for Overlays. + (line 52) +* overlays, saving and loading: Starting and Stopping Auto-Overlays. + (line 6) +* overlays, starting and stopping: Starting and Stopping Auto-Overlays. + (line 6) +* Overview: Overview. (line 6) +* package, extending: Extending the Auto-Overlays Package. + (line 6) +* package, hooks: Auto-Overlay Hooks. (line 6) +* package, in depth: Auto-Overlays in Depth. + (line 6) +* package, loading: Auto-Overlay Functions. + (line 6) +* parse function: Integrating New Overlay Classes. + (line 17) +* priority property: Overview. (line 86) +* regexp definitions, unloading: Defining Regexps. (line 70) +* regexp groups: Overview. (line 70) +* regexp sets: Overview. (line 12) +* regexp sets, sharing between buffers: Defining Regexps. (line 79) +* regexp sets, starting and stopping: Starting and Stopping Auto-Overlays. + (line 6) +* regexp sets, unloading: Defining Regexps. (line 67) +* regexps, defining: Defining Regexps. (line 6) +* regexps, loading: Defining Regexps. (line 57) +* regexps, loading and unloading: Defining Regexps. (line 6) +* regexps, unloading: Defining Regexps. (line 74) +* require: Auto-Overlay Functions. + (line 6) +* saving overlays: Starting and Stopping Auto-Overlays. + (line 6) +* scheduling functions after modification: Auto-Overlay Modification Pseudo-Hooks. + (line 6) +* searching for overlays: Searching for Overlays. + (line 6) +* self overlay class: Overview. (line 47) +* self overlay class example: Worked Example. (line 72) +* sets of regexps: Overview. (line 12) +* sharing regexp sets: Defining Regexps. (line 79) +* standard parse and suicide functions: Standard Parse and Suicide Functions. + (line 6) +* starting and stopping auto-overlays: Starting and Stopping Auto-Overlays. + (line 6) +* suicide function: Integrating New Overlay Classes. + (line 26) +* to-do: To-Do. (line 6) +* unloading regexp definitions: Defining Regexps. (line 70) +* unloading regexp sets: Defining Regexps. (line 67) +* unloading regexps: Defining Regexps. (line 74) +* updating exclusive regions: Functions for Modifying Overlays. + (line 12) +* using auto-overlays: Auto-Overlay Functions. + (line 6) +* word overlay class: Overview. (line 30) +* word overlay class example: Worked Example. (line 33) +* worked example: Worked Example. (line 6) + + +File: auto-overlay-manual.info, Node: Copying this Manual, Prev: Concept Index, Up: Top + +Appendix D Copying this Manual +****************************** + +* Menu: + +* GNU Free Documentation License:: + + +File: auto-overlay-manual.info, Node: GNU Free Documentation License, Up: Copying this Manual + +D.1 GNU Free Documentation License +================================== + + Version 1.2, November 2002 + + Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + 0. PREAMBLE + + The purpose of this License is to make a manual, textbook, or other + functional and useful document "free" in the sense of freedom: to + assure everyone the effective freedom to copy and redistribute it, + with or without modifying it, either commercially or + noncommercially. Secondarily, this License preserves for the + author and publisher a way to get credit for their work, while not + being considered responsible for modifications made by others. + + This License is a kind of "copyleft", which means that derivative + works of the document must themselves be free in the same sense. + It complements the GNU General Public License, which is a copyleft + license designed for free software. + + We have designed this License in order to use it for manuals for + free software, because free software needs free documentation: a + free program should come with manuals providing the same freedoms + that the software does. But this License is not limited to + software manuals; it can be used for any textual work, regardless + of subject matter or whether it is published as a printed book. + We recommend this License principally for works whose purpose is + instruction or reference. + + 1. APPLICABILITY AND DEFINITIONS + + This License applies to any manual or other work, in any medium, + that contains a notice placed by the copyright holder saying it + can be distributed under the terms of this License. Such a notice + grants a world-wide, royalty-free license, unlimited in duration, + to use that work under the conditions stated herein. The + "Document", below, refers to any such manual or work. Any member + of the public is a licensee, and is addressed as "you". You + accept the license if you copy, modify or distribute the work in a + way requiring permission under copyright law. + + A "Modified Version" of the Document means any work containing the + Document or a portion of it, either copied verbatim, or with + modifications and/or translated into another language. + + A "Secondary Section" is a named appendix or a front-matter section + of the Document that deals exclusively with the relationship of the + publishers or authors of the Document to the Document's overall + subject (or to related matters) and contains nothing that could + fall directly within that overall subject. (Thus, if the Document + is in part a textbook of mathematics, a Secondary Section may not + explain any mathematics.) The relationship could be a matter of + historical connection with the subject or with related matters, or + of legal, commercial, philosophical, ethical or political position + regarding them. + + The "Invariant Sections" are certain Secondary Sections whose + titles are designated, as being those of Invariant Sections, in + the notice that says that the Document is released under this + License. If a section does not fit the above definition of + Secondary then it is not allowed to be designated as Invariant. + The Document may contain zero Invariant Sections. If the Document + does not identify any Invariant Sections then there are none. + + The "Cover Texts" are certain short passages of text that are + listed, as Front-Cover Texts or Back-Cover Texts, in the notice + that says that the Document is released under this License. A + Front-Cover Text may be at most 5 words, and a Back-Cover Text may + be at most 25 words. + + A "Transparent" copy of the Document means a machine-readable copy, + represented in a format whose specification is available to the + general public, that is suitable for revising the document + straightforwardly with generic text editors or (for images + composed of pixels) generic paint programs or (for drawings) some + widely available drawing editor, and that is suitable for input to + text formatters or for automatic translation to a variety of + formats suitable for input to text formatters. A copy made in an + otherwise Transparent file format whose markup, or absence of + markup, has been arranged to thwart or discourage subsequent + modification by readers is not Transparent. An image format is + not Transparent if used for any substantial amount of text. A + copy that is not "Transparent" is called "Opaque". + + Examples of suitable formats for Transparent copies include plain + ASCII without markup, Texinfo input format, LaTeX input format, + SGML or XML using a publicly available DTD, and + standard-conforming simple HTML, PostScript or PDF designed for + human modification. Examples of transparent image formats include + PNG, XCF and JPG. Opaque formats include proprietary formats that + can be read and edited only by proprietary word processors, SGML or + XML for which the DTD and/or processing tools are not generally + available, and the machine-generated HTML, PostScript or PDF + produced by some word processors for output purposes only. + + The "Title Page" means, for a printed book, the title page itself, + plus such following pages as are needed to hold, legibly, the + material this License requires to appear in the title page. For + works in formats which do not have any title page as such, "Title + Page" means the text near the most prominent appearance of the + work's title, preceding the beginning of the body of the text. + + A section "Entitled XYZ" means a named subunit of the Document + whose title either is precisely XYZ or contains XYZ in parentheses + following text that translates XYZ in another language. (Here XYZ + stands for a specific section name mentioned below, such as + "Acknowledgements", "Dedications", "Endorsements", or "History".) + To "Preserve the Title" of such a section when you modify the + Document means that it remains a section "Entitled XYZ" according + to this definition. + + The Document may include Warranty Disclaimers next to the notice + which states that this License applies to the Document. These + Warranty Disclaimers are considered to be included by reference in + this License, but only as regards disclaiming warranties: any other + implication that these Warranty Disclaimers may have is void and + has no effect on the meaning of this License. + + 2. VERBATIM COPYING + + You may copy and distribute the Document in any medium, either + commercially or noncommercially, provided that this License, the + copyright notices, and the license notice saying this License + applies to the Document are reproduced in all copies, and that you + add no other conditions whatsoever to those of this License. You + may not use technical measures to obstruct or control the reading + or further copying of the copies you make or distribute. However, + you may accept compensation in exchange for copies. If you + distribute a large enough number of copies you must also follow + the conditions in section 3. + + You may also lend copies, under the same conditions stated above, + and you may publicly display copies. + + 3. COPYING IN QUANTITY + + If you publish printed copies (or copies in media that commonly + have printed covers) of the Document, numbering more than 100, and + the Document's license notice requires Cover Texts, you must + enclose the copies in covers that carry, clearly and legibly, all + these Cover Texts: Front-Cover Texts on the front cover, and + Back-Cover Texts on the back cover. Both covers must also clearly + and legibly identify you as the publisher of these copies. The + front cover must present the full title with all words of the + title equally prominent and visible. You may add other material + on the covers in addition. Copying with changes limited to the + covers, as long as they preserve the title of the Document and + satisfy these conditions, can be treated as verbatim copying in + other respects. + + If the required texts for either cover are too voluminous to fit + legibly, you should put the first ones listed (as many as fit + reasonably) on the actual cover, and continue the rest onto + adjacent pages. + + If you publish or distribute Opaque copies of the Document + numbering more than 100, you must either include a + machine-readable Transparent copy along with each Opaque copy, or + state in or with each Opaque copy a computer-network location from + which the general network-using public has access to download + using public-standard network protocols a complete Transparent + copy of the Document, free of added material. If you use the + latter option, you must take reasonably prudent steps, when you + begin distribution of Opaque copies in quantity, to ensure that + this Transparent copy will remain thus accessible at the stated + location until at least one year after the last time you + distribute an Opaque copy (directly or through your agents or + retailers) of that edition to the public. + + It is requested, but not required, that you contact the authors of + the Document well before redistributing any large number of + copies, to give them a chance to provide you with an updated + version of the Document. + + 4. MODIFICATIONS + + You may copy and distribute a Modified Version of the Document + under the conditions of sections 2 and 3 above, provided that you + release the Modified Version under precisely this License, with + the Modified Version filling the role of the Document, thus + licensing distribution and modification of the Modified Version to + whoever possesses a copy of it. In addition, you must do these + things in the Modified Version: + + A. Use in the Title Page (and on the covers, if any) a title + distinct from that of the Document, and from those of + previous versions (which should, if there were any, be listed + in the History section of the Document). You may use the + same title as a previous version if the original publisher of + that version gives permission. + + B. List on the Title Page, as authors, one or more persons or + entities responsible for authorship of the modifications in + the Modified Version, together with at least five of the + principal authors of the Document (all of its principal + authors, if it has fewer than five), unless they release you + from this requirement. + + C. State on the Title page the name of the publisher of the + Modified Version, as the publisher. + + D. Preserve all the copyright notices of the Document. + + E. Add an appropriate copyright notice for your modifications + adjacent to the other copyright notices. + + F. Include, immediately after the copyright notices, a license + notice giving the public permission to use the Modified + Version under the terms of this License, in the form shown in + the Addendum below. + + G. Preserve in that license notice the full lists of Invariant + Sections and required Cover Texts given in the Document's + license notice. + + H. Include an unaltered copy of this License. + + I. Preserve the section Entitled "History", Preserve its Title, + and add to it an item stating at least the title, year, new + authors, and publisher of the Modified Version as given on + the Title Page. If there is no section Entitled "History" in + the Document, create one stating the title, year, authors, + and publisher of the Document as given on its Title Page, + then add an item describing the Modified Version as stated in + the previous sentence. + + J. Preserve the network location, if any, given in the Document + for public access to a Transparent copy of the Document, and + likewise the network locations given in the Document for + previous versions it was based on. These may be placed in + the "History" section. You may omit a network location for a + work that was published at least four years before the + Document itself, or if the original publisher of the version + it refers to gives permission. + + K. For any section Entitled "Acknowledgements" or "Dedications", + Preserve the Title of the section, and preserve in the + section all the substance and tone of each of the contributor + acknowledgements and/or dedications given therein. + + L. Preserve all the Invariant Sections of the Document, + unaltered in their text and in their titles. Section numbers + or the equivalent are not considered part of the section + titles. + + M. Delete any section Entitled "Endorsements". Such a section + may not be included in the Modified Version. + + N. Do not retitle any existing section to be Entitled + "Endorsements" or to conflict in title with any Invariant + Section. + + O. Preserve any Warranty Disclaimers. + + If the Modified Version includes new front-matter sections or + appendices that qualify as Secondary Sections and contain no + material copied from the Document, you may at your option + designate some or all of these sections as invariant. To do this, + add their titles to the list of Invariant Sections in the Modified + Version's license notice. These titles must be distinct from any + other section titles. + + You may add a section Entitled "Endorsements", provided it contains + nothing but endorsements of your Modified Version by various + parties--for example, statements of peer review or that the text + has been approved by an organization as the authoritative + definition of a standard. + + You may add a passage of up to five words as a Front-Cover Text, + and a passage of up to 25 words as a Back-Cover Text, to the end + of the list of Cover Texts in the Modified Version. Only one + passage of Front-Cover Text and one of Back-Cover Text may be + added by (or through arrangements made by) any one entity. If the + Document already includes a cover text for the same cover, + previously added by you or by arrangement made by the same entity + you are acting on behalf of, you may not add another; but you may + replace the old one, on explicit permission from the previous + publisher that added the old one. + + The author(s) and publisher(s) of the Document do not by this + License give permission to use their names for publicity for or to + assert or imply endorsement of any Modified Version. + + 5. COMBINING DOCUMENTS + + You may combine the Document with other documents released under + this License, under the terms defined in section 4 above for + modified versions, provided that you include in the combination + all of the Invariant Sections of all of the original documents, + unmodified, and list them all as Invariant Sections of your + combined work in its license notice, and that you preserve all + their Warranty Disclaimers. + + The combined work need only contain one copy of this License, and + multiple identical Invariant Sections may be replaced with a single + copy. If there are multiple Invariant Sections with the same name + but different contents, make the title of each such section unique + by adding at the end of it, in parentheses, the name of the + original author or publisher of that section if known, or else a + unique number. Make the same adjustment to the section titles in + the list of Invariant Sections in the license notice of the + combined work. + + In the combination, you must combine any sections Entitled + "History" in the various original documents, forming one section + Entitled "History"; likewise combine any sections Entitled + "Acknowledgements", and any sections Entitled "Dedications". You + must delete all sections Entitled "Endorsements." + + 6. COLLECTIONS OF DOCUMENTS + + You may make a collection consisting of the Document and other + documents released under this License, and replace the individual + copies of this License in the various documents with a single copy + that is included in the collection, provided that you follow the + rules of this License for verbatim copying of each of the + documents in all other respects. + + You may extract a single document from such a collection, and + distribute it individually under this License, provided you insert + a copy of this License into the extracted document, and follow + this License in all other respects regarding verbatim copying of + that document. + + 7. AGGREGATION WITH INDEPENDENT WORKS + + A compilation of the Document or its derivatives with other + separate and independent documents or works, in or on a volume of + a storage or distribution medium, is called an "aggregate" if the + copyright resulting from the compilation is not used to limit the + legal rights of the compilation's users beyond what the individual + works permit. When the Document is included in an aggregate, this + License does not apply to the other works in the aggregate which + are not themselves derivative works of the Document. + + If the Cover Text requirement of section 3 is applicable to these + copies of the Document, then if the Document is less than one half + of the entire aggregate, the Document's Cover Texts may be placed + on covers that bracket the Document within the aggregate, or the + electronic equivalent of covers if the Document is in electronic + form. Otherwise they must appear on printed covers that bracket + the whole aggregate. + + 8. TRANSLATION + + Translation is considered a kind of modification, so you may + distribute translations of the Document under the terms of section + 4. Replacing Invariant Sections with translations requires special + permission from their copyright holders, but you may include + translations of some or all Invariant Sections in addition to the + original versions of these Invariant Sections. You may include a + translation of this License, and all the license notices in the + Document, and any Warranty Disclaimers, provided that you also + include the original English version of this License and the + original versions of those notices and disclaimers. In case of a + disagreement between the translation and the original version of + this License or a notice or disclaimer, the original version will + prevail. + + If a section in the Document is Entitled "Acknowledgements", + "Dedications", or "History", the requirement (section 4) to + Preserve its Title (section 1) will typically require changing the + actual title. + + 9. TERMINATION + + You may not copy, modify, sublicense, or distribute the Document + except as expressly provided for under this License. Any other + attempt to copy, modify, sublicense or distribute the Document is + void, and will automatically terminate your rights under this + License. However, parties who have received copies, or rights, + from you under this License will not have their licenses + terminated so long as such parties remain in full compliance. + + 10. FUTURE REVISIONS OF THIS LICENSE + + The Free Software Foundation may publish new, revised versions of + the GNU Free Documentation License from time to time. Such new + versions will be similar in spirit to the present version, but may + differ in detail to address new problems or concerns. See + `http://www.gnu.org/copyleft/'. + + Each version of the License is given a distinguishing version + number. If the Document specifies that a particular numbered + version of this License "or any later version" applies to it, you + have the option of following the terms and conditions either of + that specified version or of any later version that has been + published (not as a draft) by the Free Software Foundation. If + the Document does not specify a version number of this License, + you may choose any version ever published (not as a draft) by the + Free Software Foundation. + +D.1.1 ADDENDUM: How to use this License for your documents +---------------------------------------------------------- + +To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and license +notices just after the title page: + + Copyright (C) YEAR YOUR NAME. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.2 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover + Texts. A copy of the license is included in the section entitled ``GNU + Free Documentation License''. + + If you have Invariant Sections, Front-Cover Texts and Back-Cover +Texts, replace the "with...Texts." line with this: + + with the Invariant Sections being LIST THEIR TITLES, with + the Front-Cover Texts being LIST, and with the Back-Cover Texts + being LIST. + + If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. + + If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of +free software license, such as the GNU General Public License, to +permit their use in free software. + + + +Tag Table: +Node: Top795 +Node: Overview2850 +Node: Auto-Overlay Functions7841 +Node: Defining Regexps9295 +Node: Starting and Stopping Auto-Overlays14154 +Node: Searching for Overlays19680 +Node: Worked Example23678 +Node: Extending the Auto-Overlays Package44510 +Ref: Extending the Auto-Overlays Package-Footnote-145572 +Node: Auto-Overlays in Depth45781 +Ref: Auto-Overlays in Depth-Footnote-148574 +Ref: Auto-Overlays in Depth-Footnote-248755 +Ref: Auto-Overlays in Depth-Footnote-348909 +Node: Integrating New Overlay Classes48939 +Node: Functions for Writing New Overlay Classes51658 +Node: Standard Parse and Suicide Functions52592 +Node: Functions for Modifying Overlays54065 +Node: Functions for Querying Overlays57797 +Node: Auto-Overlay Hooks59629 +Node: Auto-Overlay Modification Pseudo-Hooks60684 +Ref: Auto-Overlay Modification Pseudo-Hooks-Footnote-162777 +Node: To-Do62837 +Node: Function Index63994 +Node: Variable Index68574 +Node: Concept Index69369 +Node: Copying this Manual86107 +Node: GNU Free Documentation License86309 + +End Tag Table diff --git a/packages/auto-overlays/auto-overlay-nested.el b/packages/auto-overlays/auto-overlay-nested.el new file mode 100644 index 000000000..c9a72f198 --- /dev/null +++ b/packages/auto-overlays/auto-overlay-nested.el @@ -0,0 +1,219 @@ +;;; auto-overlay-nested.el --- nested start/end-delimited automatic overlays + + +;; Copyright (C) 2005-2015 Free Software Foundation, Inc + +;; Author: Toby Cubitt +;; Maintainer: Toby Cubitt +;; URL: http://www.dr-qubit.org/emacs.php +;; Repository: http://www.dr-qubit.org/git/predictive.git + +;; This file is part of the 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 program 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 this program. If not, see . + + +;;; Code: + +(require 'auto-overlays) +(provide 'auto-overlay-nested) + + +;; set nested overlay parsing and suicide functions, and indicate class +;; requires separate start and end regexps +(put 'nested 'auto-overlay-parse-function 'auto-o-parse-nested-match) +(put 'nested 'auto-overlay-suicide-function 'auto-o-nested-suicide) +(put 'nested 'auto-overlay-complex-class t) + + + +(defun auto-o-parse-nested-match (o-match) + ;; Perform any necessary updates of auto overlays due to a match for a + ;; nested regexp. + + (let* ((overlay-stack (auto-o-nested-stack o-match)) + (o (car overlay-stack))) + (cond + ;; if the stack is empty, just create and return a new unmatched overlay + ((null overlay-stack) + (auto-o-make-nested o-match 'unmatched)) + + ;; if appropriate edge of innermost overlay is unmatched, just match it + ((or (and (eq (auto-o-edge o-match) 'start) + (not (auto-o-start-matched-p o))) + (and (eq (auto-o-edge o-match) 'end) + (not (auto-o-end-matched-p o)))) + (auto-o-match-overlay o o-match) + ;; return nil since haven't created any new overlays + nil) + + ;; otherwise... + (t + ;; create new innermost overlay and add it to the overlay stack + (push (auto-o-make-nested o-match) overlay-stack) + ;; sort out the overlay stack + (auto-o-nested-stack-cascade overlay-stack) + ;; return newly created overlay + (car overlay-stack))) + )) + + + + +(defun auto-o-nested-suicide (o-self) + ;; Called when match no longer matches. Unmatch the match overlay O-SELF, if + ;; necessary deleting its parent overlay or cascading the stack. + + (let* ((overlay-stack (auto-o-nested-stack o-self)) + (o-parent (car overlay-stack))) + + (cond + ;; if other end of parent is unmatched, just delete parent + ((not (auto-o-edge-matched-p + o-parent + (if (eq (auto-o-edge o-self) 'start) 'end 'start))) + (auto-o-delete-overlay o-parent)) + + ;; if parent is the only overlay in the stack... + ((= (length overlay-stack) 1) + ;; if we're a start match, make parent start-unmatched + (if (eq (auto-o-edge o-self) 'start) + (auto-o-match-overlay o-parent 'unmatched nil) + ;; if we're an end match, make parent end-unmatched + (auto-o-match-overlay o-parent nil 'unmatched))) + + ;; otherwise, unmatch ourselves from parent and cascade the stack + (t + (overlay-put o-parent (auto-o-edge o-self) nil) + (overlay-put o-self 'parent nil) + (auto-o-nested-stack-cascade overlay-stack)) + ))) + + + + +(defun auto-o-make-nested (o-match &optional unmatched) + ;; Create a nested overlay for match overlay O-MATCH. + ;; If UNMATCHED is nil, overlay will start and end at O-MATCH. + ;; If non-nil, overlay will start or end from O-MATCH (depending on whether + ;; O-MATCH is a 'start or 'end match) and stretch till end or beginning of + ;; buffer. + + (let (o-new pos) + ;; create new nested overlay and match it with O-MATCH + (cond + ((eq (auto-o-edge o-match) 'start) + (setq pos (overlay-get o-match 'delim-end)) + (setq o-new (make-overlay pos pos nil nil 'rear-advance)) + (overlay-put o-new 'auto-overlay t) + (overlay-put o-new 'set-id (overlay-get o-match 'set-id)) + (overlay-put o-new 'definition-id (overlay-get o-match 'definition-id)) + (auto-o-match-overlay o-new o-match 'unmatched)) + + ((eq (auto-o-edge o-match) 'end) + (setq pos (overlay-get o-match 'delim-start)) + (setq o-new (make-overlay pos pos nil nil 'rear-advance)) + (overlay-put o-new 'auto-overlay t) + (overlay-put o-new 'set-id (overlay-get o-match 'set-id)) + (overlay-put o-new 'definition-id (overlay-get o-match 'definition-id)) + (auto-o-match-overlay o-new 'unmatched o-match))) + + ;; return the new overlay + o-new)) + + + +(defun auto-o-nested-stack-cascade (overlay-stack) + ;; Cascade the ends of the overlays in OVERLAY-STACK up or down the stack, + ;; so as to re-establish a valid stack. It assumes that only the innermost + ;; is incorrect. + + (let ((o (car overlay-stack)) o1) + (cond + + ;; if innermost overlay is start-matched (and presumably + ;; end-unmatched)... + ((auto-o-start-matched-p o) + ;; cascade overlay end matches up through stack until one is left + (dotimes (i (- (length overlay-stack) 1)) + (setq o (nth i overlay-stack)) + (setq o1 (nth (+ i 1) overlay-stack)) + (auto-o-match-overlay o nil + (if (overlay-get o1 'end) + (overlay-get o1 'end) + 'unmatched) + nil nil 'protect-match)) + ;; if final overlay is start-matched, make it end-unmatched, otherwise + ;; delete it + (if (auto-o-start-matched-p o1) + ;; FIXME: could postpone re-parsing here in case it can be avoided + (auto-o-match-overlay o1 nil 'unmatch nil nil 'protect-match) + (auto-o-delete-overlay o1 nil 'protect-match))) + + + ;; if innermost overlay is end-matched (and presumably + ;; start-unmatched)... + ((auto-o-end-matched-p o) + ;; cascade overlay start matches up through stack until one is left + (dotimes (i (- (length overlay-stack) 1)) + (setq o (nth i overlay-stack)) + (setq o1 (nth (+ i 1) overlay-stack)) + (auto-o-match-overlay o (if (overlay-get o1 'start) + (overlay-get o1 'start) + 'unmatched) + nil nil nil 'protect-match)) + ;; if final overlay is end-matched, make it start-unmatched, otherwise + ;; delete it + (if (auto-o-end-matched-p o1) + ;; FIXME: could postpone re-parsing here in case it can be avoided + (auto-o-match-overlay o1 'unmatch nil nil nil 'protect-match) + (auto-o-delete-overlay o1 nil 'protect-match)))) + ) +) + + + + +(defun auto-o-nested-stack (o-match) + ;; Return a list of the overlays that overlap and correspond to same entry + ;; as match overlay O-MATCH, ordered from innermost to outermost. (Assumes + ;; overlays are correctly stacked.) The parent of O-MATCH is guaranteed to + ;; come before any other overlay that has exactly the same length (which + ;; implies they cover identical regions if overlays are correctly + ;; stacked). For other overlays with identical lengths, the order is + ;; undefined. + + ;; find overlays corresponding to same entry overlapping O-MATCH + (let ((overlay-stack (auto-overlays-at-point + (if (eq (auto-o-edge o-match) 'start) + (overlay-get o-match 'delim-end) + (overlay-get o-match 'delim-start)) + (list '(eq auto-overlay t) + (list 'eq 'set-id (overlay-get o-match 'set-id)) + (list 'eq 'definition-id + (overlay-get o-match 'definition-id))))) + (o-parent (overlay-get o-match 'parent))) + ;; sort the list by overlay length, i.e. from innermost to outermose + (sort overlay-stack + (lambda (a b) + (let ((len-a (- (overlay-end a) (overlay-start a))) + (len-b (- (overlay-end b) (overlay-start b)))) + ;; parent of O-MATCH comes before any other overlay with + ;; identical length, otherwise sort by length + (if (= len-a len-b) (eq o-parent a) (< len-a len-b))))) + ) +) + + +;; auto-overlay-nested.el ends here diff --git a/packages/auto-overlays/auto-overlay-self.el b/packages/auto-overlays/auto-overlay-self.el new file mode 100644 index 000000000..b5c61cdbf --- /dev/null +++ b/packages/auto-overlays/auto-overlay-self.el @@ -0,0 +1,321 @@ +;;; auto-overlay-self.el --- self-delimited automatic overlays + + +;; Copyright (C) 2005-2015 Free Software Foundation, Inc + +;; Author: Toby Cubitt +;; Maintainer: Toby Cubitt +;; URL: http://www.dr-qubit.org/emacs.php +;; Repository: http://www.dr-qubit.org/git/predictive.git + +;; This file is part of the 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 program 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 this program. If not, see . + + +;;; Code: + +(require 'auto-overlays) +(provide 'auto-overlay-self) + +(defvar auto-o-pending-self-cascade nil) + +;; set self overlay parsing and suicide functions +(put 'self 'auto-overlay-parse-function 'auto-o-parse-self-match) +(put 'self 'auto-overlay-suicide-function 'auto-o-self-suicide) + +;; add initialisation and clear functions to hooks +(add-hook 'auto-overlay-load-hook 'auto-o-self-load) +(add-hook 'auto-overlay-unload-hook 'auto-o-self-unload) + + + +(defun auto-o-self-load () + ;; Make sure `auto-o-perform-self-cascades' is in `before-change-functions', + ;; so that any cascading that is required is performed before anything else + ;; happens. + (add-hook 'before-change-functions 'auto-o-perform-self-cascades + nil t) + ;; initialise variables + (setq auto-o-pending-self-cascade nil) +) + + +(defun auto-o-self-unload () + ;; Remove `auto-o-perform-self-cascades' from `before-change-functions'. + (remove-hook 'before-change-functions 'auto-o-perform-self-cascades t) +) + + + + +(defun auto-o-parse-self-match (o-match) + ;; perform any necessary updates of auto overlays due to a match for a self + ;; regexp + + (let* ((overlay-list (auto-o-self-list o-match)) + (o (car overlay-list))) + + (cond + ;; if stack is empty, create a new end-unmatched overlay, adding it to + ;; the list of unascaded overlays (avoids treating it as a special + ;; case), and return it + ((null overlay-list) + (auto-o-make-self o-match nil)) + + ;; if new delimiter is inside the first existing overlay and existing one + ;; is end-unmatched, just match it + ((and (not (overlay-get o 'end)) + (>= (overlay-get o-match 'delim-start) (overlay-start o))) + (auto-o-match-overlay o nil o-match 'no-props) + ;; remove it from the list of uncascaded overlays + (setq auto-o-pending-self-cascade (delq o auto-o-pending-self-cascade)) + ;; return nil since haven't created any new overlays + nil) + + + ;; otherwise... + (t + (let (o-new) + ;; if the new match is outside existing overlays... + (if (< (overlay-get o-match 'delim-end) (overlay-start o)) + ;; create overlay from new match till start of next match, and add + ;; it to the list of uncascaded overlays + (setq o-new (auto-o-make-self + o-match + (overlay-get (overlay-get o 'start) 'delim-start))) + + ;; if the new match is inside an existing overlay... + (setq o (pop overlay-list)) + ;; create overlay from end of existing one till start of the one + ;; after (or end of buffer if there isn't one), and add it to the + ;; list of uncascaded overlays + (setq o-new (auto-o-make-self + (overlay-get o 'end) + (when overlay-list + (overlay-get (overlay-get (car overlay-list) 'start) + 'delim-start)))) + ;; match end of existing one with the new match, protecting its old + ;; end match which is now matched with start of new one + (auto-o-match-overlay o nil o-match 'no-props nil 'protect-match)) + + ;; return newly created overlay + o-new)) + )) +) + + + + +(defun auto-o-self-suicide (o-self) + ;; Called when match no longer matches. Unmatch the match overlay O-SELF, if + ;; necessary deleting its parent overlay or cascading. + + (let ((o-parent (overlay-get o-self 'parent))) + (cond + ;; if parent is end-unmatched, delete it from buffer and from list of + ;; uncascaded overlays + ((not (auto-o-end-matched-p o-parent)) + (auto-o-delete-overlay o-parent) + (setq auto-o-pending-self-cascade + (delq o-parent auto-o-pending-self-cascade))) + + ;; if we match the end of parent... + ((eq (overlay-get o-parent 'end) o-self) + ;; unmatch ourselves from parent and extend parent till next overlay, or + ;; end of buffer if there is none + (let ((o (nth 1 (auto-o-self-list o-self)))) + (auto-o-match-overlay + o-parent nil (if o (overlay-get (overlay-get o 'start) 'delim-start) + 'unmatched))) + ;; add parent to uncascaded overlay list + (push o-parent auto-o-pending-self-cascade)) + + ;; if we match the start of parent... + (t + (let* ((o-end (overlay-get o-parent 'end)) + (o (nth 1 (auto-o-self-list o-end)))) + ;; unmatch ourselves from parent and "flip" + (auto-o-match-overlay + o-parent o-end + (if o (overlay-get (overlay-get o 'start) 'delim-start) + 'unmatched))) + ;; add parent to uncascaded overlay list + (push o-parent auto-o-pending-self-cascade)) + )) +) + + + + +(defun auto-o-make-self (o-start &optional end) + ;; Create a self overlay starting at match overlay O-START. + ;; If END is a number or marker, the new overlay is end-unmatched and ends + ;; at the buffer location specified by the number or marker. + ;; If END is nil, the new overlay is end-unmatched and ends at the end of + ;; the buffer. + (let (o-new) + + ;; create new overlay (location ensures right things happen when matched) + (let (pos) + (cond + ((overlayp end) (setq pos (overlay-get end 'delim-start))) + ((number-or-marker-p end) (setq pos end)) + (t (setq pos (point-max)))) + (setq o-new (make-overlay pos pos nil nil 'rear-advance))) + + ;; give overlay some basic properties + (overlay-put o-new 'auto-overlay t) + (overlay-put o-new 'set-id (overlay-get o-start 'set-id)) + (overlay-put o-new 'definition-id (overlay-get o-start 'definition-id)) + + ;; if overlay is end-unmatched, add it to the list of uncascaded overlays + (unless (overlayp end) (push o-new auto-o-pending-self-cascade)) + + ;; match the new overlay and return it + (auto-o-match-overlay o-new o-start (if (overlayp end) end nil)) + o-new) +) + + + + +(defun auto-o-perform-self-cascades (beg end) + ;; Perform any necessary self-overlay cascading before the text in the + ;; buffer is modified. Called from `before-change-functions'. + + ;; check all overlays waiting to be cascaded, from first in buffer to last + (dolist (o (sort auto-o-pending-self-cascade + (lambda (a b) (< (overlay-start a) (overlay-start b))))) + ;; if buffer modification occurs after the end of an overlay waiting to be + ;; cascaded, cascade all overlays between it and the modified text + (when (and (overlay-end o) (< (overlay-end o) end)) + (auto-o-self-cascade (auto-o-self-list (overlay-get o 'start) end)))) +) + + + + +(defun auto-o-self-cascade (overlay-list) + ;; "Flip" overlays down through buffer (assumes first overlay in list is + ;; end-unmatched). + (when (> (length overlay-list) 1) + (let ((o (car overlay-list)) + (o1 (nth 1 overlay-list))) + + ;; match first (presumably end-matched) overlay and remove it from list + (pop overlay-list) + (auto-o-match-overlay o nil (overlay-get o1 'start) 'no-props) + ;; remove it from list of uncascaded overlays + (setq auto-o-pending-self-cascade (delq o auto-o-pending-self-cascade)) + ;; if we've hit an end-unmatched overlay, we can stop cascading + (if (not (auto-o-end-matched-p o1)) + (progn + (auto-o-delete-overlay o1 nil 'protect-match) + (setq auto-o-pending-self-cascade + (delq o1 auto-o-pending-self-cascade))) + + ;; otherwise, cascade overlay list till one is left or we hit an + ;; end-unmached overlay + (unless + (catch 'stop + (dotimes (i (1- (length overlay-list))) + (setq o (nth i overlay-list)) + (setq o1 (nth (1+ i) overlay-list)) + (auto-o-match-overlay o (overlay-get o 'end) + (overlay-get o1 'start) + 'no-props nil 'protect-match) + ;; if we hit an end-unmatched overlay, we can stop cascading + (when (not (auto-o-end-matched-p o1)) + (throw 'stop (progn + ;; delete the end-unmatched overlay + (auto-o-delete-overlay o1 nil 'protect-match) + ;; remove it from uncascaded overlays list + (setq auto-o-pending-self-cascade + (delq o1 auto-o-pending-self-cascade)) + ;; return t to indicate cascading ended early + t))))) + + ;; if there's an overlay left, "flip" it so it's end-unmatched and + ;; extends to next overlay in buffer, and add it to the list of + ;; unmatched overlays + (let (pos) + (setq o (car (last overlay-list))) + (if (setq o1 (nth 1 (auto-o-self-list (overlay-get o 'end)))) + (setq pos (overlay-get (overlay-get o1 'start) 'delim-start)) + (setq pos (point-max))) + (auto-o-match-overlay o (overlay-get o 'end) pos + 'no-props nil 'protect-match)) + (push o auto-o-pending-self-cascade))) + )) +) + + + + +;; (defun auto-o-self-list (o-start &optional end) +;; ;; Return list of self overlays ending at or after match overlay O-START and +;; ;; starting before or at END, corresponding to same entry as O-START. If END +;; ;; is null, all overlays after O-START are included. + +;; (when (null end) (setq end (point-max))) + +;; (let (overlay-list) +;; ;; create list of all overlays corresponding to same entry between O-START +;; ;; and END +;; (mapc (lambda (o) (when (and (>= (overlay-end o) +;; (overlay-get o-start 'delim-start)) +;; (<= (overlay-start o) end)) +;; (push o overlay-list))) +;; (auto-overlays-in +;; (point-min) (point-max) +;; (list +;; '(identity auto-overlay) +;; (list 'eq 'set-id (overlay-get o-start 'set-id)) +;; (list 'eq 'definition-id (overlay-get o-start 'definition-id))))) +;; ;; sort the list by start position, from first to last +;; (sort overlay-list +;; (lambda (a b) (< (overlay-start a) (overlay-start b))))) +;; ) + + + +(defun auto-o-self-list (o-start &optional end) + ;; Return list of self overlays ending at or after match overlay O-START and + ;; starting before or at END, corresponding to same entry as O-START. If END + ;; is null, all overlays after O-START are included. + + (when (null end) (setq end (point-max))) + + (let (overlay-list) + ;; create list of all overlays corresponding to same entry between O-START + ;; and END + (setq overlay-list + ;; Note: We subtract 1 from start and add 1 to end to catch overlays + ;; that end at start or start at end. This seems to give the + ;; same results as the old version of `auto-o-self-list' + ;; (above) in all circumstances. + (auto-overlays-in + (1- (overlay-get o-start 'delim-start)) (1+ end) + (list + '(identity auto-overlay) + (list 'eq 'set-id (overlay-get o-start 'set-id)) + (list 'eq 'definition-id (overlay-get o-start 'definition-id))))) + ;; sort the list by start position, from first to last + (sort overlay-list + (lambda (a b) (< (overlay-start a) (overlay-start b))))) +) + + +;;; auto-overlay-self.el ends here diff --git a/packages/auto-overlays/auto-overlay-word.el b/packages/auto-overlays/auto-overlay-word.el new file mode 100644 index 000000000..59c81a0b7 --- /dev/null +++ b/packages/auto-overlays/auto-overlay-word.el @@ -0,0 +1,70 @@ +;;; auto-overlay-word.el --- automatic overlays for single "words" + + +;; Copyright (C) 2005-2015 Free Software Foundation, Inc + +;; Author: Toby Cubitt +;; Maintainer: Toby Cubitt +;; URL: http://www.dr-qubit.org/emacs.php +;; Repository: http://www.dr-qubit.org/git/predictive.git + +;; This file is part of the 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 program 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 this program. If not, see . + + +;;; Code: + +(require 'auto-overlays) +(provide 'auto-overlay-word) + + +;; set word overlay parsing and suicide functions +(put 'word 'auto-overlay-parse-function 'auto-o-parse-word-match) +(put 'word 'auto-overlay-suicide-function + (lambda (o) (auto-o-delete-overlay (overlay-get o 'parent)))) + + + +(defun auto-o-parse-word-match (o-match) + ;; Create a new word overlay for new word match + (let ((o-new (make-overlay (overlay-get o-match 'delim-start) + (overlay-get o-match 'delim-end) + nil nil 'rear-advance))) + ;; give overlays appropriate properties + (overlay-put o-new 'auto-overlay t) + (overlay-put o-new 'set-id (overlay-get o-match 'set-id)) + (overlay-put o-new 'definition-id (overlay-get o-match 'definition-id)) + (overlay-put o-new 'start o-match) + (overlay-put o-match 'parent o-new) + ;; bundle properties inside list if not already, then update overlay + ;; properties + (let ((props (auto-o-props o-match))) + (when (symbolp (car props)) (setq props (list props))) + (dolist (p (auto-o-props o-match)) + (overlay-put o-new (car p) (cdr p)))) + + ;; if new overlay is exclusive, delete lower priority overlays within it + (when (and (overlay-get o-new 'exclusive) + (/= (overlay-start o-new) (overlay-end o-new))) + (auto-o-update-exclusive (overlay-get o-new 'set) + (overlay-start o-new) (overlay-end o-new) + nil (overlay-get o-new 'priority))) + + ;; return new overlay + o-new) +) + + +;; auto-overlay-word.el ends here diff --git a/packages/auto-overlays/auto-overlays-compat.el b/packages/auto-overlays/auto-overlays-compat.el new file mode 100644 index 000000000..cd6fcd1ad --- /dev/null +++ b/packages/auto-overlays/auto-overlays-compat.el @@ -0,0 +1,51 @@ +;;; auto-overlays-compat.el --- compatability functions for auto-overlays package + + +;; Copyright (C) 2005-2015 Free Software Foundation, Inc + +;; Author: Toby Cubitt +;; Version: 0.3.2 +;; Keywords: auto-overlay, automatic, overlays, compatability +;; URL: http://www.dr-qubit.org/emacs.php + +;; This file is NOT part of the 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 program 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 this program. If not, see . + + +;;; Code: + +(provide 'auto-overlays-compat) + + +(defun auto-overlays-compat-line-number-at-pos (&optional pos) + "Return (narrowed) buffer line number at position POS. +\(Defaults to the point.\)" + (unless pos (setq pos (point))) + ;; note: need to add 1 if at beginning of line + (+ (count-lines (point-min) pos) + (if (save-excursion (goto-char pos) (bolp)) 1 0)) +) + + +(defun auto-overlays-compat-replace-regexp-in-string (regexp rep string) + "Return a new string with all matches for REGEXP in STRING replaced +with REP." + (let ((str string)) + (while (string-match regexp str) + (setq str (replace-match rep nil nil str))) + str) +) + +;;; auto-overlays-compat.el ends here diff --git a/packages/auto-overlays/auto-overlays.el b/packages/auto-overlays/auto-overlays.el new file mode 100644 index 000000000..3cd9af238 --- /dev/null +++ b/packages/auto-overlays/auto-overlays.el @@ -0,0 +1,1710 @@ +;;; auto-overlays.el --- Automatic regexp-delimited overlays + + +;; Copyright (C) 2005-2015 Free Software Foundation, Inc + +;; Version: 0.10.8 +;; Author: Toby Cubitt +;; Maintainer: Toby Cubitt +;; Keywords: extensions +;; URL: http://www.dr-qubit.org/emacs.php +;; Repository: http://www.dr-qubit.org/git/predictive.git + +;; This file is part of the 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 program 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 this program. If not, see . + + +;;; Code: + +(defvar auto-overlay-regexps nil) +(make-variable-buffer-local 'auto-overlay-regexps) +(defvar auto-overlay-load-hook nil) +(defvar auto-overlay-unload-hook nil) + + +(eval-when-compile (require 'cl)) +(require 'auto-overlay-common) +(provide 'auto-overlays) + + +;; (defvar auto-overlay-list nil) +;; (make-variable-buffer-local 'auto-overlay-list) +(defvar auto-o-pending-updates nil) +(make-variable-buffer-local 'auto-o-pending-updates) +(defvar auto-o-pending-suicides nil) +(make-variable-buffer-local 'auto-o-pending-suicides) +(defvar auto-o-pending-pre-suicide nil) +(make-variable-buffer-local 'auto-o-pending-pre-suicide) +(defvar auto-o-pending-post-suicide nil) +(make-variable-buffer-local 'auto-o-pending-post-suicide) +(defvar auto-o-pending-post-update nil) +(make-variable-buffer-local 'auto-o-pending-post-update) + + + + +;;;======================================================== +;;; Code-tidying macros + +(defmacro auto-o-create-set (set-id) + ;; Add blank entry for a new regexp set SET-ID to `auto-overlay-regexps'. + `(push (list ,set-id nil) auto-overlay-regexps)) + + +(defmacro auto-o-delete-set (set-id) + ;; Delete SET-ID entry from `auto-overlay-regexps'. + `(setq auto-overlay-regexps + (assq-delete-all ,set-id auto-overlay-regexps))) + + +(defmacro auto-o-get-full-buffer-list (set-id) + ;; Return the list of buffers and associated properties for regexp set + ;; SET-ID. + `(nth 1 (assq ,set-id auto-overlay-regexps))) + + +(defmacro auto-o-get-buffer-list (set-id) + ;; Return list of buffers using regexp set SET-ID. + `(mapcar 'car (auto-o-get-full-buffer-list ,set-id))) + + +(defmacro auto-o-get-regexps (set-id) + ;; Return the list of regexp definitions for regexp set SET-ID. + `(cddr (assq ,set-id auto-overlay-regexps))) + + +;; (defmacro auto-o-set-regexps (set-id regexps) +;; ;; Set the list of regexp definitions for regexp set SET-ID. +;; `(setcdr (cdr (assq ,set-id auto-overlay-regexps)) ,regexps)) + + + + +;; (defmacro auto-o-set-buffer-list (set-id list) +;; ;; Set the list of buffers that use the regexp set SET-ID to LIST. +;; `(let ((set (assq ,set-id auto-overlay-regexps))) +;; (and set (setcar (cddr set) ,list)))) + + +(defmacro auto-o-add-to-buffer-list (set-id buffer) + ;; Add BUFFER to the list of buffers using regexp set SET-ID. + `(let ((set (assq ,set-id auto-overlay-regexps))) + (and set + (null (assq ,buffer (cadr set))) + (setcar (cdr set) (cons (cons ,buffer nil) (cadr set)))))) + + +(defmacro auto-o-delete-from-buffer-list (set-id buffer) + ;; Remove BUFFER from the list of buffers using regexp set SET-ID. + `(let ((set (assq ,set-id auto-overlay-regexps))) + (and set + (setcar (cdr set) (assq-delete-all ,buffer (cadr set)))))) + + + + +(defmacro auto-o-enabled-p (set-id &optional buffer) + ;; Return non-nil if regexp set identified by SET-ID is enabled in BUFFER. + `(let ((buff (or ,buffer (current-buffer)))) + (cdr (assq buff (auto-o-get-full-buffer-list ,set-id))))) + + +(defmacro auto-o-enable-set (set-id buffer) + ;; Set enabled flag for BUFFER in regexp set SET-ID. + `(setcdr (assq ,buffer (auto-o-get-full-buffer-list ,set-id)) t)) + + +(defmacro auto-o-disable-set (set-id buffer) + ;; Unset enabled flag for BUFFER in regexp set SET-ID. + `(setcdr (assq ,buffer (auto-o-get-full-buffer-list ,set-id)) nil)) + + + + +(defmacro auto-o-append-regexp (set-id entry) + ;; Append regexp ENTRY to SET-ID's regexps. + `(nconc (auto-o-get-regexps ,set-id) (list ,entry))) + + +(defmacro auto-o-prepend-regexp (set-id entry) + ;; Prepend regexp ENTRY to SET-ID's regexps. + `(setcdr (cdr (assq ,set-id auto-overlay-regexps)) + (nconc (list ,entry) (auto-o-get-regexps ,set-id)))) + + +(defmacro auto-o-insert-regexp (set-id pos entry) + ;; Insert regexp ENTRY in SET-ID's regexps at POS. + `(setcdr (nthcdr (1- pos) (auto-o-get-regexps ,set-id)) + (nconc (list ,entry) (nthcdr pos (auto-o-get-regexps ,set-id))))) + + + +(defmacro auto-o-entry (set-id definition-id &optional regexp-id) + ;; Return regexp entry identified by SET-ID, DEFINITION-ID and REGEXP-ID. + `(if ,regexp-id + (cdr (assq ,regexp-id + (cdr (assq ,definition-id + (auto-o-get-regexps ,set-id))))) + (cdr (assq ,definition-id (cddr (assq ,set-id auto-overlay-regexps)))))) + + +(defmacro auto-o-entry-class (set-id definition-id) + ;; Return class corresponding to SET-ID and DEFINITION-ID. + `(cadr (assq ,definition-id (auto-o-get-regexps ,set-id)))) + + +(defmacro auto-o-class (o-match) + ;; Return class of match overlay O-MATCH. + `(auto-o-entry-class (overlay-get ,o-match 'set-id) + (overlay-get ,o-match 'definition-id))) + + +(defmacro auto-o-entry-regexp (set-id definition-id &optional regexp-id) + ;; Return regexp corresponsing to SET-ID, DEFINITION-ID and REGEXP-ID. + `(let ((regexp (nth 1 (auto-o-entry ,set-id ,definition-id ,regexp-id)))) + (if (atom regexp) regexp (car regexp)))) + + +(defmacro auto-o-regexp (o-match) + ;; Return match overlay O-MATCH's regexp. + `(auto-o-entry-regexp (overlay-get ,o-match 'set-id) + (overlay-get ,o-match 'definition-id) + (overlay-get ,o-match 'regexp-id))) + + +(defmacro auto-o-entry-regexp-group (set-id definition-id &optional regexp-id) + ;; Return regexp group corresponsing to SET-ID, DEFINITION-ID and REGEXP-ID, + ;; or 0 if none is specified. + `(let ((regexp (nth 1 (auto-o-entry ,set-id ,definition-id ,regexp-id)))) + (cond + ((atom regexp) 0) + ((atom (cdr regexp)) (cdr regexp)) + (t (cadr regexp))))) + + +(defmacro auto-o-regexp-group (o-match) + ;; Return match overlay O-MATCH's regexp group. + `(auto-o-entry-regexp-group (overlay-get ,o-match 'set-id) + (overlay-get ,o-match 'definition-id) + (overlay-get ,o-match 'regexp-id))) + + +(defmacro auto-o-entry-regexp-group-nth (n set-id definition-id + &optional regexp-id) + ;; Return Nth regexp group entry corresponsing to SET-ID, DEFINITION-ID and + ;; REGEXP-ID, or 0 if there is no Nth entry. + `(let ((regexp (nth 1 (auto-o-entry ,set-id ,definition-id ,regexp-id)))) + (cond + ((atom regexp) 0) + ((> (1+ ,n) (length (cdr regexp))) 0) + (t (nth ,n (cdr regexp)))))) + + +(defmacro auto-o-regexp-group-nth (n o-match) + ;; Return match overlay O-MATCH's Nth regexp group entry, or 0 if there is + ;; no Nth entry. + `(auto-o-entry-regexp-group-nth ,n + (overlay-get ,o-match 'set-id) + (overlay-get ,o-match 'definition-id) + (overlay-get ,o-match 'regexp-id))) + + +(defmacro auto-o-entry-props (set-id definition-id &optional regexp-id) + ;; Return properties of regexp corresponding to SET-ID, DEFINITION-ID and + ;; REGEXP-ID. + `(nthcdr 2 (auto-o-entry ,set-id ,definition-id ,regexp-id))) + + +(defmacro auto-o-props (o-match) + ;; Return properties associated with match overlay O-MATCH. + `(auto-o-entry-props (overlay-get ,o-match 'set-id) + (overlay-get ,o-match 'definition-id) + (overlay-get ,o-match 'regexp-id))) + + +(defmacro auto-o-entry-edge (set-id definition-id regexp-id) + ;; Return edge ('start or 'end) of regexp with SET-ID, DEFINITION-ID and + ;; REGEXP-ID + `(car (auto-o-entry ,set-id ,definition-id ,regexp-id))) + + +(defmacro auto-o-edge (o-match) + ;; Return edge ('start or 'end) of match overlay O-MATCH + `(auto-o-entry-edge (overlay-get ,o-match 'set-id) + (overlay-get ,o-match 'definition-id) + (overlay-get ,o-match 'regexp-id))) + + +(defmacro auto-o-parse-function (o-match) + ;; Return appropriate parse function for match overlay O-MATCH. + `(get (auto-o-class ,o-match) 'auto-overlay-parse-function)) + + +(defmacro auto-o-suicide-function (o-match) + ;; Return appropriate suicide function for match overlay O-MATCH. + `(get (auto-o-class ,o-match) 'auto-overlay-suicide-function)) + + +(defmacro auto-o-match-function (o-match) + ;; Return match function for match overlay O-MATCH, if any. + `(get (auto-o-class ,o-match) 'auto-overlay-match-function)) + + +(defmacro auto-o-edge-matched-p (overlay edge) + ;; test if EDGE of OVERLAY is matched + `(overlay-get ,overlay ,edge)) + + +(defmacro auto-o-start-matched-p (overlay) + ;; test if OVERLAY is start-matched + `(overlay-get ,overlay 'start)) + + +(defmacro auto-o-end-matched-p (overlay) + ;; test if OVERLAY is end-matched + `(overlay-get ,overlay 'end)) + + +;; (defmacro auto-o-entry-compound-class-p (set-id definition-id) +;; ;; Return non-nil if regexp corresponding to SET-ID and DEFINITION-ID +;; ;; contains a list of regexp entries rather than a single entry. +;; `(let ((entry (cadr (auto-o-entry ,set-id ,definition-id)))) +;; (and (listp entry) +;; (or (symbolp (cdr entry)) +;; (and (listp (cdr entry)) (symbolp (cadr entry))))))) + +;; (defmacro auto-o-compound-class-p (o-match) +;; ;; Return non-nil if O-MATCH's regexp class is a compound class +;; ;; (can just check for 'regexp-id property instead of checking regexp +;; ;; definitions, since this is always set for such match overlays) +;; `(overlay-get ,o-match 'regexp-id)) + + +(defmacro auto-o-entry-complex-class-p (set-id definition-id) + ;; Return non-nil if regexp corresponding to SET-ID and DEFINITION-ID + ;; requires separate start and end regexps + `(get (auto-o-entry-class ,set-id ,definition-id) + 'auto-overlay-complex-class)) + + +(defmacro auto-o-complex-class-p (o-match) + ;; Return non-nil if O-MATCH's regexp class is a compound class + `(get (auto-o-class ,o-match) 'auto-overlay-complex-class)) + + + +(defmacro auto-o-rank (o-match) + ;; Return the rank of match overlay O-MATCH + `(auto-o-assq-position + (overlay-get ,o-match 'regexp-id) + (cddr (assq (overlay-get ,o-match 'definition-id) + (auto-o-get-regexps (overlay-get ,o-match 'set-id)))))) + + +(defmacro auto-o-overlay-filename (set-id) + ;; Return the default filename to save overlays in + `(concat "auto-overlays-" + (replace-regexp-in-string + "\\." "-" (file-name-nondirectory (or (buffer-file-name) + (buffer-name)))) + "-" (symbol-name ,set-id))) + + + + +;;;============================================================ +;;; Replacements for CL functions + +(defun auto-o-assq-position (key alist) + "Find the first association of KEY in ALIST. +Return the index of the matching item, or nil of not found. +Comparison is done with 'eq." + (let (el (i 0)) + (catch 'found + (while (setq el (nth i alist)) + (when (eq key (car el)) (throw 'found i)) + (setq i (1+ i)) + nil)))) + + + +(defun auto-o-position (item list) + "Find the first occurrence of ITEM in LIST. +Return the index of the matching item, or nil of not found. +Comparison is done with 'equal." + (let (el (i 0)) + (catch 'found + (while (setq el (nth i list)) + (when (equal item el) (throw 'found i)) + (setq i (1+ i)) + nil)))) + + + +(defun auto-o-sublist (list start &optional end) + "Return the sub-list of LIST from START to END. +If END is omitted, it defaults to the length of the list +If START or END is negative, it counts from the end." + (let (len) + ;; sort out arguments + (if end + (when (< end 0) (setq end (+ end (setq len (length list))))) + (setq end (or len (setq len (length list))))) + (when (< start 0) + (setq start (+ start (or len (length list))))) + + ;; construct sub-list + (let (res) + (while (< start end) + (push (nth start list) res) + (setq start (1+ start))) + (nreverse res)))) + + +(defmacro auto-o-adjoin (item list) + "Cons ITEM onto front of LIST if it's not already there. +Comparison is done with `eq'." + `(if (memq ,item ,list) ,list (setf ,list (cons ,item ,list)))) + + + +;;;========================================================= +;;; auto-overlay definition functions + +(defun auto-overlay-load-definition (set-id definition &optional pos) + "Load DEFINITION into the set of auto-overlay definitions SET-ID +in the current buffer. If SET-ID does not exist, it is created. + +If POS is nil, DEFINITION is added at the end of the list of +auto-overlay definitions. If it is t, it is added at the +beginning. If it is an integer, it is added at that position in +the list. The position in the list makes no difference to the +behaviour of the auto-overlays. But it can make a difference to +the speed and efficiency. In general, higher-priority and +exclusive DEFINITIONS should appear earlier in the list. + +If DEFINITION-ID is supplied, it should be a symbol that can be +used to uniquely identify DEFINITION (see +`auto-overlay-unload-definition'). + + +DEFINITION should be a list of the form: + + (CLASS @optional :id DEFINITION-ID @rest REGEXP1 REGEXP2 ... ) + +CLASS is a symbol specifying the auto-overlay class. The standard +classes are 'word, 'line, 'self, 'flat and 'nested. The :id +property is optional. It should be a symbol that can be used to +uniquely identify DEFINITION (see +`auto-overlay-unload-definition'). + +The REGEXP's should be lists of the form: + + (RGXP &optional :edge EDGE :id REGEXP-ID + &rest PROPERTY1 PROPERTY2 ... ) + +RGXP is either a single regular expression (a string), or a cons +cell of the form (RGXP . GROUP) where RGXP is a regular +expression and GROUP is an integer specifying which group in the +regular expression forms the delimiter for the auto-overlay. The +rest of the PROPERTY entries should be cons cells of the +form (NAME . VALUE) where NAME is an overlay property name (a +symbol) and VALUE is its value. + +The properties :edge and :id are optional. The :edge property +EDGE should be one of the symbols 'start or 'end. If it is not +specified, :edge is assumed to be 'start. The :id property is a +symbol that can be used to uniquely identify REGEXP (see +`auto-overlay-unload-regexp')." + + (let ((regexps (auto-o-get-regexps set-id)) + (class (car definition)) + definition-id) + ;; if SET-ID doesn't exist in regexp list, create empty set + (when (null regexps) + (auto-o-create-set set-id) + (auto-o-add-to-buffer-list set-id (current-buffer)) + (setq regexps (auto-o-get-regexps set-id))) + + (let (n) + (if (null (setq n (auto-o-position :id definition))) + ;; if DEFINITION-ID is not specified, create a unique numeric + ;; DEFINITION-ID + (setq definition-id + (1+ (apply 'max -1 + (mapcar (lambda (elt) + (if (integerp (car elt)) + (car elt) -1)) + regexps)))) + ;; if DEFINITION-ID is specified, check it's unique + (setq definition-id (nth (1+ n) definition)) + (setq definition (append (auto-o-sublist definition 0 n) + (auto-o-sublist definition (+ n 2)))) + (when (assq definition-id regexps) + (error "Definition ID \"%s\" is not unique" + (symbol-name definition-id))) + )) + + (cond + ;; adding first entry or at start + ((or (eq pos t) (= (length regexps) 0) + (and (integerp pos) (<= pos 0))) + (auto-o-prepend-regexp set-id (list definition-id class))) + ;; adding at end + ((or (null pos) (and (integerp pos) (>= pos (length regexps)))) + (auto-o-append-regexp set-id (list definition-id class))) + ;; adding at POS + ((integerp pos) + (auto-o-insert-regexp set-id pos (list definition-id class)))) + + ;; load regexp definitions + (dolist (regexp (cdr definition)) + (auto-overlay-load-regexp set-id definition-id regexp)) + + definition-id)) ; return new entry ID + + + +(defun auto-overlay-load-regexp (set-id definition-id regexp &optional pos) + "Load REGEXP into the auto-overlay definition identified by +DEFINITION-ID in the regexp list named SET-ID in the current +buffer. + +If POS is nil, REGEXP is added at the end of the definition. If +it is t, it is added at the beginning. If it is an integer, it is +added at that position. + + +REGEXP should be a list of the form: + + (RGXP &optional :edge EDGE :id REGEXP-ID + &rest PROPERTY1 PROPERTY2 ... ) + +RGXP is either a single regular expression (a string), or a cons +cell of the form (RGXP . GROUP) where RGXP is a regular +expression and GROUP is an integer specifying which group in the +regular expression forms the delimiter for the auto-overlay. The +rest of the PROPERTY entries should be cons cells of the +form (NAME . VALUE) where NAME is an overlay property name (a +symbol) and VALUE is its value. + +The properties :edge and :id are optional. The :edge property +EDGE should be one of the symbols 'start or 'end. If it is not +specified, :edge is assumed to be 'start. The :id property is a +symbol that can be used to uniquely identify REGEXP (see +`auto-overlay-unload-regexp')." + + (let ((defs (assq definition-id (auto-o-get-regexps set-id))) + regexp-id rgxp edge props) + (when (null defs) + (error "Definition \"%s\" not found in auto-overlay regexp set %s" + (symbol-name definition-id) (symbol-name set-id))) + + ;; extract regexp + (setq rgxp (car regexp)) + (setq regexp (cdr regexp)) + (let (n) + ;; extract edge + (if (null (setq n (auto-o-position :edge regexp))) + (setq edge 'start) ; assume 'start if unspecified + (setq edge (nth (1+ n) regexp)) + (setq regexp (append (auto-o-sublist regexp 0 n) + (auto-o-sublist regexp (+ n 2))))) + ;; extract regexp-id + (if (setq n (auto-o-position :id regexp)) + (progn + (setq regexp-id (nth (1+ n) regexp)) + (when (assq regexp-id defs) + (error "Regexp ID \"%s\" is not unique" + (symbol-name regexp-id))) + (setq regexp (append (auto-o-sublist regexp 0 n) + (auto-o-sublist regexp (+ n 2))))) + ;; if no id is specified, create a unique numeric ID + (setq regexp-id + (1+ (apply 'max -1 + (mapcar (lambda (elt) + (if (integerp (car elt)) (car elt) -1)) + (cddr defs)))))) + ;; extract properties + (setq props regexp)) + + ;; create regexp definition + (setq regexp (append (list regexp-id edge rgxp) props)) + + (cond + ;; adding at end + ((or (null pos) (and (integerp pos) (>= pos (length (cddr defs))))) + (if (= (length (cddr defs)) 0) + (setcdr (cdr defs) (list regexp)) + (nconc (cddr defs) (list regexp)))) + ;; adding at start + ((or (eq pos t) (and (integerp pos) (<= pos 0))) + (setcdr (cdr defs) (nconc (list regexp) (cddr defs)))) + ;; adding at POS + ((integerp pos) + (setcdr (nthcdr (1- pos) (cddr defs)) + (nconc (list regexp) (nthcdr pos (cddr defs)))))) + + regexp-id)) ; return new subentry ID + + + +(defun auto-overlay-unload-set (set-id) + "Unload the entire regexp set SET-ID from the current buffer." + + ;; disable regexp set to delete overlays, then delete regexp set from + ;; current buffer + (when (auto-o-enabled-p set-id) + (auto-overlay-stop set-id)) + (auto-o-delete-from-buffer-list set-id (current-buffer)) + (auto-o-delete-set set-id)) + + + +(defun auto-overlay-unload-definition (set-id definition-id) + "Unload auto-overlay definition DEFINITION-ID in set SET-ID +from the current buffer. Returns the deleted definition." + + (save-excursion + ;; call suicide function for corresponding overlays in all buffers in + ;; which the set is enabled + (dolist (buff (auto-o-get-buffer-list set-id)) + (set-buffer buff) + (when (auto-o-enabled-p set-id) + (mapc (lambda (o) (auto-o-suicide o 'force)) + (auto-overlays-in (point-min) (point-max) + `((eq set-id ,set-id) + (eq definition-id ,definition-id)))))) + ;; delete definition + (let ((olddef (assq definition-id (auto-o-get-regexps set-id))) + def-id class regexps regexp edge regexp-id props) + ;; safe to delete by side effect here because definition is guaranteed + ;; not to be the first element of the list (the first two elements of a + ;; regexp set are always the set-id and the buffer list) + (assq-delete-all definition-id (assq set-id auto-overlay-regexps)) + + + ;; massage deleted definition into form suitable for + ;; `auto-overlay-load-definition' + (setq def-id (nth 0 olddef) + class (nth 1 olddef) + regexps (nthcdr 2 olddef)) + (setq olddef (list class :id def-id)) + (dolist (rgxp regexps) + (setq regexp-id (nth 0 rgxp) + edge (nth 1 rgxp) + regexp (nth 2 rgxp) + props (nthcdr 3 rgxp)) + (setq olddef + (append olddef + (list (append (list regexp :edge edge :id regexp-id) + props))))) + olddef))) ; return deleted definition + + + +(defun auto-overlay-unload-regexp (set-id definition-id regexp-id) + "Unload the regexp identified by REGEXP-ID from auto-overlay +definition DEFINITION-ID in set SET-ID of the current buffer. +Returns the deleted regexp." + + (save-excursion + ;; call suicide function for corresponding overlays in all buffers in + ;; which the set is enabled + (dolist (buff (auto-o-get-buffer-list set-id)) + (set-buffer buff) + (when (auto-o-enabled-p set-id) + (mapc (lambda (o) (auto-o-suicide o 'force)) + (auto-overlays-in (point-min) (point-max) + `((identity auto-overlay-match) + (eq set-id ,set-id) + (eq definition-id ,definition-id) + (eq regexp-id ,regexp-id)))))) + ;; delete regexp entry + (let* ((def (cdr (assq definition-id (auto-o-get-regexps set-id)))) + (oldregexp (assq regexp-id def)) + id edge regexp props) + ;; can safely delete by side effect here because the regexp definition + ;; is guaranteed not to be the first element of the list (the first two + ;; elements of a definition are always the :id and class) + (assq-delete-all regexp-id def) + + ;; massage deleted definition into form suitable for + ;; `auto-overlay-load-definition' + (setq id (nth 0 oldregexp) + edge (nth 1 oldregexp) + regexp (nth 2 oldregexp) + props (nthcdr 3 oldregexp)) + (setq oldregexp (append (list regexp :edge edge :id id) props)) + oldregexp)) ; return deleted regexp +) + + + +(defun auto-overlay-share-regexp-set (set-id from-buffer &optional to-buffer) + "Make TO-BUFFER share the regexp set identified by SET-ID with FROM-BUFFER. +Any changes to that regexp set in either buffer will be reflected in the +other. TO-BUFFER defaults to the current buffer." + + (unless to-buffer (setq to-buffer (current-buffer))) + (let (regexps) + ;; get regexp set from FROM-BUFFER + (with-current-buffer from-buffer + (setq regexps (assq set-id auto-overlay-regexps)) + ;; delete any existing set with same ID, and add regexp set to TO-BUFFER + (set-buffer to-buffer) + (setq auto-overlay-regexps + (assq-delete-all set-id auto-overlay-regexps)) + (push regexps auto-overlay-regexps) + ;; add TO-BUFFER to list of buffers using regexp set SET-ID + (auto-o-add-to-buffer-list set-id to-buffer) + ))) + + + +(defun auto-overlay-start (set-id &optional buffer save-file no-regexp-check) + "Activate the set of auto-overlay regexps identified by SET-ID +in BUFFER, or the current buffer if none is specified. + +If optional argument SAVE-FILE is nil, it will try to load the +overlays from the default save file if it exists. If SAVE-FILE is +a string, it specifies the location of the file (if only a +directory is given, it will look for the default filename in that +directory). Anything else will cause the save file to be ignored, +and the buffer will be reparsed from scratch, as it will be if +the save file does not exist. + +If the overlays are being loaded from a save file, but optional +argument NO-REGEXP-CHECK is non-nil, the file of saved overlays +will be used, but no check will be made to ensure regexp +refinitions are the same as when the overlays were saved." + + (save-excursion + (when buffer (set-buffer buffer)) + ;; run initialisation hooks + (run-hooks 'auto-overlay-load-hook) + ;; add hook to run all the various functions scheduled be run after a + ;; buffer modification + (add-hook 'after-change-functions 'auto-o-run-after-change-functions + nil t) + ;; add hook to schedule an update after a buffer modification + (add-hook 'after-change-functions 'auto-o-schedule-update nil t) + ;; add hook to simulate missing `delete-in-front-hooks' and + ;; `delete-behind-hooks' overlay properties + (add-hook 'after-change-functions + 'auto-o-schedule-delete-in-front-or-behind-suicide nil t) + + ;; set enabled flag for regexp set, and make sure buffer is in buffer list + ;; for the regexp set + (auto-o-enable-set set-id (current-buffer)) + + ;; try to load overlays from file + (unless (and (or (null save-file) (stringp save-file)) + (auto-overlay-load-overlays set-id nil save-file + no-regexp-check)) + ;; if loading was unsuccessful, search for new auto overlays + (let ((lines (count-lines (point-min) (point-max)))) + (goto-char (point-min)) + (message "Scanning for auto-overlays...(line 1 of %d)" + lines) + (dotimes (i lines) + (when (= 9 (mod i 10)) + (message + "Scanning for auto-overlays...(line %d of %d)" + (+ i 1) lines)) + (auto-overlay-update nil nil set-id) + (forward-line 1)) + (message "Scanning for auto-overlays...done"))) + )) + + + +(defun auto-overlay-stop (set-id &optional buffer save-file leave-overlays) + "Clear all auto-overlays in the set identified by SET-ID +from BUFFER, or the current buffer if none is specified. + +If SAVE-FILE is non-nil and the buffer is associated with a file, +save the overlays to a file to speed up loading if the same set +of regexp definitions is enabled again. If SAVE-FILE is a string, +it specifies the location of the file to save to (if it only +specifies a directory, the default filename is used). Anything +else will cause the overlays to be saved to the default file name +in the current directory. + +If LEAVE-OVERLAYS is non-nil, don't bother deleting the overlays +from the buffer \(this is generally a bad idea, unless the buffer +is about to be killed in which case it speeds things up a bit\)." + + (save-excursion + (when buffer (set-buffer buffer)) + ;; disable overlay set + (auto-o-disable-set set-id (current-buffer)) + + ;; if SAVE-FILE is non-nil and buffer is associated with a file, save + ;; overlays to file + (when save-file + (unless (stringp save-file) (setq save-file nil)) + (auto-overlay-save-overlays set-id nil save-file)) + + ;; delete overlays unless told not to bother + (unless leave-overlays + (mapc 'delete-overlay + (auto-overlays-in + (point-min) (point-max) + (list + (list (lambda (overlay match) (or overlay match)) + '(auto-overlay auto-overlay-match)) + (list 'eq 'set-id set-id)) + nil 'inactive))) + + ;; if there are no more active auto-overlay definitions... + (unless (catch 'enabled + (dolist (set auto-overlay-regexps) + (when (auto-o-enabled-p (car set)) + (throw 'enabled t))) + nil) + ;; run clear hooks + (run-hooks 'auto-overlay-unload-hook) + ;; reset variables + (remove-hook 'after-change-functions 'auto-o-schedule-update t) + (remove-hook 'after-change-functions + 'auto-o-run-after-change-functions t) + (setq auto-o-pending-suicides nil + auto-o-pending-updates nil + auto-o-pending-post-suicide nil)))) + + + +(defun auto-overlay-save-overlays (set-id &optional buffer file) + "Save overlays in set SET-ID in BUFFER to FILE. +Defaults to the current buffer. + +If FILE is nil or a directory, and if the buffer is associated +with a file, the filename is constructed from the buffer's file +name and SET-ID. The directory is created if necessary. If the +buffer is not associated with a file and FILE doesn't specify a +filename, an error occurs. + +The overlays can be loaded again later using +`auto-overlay-load-overlays'." + + (save-excursion + (when buffer (set-buffer buffer)) + + ;; construct filename + (let ((path (or (and file (file-name-directory file)) "")) + (filename (or (and file (file-name-nondirectory file)) ""))) + ;; use default filename if none supplied + (when (string= filename "") + (if (buffer-file-name) + (setq filename (auto-o-overlay-filename set-id)) + (error "Can't save overlays to default filename when buffer isn't\ + visiting a file"))) + ;; create directory if it doesn't exist + (make-directory path t) + ;; construct full path to file, since that's all we need from now on + (setq file (concat path filename))) + + ;; create temporary buffer + (let ((buff (generate-new-buffer " *auto-overlay-save*")) + overlay-list) + ;; write md5 digests to first two lines + (prin1 (md5 (current-buffer)) buff) + (terpri buff) + (prin1 (md5 (prin1-to-string (auto-o-get-regexps set-id))) buff) + (terpri buff) + + ;; get sorted list of all match overlays in set SET-ID + (setq overlay-list + (auto-overlays-in (point-min) (point-max) + (list '(identity auto-overlay-match) + (list 'eq 'set-id set-id)))) + (setq overlay-list + (sort overlay-list + (lambda (a b) + (or (< (overlay-start a) (overlay-start b)) + (and (= (overlay-start a) (overlay-start b)) + (> (overlay-end a) (overlay-end b))))))) + + ;; write overlay data to temporary buffer + (mapc (lambda (o) + (prin1 (list (overlay-get o 'definition-id) + (overlay-get o 'regexp-id) + (overlay-start o) + (overlay-end o) + (marker-position (overlay-get o 'delim-start)) + (marker-position (overlay-get o 'delim-end))) + buff) + (terpri buff)) + overlay-list) + + ;; save the buffer and kill it + (with-current-buffer buff (write-file file)) + (kill-buffer buff)) + )) + + + +(defun auto-overlay-load-overlays (set-id &optional buffer + file no-regexp-check) + "Load overlays for BUFFER from FILE. +Returns t if successful, nil otherwise. +Defaults to the current buffer. + +If FILE is null, or is a string that only specifies a directory, +the filename is constructed from the buffer's file name and +SET-ID. If the buffer is not associated with a file and FILE +doesn't specify a full filename, an error occurs. + +The FILE should be generated by `auto-overlay-save-overlays'. By +default, the buffer contents and regexp definitions for SET-ID +will be checked to make sure neither have changed since the +overlays were saved. If they don't match, the saved overlay data +will not be loaded, and the function will return nil. + +If NO-REGEXP-CHECK is non-nil, the check for matching regexp +definitions will be skipped; the saved overlays will be loaded +even if different regexp definitions were active when the +overlays were saved." + + (save-excursion + (when buffer (set-buffer buffer)) + + ;; construct filename + (let ((path (or (and file (file-name-directory file)) "")) + (filename (and file (file-name-nondirectory file)))) + ;; use default filename if none supplied + ;; FIXME: should we throw error if buffer not associated with file? + (when (string= filename "") + (setq filename (auto-o-overlay-filename set-id))) + ;; construct full path to file, since that's all we need from now on + (setq file (concat path filename))) + + + ;; return nil if file does not exist + (if (not (file-exists-p file)) + nil + + ;; otherwise... + (let ((buff (find-file-noselect file t)) + md5-buff md5-regexp data o-match o-new lines + (i 0)) + + ;; read md5 digests from first two lines of FILE + (with-current-buffer buff (goto-char (point-min))) + (setq md5-buff (read buff)) + (setq md5-regexp (read buff)) + + + ;; if saved buffer md5 sum doesn't match buffer contents, or if saved + ;; regexp md5 sum doesn't match regexp definitions and checking is not + ;; overridden, return nil + (if (not (and (string= md5-buff (md5 (current-buffer))) + (or no-regexp-check + (string= md5-regexp + (md5 (prin1-to-string + (auto-o-get-regexps set-id))))))) + (progn (kill-buffer buff) nil) + + ;; count number of overlays, for progress message + (with-current-buffer buff + (setq lines (count-lines (point) (point-max)))) + + ;; read overlay data from FILE until we reach the end + (message "Loading auto-overlays...(1 of %d)" lines) + (while (condition-case nil (setq data (read buff)) ('end-of-file)) + ;; create a match overlay corresponding to the data + (setq o-match (auto-o-make-match + set-id (nth 0 data) (nth 1 data) (nth 2 data) + (nth 3 data) (nth 4 data) (nth 5 data))) + ;; call the appropriate parse function, unless match overlay is + ;; within a higher priority exclusive overlay + (unless (auto-o-within-exclusive-p + (overlay-get o-match 'delim-start) + (overlay-get o-match 'delim-end) + (assq 'priority (auto-o-entry-props + (overlay-get o-match 'definition-id) + (overlay-get o-match 'regexp-id)))) + (setq o-new + (funcall (auto-o-parse-function o-match) o-match)) + (unless (listp o-new) (setq o-new (list o-new))) + ;; give any new overlays some basic properties + (mapc (lambda (o) + (overlay-put o 'auto-overlay t) + (overlay-put o 'set-id set-id) + (overlay-put o 'definition-id + (overlay-get o-match 'definition-id)) + (overlay-put o 'regexp-id + (overlay-get o-match 'regexp-id))) + o-new) + ;; run match function if there is one + (let ((match-func (auto-o-match-function o-match))) + (when match-func (funcall match-func o-match)))) + ;; display progress message + (setq i (1+ i)) + (when (= 0 (mod i 10)) + (message "Loading auto-overlays...(%d of %d)" i lines))) + + (kill-buffer buff) + t))))) ; return t to indicate successful loading) + + + + + +;;;============================================================= +;;; auto-overlay overlay functions + +(defun auto-o-run-after-change-functions (beg end len) + ;; Assigned to the `after-change-functions' hook. Run all the various + ;; functions that should run after a change to the buffer, in the correct + ;; order. + + ;; ignore changes that aren't either insertions or deletions + (when (and (not undo-in-progress) + (or (and (/= beg end) (= len 0)) ; insertion + (and (= beg end) (/= len 0)))) ; deletion + ;; repeat until all the pending functions have been cleared (it may be + ;; necessary to run multiple times since the pending functions may + ;; themselves cause more functions to be added to the pending lists) + (while (or auto-o-pending-pre-suicide auto-o-pending-suicides + auto-o-pending-post-suicide auto-o-pending-updates + auto-o-pending-post-update) + ;; run pending pre-suicide functions + (when auto-o-pending-pre-suicide + (mapc (lambda (f) (apply (car f) (cdr f))) + auto-o-pending-pre-suicide) + (setq auto-o-pending-pre-suicide nil)) + ;; run pending suicides + (when auto-o-pending-suicides + (mapc 'auto-o-suicide auto-o-pending-suicides) + (setq auto-o-pending-suicides nil)) + ;; run pending post-suicide functions + (when auto-o-pending-post-suicide + (mapc (lambda (f) (apply (car f) (cdr f))) + auto-o-pending-post-suicide) + (setq auto-o-pending-post-suicide nil)) + ;; run updates + (when auto-o-pending-updates + (mapc (lambda (l) (auto-overlay-update (car l) (cdr l))) + auto-o-pending-updates) + (setq auto-o-pending-updates nil)) + ;; run pending post-update functions + (when auto-o-pending-post-update + (mapc (lambda (f) (apply (car f) (cdr f))) + auto-o-pending-post-update) + (setq auto-o-pending-post-update nil)) + )) + + ;; ;; FIXME: horrible hack to delete all marker update entries in latest + ;; ;; `buffer-undo-list' change group, since undoing these can badly + ;; ;; mess up the overlays + ;; (while (and (consp (car buffer-undo-list)) + ;; (markerp (caar buffer-undo-list))) + ;; (setq buffer-undo-list (cdr buffer-undo-list))) + ;; (let ((p buffer-undo-list)) + ;; (while (cadr p) + ;; (if (and (consp (cadr p)) (markerp (car (cadr p)))) + ;; (setcdr p (cddr p)) + ;; (setq p (cdr p))))) + ) + + + +(defun auto-o-schedule-update (start &optional end unused set-id) + ;; Schedule `auto-overlay-update' of lines between positions START and END + ;; (including lines containing START and END), optionally restricted to + ;; SET-ID. If END is not supplied, schedule update for just line containing + ;; START. The update will be run by `auto-o-run-after-change-functions' + ;; after buffer modification is complete. This function is assigned to + ;; `after-change-functions'. + + (save-restriction + (widen) ; need to widen, since goto-line goes to absolute line + (setq start (line-number-at-pos start)) + (setq end (if end (line-number-at-pos end) start)) + + (let ((pending auto-o-pending-updates)) + (cond + ;; if pending list is empty, just add new entry to the list + ((null pending) + (setq auto-o-pending-updates (list (cons start end)))) + + ;; if start of the new entry is before start of the first entry in + ;; pending list, add new entry to front of the list + ((<= start (caar pending)) + (setq auto-o-pending-updates (nconc (list (cons start end)) pending)) + (setq pending auto-o-pending-updates)) + + ;; otherwise... + (t + ;; search for entry in pending list that new one should come after + ;; Note: we do an O(n) linear search here, as opposed to the O(log n) + ;; we would get were we to store the entries in a binary tree. But the + ;; pending list is unlikely to ever be all that long, so the + ;; optimisation almost certainly isn't worth the effort. + (catch 'found + (while (cdr pending) + (when (<= start (car (cadr pending))) (throw 'found t)) + (setq pending (cdr pending)))) + ;; if start of new entry is before end of entry it should come after, + ;; merge it with that entry + (if (<= start (1+ (cdar pending))) + (when (> end (cdar pending)) (setcdr (car pending) end)) + ;; otherwise, insert new entry after it + (setcdr pending (nconc (list (cons start end)) (cdr pending))) + (setq pending (cdr pending))) + )) + + ;; merge new entry with successive entries until end of merged entry is + ;; before start of next entry (see above note about O(n) vs. O(log n)) + (while (and (cdr pending) + (>= (1+ (cdar pending)) (car (cadr pending)))) + (setcdr (car pending) (max (cdar pending) (cdr (cadr pending)))) + (setcdr pending (cddr pending))) + ))) + + + +(defun auto-o-schedule-delete-in-front-or-behind-suicide (start end len) + ;; Schedule `auto-o-suicide' for any overlay that has had characters deleted + ;; in front or behind it, to simulate missing `delete-in-front-hooks' and + ;; `delete-behind-hooks' overlay properties + (unless (= len 0) + (dolist (o (auto-overlays-at-point nil '(identity auto-overlay-match))) + (when (or (= (overlay-end o) start) (= (overlay-start o) end)) + (auto-o-adjoin o auto-o-pending-suicides))))) + + + +(defun auto-o-schedule-suicide (o-self &optional modified &rest unused) + ;; Schedule `auto-o-suicide' to run after buffer modification is + ;; complete. It will be run by `auto-o-run-after-change-functions'. Assigned + ;; to overlay modification and insert in-front/behind hooks. + (unless modified (auto-o-adjoin o-self auto-o-pending-suicides))) + + + +(defun auto-overlay-update (&optional start end set-id) + ;; Parse lines from line number START to line number END. If only START is + ;; supplied, just parse that line. If neither are supplied, parse line + ;; containing the point. If SET-ID is specified, only look for matches in + ;; that set of overlay regexps definitions. + + (save-restriction + (widen) + (let (regexp-entry definition-id class regexp group priority set-id + regexp-id o-match o-overlap o-new) + (unless start (setq start (line-number-at-pos))) + (save-excursion + (save-match-data + ;; (goto-line start) without messing around with mark and messages + ;; Note: this is a bug in simple.el; there clearly can be a need for + ;; non-interactive calls to goto-line from Lisp code, and + ;; there's no warning about doing this. Yet goto-line *always* + ;; calls push-mark, which usually *shouldn't* be invoked by + ;; Lisp programs, as its docstring warns. + (goto-char 1) + (if (eq selective-display t) + (re-search-forward "[\n\C-m]" nil 'end (1- start)) + (forward-line (1- start))) + + (dotimes (i (if end (1+ (- end start)) 1)) + + ;; check each enabled set of overlays, or just the specified set + (dotimes (s (if set-id 1 (length auto-overlay-regexps))) + (setq set-id (or set-id (car (nth s auto-overlay-regexps)))) + (when (auto-o-enabled-p set-id) + + ;; check each auto-overlay definition in regexp set + (dolist (regexp-entry (auto-o-get-regexps set-id)) + (setq definition-id (pop regexp-entry)) + (setq class (pop regexp-entry)) + + ;; check all regexps for current definition + (dotimes (rank (length regexp-entry)) + (setq regexp-id (car (nth rank regexp-entry))) + + ;; extract regexp properties from current entry + (setq regexp (auto-o-entry-regexp set-id definition-id + regexp-id)) + (setq group (auto-o-entry-regexp-group + set-id definition-id regexp-id)) + (setq priority + (cdr (assq 'priority + (auto-o-entry-props + set-id definition-id regexp-id)))) + + + ;; look for matches in current line, ensuring case *is* + ;; significant + (forward-line 0) + (while (let ((case-fold-search nil)) + (re-search-forward regexp (line-end-position) t)) + ;; sanity check regexp definition against match + (when (or (null (match-beginning group)) + (null (match-end group))) + (error "Match for regexp \"%s\" has no group %d" + regexp group)) + + (cond + ;; ignore match if it already has a match overlay + ((auto-o-matched-p (match-beginning 0) (match-end 0) + set-id definition-id regexp-id)) + + + ;; if existing match overlay corresponding to same entry + ;; and edge but different subentry overlaps new match... + ((setq o-overlap + (auto-o-overlapping-match + (match-beginning group) (match-end group) + set-id definition-id regexp-id + (auto-o-entry-edge set-id definition-id + regexp-id))) + ;; if new match takes precedence, replace existing one + ;; with new one, otherwise ignore new match + (when (< rank (auto-o-rank o-overlap)) + (delete-overlay o-overlap) + (setq o-match (auto-o-make-match + set-id definition-id regexp-id + (match-beginning 0) (match-end 0) + (match-beginning group) + (match-end group))) + (when (overlay-get o-overlap 'parent) + (auto-o-match-overlay + (overlay-get o-overlap 'parent) + o-match)) + ;; run match function if there is one + (let ((match-func (auto-o-match-function o-match))) + (when match-func (funcall match-func o-match))))) + + ;; if match is within a higher priority exclusive + ;; overlay, create match overlay but don't parse it + ((auto-o-within-exclusive-p (match-beginning group) + (match-end group) + priority) + (auto-o-make-match set-id definition-id regexp-id + (match-beginning 0) (match-end 0) + (match-beginning group) + (match-end group))) + + + ;; if we're going to parse the new match... + (t + ;; create a match overlay for it + (setq o-match (auto-o-make-match + set-id definition-id regexp-id + (match-beginning 0) (match-end 0) + (match-beginning group) + (match-end group))) + ;; call the appropriate parse function + (setq o-new + (funcall (auto-o-parse-function o-match) o-match)) + (unless (listp o-new) (setq o-new (list o-new))) + ;; give any new overlays some basic properties + (mapc (lambda (o) + (overlay-put o 'auto-overlay t) + (overlay-put o 'set-id set-id) + (overlay-put o 'definition-id definition-id) + (overlay-put o 'regexp-id regexp-id)) + o-new) + ;; run match function if there is one + (let ((match-func (auto-o-match-function o-match))) + (when match-func (funcall match-func o-match))))) + + + ;; go to character one beyond the start of the match, to + ;; make sure we don't miss the next match (if we find the + ;; same one again, it will just be ignored) + (goto-char (+ (match-beginning 0) 1))))) + (forward-line 1)) + ))) + )))) + + + + +(defun auto-o-suicide (o-self &optional force) + ;; This function is assigned to all match overlay modification hooks, and + ;; calls the appropriate suicide function for match overlay O-SELF. + ;; If FORCE is non-nil, O-SELF is deleted irrespective of whether its + ;; overlay still matches. + + ;; have to widen temporarily + (save-restriction + (widen) +;; ;; this condition is here to avoid a weird Emacs bug(?) where the +;; ;; modification-hooks seem to be called occasionally for overlays that +;; ;; have already been deleted +;; (when (overlay-buffer o-self) + ;; if match overlay no longer matches the text it covers... + (unless (and (not force) + (overlay-buffer o-self) + (save-excursion + (goto-char (overlay-start o-self)) + (looking-at (auto-o-regexp o-self))) + (= (match-end 0) (overlay-end o-self))) + + ;; if we have a parent overlay... + (let ((o-parent (overlay-get o-self 'parent)) + o-other) + (when o-parent + ;; if our regexp class is a compound class... + (when (auto-o-complex-class-p o-self) + (setq o-other + (overlay-get o-parent (if (eq (auto-o-edge o-self) 'start) + 'start 'end))) + ;; if parent's properties have been set by us, remove them + (when (or (null o-other) + (>= (auto-o-rank o-self) + (auto-o-rank o-other))) + (dolist (p (auto-o-props o-self)) + (overlay-put o-parent (car p) nil)))) + ;; call appropriate suicide function + (funcall (auto-o-suicide-function o-self) o-self))) + + ;; schedule an update (necessary since if match regexp contains + ;; "context", we may be comitting suicide only for the match overlay + ;; to be recreated in a slightly different place) + (auto-o-schedule-update (overlay-start o-self)) + ;; delete ourselves + (delete-overlay o-self));) + )) + + + + +(defun auto-o-update-exclusive (set-id beg end old-priority new-priority) + ;; If priority has increased, delete all overlays between BEG end END that + ;; have priority lower than NEW-PRIORITY. If priority has decreased, re-parse + ;; all matches with priority lower than OLD-PRIORITY. + + (let (overlay-list) + (cond + ;; if priority has increased... + ((and new-priority + (or (null old-priority) (> new-priority old-priority))) + ;; find overlays entirely within BEG and END that are both start and end + ;; matched and have priority lower than NEW-PRIORITY + (setq overlay-list + (auto-overlays-in + beg end + (list '(identity auto-overlay) + (list 'eq 'set-id set-id) + '(identity start) + (list (lambda (definition-id start end) + (or (null (auto-o-entry-complex-class-p + set-id definition-id)) + (and start end))) + '(definition-id start end)) + (list (lambda (pri new) (or (null pri) (< pri new))) + 'priority new-priority)) + 'within)) + ;; mark overlays in list as inactive (more efficient than calling + ;; suicide functions or deleting the overlays, and leaves them intact in + ;; case the exclusivity of the region is later reduced - see below) + (dolist (o overlay-list) (overlay-put o 'inactive t)) + + ;; find match overlays between BEG and END that have priority lower then + ;; NEW-PRIORITY but still have an active parent overlay + (setq overlay-list + (auto-overlays-in + beg end + (list '(identity auto-overlay-match) + (list 'eq 'set-id set-id) + ;; note: parentless overlays are possible if a suicide is + ;; in progress, so need to check overlay has a parent first + '(identity parent) + (list (lambda (parent) + (not (overlay-get parent 'inactive))) + 'parent) + (list (lambda (set-id definition-id regexp-id new-pri) + (let ((pri (cdr (assq + 'priority + (auto-o-entry-props + set-id definition-id regexp-id))))) + (or (null pri) (< pri new-pri)))) + '(set-id definition-id regexp-id) + (list new-priority))))) + ;; call appropriate suicide function for each match overlay in list + (dolist (o overlay-list) (funcall (auto-o-suicide-function o) o))) + + + ;; if priority has decreased... + ((and old-priority + (or (null new-priority) (< new-priority old-priority))) + ;; find inactive overlays entirely within BEG and END that have priority + ;; higher or equal to NEW-PRIORITY + (setq overlay-list + (auto-overlays-in + beg end + (list '(identity auto-overlay) + (list 'eq 'set-id set-id) + '(identity inactive) + (list (lambda (pri new) (or (null new) (>= pri new))) + 'priority new-priority)) + 'within 'inactive)) + ;; mark overlays in list as active again + (dolist (o overlay-list) (overlay-put o 'inactive nil)) + + ;; find match overlays between BEG and END that have priority higher or + ;; equal to NEW-PRIORITY but no parent overlay + (setq overlay-list + (auto-overlays-in + beg end + (list '(identity auto-overlay-match) + (list 'eq 'set-id set-id) + '(null parent) + (list (lambda (set-id definition-id regexp-id new-pri) + (let ((pri (cdr (assq + 'priority + (auto-o-entry-props + set-id definition-id regexp-id))))) + (or (null new-pri) (>= pri new-pri)))) + '(set-id definition-id regexp-id) + (list new-priority))))) + ;; call appropriate parse function for each match overlay in list + (dolist (o-match overlay-list) + (when (not (auto-o-within-exclusive-p o-match)) + (let ((o-new (funcall (auto-o-parse-function o-match) o-match))) + ;; give any new overlays the basic properties and add them to + ;; `auto-overlay-list' + (unless (listp o-new) (setq o-new (list o-new))) + (mapc (lambda (o) + (overlay-put o 'auto-overlay t) + (overlay-put o 'set-id set-id) + (overlay-put o 'definition-id + (overlay-get o-match 'definition-id)) + (overlay-put o 'regexp-id + (overlay-get o-match 'regexp-id))) + o-new))))) + ))) + + + + +(defun auto-o-make-match (set-id definition-id regexp-id start end + &optional delim-start delim-end) + ;; Create a new match overlay and give it the appropriate properties. + (let ((o-match (make-overlay start end nil 'front-advance nil))) + (overlay-put o-match 'auto-overlay-match t) + (overlay-put o-match 'set-id set-id) + (overlay-put o-match 'definition-id definition-id) + (overlay-put o-match 'regexp-id regexp-id) + (overlay-put o-match 'delim-start + (set-marker (make-marker) + (if delim-start delim-start start))) + (overlay-put o-match 'delim-end + (set-marker (make-marker) + (if delim-end delim-end end))) + (set-marker-insertion-type (overlay-get o-match 'delim-start) t) + (set-marker-insertion-type (overlay-get o-match 'delim-end) nil) + (overlay-put o-match 'modification-hooks '(auto-o-schedule-suicide)) + (overlay-put o-match 'insert-in-front-hooks '(auto-o-schedule-suicide)) + (overlay-put o-match 'insert-behind-hooks '(auto-o-schedule-suicide)) + ;; return the new match overlay + o-match)) + + + + +(defun auto-o-match-overlay (overlay start &optional end + no-props no-parse protect-match) + "Match start and end of OVERLAY with START and END match overlays. +If START or END are numbers or markers, move that edge to the +buffer location specified by the number or marker and make it +unmatched. If START or END are non-nil but neither of the above, +make that edge unmatched. If START or END are null, don't change +that edge. However, if END is null, and START is an 'end overlay, +match end of OVERLAY rather than start. + +If NO-PARSE is non-nil, block re-parsing due to exclusive overlay +changes. If NO-PROPS is non-nil, block updating of overlay's +properties. If PROTECT-MATCH is non-nil, don't modify any match +overlays associated with OVERLAY (i.e. don't modify their 'parent +properties)." + + (let ((old-start (overlay-start overlay)) + (old-end (overlay-end overlay)) + (old-o-start (overlay-get overlay 'start)) + (old-o-end (overlay-get overlay 'end)) + (old-exclusive (overlay-get overlay 'exclusive)) + (old-priority (overlay-get overlay 'priority))) + + ;; if END is null, we're not unmatching, and START is an end overlay, + ;; match end of overlay instead of start (Note: assumes we're matching an + ;; overlay class with 'start and 'end regexps) + (when (and (null end) (overlayp start) (eq (auto-o-edge start) 'end)) + (setq end start) + (setq start nil)) + + + ;; move overlay to new location + (move-overlay overlay + (cond + ((overlayp start) (overlay-get start 'delim-end)) + ((number-or-marker-p start) start) + (start (point-min)) + (t (overlay-start overlay))) + (cond + ((overlayp end) (overlay-get end 'delim-start)) + ((number-or-marker-p end) end) + (end (point-max)) + (t (overlay-end overlay)))) + + ;; if changing start match... + (when start + ;; sort out parent property of old start match + (when (and old-o-start (not (eq old-o-start end)) (null protect-match)) + (overlay-put old-o-start 'parent nil)) + ;; if unmatching start, set start property to nil + (if (not (overlayp start)) + (overlay-put overlay 'start nil) + ;; if matching start, set start property to new start match + (overlay-put overlay 'start start) + (overlay-put start 'parent overlay))) + + ;; if changing end match... + (when end + ;; sort out parent property of old end match + (when (and old-o-end (not (eq old-o-end start)) (null protect-match)) + (overlay-put old-o-end 'parent nil)) + ;; if unmatching end, set end property to nil + (if (not (overlayp end)) + (overlay-put overlay 'end nil) + ;; if matching end, set end property to new end match + (overlay-put overlay 'end end) + (overlay-put end 'parent overlay))) + + + ;; unless it's blocked, update properties if new match takes precedence + ;; (Note: this sometimes sets the overlay's properties to the ones it + ;; already had, but it hardly seems worth checking for that) + (unless no-props + ;; when start was previously matched and is being changed, remove + ;; properties due to old start match + ;; Note: no need to check if properties were really set by start match, + ;; since if not they will be recreated below + (when (and start old-o-start) + (dolist (p (auto-o-props old-o-start)) + (overlay-put overlay (car p) nil))) + ;; when end was previously matched and is being changed, remove + ;; properties due to old end match (see note above) + (when (and end old-o-end) + (dolist (p (auto-o-props old-o-end)) + (overlay-put overlay (car p) nil))) + ;; sort out properties due to new matches + (let (props) + (cond + ;; if start has been unmatched, use properties of end match + ((not (auto-o-start-matched-p overlay)) + (setq props (auto-o-props (overlay-get overlay 'end)))) + ;; if end has been unmatched, use properties of start match + ((not (auto-o-end-matched-p overlay)) + (setq props (auto-o-props (overlay-get overlay 'start)))) + (t ;; otherwise, use properties of whichever match takes precedence + (let ((o-start (overlay-get overlay 'start)) + (o-end (overlay-get overlay 'end))) + (if (<= (auto-o-rank o-start) + (auto-o-rank o-end)) + (setq props (auto-o-props o-start)) + (setq props (auto-o-props o-end)))))) + ;; bundle properties inside a list if not already, then update them + (when (symbolp (car props)) (setq props (list props))) + (dolist (p props) (overlay-put overlay (car p) (cdr p))))) + + + ;; unless it's blocked or overlay is inactive, check if anything needs + ;; reparsing due to exclusive overlay changes + (unless (or no-parse (overlay-get overlay 'inactive)) + (let ((set-id (overlay-get overlay 'set-id)) + (start (overlay-start overlay)) + (end (overlay-end overlay)) + (exclusive (overlay-get overlay 'exclusive)) + (priority (overlay-get overlay 'priority))) + (cond + + ;; if overlay wasn't and still isn't exclusive, do nothing + ((and (null exclusive) (null old-exclusive))) + + ;; if overlay has become exclusive, delete lower priority overlays + ;; within it + ((and (null old-exclusive) exclusive) + (auto-o-update-exclusive set-id start end nil priority)) + + ;; if overlay was exclusive but no longer is, re-parse region it + ;; used to cover + ((and old-exclusive (null exclusive)) + (auto-o-update-exclusive set-id old-start old-end old-priority nil)) + + ;; if overlay was and is exclusive, and has been moved to a + ;; completely different location re-parse old location and delete + ;; lower priority overlays within new location + ((or (< end old-start) (> start old-start)) + (auto-o-update-exclusive set-id start end old-priority nil) + (auto-o-update-exclusive set-id start end nil priority)) + + ;; if overlay was and is exclusive, and overlaps its old location... + (t + ;; if priority has changed, re-parse/delete in overlap region + (when (/= old-priority priority) + (auto-o-update-exclusive set-id + (max start old-start) (min end old-end) + old-priority priority)) + (cond + ;; if overlay was exclusive and start has shrunk, re-parse + ;; uncovered region + ((and (> start old-start) old-exclusive) + (auto-o-update-exclusive set-id old-start start old-priority nil)) + ;; if overlay is exclusive and has grown, delete lower priority + ;; overlays in newly covered region + ((and (< start old-start) exclusive) + (auto-o-update-exclusive set-id start old-start nil priority))) + (cond + ;; if overlay was exclusive and end has shrunk, re-parse + ((and (< end old-end) old-exclusive) + (auto-o-update-exclusive set-id end old-end old-priority nil)) + ;; if overlay is exclusive and has grown, delete lower priority + ((and (> end old-end) exclusive) + (auto-o-update-exclusive set-id old-end end nil priority)))) + ))) + )) + + + + +(defun auto-o-delete-overlay (overlay &optional no-parse protect-match) + "Delete OVERLAY from buffer. + +If PROTECT-MATCH is non-nil, don't modify any match overlays +associated with OVERLAY (i.e. leave their 'parent properties +alone). If NO-PARSE is non-nil, block re-parsing due to exclusive +overlay changes." + + (let ((start (overlay-start overlay)) + (end (overlay-end overlay)) + o-match) + ;; delete overlay from buffer and `auto-overlay-list' + (delete-overlay overlay) + (unless (setq o-match (overlay-get overlay 'start)) + (setq o-match (overlay-get overlay 'end))) +;; (auto-o-delete-from-overlay-list overlay) + + ;; unless blocked, if overlay's exclusive flag was set, re-parse region it + ;; covered + (when (and (null no-parse) (overlay-get overlay 'exclusive)) + (auto-o-update-exclusive (overlay-get overlay 'set-id) start end + (overlay-get overlay 'priority) nil)) + + ;; Note: it's vital that the match overlays' parent properties are only + ;; set to nil *after* `auto-update-exclusive' is run: if the overlay + ;; overlapped one of its match overlays, the newly parentless match + ;; overlay would be re-parsed by `auto-update-exclusive', which would + ;; re-create the parent overlay that's just been deleted! + + ;; unmatch match overlays + (unless protect-match + (when (setq o-match (overlay-get overlay 'start)) + (overlay-put o-match 'parent nil)) + (when (setq o-match (overlay-get overlay 'end)) + (overlay-put o-match 'parent nil))) + )) + + + + +(defun auto-o-matched-p (beg end set-id definition-id &optional regexp-id) + ;; Determine if characters between BEG end END are already matched by a + ;; match overlay corresponding to DEFINITION-ID (and optionally REGEXP-ID) + ;; of regexp set SET-ID. + (let (o-match) + (catch 'match + (mapc (lambda (o) + (when (and (overlay-get o 'auto-overlay-match) + (eq (overlay-get o 'set-id) set-id) + (eq (overlay-get o 'definition-id) definition-id) + (eq (overlay-get o 'regexp-id) regexp-id) + (= (overlay-start o) beg) + (= (overlay-end o) end)) + (setq o-match o) + (throw 'match t))) + (overlays-in beg end))) + o-match)) + + + + +(defun auto-o-within-exclusive-p (match &optional end priority) + ;; If MATCH is an overlay, determine if it is within a higher priority + ;; exclusive overlay. If MATCH is a number or marker, determine whether + ;; region between MATCH and END is within an exclusive overlay with higher + ;; priority than PRIORITY. + + (when (null end) + (setq end (overlay-get match 'delim-end)) + (setq priority (overlay-get match 'priority)) + (setq match (overlay-get match 'delim-start))) + + ;; look for higher priority exclusive overlays + (auto-overlays-in + match end + (list '(identity auto-overlay) + '(identity exclusive) + (list (lambda (p q) (and p (or (null q) (> p q)))) + 'priority priority))) +) + + + + +(defun auto-o-overlapping-match (beg end set-id definition-id regexp-id edge) + ;; Returns any match overlay corresponding to same SET-ID, DEFINITION-ID and + ;; EDGE but different REGEXP-ID whose delimiter overlaps region from BEG to + ;; END. (Only returns first one it finds; which is returned if more than one + ;; exists is undefined.) + (let (o-overlap) + (catch 'match + (mapc (lambda (o) + (when (and (overlay-get o 'auto-overlay-match) + (eq (overlay-get o 'set-id) set-id) + (eq (overlay-get o 'definition-id) definition-id) + (not (eq (overlay-get o 'regexp-id) regexp-id)) + (eq (auto-o-edge o) edge) + ;; check delimiter (not just o) overlaps BEG to END + (< (overlay-get o 'delim-start) end) + (> (overlay-get o 'delim-end) beg)) + (setq o-overlap o) + (throw 'match t))) + (overlays-in beg end))) + o-overlap)) + + + + +;;; =============================================================== +;;; Compatibility Stuff + +(unless (fboundp 'line-number-at-pos) + (require 'auto-overlays-compat) + (defalias 'line-number-at-pos + 'auto-overlays-compat-line-number-at-pos)) + + +(unless (fboundp 'replace-regexp-in-string) + (require 'auto-overlays-compat) + (defalias 'replace-regexp-in-string + 'auto-overlays-compat-replace-regexp-in-string)) + +;;; auto-overlays.el ends here diff --git a/packages/auto-overlays/dir b/packages/auto-overlays/dir new file mode 100644 index 000000000..ea6a67903 --- /dev/null +++ b/packages/auto-overlays/dir @@ -0,0 +1,19 @@ +This is the file .../info/dir, which contains the +topmost node of the Info hierarchy, called (dir)Top. +The first time you invoke Info you start off looking at this node. + +File: dir, Node: Top This is the top of the INFO tree + + This (the Directory node) gives a menu of major topics. + Typing "q" exits, "?" lists all Info commands, "d" returns here, + "h" gives a primer for first-timers, + "mEmacs" visits the Emacs manual, etc. + + In Emacs, you can click mouse button 2 on a menu item or cross reference + to select it. + +* Menu: + +Emacs +* auto-overlays (auto-overlay-manual). + Automatic regexp-delimited overlays -- 2.39.2