emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/zones 353fc38: Fix Emacs-22 miscompilation


From: Stefan Monnier
Subject: [elpa] externals/zones 353fc38: Fix Emacs-22 miscompilation
Date: Sun, 6 Jan 2019 22:32:00 -0500 (EST)

branch: externals/zones
commit 353fc38a6544eb59887bee045e373406f1d038a5
Author: Stefan Monnier <address@hidden>
Commit: Stefan Monnier <address@hidden>

    Fix Emacs-22 miscompilation
    
    (condition-case-unless-debug): Use full macro definition for Emacs 22, to
    prevent compiler mishandling.
    (zz-izone-limits): IZONES arg is no longer optional - explicit list of 
izones,
    so can handle null izones.
    (zz-narrow): Correctly handle negative arg when no more zones to pop off.
    (zz-add-zones-matching-regexp): let*, not let.
    Protect isearchp-dim-outside-search-area-flag with bound-and-true-p.
    (zz-choose-zone-by-id-and-text, zz-dotted-zones-from-izones, 
zz-order-zones):
    New commands.  Regroup some definitions.
    (zz-add-zone): Do not add if zone would cover whole buffer.
    Use zz-user-error, not error.
    (zz-set-zones-from-face): Remove unused arg MSGP.
    (zz-(do|map)-(i)zones): Add arg UNITE-P - do not unite by default.
---
 zones.el | 2543 ++++++++++++++++++++++++++++++++------------------------------
 1 file changed, 1314 insertions(+), 1229 deletions(-)

diff --git a/zones.el b/zones.el
index 99f8b79..1bf94f0 100644
--- a/zones.el
+++ b/zones.el
@@ -1,17 +1,17 @@
 ;;; zones.el --- Zones of text - like multiple regions
 ;;
-;; Copyright (C) 2010-2018  Free Software Foundation, Inc.
+;; Copyright (C) 2010-2019  Free Software Foundation, Inc.
 ;;
 ;; Filename: zones.el
 ;; Description:  Zones of text - like multiple regions
 ;; Author: Drew Adams
 ;; Maintainer: Drew Adams <address@hidden>
 ;; Created: Sun Apr 18 12:58:07 2010 (-0700)
-;; Version: 2018.11.21
+;; Version: 2018.12.28
 ;; Package-Requires: ()
-;; Last-Updated: Wed Nov 21 06:57:27 2018 (-0800)
+;; Last-Updated: Fri Dec 28 10:11:11 2018 (-0800)
 ;;           By: dradams
-;;     Update #: 2644
+;;     Update #: 2961
 ;; URL: https://elpa.gnu.org/packages/zones.html
 ;; URL: https://www.emacswiki.org/emacs/download/zones.el
 ;; Doc URL: https://www.emacswiki.org/emacs/Zones
@@ -21,8 +21,7 @@
 ;;
 ;; Features that might be required by this library:
 ;;
-;;   `backquote', `bytecomp', `cconv', `cl', `cl-lib', `gv',
-;;   `macroexp'.
+;;   None
 ;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;
@@ -66,7 +65,13 @@
 ;;    (@> "Keys")
 ;;    (@> "Command `zz-narrow-repeat'")
 ;;    (@> "Define Your Own Commands")
-;;  (@> "Change log")
+;;  (@> "Change Log")
+;;  (@> "Compatibility Code for Older Emacs Versions")
+;;  (@> "Variables and Faces")
+;;  (@> "Advice for Standard Functions")
+;;  (@> "General Commands")
+;;  (@> "General Non-Interactive Functions")
+;;  (@> "Key Bindings")
 
 ;;(@* "Things Defined Here")
 ;;
@@ -100,16 +105,18 @@
 ;;
 ;;    `zz-add-key-bindings-to-narrow-map', `zz-buffer-narrowed-p'
 ;;    (Emacs 22-23), `zz-buffer-of-markers', `zz-car-<',
-;;    `zz-do-izones', `zz-do-zones', `zz-dot-pairs', `zz-every',
-;;    `zz-izone-has-other-buffer-marker-p', `zz-izone-limits',
-;;    `zz-izone-limits-in-bufs', `zz-izones-from-noncontiguous-region'
-;;    (Emacs 25+), `zz-izones-from-zones', `zz-izone-p', `zz-izones-p',
+;;    `zz-choose-zone-by-id-and-text', `zz-do-izones',
+;;    `zz-dotted-zones-from-izones', `zz-do-zones', `zz-dot-pairs',
+;;    `zz-every', `zz-izone-has-other-buffer-marker-p',
+;;    `zz-izone-limits', `zz-izone-limits-in-bufs',
+;;    `zz-izones-from-noncontiguous-region' (Emacs 25+),
+;;    `zz-izones-from-zones', `zz-izone-p', `zz-izones-p',
 ;;    `zz-izones-renumber', `zz-map-izones', `zz-map-zones',
 ;;    `zz-marker-from-object', `zz-markerize', `zz-max', `zz-min',
 ;;    `zz-narrow-advice', `zz-narrowing-lighter',
 ;;    `zz-noncontiguous-region-from-izones',
 ;;    `zz-noncontiguous-region-from-zones', `zz-number-or-marker-p',
-;;    `zz-overlays-to-zones', `zz-overlay-to-zone',
+;;    `zz-order-zones', `zz-overlays-to-zones', `zz-overlay-to-zone',
 ;;    `zz-overlay-union', `zz-rassoc-delete-all',
 ;;    `zz-readable-marker', `zz-readable-marker-p',
 ;;    `zz-read-any-variable', `zz-read-bufs', `zz-regexp-car-member',
@@ -160,9 +167,8 @@
 ;;  ** Compatibility **
 ;;
 ;;  Some of the functions defined here are not available for Emacs
-;;  versions prior to Emacs 22.  Others are not available for versions
-;;  prior to Emacs 23.  Still others are available only starting with
-;;  Emacs 25.  This is mentioned where applicable.
+;;  versions prior to 23.  Still others are available only starting
+;;  with Emacs 25.  This is mentioned where applicable.
 ;;
 ;;
 ;;(@* "Zones")
@@ -439,7 +445,7 @@
 ;;  C-x n u   `zz-unite-zones' - Unite (coalesce) zones
 ;;  C-x n v   `zz-set-izones-var' - Set current zones-set variable
 ;;  C-x n w   `widen'
-;;  C-x n x   `zz-narrow-repeat' - Cycle zones as buffer narrowing
+;;  C-x n x   `zz-narrow-repeat' - Cycle or pop zones as narrowings
 ;;  C-x n C-x `zz-select-zone-repeat' - Cycle zones as active region
 ;;
 ;;
@@ -452,10 +458,10 @@
 ;;  added to the izone list of the current buffer (by default,
 ;;  buffer-local variable `zz-izones').
 ;;
-;;  You can then use `C-x n x' to cycle among previous buffer
-;;  narrowings.  Repeating `x' repeats the action: `C-x n x x x x'
-;;  etc.  Each time you hit `x' a different narrowing is made current.
-;;  This gives you an easy way to browse your past narrowings.
+;;  You can then use `C-x n x' to cycle or pop previous narrowings.
+;;  Repeating `x' repeats the action: `C-x n x x x x' etc.  Each time
+;;  you hit `x' a different narrowing is made current.  This gives you
+;;  an easy way to browse your past narrowings.
 ;;
 ;;  If the izone variable is not buffer-local then `zz-narrow-repeat'
 ;;  can cycle among the narrowings in different buffers, switching the
@@ -470,10 +476,14 @@
 ;;    resets (empties) the current izone variable.
 ;;
 ;;  * A numeric prefix arg N takes you directly to the abs(N)th
-;;    previous buffer narrowing.  That is, it widens abs(N) times.
-;;    Positive and negative args work the same, except that a negative
-;;    arg also pops entries off the ring: it removes the ring entries
-;;    from the most recent back through the (-)Nth one.
+;;    previous buffer narrowing.  That is, it acts abs(N) times.
+;;
+;;  A negative arg work like a positive one, except that it also pops
+;;  entries off the ring: it removes entries from the most recent back
+;;  through the (-)Nth one.  For example, `C-- C-x n x x x' pops the
+;;  last added narrowing each time you hit `x'.  You can thus use the
+;;  list of recorded zones as a narrowing stack: narrow commands push
+;;  to the stack, and `C-- C-x n x' pops it.
 ;;
 ;;  By default, `C-x n x' is bound to command `zz-narrow-repeat'.
 ;;  (For Emacs versions prior to 22 it is bound by default to
@@ -529,7 +539,10 @@
 ;; (defun hlt-highlight-regions (&optional regions face msgp mousep
 ;;                                         buffers)
 ;;   "Apply `hlt-highlight-region' to regions in `zz-izones'."
-;;   (interactive (list (zz-izone-limits) nil t current-prefix-arg))
+;;   (interactive (list (zz-izone-limits zz-izones)
+;;                      nil
+;;                      t
+;;                      current-prefix-arg))
 ;;   (dolist (start+end  regions)
 ;;     (hlt-highlight-region (nth 0 start+end) (nth 1 start+end)
 ;;                           face msgp mousep buffers)))
@@ -542,8 +555,20 @@
 ;;
 ;;; Change Log:
 ;;
-;;(@* "Change log")
-;;
+;;(@* "Change Log")
+;;
+;; 2018/12/28 dadams
+;;     Fix condition-case-unless-debug for Emacs 22.  Use full macro 
definition, to prevent E22 compiler warning.
+;;     zz-izone-limits: IZONES arg is no longer optional - explicit list of 
izones, so can handle null izones.
+;;     zz-narrow: Correctly handle negative arg when no more zones to pop off.
+;;     zz-add-zones-matching-regexp:
+;;       let*, not let.  Protect isearchp-dim-outside-search-area-flag with 
bound-and-true-p.
+;; 2018/12/10 dadams
+;;     Added: zz-choose-zone-by-id-and-text, zz-dotted-zones-from-izones, 
zz-order-zones.
+;;     Regrouped some definitions.
+;;     zz-add-zone: Do not add if zone would cover whole buffer.  Use 
zz-user-error, not error.
+;;     zz-set-zones-from-face: Removed unused arg MSGP.
+;;     zz-(do|map)-(i)zones: Added arg UNITE-P - do not unite by default.
 ;; 2018/11/21 dadams
 ;;     Added: zz-add-zones-matching-regexp, zz-set-zones-matching-regexp, 
zz-toggles-map,
 ;;            condition-case-unless-debug alias.
@@ -855,6 +880,7 @@
 
 ;; Quiet the byte-compiler.
 (defvar hlt-last-face)                  ; In `highlight.el'
+(defvar isearchp-dim-outside-search-area-flag) ; In `isearch+.el'
 (defvar mode-line-modes)                ; Emacs 22+
 (defvar narrow-map)                     ; Emacs 23+
 (defvar region-extract-function)        ; Emacs 25+
@@ -862,14 +888,46 @@
 (defvar repeat-previous-repeated-command) ; In `repeat.el'
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-
-(unless (fboundp 'condition-case-unless-debug) ; Emacs 22-23.
-  (defalias 'condition-case-unless-debug 'condition-case-no-debug))
 
-(defalias 'zz-user-error
-  (if (fboundp 'user-error) #'user-error #'error)) ; For Emacs 22-23.
+
+;;(@* "Compatibility Code for Older Emacs Versions")
+
+;;; Compatibility Code for Older Emacs Versions ----------------------
+
+;; When byte-compiled by Emacs 22 this gives a false-positive unbound-variable 
warning.
+;; (unless (fboundp 'condition-case-unless-debug)
+;;   (defalias 'condition-case-unless-debug (if (fboundp 
'condition-case-no-debug)
+;;                                              'condition-case-no-debug ; 
Emacs 23
+;;                                            'condition-case))) ; Emacs 22
+
+(unless (fboundp 'condition-case-unless-debug)
+  (defmacro condition-case-unless-debug (var bodyform &rest handlers)
+    "Like `condition-case' except that it does not prevent debugging.
+More specifically if `debug-on-error' is set then the debugger will be invoked
+even if this catches the signal."
+    (declare (debug condition-case) (indent 2)) ; 
+    `(condition-case ,var
+         ,bodyform
+       ,@(mapcar (lambda (handler)
+                   `((debug ,@(if (listp (car handler)) (car handler) (list 
(car handler))))
+                     ,@(cdr handler)))
+                 handlers))))
+
+(defalias 'zz-user-error (if (fboundp 'user-error) #'user-error #'error)) ; 
For Emacs 22-23.
+
+(defalias 'zz-buffer-narrowed-p (if (fboundp 'buffer-narrowed-p) ; For Emacs 
22-23.
+                                    #'buffer-narrowed-p
+                                  (lambda () (/= (- (point-max) (point-min)) 
(buffer-size)))))
+
+(defalias 'zz-string-match-p (if (fboundp 'string-match-p) ; For Emacs 22.
+                                 #'string-match-p
+                               (lambda (regexp string &optional start)
+                                 "Like `string-match', but this saves and 
restores the match data."
+                                 (save-match-data (string-match regexp string 
start)))))
+
+;;(@* "Variables and Faces")
 
+;;; Variables and Faces ----------------------------------------------
 
 (defgroup zones nil
   "Zones of text - like multiple regions."
@@ -956,486 +1014,411 @@ cons whose care is the abstract (a string).")
 
 (defvar zz-zone-abstract-limit 68
   "Max number of chars of zone text to include in default zone abstract.")
+
+;;(@* "Advice for Standard Functions")
 
-(defun zz-zone-abstract-function-default (izone)
-  "Default value of `zz-zone-abstract-function'.
-The abstract it produces for IZONE is (the absolute value of) the zone
-ID, followed by the first `zz-zone-abstract-limit' chars of the zone
-text.  The return value of the function is a cons, (ABSTRACT . IZONE),
-whose car is the abstract and whose cdr is the izone."
-  (let ((id   (abs (car izone)))
-        (beg  (cadr izone))
-        (end  (caddr izone)))
-    (cons (format "%d %s" id (buffer-substring beg (min (+ beg 
zz-zone-abstract-limit) end))) izone)))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Advice for Standard Functions ------------------------------------
 
-(defun zz-zone-ordered (zone)
-  "Return ZONE or ZONE with its car and cadr reversed, so car <= cadr.
-The cddr of ZONE remains as it was."
-  (let ((beg    (car  zone))
-        (end    (cadr zone))
-        (extra  (cddr zone)))
-    (when (zz-readable-marker-p beg) (setq beg  (nth 2 beg)))
-    (when (zz-readable-marker-p end) (setq end  (nth 2 end)))
-    (if (<= beg end) zone `(,end ,beg ,@extra))))
+(defun zz-narrow-advice (interactive-p)
+  "Advice for narrowing functions.
+Call `zz-add-zone' if interactive or if `zz-add-zone-anyway-p'."
+  (when (or interactive-p  zz-add-zone-anyway-p)
+    (zz-add-zone (point-min) (point-max) nil nil nil "Narrowed, and recorded 
zone: ")))
 
-(defun zz-zones-overlap-p (zone1 zone2)
-  "Return non-nil if ZONE1 and ZONE2 overlap.
-Assumes that each zone is ordered (its car <= its cadr).
-The cddrs are ignored.
+(defadvice narrow-to-region (after zz-add-zone--region activate)
+  "Push the region limits to the current `zz-izones-var'.
+You can use `C-x n x' to widen to a previous buffer restriction.
 
-Zones that use markers do not overlap if the marker buffers differ."
-  (and (zz-zones-same-buffer-name-p zone1 zone2)
-       (progn (when (< (car zone2) (car zone1)) (setq zone1 (prog1 zone2 (setq 
zone2 zone1))))
-              (<= (car zone2) (cadr zone1)))))
+This is a destructive operation. The list structure of the variable
+value can be modified."
+  (zz-narrow-advice (interactive-p)))
 
-(defun zz-zones-same-buffer-name-p (zone1 zone2)
-  "Return non-nil if ZONE1 and ZONE2 apply to the same buffer.
-This is the case if `zz-zone-buffer-name' returns the same name for
-each.  (A buffer with that name need not exist.)"
-  (eq (zz-zone-buffer-name zone1) (zz-zone-buffer-name zone2)))
+(defadvice narrow-to-defun (after zz-add-zone--defun activate)
+  "Push the defun limits to the current `zz-izones-var'.
+You can use `C-x n x' to widen to a previous buffer restriction.
 
-(defun zz-zone-buffer-name (zone)
-  "Return the name of the buffer used by ZONE.
-If the two ZONE positions specify different buffers, or if either is a
-marker that points nowhere, then raise an error."
-  (let* ((lim1  (car zone))
-         (lim2  (cadr zone))
-         (buf1  (cond ((markerp lim1)               (and (marker-buffer lim1)
-                                                         (buffer-name 
(marker-buffer lim1))))
-                      ((zz-readable-marker-p lim1)  (cadr lim1))
-                      (t                            (buffer-name 
(current-buffer)))))
-         (buf2  (cond ((markerp lim2)               (and (marker-buffer lim2)
-                                                         (buffer-name 
(marker-buffer lim2))))
-                      ((zz-readable-marker-p lim2)  (cadr lim2))
-                      (t                            (buffer-name 
(current-buffer))))))
-    (unless (and buf1  buf2) (error "Zone has marker(s) that point nowhere: 
%S" zone))
-    (unless (equal buf1 buf2) (error "Zone has conflicting buffers: %S" zone))
-    buf1))
+This is a destructive operation. The list structure of the variable
+value can be modified."
+  (zz-narrow-advice (interactive-p)))
 
-(defun zz-do-zones (function &optional zones)
-  "Like `zz-map-zones', but without returning the result of mapping.
-The return value is undefined."
-  (when (functionp function)
-    (when (zz-izones-p zones) (setq zones  (zz-izone-limits zones nil 
'ONLY-THIS-BUFFER)))
-    (setq zones  (zz-zone-union zones))
-    (dolist (zone  zones) (funcall function (car zone) (cadr zone)))))
+;; Call `zz-add-zone' if interactive or `zz-add-zone-anyway-p'.
+;;
+(defadvice narrow-to-page (after zz-add-zone--defun activate)
+  "Push the page limits to the current `zz-izones-var'.
+You can use `C-x n x' to widen to a previous buffer restriction.
 
-(defun zz-map-zones (function &optional zones)
-  "Map binary FUNCTION over ZONES, applying it to the limits of each zone.
-ZONES can be a list of basic zones or a list like `zz-izones', that
-is, zones that have identifiers.  By default, ZONES is the value of
-`zz-izones'."
-  (if (not (functionp function))
-      (or zones  zz-izones)
-    (when (zz-izones-p zones) (setq zones  (zz-izone-limits zones nil 
'ONLY-THIS-BUFFER)))
-    (setq zones  (zz-zone-union zones))
-    (mapcar (lambda (zone) (funcall function (car zone) (cadr zone))) zones)))
+This is a destructive operation. The list structure of the variable
+value can be modified."
+  (zz-narrow-advice (interactive-p)))
+
+;;(@* "General Commands")
 
-(defun zz-do-izones (function &optional izones)
-  "Like `zz-map-izones', but without returning the result of mapping.
-The return value is undefined."
-  (when (functionp function)
-    (setq izones  (zz-unite-zones izones))
-    (dolist (izone  izones) (funcall function (car izone) (cadr izone) (caddr 
izone)))))
+;;; General Commands -------------------------------------------------
 
-(defun zz-map-izones (function &optional izones)
-  "Map FUNCTION over IZONES.
-Apply FUNCTION to the first three elements of each izone, that is, the
- identifier and the zone limits.
-IZONES is a list like `zz-izones', that is, zones with identifiers.
-By default, IZONES is the value of `zz-izones'."
-  (if (not (functionp function))
-      (or izones  zz-izones)
-    (setq izones  (zz-unite-zones izones))
-    (mapcar (lambda (izone) (funcall function (car izone) (cadr izone) (caddr 
izone))) izones)))
+;;;###autoload
+(defalias 'zz-select-region-by-id-and-text #'zz-select-zone-by-id-and-text)
+;;;###autoload
+(defun zz-select-zone-by-id-and-text (id &optional variable msgp) ; Bound to 
`C-x n #'
+  "Select a zone by completing against its ID and its text (content).
+The text of the chosen zone is made the active region.
 
-(defun zz-zones-complement (zones &optional beg end)
-  "Return a list of zones that is the complement of ZONES, from BEG to END.
-ZONES is assumed to be a union, i.e., sorted by car, with no overlaps.
-Any extra info in a zone of ZONES, i.e., after the cadr, is ignored."
-  (setq beg  (zz-marker-from-object (or beg  (point-min)))
-        end  (zz-marker-from-object (or end  (point-max))))
-  (let ((res  ()))
-    (dolist (zone  zones)
-      (push (list beg (car zone)) res)
-      (setq beg  (cadr zone)))
-    (setq res  (nreverse (push (list beg end) res)))))
+The zones to choose from are those of VARIABLE that are in the current
+buffer.  VARIABLE defaults to the value of `zz-izones-var'.  With a
+prefix arg you are prompted for a different variable to use.
 
-(defun zz-two-zone-union (zone1 zone2)
-  "Return the union of ZONE1 and ZONE2, or nil if they do not overlap.
-Assumes that each zone is ordered (its car <= its cadr).
+Non-interactively:
+* VARIABLE is the optional izones variable to use.
+* Non-nil MSGP means show a status message."
+  (interactive
+   (let* ((var     (or (and current-prefix-arg  (zz-read-any-variable 
"Variable: " zz-izones-var t))
+                       zz-izones-var))
+          (izones  (zz-remove-izones-w-other-buffer-markers (symbol-value 
var)))
+          (num     (string-to-number (completing-read "Zone: "
+                                                      (mapcar 
zz-zone-abstract-function izones) nil t))))
+     (list num var t)))
+  (let* ((izone  (assq (- id) (zz-remove-izones-w-other-buffer-markers 
(symbol-value variable))))
+         (beg    (cadr izone))
+         (end    (caddr izone)))
+    (goto-char beg)
+    (push-mark end nil t)
+    (when msgp (message "Izone #%d selected" (car izone)))))
 
-The cddr of a non-nil result (its EXTRA information, which must be a
-list) is the union of the EXTRA information of each zone:
+;;;###autoload
+(defalias 'zz-select-region #'zz-select-zone)
+;;;###autoload
+(defun zz-select-zone (arg &optional msgp) ; Not bound.
+  "Select a zone in `zz-izones-var', and make it the active region.
+With no prefix arg, select the last-recorded zone.
+With a numeric prefix arg N, select the Nth last-recorded zone.
 
- (zz-set-union (cddr zone1) (cddr zone2))
+Note that if the value of `zz-izones-var' is not buffer-local then you
+can use this command to cycle among zones in multiple buffers."
+  (interactive "p\np")
+  (let* ((var   zz-izones-var)
+         (val   (symbol-value var))
+         (cntr  (abs arg))
+         (len   (length val)))
+    (unless (cadr val) (error "No zone to select"))
+    (when (> cntr len)
+      (when msgp (message "Only %d zones available.  Using zone #%d" len len) 
(sit-for 1))
+      (setq cntr  (min cntr len)))
+    (let ((latest  ()))
+      (while (> cntr 0)
+        (push (nth (1- cntr) val) latest)
+        (setq cntr  (1- cntr)))
+      (setq latest  (nreverse latest))
+      (setq val  (set var (append (nthcdr arg val) latest))
+            val  (set var (mapcar #'zz-markerize val)))
+      (let* ((izone                  (car val))
+             (beg                    (nth 1 izone))
+             (end                    (nth 2 izone))
+             (other-buf              nil))
+        (when (and (not (local-variable-p var))
+                   (setq other-buf  (zz-izone-has-other-buffer-marker-p 
izone)) ; Returns marker or nil.
+                   (or (not (markerp beg))  (not (markerp end))  (eq 
(marker-buffer beg) (marker-buffer end)))
+                   (setq other-buf  (marker-buffer other-buf)))
+          (pop-to-buffer other-buf))
+        (goto-char beg)
+        (push-mark end nil t)
+        (when msgp
+          (message "Selected zone #%d (in zone-creation order)%s"
+                   (caar val) (if other-buf (format " in `%s'" other-buf) 
"")))))))
 
-This is a non-destructive operation: The result is a new list."
-  (and (zz-zones-overlap-p zone1 zone2)  `(,(zz-min (car zone1)  (car zone2))
-                                            ,(zz-max (cadr zone1) (cadr zone2))
-                                            ,@(zz-set-union (cddr zone1) (cddr 
zone2)))))
+;; This is a non-destructive operation.
+;;
+;;;###autoload
+(defun zz-narrow (arg &optional msgp)   ; Not bound.
+  "Widen to a previous buffer restriction (narrowing).
+The candidates are the zones in the current `zz-izones-var'.
 
-(defun zz-zone-union (zones &optional buffer)
-  "Return the union (coalescence) of the zones in list ZONES.
-Each element of ZONES is a list of two zone limits, possibly followed
-by extra info: (LIMIT1 LIMIT2 . EXTRA), where EXTRA is a list.
-The limits need not be in numerical order.
+With no prefix arg, widen to the previous narrowing.
+With a plain prefix arg (`C-u'), widen completely.
+With a zero  prefix arg (`C-0'), widen completely and reset (empty)
+ the list of zones for this buffer.
+With a numeric prefix arg N, widen abs(N) times (to the abs(N)th
+ previous narrowing).  Positive and negative args work the same,
+ except that a negative arg also pops entries off the ring: it removes
+ the ring entries from the most recent back through the (-)Nth one."
+  (interactive "P\np")
+  (let* ((var  zz-izones-var)
+         (val  (symbol-value var)))
+    (unless val (error "No previous narrowing"))
+    (cond ((or (consp arg)  (and (null (cdr val))  (zz-buffer-narrowed-p)))
+           (widen)
+           (setq zz-lighter-narrowing-part  "")
+           (zz-narrowing-lighter)
+           (when msgp (message "No longer narrowed")))
+          ((= (prefix-numeric-value arg) 0)
+           (set var ())
+           (widen)
+           (setq zz-lighter-narrowing-part  "")
+           (zz-narrowing-lighter)
+           (when msgp (message "No longer narrowed; no more narrowings")))
+          (t
+           (setq arg  (prefix-numeric-value arg))
+           (let ((latest  ())
+                 (cntr    (abs arg)))
+             (while (> cntr 0)
+               (push (nth (1- cntr) val) latest)
+               (setq cntr  (1- cntr)))
+             (setq latest  (nreverse latest))
+             (when (< arg 0) (setq arg     (abs arg)
+                                   latest  ()))
+             (setq val                         (set var (append (nthcdr arg 
val) latest))
+                   val                         (set var (mapcar #'zz-markerize 
val)))
+             (cond (val
+                    (setq zz-lighter-narrowing-part   (format "-%d" (caar 
val)))
+                    (condition-case err
+                        (let* ((zz-add-zone-anyway-p  t)
+                               (izone                  (car val))
+                               (beg                    (nth 1 izone))
+                               (end                    (nth 2 izone))
+                               (other-buf              nil))
+                          (when (and (not (local-variable-p var))
+                                     (setq other-buf  
(zz-izone-has-other-buffer-marker-p izone)) ; Marker or nil.
+                                     (or (not (markerp beg))  (not (markerp 
end))
+                                         (eq (marker-buffer beg) 
(marker-buffer end))) ; Same other buffer.
+                                     (setq other-buf  (marker-buffer 
other-buf)))
+                            (pop-to-buffer other-buf))
+                          (narrow-to-region beg end)
+                          (zz-narrowing-lighter))
+                      (args-out-of-range (set var  (cdr val))
+                                         (error "Restriction removed because 
of invalid limits"))
+                      (error (error "%s" (error-message-string err)))))
+                   (t ; No zones now.  E.g., negative ARG popped off the last 
one.
+                    (widen)
+                    (setq zz-lighter-narrowing-part  "")
+                    (zz-narrowing-lighter)
+                    (when msgp (message "No longer narrowed")))))))))
 
-Each limit can be a number or a marker, but zones with markers for
-buffers other than BUFFER (default: current buffer) are ignored.
+;;;###autoload
+(defun zz-add-zone (start end &optional variable not-buf-local-p set-var-p 
msg) ; Bound to `C-x n a'.
+  "Add an izone for the text from START to END to the izones of VARIABLE.
+But do not add a zone if it would cover the entire buffer.
+Return the new value of VARIABLE.
 
-Any zones that use markers for a buffer other than BUFFER (default:
-current buffer) are excluded.
+This is a destructive operation: The list structure of the variable
+value can be modified.
 
-Returns a new list, which is sorted by the lower limit of each zone,
-which is its car.  (This is a non-destructive operation.)
+VARIABLE defaults to the value of `zz-izones-var'.
+START and END are as for `narrow-to-region'.
 
-Each zone in ZONES is first ordered, so that its car <= its cadr.
-The resulting zones are then sorted by their cars.
+With a prefix arg you are prompted for a different variable to use, in
+place of the current value of `zz-izones-var'.  The particular prefix
+arg determines whether the variable, if unbound, is made buffer-local,
+and whether `zz-izones-var' is set to the variable symbol:
 
-`zz-two-zone-union' is then applied recursively to coalesce
-overlapping or adjacent zones.  This means also that any EXTRA info is
-combined whenever zones are merged together."
-  (let* ((filtered-zones  (zz-remove-zones-w-other-buffer-markers zones 
buffer))
-         (flipped-zones   (mapcar #'zz-zone-ordered filtered-zones))
-         (sorted-zones    (sort flipped-zones #'zz-car-<)))
-    (zz-zone-union-1 sorted-zones)))
+  prefix arg          buffer-local   set `zz-izones-var'
+  ----------          ------------   -------------------
+  Plain `C-u'         yes            yes
+  > 0 (e.g. `C-1')    yes            no
+  = 0 (e.g. `C-0')    no             yes
+  < 0 (e.g. `C--')    no             no
 
-;; Recursive version.
-;; (defun zz-zone-union-1 (zones)
-;;   "Helper for `zz-zone-union'."
-;;   (if (null (cdr zones))
-;;       zones
-;;     (let ((new  (zz-two-zone-union (car zones) (cadr zones))))
-;;       (if new
-;;           (zz-zone-union-1 (cons new (cddr zones)))
-;;         (cons (car zones) (zz-zone-union-1 (cdr zones)))))))
+Non-interactively:
+* VARIABLE is the optional izones variable to use.
+* Non-nil NOT-BUF-LOCAL-P means do not make VARIABLE buffer-local.
+* Non-nil SET-VAR-P means set `zz-izones-var' to VARIABLE.
+* Non-nil MSG means echo the zone limits, preceded by string MSG."
+  (interactive (let* ((beg    (region-beginning))
+                      (end    (region-end))
+                      (var    (or (and current-prefix-arg  
(zz-read-any-variable "Variable: " zz-izones-var))
+                                  zz-izones-var))
+                      (npref  (prefix-numeric-value current-prefix-arg))
+                      (nloc   (and current-prefix-arg  (<= npref 0)  (not 
(boundp var))))
+                      (setv   (and current-prefix-arg  (or (consp 
current-prefix-arg)  (= npref 0)))))
+                 (list beg end var nloc setv "Recorded zone: ")))
+  (let* ((mrk1     (make-marker))
+         (mrk2     (make-marker))
+         (var      (or variable  zz-izones-var))
+         (_IGNORE  (unless (or not-buf-local-p  (boundp var)) 
(make-local-variable var)))
+         (_IGNORE  (when set-var-p (setq zz-izones-var  var)))
+         (_IGNORE  (unless (boundp var) (set var ())))
+         (val      (symbol-value var))
+         sans-id  id-cons  id izone)
+    (unless (zz-izones-p val) (zz-user-error "Not an izones variable: `%s', 
value: `%S'" var val))
+    (move-marker mrk1 start)
+    (move-marker mrk2 end)
+    (setq sans-id  (list mrk1 mrk2)
+          id-cons  (rassoc sans-id val)
+          id       (if id-cons (car id-cons) (- (1+ (length val)))) ; 1-based, 
not 0-based.
+          val      (set var (zz-rassoc-delete-all sans-id val))) ; Destructive 
operation.
+    (when (and (= mrk1 1)  (= mrk2 (1+ (buffer-size))))
+      (zz-user-error "Zone not created - it would cover whole buffer"))
+    (setq izone  `(,id ,mrk1 ,mrk2))
+    (set var `(,izone ,@val))
+    (when msg (message "%s%d to %d" msg (marker-position mrk1) 
(marker-position mrk2)))
+    (symbol-value var)))
 
-(defun zz-zone-union-1 (zones)
-  "Helper for `zz-zone-union'."
-  (if (null (cdr zones))
-      zones
-    (let ((acc  ())
-          new)
-      (while zones
-        (setq new  (and (cdr zones)  (zz-two-zone-union (car zones) (cadr 
zones))))
-        (if new
-            (setq zones  (cons new (cddr zones)))
-          (setq acc    (cons (car zones) acc)
-                zones  (cdr zones))))
-      (setq acc  (nreverse acc)))))
+;;;###autoload
+(defun zz-delete-zone (id &optional variable msgp) ; Bound to `C-x n C-d'.
+  "Delete a zone by completing against its ID and its text (content).
+Delete the zone from VARIABLE, and renumber those remaining.
+Return the new value of VARIABLE.
 
-(defun zz-car-< (zone1 zone2)
-  "Return non-nil if car of ZONE1 < car of ZONE2.
-Each car can be a number or a marker.
+This is a destructive operation: The list structure of the variable
+value can be modified.
 
-* Two numbers or two markers in the same buffer: Use `<'.
-* Two markers in different buffers: Use `string<' of the buffer names.
-* Only one is a marker:
-  If its buffer is current then treat it as a number, using `<'.
-  Else return false if the marker is for ZONE1 and return true if it
-       is for ZONE2."
-  (let* ((p1  (car zone1))
-         (p2  (car zone2))
-         (m1  (markerp p1))
-         (m2  (markerp p2))
-         (b1  (and m1  (marker-buffer p1)))
-         (b2  (and m2  (marker-buffer p2))))
-    (cond ((and (not m1)  (not m2)) (< p1 p2))
-          ((and m1  m2)   (if (eq b1 b2) (< p1 p2) (string< (buffer-name b1) 
(buffer-name b2))))
-          (m1             (and (eq (current-buffer) b1)  (< p1 p2)))
-          (m2             (or (not (eq (current-buffer) b2))  (< p1 p2))))))
+VARIABLE defaults to the value of `zz-izones-var'.  With a prefix arg
+you are prompted for a different variable to use.
 
-(defun zz-two-zone-intersection (zone1 zone2)
-  "Return intersection of ZONE1 and ZONE2.
-\(The result is nil if they do not overlap.)
-Assumes that each zone is ordered (its car <= its cadr).
+Non-nil optional arg NOMSG means do not display a status message."
+  (interactive
+   (let* ((var      (or (and current-prefix-arg (zz-read-any-variable 
"Variable: " zz-izones-var t))
+                        zz-izones-var))
+          (izones   (symbol-value var))
+          (_IGNORE  (unless (zz-izones-p izones)
+                      (error "Not an izones variable: `%s', value: `%S'" var 
izones)))
+          (_IGNORE  (unless izones (error "No zones - variable `%s' is empty" 
var)))
+          (len      (length izones))
+          (num      (if (= len 1)
+                        1
+                      (string-to-number (completing-read (format "Delete zone 
with ID (1 to %d): " len)
+                                                         (mapcar 
zz-zone-abstract-function izones) nil t)))))
+     (list num var t)))
+  (unless variable (setq variable  zz-izones-var))
+  (let ((izones  (symbol-value variable)))
+    (unless (zz-izones-p izones) (error "Not an izones variable: `%s', value: 
`%S'" variable izones))
+    (unless izones (error "No zones - variable `%s' is empty" variable))
+    (set variable (assq-delete-all (- id) izones)))
+  (zz-izones-renumber variable)
+  (when msgp (message "Deleted zone with ID %d" id))
+  (symbol-value variable))
 
-The cddr of a non-nil result (its list of EXTRA information) is the
-intersection of the EXTRA information of each zone:
+;;;###autoload
+(defun zz-narrow-repeat ()              ; Bound to `C-x n x'.
+  "Cycle to the next buffer restriction (narrowing).
+This is a repeatable version of `zz-narrow'.
 
- (zz-set-intersection (cddr zone1) (cddr zone2))
+Note that if the value of `zz-izones-var' is not buffer-local then you
+can use this command to cycle among zones in multiple buffers."
+  (interactive)
+  (zz-repeat-command 'zz-narrow))
 
-This is a non-destructive operation: The result is a new list."
-  (and (zz-zones-overlap-p zone1 zone2)  `(,(zz-max (car zone1)  (car zone2))
-                                            ,(zz-min (cadr zone1) (cadr zone2))
-                                            ,@(zz-set-intersection (cddr 
zone1) (cddr zone2)))))
+;;;###autoload
+(defalias 'zz-select-region-repeat #'zz-select-zone-repeat)
+;;;###autoload
+(defun zz-select-zone-repeat ()         ; Bound to `C-x n C-x'.
+  "Cycle to the next zone, and make it the active region.
+Zones are cycled in chronological order of their recording.
+This is a repeatable version of `zz-select-zone'."
+  (interactive)
+  (zz-repeat-command 'zz-select-zone))
 
-(defun zz-zone-intersection (zones)
-  "Return the intersection of the zones in list ZONES.
-Each element of ZONES is a list of two zone limits, possibly followed
-by extra info: (LIMIT1 LIMIT2 . EXTRA), where EXTRA is a list.
+;;;###autoload
+(defun zz-set-izones-var (variable &optional localp) ; Bound to `C-x n v'
+  "Set `zz-izones-var' to VARIABLE, for which you are prompted.
+With a prefix arg, make VARIABLE automatically be buffer-local."
+  (interactive (list (zz-read-any-variable "Variable: " zz-izones-var) 
current-prefix-arg))
+  (setq zz-izones-var  variable)
+  (when localp (make-variable-buffer-local variable)))
 
-The limits do not need to be in numerical order.
+;;;###autoload
+(defun zz-clone-zones (from-variable to-variable &optional msgp) ; Bound to 
`C-x n c'
+  "Clone FROM-VARIABLE to TO-VARIABLE.
+Return the new value of TO-VARIABLE.
+That is, copy the zones of FROM-VARIABLE to (emptied) TO-VARIABLE.
+A non-destructive operation: The value of TO-VARIABLE is a new list,
+ with only the zones from FROM-VARIABLE.
+Return the value of TO-VARIABLE.
 
-Returns a new list, which is sorted by the lower limit of each zone,
-which is its car.  (This is a non-destructive operation.)
+You are prompted for FROM-VARIABLE and TO-VARIABLE.
 
-Each zone in ZONES is first ordered, so that its car <= its cadr.
-The resulting zones are then sorted by their cars.
+With a non-negative (>= 0) prefix arg, make TO-VARIABLE buffer-local.
+With a non-positive (<= 0) prefix arg, set `zz-izones-var' to the
+TO-VARIABLE symbol.  (Zero: do both.)
 
-`zz-two-zone-intersection' is then applied recursively to combine
-overlapping zones.  This means also that any EXTRA info is combined
-when zones are merged together."
-  (let* ((flipped-zones  (mapcar #'zz-zone-ordered zones))
-         (sorted-zones   (sort flipped-zones (lambda (z1 z2) (< (car z1) (car 
z2))))))
-    (zz-zone-intersection-1 sorted-zones)))
+FROM-VARIABLE defaults to the value of `zz-izones-var'.
 
-(defun zz-zone-intersection-1 (zones)
-  "Helper for `zz-zone-intersection'."
-  (if (null (cdr zones))
-      zones
-    (let ((new  (zz-two-zone-intersection (car zones) (cadr zones))))
-      (and new  (zz-zone-intersection-1 (cons new (cddr zones)))))))
+Non-interactively: Non-nil MSGP means show a status message."
+  (interactive
+   (let ((from-var  (zz-read-any-variable "Copy variable: " zz-izones-var t))
+         (to-var    (zz-read-any-variable "To variable: "))
+         (npref     (and current-prefix-arg  (prefix-numeric-value 
current-prefix-arg))))
+     (when (and npref  (>= npref 0)) (make-local-variable to-var))
+     (when (and npref  (<= npref 0)) (setq zz-izones-var to-var))
+     (list from-var to-var t)))
+  (prog1 (set to-variable (copy-sequence (symbol-value from-variable)))
+    (when msgp (message "Cloned `%s' to `%s'" from-variable to-variable))))
 
-;; From `cl-seq.el', function `union', without keyword treatment.
-(defun zz-set-union (list1 list2)
-  "Combine LIST1 and LIST2 using a set-union operation.
-The result list contains all items that appear in either LIST1 or
-LIST2.  This is a non-destructive function: it copies the data if
-necessary."
-  (cond ((null list1)         list2)
-        ((null list2)         list1)
-        ((equal list1 list2)  list1)
-        (t
-         (unless (>= (length list1) (length list2)) (setq list1  (prog1 list2 
(setq list2  list1)))) ; Swap.
-         (while list2
-           (unless (member (car list2) list1) (setq list1  (cons (car list2) 
list1)))
-           (setq list2  (cdr list2)))
-         list1)))
+;;;###autoload
+(defalias 'zz-clone-and-coalesce-zones #'zz-clone-and-unite-zones)
+;;;###autoload
+(defun zz-clone-and-unite-zones (from-variable to-variable &optional msgp) ; 
Bound to `C-x n C'
+  "Clone FROM-VARIABLE to TO-VARIABLE, then unite (coalesce) TO-VARIABLE.
+That is, use`zz-clone-zones' to fill TO-VARIABLE, then use
+`zz-unite-zones' on TO-VARIABLE.
 
-;; From `cl-seq.el', function `intersection', without keyword treatment.
-(defun zz-set-intersection (list1 list2)
-  "Set intersection of lists LIST1 and LIST2.
-This is a non-destructive operation: it copies the data if necessary."
-  (and list1  list2
-       (if (equal list1 list2)
-           list1
-         (let ((result  ()))
-           (unless (>= (length list1) (length list2)) (setq list1  (prog1 
list2 (setq list2  list1)))) ; Swap.
-           (while list2
-             (when (member (car list2) list1) (setq result  (cons (car list2) 
result)))
-             (setq list2  (cdr list2)))
-           result))))
+Just as for `zz-clone-zones':
+ With a non-negative (>= 0) prefix arg, make TO-VARIABLE buffer-local.
+ With a non-positive (<= 0) prefix arg, set `zz-izones-var' to the
+ TO-VARIABLE symbol.  (Zero: do both.)
 
-(defun zz-min (&rest ns)
-  "Like `min', but if the args include a marker then return a marker.
-Raise an error if the args include markers from different buffers."
-  (let ((buf  (zz-buffer-of-markers ns))
-        (min  (apply #'min ns)))
-    (if (not buf)
-        min
-      (with-current-buffer (get-buffer-create buf)
-        (set-marker (copy-marker min) min buf)))))
+United zones are in ascending order of their cars.
+Return the new value of TO-VARIABLE.
 
-(defun zz-max (&rest ns)
-  "Like `max', but if the args include a marker then return a marker.
-Raise an error if the args include markers from different buffers."
-  (let ((buf  (zz-buffer-of-markers ns))
-        (max  (apply #'max ns)))
-    (if (not buf)
-        max
-      (with-current-buffer (get-buffer-create buf) (set-marker (copy-marker 
max) max buf)))))
+Use this when you do not want to unite the zones of FROM-VARIABLE (for
+example, you want to use them as possibly overlapping buffer
+narrowings), but you also want to act on the united zones (for
+example, to search them).
 
-(defun zz-buffer-of-markers (ns)
-  "Return the buffer of the markers in list NS, or nil if no markers.
-Raise an error if NS contains markers from different buffers."
-  (let ((mkr  (car (zz-some #'markerp ns))))
-    (and mkr
-         (progn
-           (unless (zz-every (lambda (nn) (or (not (markerp nn)) (eq 
(marker-buffer nn) (marker-buffer mkr)))) ns)
-             (error "List contains markers from different buffers"))
-           t)
-         (marker-buffer mkr))))
+FROM-VARIABLE defaults to the value of `zz-izones-var'.
 
-;; Similar to `every' in `cl-extra.el', without non-list sequences and multiple
-;; sequences.
-(defun zz-every (predicate list)
-  "Return t if PREDICATE is true for all elements of LIST; else nil."
-  (while (and list  (funcall predicate (car list)))  (setq list  (cdr list)))
-  (null list))
-
-;; Same as `bmkp-some' in `bookmark+-1.el'.
-;; This is NOT the same as `some' in `cl-extra.el', even without non-list 
sequences and multiple sequences.
-;;
-;; If PREDICATE is satisfied by a list element ELEMENT, so that it returns a 
non-nil value VALUE for ELEMENT,
-;; then this returns the cons (ELEMENT . VALUE).  It does not return just 
VALUE.
-(defun zz-some (predicate list)
-  "Return non-nil if PREDICATE applied to some element of LIST is true.
-The value returned is a cons, (ELEMENT . VALUE), where ELEMENT is the
-first list element that satisfies PREDICATE and VALUE is the value of
-PREDICATE applied to ELEMENT."
-  (let (elt val)
-    (catch 'zz-some
-      (while list
-        (when (setq val  (funcall predicate (setq elt  (pop list))))
-          (throw 'zz-some (cons elt val))))
-      nil)))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;
+Non-interactively: Non-nil MSGP means show a status message."
+  (interactive
+   (let ((from-var  (zz-read-any-variable "Copy variable: " zz-izones-var t))
+         (to-var    (zz-read-any-variable "To variable: "))
+         (npref     (and current-prefix-arg  (prefix-numeric-value 
current-prefix-arg))))
+     (when (and npref  (>= npref 0)) (make-local-variable to-var))
+     (when (and npref  (<= npref 0)) (setq zz-izones-var to-var))
+     (list from-var to-var t)))
+  (set to-variable (copy-sequence (symbol-value from-variable)))
+  (prog1 (zz-unite-zones to-variable)
+    (when msgp (message "Cloned `%s' to `%s' and united `%s'" from-variable 
to-variable to-variable))))
 
 ;;;###autoload
-(defalias 'zz-select-region-by-id-and-text #'zz-select-zone-by-id-and-text)
+(defalias 'zz-coalesce-zones #'zz-unite-zones)
 ;;;###autoload
-(defun zz-select-zone-by-id-and-text (id &optional variable msgp) ; Bound to 
`C-x n #'
-  "Select a zone by completing against its ID and its text (content).
-The text of the chosen zone is made the active region.
+(defun zz-unite-zones (&optional variable msgp) ; Bound to `C-x n u'
+  "Coalesce (unite) the izones of VARIABLE.
+A non-destructive operation: The new value of VARIABLE is a new list.
+Return the new value of VARIABLE.
 
-The zones to choose from are those of VARIABLE that are in the current
-buffer.  VARIABLE defaults to the value of `zz-izones-var'.  With a
-prefix arg you are prompted for a different variable to use.
+United zones are in ascending order of their cars.
+
+VARIABLE defaults to the value of `zz-izones-var'.
+With a prefix arg you are prompted for a different variable to use, in
+place of the current value of `zz-izones-var'.  If the prefix arg is
+non-negative (>= 0) then make the variable buffer-local.  If the
+prefix arg is non-positive (<= 0) then set `zz-izones-var' to that
+variable symbol.  (Zero: do both.)
 
 Non-interactively:
 * VARIABLE is the optional izones variable to use.
 * Non-nil MSGP means show a status message."
-  (interactive
-   (let* ((var     (or (and current-prefix-arg  (zz-read-any-variable 
"Variable: " zz-izones-var t))
-                       zz-izones-var))
-          (izones  (zz-remove-izones-w-other-buffer-markers (symbol-value 
var)))
-          (num     (string-to-number (completing-read "Zone: "
-                                                      (mapcar 
zz-zone-abstract-function izones) nil t))))
-     (list num var t)))
-  (let* ((izone  (assq (- id) (zz-remove-izones-w-other-buffer-markers 
(symbol-value variable))))
-         (beg    (cadr izone))
-         (end    (caddr izone)))
-    (goto-char beg)
-    (push-mark end nil t)
-    (when msgp (message "Izone #%d selected" (car izone)))))
-
-;;;###autoload
-(defalias 'zz-select-region #'zz-select-zone)
-;;;###autoload
-(defun zz-select-zone (arg &optional msgp) ; Not bound.
-  "Select a zone in `zz-izones-var', and make it the active region.
-With no prefix arg, select the last-recorded zone.
-With a numeric prefix arg N, select the Nth last-recorded zone.
-
-Note that if the value of `zz-izones-var' is not buffer-local then you
-can use this command to cycle among zones in multiple buffers."
-  (interactive "p\np")
-  (let* ((var   zz-izones-var)
-         (val   (symbol-value var))
-         (cntr  (abs arg))
-         (len   (length val)))
-    (unless (cadr val) (error "No zone to select"))
-    (when (> cntr len)
-      (when msgp (message "Only %d zones available.  Using zone #%d" len len) 
(sit-for 1))
-      (setq cntr  (min cntr len)))
-    (let ((latest  ()))
-      (while (> cntr 0)
-        (push (nth (1- cntr) val) latest)
-        (setq cntr  (1- cntr)))
-      (setq latest  (nreverse latest))
-      (setq val  (set var (append (nthcdr arg val) latest))
-            val  (set var (mapcar #'zz-markerize val)))
-      (let* ((izone                  (car val))
-             (beg                    (nth 1 izone))
-             (end                    (nth 2 izone))
-             (other-buf              nil))
-        (when (and (not (local-variable-p var))
-                   (setq other-buf  (zz-izone-has-other-buffer-marker-p 
izone)) ; Returns marker or nil.
-                   (or (not (markerp beg))  (not (markerp end))  (eq 
(marker-buffer beg) (marker-buffer end)))
-                   (setq other-buf  (marker-buffer other-buf)))
-          (pop-to-buffer other-buf))
-        (goto-char beg)
-        (push-mark end nil t)
-        (when msgp
-          (message "Selected zone #%d (in zone-creation order)%s"
-                   (caar val) (if other-buf (format " in `%s'" other-buf) 
"")))))))
+  (interactive (let* ((var    (and current-prefix-arg  (zz-read-any-variable 
"Variable: " zz-izones-var t)))
+                      (npref  (prefix-numeric-value current-prefix-arg)))
+                 (when (and current-prefix-arg  (>= npref 0)) 
(make-local-variable var))
+                 (when (and current-prefix-arg  (<= npref 0)) (setq 
zz-izones-var var))
+                 (list var t)))
+  (let* ((var         (or variable  zz-izones-var))
+         (_IGNORE     (unless (boundp var) (set var ())))
+         (val         (symbol-value var))
+         (_IGNORE     (unless (zz-izones-p val) (error "Not an izones 
variable: `%s', value: `%S'" var val)))
+         (zone-union  (zz-zone-union (zz-izone-limits val))))
+    (set var  (zz-izones-from-zones zone-union))
+    (when msgp
+      (let ((len  (length (symbol-value var))))
+        (message "Zones united for variable `%s': %d zone%s now" var len (if 
(> len 1) "s" ""))))
+    (symbol-value var)))
 
-;; This is a non-destructive operation.
-;;
 ;;;###autoload
-(defun zz-narrow (arg &optional msgp)   ; Not bound.
-  "Widen to a previous buffer restriction (narrowing).
-The candidates are the zones in the current `zz-izones-var'.
-
-With no prefix arg, widen to the previous narrowing.
-With a plain prefix arg (`C-u'), widen completely.
-With a zero  prefix arg (`C-0'), widen completely and reset (empty)
- the list of zones for this buffer.
-With a numeric prefix arg N, widen abs(N) times (to the abs(N)th
- previous narrowing).  Positive and negative args work the same,
- except that a negative arg also pops entries off the ring: it removes
- the ring entries from the most recent back through the (-)Nth one."
-  (interactive "P\np")
-  (let* ((var  zz-izones-var)
-         (val  (symbol-value var)))
-    (unless val (error "No previous narrowing"))
-    (cond ((or (consp arg)  (and (null (cdr val))  (zz-buffer-narrowed-p)))
-           (widen)
-           (setq zz-lighter-narrowing-part  "")
-           (zz-narrowing-lighter)
-           (when msgp (message "No longer narrowed")))
-          ((= (prefix-numeric-value arg) 0)
-           (set var ())
-           (widen)
-           (setq zz-lighter-narrowing-part  "")
-           (zz-narrowing-lighter)
-           (when msgp (message "No longer narrowed; no more narrowings")))
-          (t
-           (setq arg  (prefix-numeric-value arg))
-           (let ((latest  ())
-                 (cntr    (abs arg)))
-             (while (> cntr 0)
-               (push (nth (1- cntr) val) latest)
-               (setq cntr  (1- cntr)))
-             (setq latest  (nreverse latest))
-             (when (< arg 0) (setq arg     (abs arg)
-                                   latest  ()))
-             (setq val                         (set var (append (nthcdr arg 
val) latest))
-                   val                         (set var (mapcar #'zz-markerize 
val))
-                   zz-lighter-narrowing-part  (format "-%d" (caar val)))
-             (condition-case err
-                 (let* ((zz-add-zone-anyway-p  t)
-                        (izone                  (car val))
-                        (beg                    (nth 1 izone))
-                        (end                    (nth 2 izone))
-                        (other-buf              nil))
-                   (when (and (not (local-variable-p var))
-                              (setq other-buf  
(zz-izone-has-other-buffer-marker-p izone)) ; Marker or nil.
-                              (or (not (markerp beg))  (not (markerp end))
-                                  (eq (marker-buffer beg) (marker-buffer 
end))) ; Same other buffer.
-                              (setq other-buf  (marker-buffer other-buf)))
-                     (pop-to-buffer other-buf))
-                   (narrow-to-region beg end)
-                   (zz-narrowing-lighter))
-               (args-out-of-range (set var  (cdr val))
-                                  (error "Restriction removed because of 
invalid limits"))
-               (error (error "%s" (error-message-string err)))))))))
-
-(defun zz-narrowing-lighter ()
-  "Update minor-mode mode-line lighter to reflect narrowing/widening.
-Put `zz-narrow' on `mouse-2' for the lighter suffix."
-  (let* ((%n-cons  (zz-regexp-car-member "%n\\(.*\\)\\'" mode-line-modes)))
-    (when %n-cons
-      (setcar %n-cons (replace-regexp-in-string "%n\\(.*\\)"
-                                                (if (zz-buffer-narrowed-p) 
zz-lighter-narrowing-part "")
-                                                (car %n-cons) nil nil 1))
-      (when (> (length (car %n-cons)) 2)
-        (set-text-properties 2
-                             (length (car %n-cons))
-                             '(local-map (keymap (mode-line keymap (mouse-2 . 
zz-narrow)))
-                               mouse-face mode-line-highlight
-                               help-echo "mouse-2: Next Restriction")
-                             (car %n-cons)))
-      ;; Dunno why we need to do this.  Tried adjusting `rear-sticky' and 
`front-sticky',
-      ;; but without this the whole field (not just the suffix) gets changed, 
in effect, to the above spec.
-      (set-text-properties 0 2 '(local-map (keymap (mode-line keymap (mouse-2 
. mode-line-widen)))
-                                 mouse-face mode-line-highlight help-echo 
"mouse-2: Widen")
-                           (car %n-cons)))))
-
-(defun zz-regexp-car-member (regexp xs)
-  "Like `member', but tests by matching REGEXP against cars."
-  (and (consp xs)  (if (and (stringp (car xs))  (zz-string-match-p regexp (car 
xs)))
-                       xs
-                     (zz-regexp-car-member regexp (cdr xs)))))
-
+(defalias 'zz-add-zone-and-coalesce #'zz-add-zone-and-unite)
 ;;;###autoload
-(defun zz-add-zone (start end &optional variable not-buf-local-p set-var-p 
msg) ; Bound to `C-x n a'.
-  "Add an izone for the text from START to END to the izones of VARIABLE.
+(defun zz-add-zone-and-unite (start end &optional variable msg) ; Bound to 
`C-x n A'.
+  "Add an izone from START to END to those of VARIABLE, and coalesce.
+Use `zz-add-zone', then apply `zz-unite-zones'.
+United zones are in ascending order of their cars.
 Return the new value of VARIABLE.
 
 This is a destructive operation: The list structure of the variable
@@ -1445,866 +1428,875 @@ VARIABLE defaults to the value of `zz-izones-var'.
 START and END are as for `narrow-to-region'.
 
 With a prefix arg you are prompted for a different variable to use, in
-place of the current value of `zz-izones-var'.  The particular prefix
-arg determines whether the variable, if unbound, is made buffer-local,
-and whether `zz-izones-var' is set to the variable symbol:
-
-  prefix arg          buffer-local   set `zz-izones-var'
-  ----------          ------------   -------------------
-  Plain `C-u'         yes            yes
-  > 0 (e.g. `C-1')    yes            no
-  = 0 (e.g. `C-0')    no             yes
-  < 0 (e.g. `C--')    no             no
+place of the current value of `zz-izones-var'.  If the prefix arg is
+non-negative (>= 0) then make the variable buffer-local.  If the
+prefix arg is non-positive (<= 0) then set `zz-izones-var' to that
+variable symbol.  (Zero: do both.)
 
 Non-interactively:
 * VARIABLE is the optional izones variable to use.
-* Non-nil NOT-BUF-LOCAL-P means do not make VARIABLE buffer-local.
-* Non-nil SET-VAR-P means set `zz-izones-var' to VARIABLE.
-* Non-nil MSG means echo the zone limits, preceded by string MSG."
-  (interactive (let* ((beg    (region-beginning))
-                      (end    (region-end))
-                      (var    (or (and current-prefix-arg  
(zz-read-any-variable "Variable: " zz-izones-var))
-                                  zz-izones-var))
-                      (npref  (prefix-numeric-value current-prefix-arg))
-                      (nloc   (and current-prefix-arg  (<= npref 0)  (not 
(boundp var))))
-                      (setv   (and current-prefix-arg  (or (consp 
current-prefix-arg)  (= npref 0)))))
-                 (list beg end var nloc setv "Recorded zone: ")))
-  (let* ((mrk1     (make-marker))
-         (mrk2     (make-marker))
-         (var      (or variable  zz-izones-var))
-         (_IGNORE  (unless (or not-buf-local-p  (boundp var)) 
(make-local-variable var)))
-         (_IGNORE  (when set-var-p (setq zz-izones-var  var)))
-         (_IGNORE  (unless (boundp var) (set var ())))
-         (val      (symbol-value var))
-         sans-id  id-cons  id)
-    (unless (zz-izones-p val) (error "Not an izones variable: `%s', value: 
`%S'" var val))
-    (move-marker mrk1 start)
-    (move-marker mrk2 end)
-    (setq sans-id  (list mrk1 mrk2)
-          id-cons  (rassoc sans-id val)
-          id       (if id-cons (car id-cons) (- (1+ (length val)))) ; 1-based, 
not 0-based.
-          val      (set var (zz-rassoc-delete-all sans-id val))) ; Destructive 
operation.
-    (unless (and (= mrk1 1)  (= mrk2 (1+ (buffer-size)))) (set var `((,id 
,mrk1 ,mrk2) ,@val)))
-    (when msg (message "%s%d to %d" msg (marker-position mrk1) 
(marker-position mrk2)))
-    (symbol-value var)))
+* Non-nil MSG means echo messages for adding the zone and uniting
+  zones.  In this case MSG is the message prefix for `zz-add-zone'."
+  (interactive (let ((beg    (region-beginning))
+                     (end    (region-end))
+                     (var    (or (and current-prefix-arg  
(zz-read-any-variable "Variable: " zz-izones-var))
+                                 zz-izones-var))
+                     (npref  (prefix-numeric-value current-prefix-arg)))
+                 (when (and current-prefix-arg  (>= npref 0)) 
(make-local-variable var))
+                 (when (and current-prefix-arg  (<= npref 0)) (setq 
zz-izones-var var))
+                 (list beg end var "Zone recorded: ")))
+  (unless variable (setq variable  zz-izones-var))
+  (zz-add-zone start end variable nil nil msg)
+  (zz-unite-zones variable msg)
+  (symbol-value variable))
 
 ;;;###autoload
-(defun zz-delete-zone (id &optional variable msgp) ; Bound to `C-x n C-d'.
-  "Delete a zone by completing against its ID and its text (content).
-Delete the zone from VARIABLE, and renumber those remaining.
+(defun zz-add-zones-matching-regexp (regexp ; Bound to `C-x n r'
+                                     &optional variable beg end 
not-buf-local-p set-var-p msgp)
+  "Add matches for REGEXP as zones to the izones of VARIABLE.
+If region is active, limit action to region.  Else, use whole buffer.
 Return the new value of VARIABLE.
 
-This is a destructive operation: The list structure of the variable
-value can be modified.
-
-VARIABLE defaults to the value of `zz-izones-var'.  With a prefix arg
-you are prompted for a different variable to use.
+If `isearchp-dim-outside-search-area-flag' is non-nil then dim the
+non-contexts.  (You can use `\\[isearchp-remove-dimming]' or \
+`\\[isearchp-toggle-dimming-outside-search-area]' to remove the
+dimming.)
 
-Non-nil optional arg NOMSG means do not display a status message."
+See `zz-add-zone' for a description of VARIABLE, the use of a prefix
+arg, and the parameters when called from Lisp."
   (interactive
-   (let* ((var      (or (and current-prefix-arg (zz-read-any-variable 
"Variable: " zz-izones-var t))
-                        zz-izones-var))
-          (izones   (symbol-value var))
-          (_IGNORE  (unless (zz-izones-p izones)
-                      (error "Not an izones variable: `%s', value: `%S'" var 
izones)))
-          (_IGNORE  (unless izones (error "No zones - variable `%s' is empty" 
var)))
-          (len      (length izones))
-          (num      (if (= len 1)
-                        1
-                      (string-to-number (completing-read (format "Delete zone 
with ID (1 to %d): " len)
-                                                         (mapcar 
zz-zone-abstract-function izones) nil t)))))
-     (list num var t)))
-  (unless variable (setq variable  zz-izones-var))
-  (let ((izones  (symbol-value variable)))
-    (unless (zz-izones-p izones) (error "Not an izones variable: `%s', value: 
`%S'" variable izones))
-    (unless izones (error "No zones - variable `%s' is empty" variable))
-    (set variable (assq-delete-all (- id) izones)))
-  (zz-izones-renumber variable)
-  (when msgp (message "Deleted zone with ID %d" id))
-  (symbol-value variable))
-
-(defun zz-markerize (izone)
-  "Convert IZONE to use markers.
-IZONE is a list of an identifier (a number) and two buffer
-positions (numbers, markers, or readable-marker objects).  Positions
-that are numbers or readable-marker objects are converted to markers.
-
-This is a non-destructive operation: it returns a new list."
-  (let ((ii   1)
-        posn)
-    (while (<  ii 3)
-      (setq posn  (nth ii izone))
-      (when (and (not (markerp posn))  (or (natnump posn)  
(zz-readable-marker-p posn)))
-        (setcar (nthcdr ii  izone) (zz-marker-from-object posn)))
-      (setq ii  (1+ ii))))
-  izone)
-
-(defun zz-marker-from-object (object)
-  "Return an equivalent marker for OBJECT.
-This is a non-destructive operation: OBJECT is not modified.
-
-If OBJECT is a marker then return it.
-If it is a number then return (copy-marker OBJECT).
-If it is a readable-marker sexp then return an equivalent real marker.
-Otherwise, return nil.
-
-A readable marker is a sexp of form (marker BUFFER POSITION), where
-BUFFER is a buffer name (string) and POSITION is a buffer position
-\(number)."
-  (cond ((markerp object) object)
-        ((numberp object) (copy-marker object))
-        ((zz-readable-marker-p object)
-         (with-current-buffer (get-buffer-create (nth 1 object)) (copy-marker 
(nth 2 object))))
-        (t nil)))
-
-(defun zz-number-or-marker-p (position)
-  "Return non-nil if POSITION is a number, marker, or readable-marker object."
-  ;; Just like `number-or-marker-p', We don't check that a number arg is a 
positive integer.
-  (or (number-or-marker-p position)  (zz-readable-marker-p position)))
-
-(defun zz-readable-marker-p (object)
-  "Return non-nil if OBJECT is a readable marker.
-That is, it has form (marker BUFFER POSITION), where BUFFER is a
-buffer name (string), and POSITION is a buffer position (integer).
-OBJECT is returned."
-  (and (consp object)  (consp (cdr object))  (consp (cddr object))
-       (eq 'marker (nth 0 object))  (stringp (nth 1 object))  (integerp (nth 2 
object))
-       object))
-
-(defun zz-readable-marker (number-or-marker &optional num-buffer)
-  "Return a readable marker equivalent to NUMBER-OR-MARKER, or nil.
-Return nil if NUMBER-OR-MARKER is not `number-or-marker-p'.
-\(If NUMBER-OR-MARKER is already a readable marker then return it.)
-
-A readable marker satisfies `zz-readable-marker-p'.  It has the form
-\(marker BUFFER POSITION), where BUFFER is a buffer name (string) and
-POSITION is a buffer position (number).
-
-If NUMBER-OR-MARKER is itself a readable marker then return it.
-
-If NUMBER-OR-MARKER is a marker then use its buffer name as BUFFER.
+   (let* ((regx   (read-regexp "Add zones matching regexp: "))
+          (var    (or (and current-prefix-arg  (zz-read-any-variable 
"Variable: " zz-izones-var t))
+                      zz-izones-var))
+          (beg    (if (and transient-mark-mode  mark-active) 
(region-beginning) (point-min)))
+          (end    (if (and transient-mark-mode  mark-active) (region-end) 
(point-max)))
+          (npref  (prefix-numeric-value current-prefix-arg))
+          (nloc   (and current-prefix-arg  (<= npref 0)  (not (boundp var))))
+          (setv   (and current-prefix-arg  (or (consp current-prefix-arg)  (= 
npref 0)))))
+     (list regx var beg end nloc setv t)))
+  (unless (and beg  end) (setq beg  (point-min)
+                               end  (point-max)))
+  (unless (< beg end) (setq beg  (prog1 end (setq end  beg))))
+  (let ((last-beg  nil)
+        (num-hits  0))
+    (condition-case-unless-debug zz-add-zones-matching-regexp
+        (save-excursion
+          (goto-char (setq last-beg  beg))
+          (while (and beg  (< beg end)  (not (eobp))
+                      (progn (while (and (setq beg  (re-search-forward regexp 
end t))
+                                         (eq last-beg beg)
+                                         (not (eobp)))
+                               ;; Matched again, same place.  Advance 1 char.
+                               (forward-char) (setq beg  (1+ beg)))
+                             beg))      ; Stop if no more matches.
+            (setq num-hits  (1+ num-hits))
+            (let* ((hit-beg     (match-beginning 0))
+                   (hit-end     (match-end 0))
+                   (hit-string  (buffer-substring-no-properties hit-beg 
hit-end))
+                   (c-beg       last-beg)
+                   (c-end       (if beg (match-beginning 0) (min end 
(point-max)))) ; Truncate.
+                   )
+              (isearchp-add/remove-dim-overlay c-beg c-end 'ADD)
+              (cond ((not (string= "" hit-string))
+                     (zz-add-zone c-beg c-end variable not-buf-local-p 
set-var-p)
+                     (isearchp-add/remove-dim-overlay hit-beg hit-end nil))
+                    (t
+                     (isearchp-add/remove-dim-overlay hit-beg hit-end 'ADD))))
+            (goto-char (setq last-beg  beg))))
+      (error (error "%s" (error-message-string zz-add-zones-matching-regexp))))
+    (unless (> num-hits 0) (zz-user-error "No regexp matches"))
+    (when msgp
+      (let ((dim-msg  (if (not (bound-and-true-p 
isearchp-dim-outside-search-area-flag))
+                          ""
+                        (substitute-command-keys
+                         "; `\\[isearchp-remove-dimming]' or \
+`\\[isearchp-toggle-dimming-outside-search-area]' removes dimming"))))
+        (case num-hits
+          (1 (message "1 zone added%s" dim-msg))
+          (t (message "%d zones added or updated%s" num-hits dim-msg)))))
+    variable))
 
-If NUMBER-OR-MARKER is a number then:
- If   NUM-BUFFER names an existing buffer then use it as BUFFER.
- Else use the name of the current buffer as BUFFER.
+;;;###autoload
+(defun zz-set-zones-matching-regexp (regexp ; Bound to `C-x n R'
+                                     &optional variable beg end 
not-buf-local-p set-var-p msgp)
+  "Replace value of izones variable with zones matching REGEXP.
+Like `zz-add-zones-matching-regexp' (which see), but it replaces any
+current zones instead of adding to them."
+  (interactive
+   (let* ((var    (or (and current-prefix-arg  (zz-read-any-variable 
"Variable: " zz-izones-var t))
+                      zz-izones-var))
+          (regx   (read-regexp (format "Set `%s' to zones matching regexp: " 
var)))
+          (beg    (if (and transient-mark-mode  mark-active) 
(region-beginning) (point-min)))
+          (end    (if (and transient-mark-mode  mark-active) (region-end) 
(point-max)))
+          (npref  (prefix-numeric-value current-prefix-arg))
+          (nloc   (and current-prefix-arg  (<= npref 0)  (not (boundp var))))
+          (setv   (and current-prefix-arg  (or (consp current-prefix-arg)  (= 
npref 0)))))
+     (list regx var beg end nloc setv t)))
+  (set variable ())
+  (zz-add-zones-matching-regexp regexp variable beg end not-buf-local-p 
set-var-p msgp))
 
-This is a non-destructive operation."
-  ;; Just like `number-or-marker-p', We don't check that a number arg is a 
positive integer.
-  (cond ((zz-readable-marker-p number-or-marker) number-or-marker)
-        ((markerp number-or-marker)
-         `(marker ,(buffer-name (marker-buffer number-or-marker)) 
,(marker-position number-or-marker)))
-        ((numberp number-or-marker)
-         `(marker
-           ,(buffer-name (or (and (stringp num-buffer)  (get-buffer 
num-buffer))  (current-buffer)))
-           ,number-or-marker))
-        (t nil)))
+;;;###autoload
+(defun zz-add-zones-from-highlighting ( ; Bound to `C-x n l'
+                                       &optional start end face only-hlt-face 
overlay/text fonk-lock-p msgp)
+  "Add highlighted areas as zones to izones variable.
+By default, the text used is that highlighted with `hlt-last-face'.
+With a non-negative prefix arg you are instead prompted for the face.
 
-(defun zz-izones-p (value)
-  "Return non-nil if VALUE is a (possibly empty) list of izones.
-That is, non-nil means that VALUE has the form of `zz-izones'."
-  (and (listp value)  (listp (cdr (last value))) ; Proper list.
-       (let ((res  t))
-         (catch 'zz-izones-p
-           (dolist (xx  value)
-             (unless (setq res  (zz-izone-p xx)) (throw 'zz-izones-p nil))))
-         res)))
+With a non-positive prefix arg use face property `font-lock-face'
+instead of property `face'.
 
-(defun zz-izone-p (value)
-  "Return non-nil if VALUE is an izone.
-That is, non-nil means it has the form (ID POS1 POS2 . EXTRA),
-where ID is a negative integer, and each POS<N> is a buffer-position
-representation (`zz-number-or-marker-p')."
-  (and (consp value)  (condition-case nil
-                          (and (integerp (nth 0 value))
-                               (< (nth 0 value) 0)
-                               (zz-number-or-marker-p (nth 1 value))
-                               (zz-number-or-marker-p (nth 2 value)))
-                        (error nil))))
+The izones variable to use is the value of `zz-izones-var'.  You can
+set this to a different variable anytime using `\\[zz-set-izones-var]'.
 
-(defun zz-rassoc-delete-all (value alist)
-  "Delete from ALIST all elements whose cdr is `equal' to VALUE.
-Elements of ALIST that are not conses are ignored.
-Return the modified alist.
-This is a destructive operation."
-  (while (and (consp (car alist))  (equal (cdar alist) value)) (setq alist  
(cdr alist)))
-  (let ((tail  alist)
-        tail-cdr)
-    (while (setq tail-cdr  (cdr tail))
-      (if (and (consp (car tail-cdr))  (equal (cdar tail-cdr) value))
-         (setcdr tail (cdr tail-cdr))
-       (setq tail  tail-cdr))))
-  alist)
+All highlighting is checked, both overlays and face text properties.
 
+The number of highlighted areas added as zones is echoed in a message.
+This might be less than the number of zones added, because there can
+be multiple highlights with the same face for the same area.
 
-(defun zz-izones-renumber (&optional variable)
-  "Renumber the izones of this buffer in the current `zz-izones-var'.
-This is a destructive operation: The list structure of the variable
-value can be modified."
-  (let* ((var   (or variable  zz-izones-var))
-         (orig  (symbol-value var)))
-    (set var ())
-    (dolist (iz  orig) (zz-add-zone (cadr iz) (car (cddr iz)) var))))
+When called from Lisp:
 
-;; Non-destructive version.
-;;
-;; (defun zz-izone-limits-in-bufs (buffers &optional variable)
-;;   "Return a list of all `zz-izone-limits' for each buffer in BUFFERS.
-;; That is, return a list of all recorded buffer zones for BUFFERS.
-;; If BUFFERS is nil, return the zones recorded for the current buffer.
-;;
-;; This is a non-destructive operation: The list returned is independent
-;; of the `zz-izone-limits' list in each of the buffers.
-;;
-;; Optional arg VARIABLE is the izones variable to use.  If nil,
-;; use the value of `zz-izones-var'.  The variable is evaluated in each
-;; buffer (or in the current buffer, if BUFFERS is nil)."
-;;
-;;   (let ((limits  ()))
-;;     (dolist (buf  (or (reverse buffers)  (list (current-buffer)))) ; 
Reverse so we keep the order.
-;;       (with-current-buffer buf
-;;         (setq limits  (append (zz-izone-limits (symbol-value (or variable  
zz-izones-var))
-;;                                                buf
-;;                                                'ONLY-THIS-BUFFER)
-;;                               limits))))
-;;     limits))
+* Non-nil START and END are the buffer limits to search.
+* Non-nil FACE is the highlighting face to look for.
+* Non-nil ONLY-HLT-FACE means check only `highlight.el' highlighting.
+  (By default, any highlighting is checked.)
+* If OVERLAY/TEXT is `text-prop' then only text-property highlighting
+  is checked. If it is `overlay' then only overlay highlighting is
+  checked.  (If nil then both are checked.)
+* Non-nil FONK-LOCK-P means check property `font-lock-face'.  By
+  default (nil), check property `face'."
+  (interactive
+   (let ((numarg  (and current-prefix-arg  (prefix-numeric-value 
current-prefix-arg))))
+     (unless (require 'highlight nil t) (zz-user-error "You need library 
`highlight.el' to use this command"))
+     `(,@(hlt-region-or-buffer-limits)
+         ,(if (natnump numarg)
+              (hlt-read-bg/face-name "Create zones highlighted with face: ")
+            hlt-last-face)
+         nil nil ,(and numarg  (<= numarg 0)) t)))
+  (require 'highlight)
+  (unless (and start  end) (let ((start-end  (hlt-region-or-buffer-limits)))
+                             (setq start  (car start-end)
+                                   end    (cadr start-end))))
+  (unless face (setq face  hlt-last-face))
+  (let ((hlt-use-overlays-flag     (case overlay/text
+                                     (text-prop  nil) ; Only text property
+                                     (overlay    'only) ; Only overlay
+                                     (t          t))) ; Default: both
+        (hlt-act-on-any-face-flag  (not only-hlt-face))
+        (hlt-face-prop             (if fonk-lock-p 'font-lock-face 'face))
+        (count                     0))
+    (save-excursion
+      (save-window-excursion
+        (goto-char start)
+        (let ((zone-beg  start)
+              zone-end zone)
+          (while (and zone-beg  (< zone-beg end))
+            (setq zone      (hlt-next-highlight zone-beg end face nil nil 
'no-error-msg)
+                  zone-beg  (car zone)
+                  zone-end  (cdr zone))
+            ;; Create zone from `zone-beg' to `zone-end' if highlighted.  Add 
it to zones list.
+            (when hlt-use-overlays-flag
+              (let ((overlays  (overlays-at zone-beg)))
+                (while overlays
+                  (when (and (or hlt-act-on-any-face-flag
+                                 (equal face (overlay-get (car overlays) 
'hlt-highlight)))
+                             (equal face (overlay-get (car overlays) 
hlt-face-prop)))
+                    (zz-add-zone zone-beg zone-end)
+                    (setq count  (1+ count)))
+                  (when overlays (setq overlays  (cdr overlays))))))
+            (when (and (not (eq hlt-use-overlays-flag 'only))
+                       (or hlt-act-on-any-face-flag  (equal face 
(get-text-property (point) 'hlt-highlight)))
+                       (let ((pt-faces  (get-text-property (point) 
hlt-face-prop)))
+                         (if (consp pt-faces) (memq face pt-faces) (equal face 
pt-faces))))
+              (zz-add-zone zone-beg zone-end)
+              (setq count  (1+ count)))))))
+    (when msgp
+      (case count
+        (0 (message "NO zones added or updated"))
+        (1 (message "1 zone added or updated"))
+        (t (message "%s highlighted areas added or updated as zones" 
count))))))
 
-(defun zz-izone-limits-in-bufs (buffers &optional variable)
-  "Return a list of all `zz-izone-limits' for each buffer in BUFFERS.
-That is, return a list of all recorded buffer zones for BUFFERS.
-If BUFFERS is nil, return the zones recorded for the current buffer.
+;;;###autoload
+(defun zz-set-zones-from-highlighting ( ; Bound to `C-x n L'
+                                       &optional start end face only-hlt-face 
overlay/text fonk-lock-p msgp)
+  "Replace value of izones variable with zones from the highlighted areas.
+Like `zz-add-zones-from-highlighting' (which see), but it replaces any
+current zones instead of adding to them."
+  (interactive
+   (let ((numarg  (and current-prefix-arg  (prefix-numeric-value 
current-prefix-arg))))
+     (unless (require 'highlight nil t) (zz-user-error "You need library 
`highlight.el' to use this command"))
+     `(,@(hlt-region-or-buffer-limits)
+         ,(if (natnump numarg)
+              (hlt-read-bg/face-name "Create zones highlighted with face: ")
+            hlt-last-face)
+         nil nil ,(and numarg  (<= numarg 0)) t)))
+  (set zz-izones-var ())
+  (zz-add-zones-from-highlighting start end face only-hlt-face overlay/text 
fonk-lock-p msgp))
 
-This is a destructive operation: The list returned can have as
-sublists the `zz-izone-limits' lists of BUFFERS.
+;;;###autoload
+(defun zz-set-zones-from-face (face &optional start end variable) ; Bound to 
`C-x n f'
+  "Set an izones variable to (united) zones of a face or background color.
+You are prompted for a face name or a color name.  If you enter a
+color, it is used for the face background.  The face foreground is
+determined by the value of `hlt-auto-face-foreground'.
+The variable defaults to `zz-izones'.  With a prefix arg you are
+  prompted for a different izones variable."
+  (interactive
+   (progn
+     (unless (require 'highlight nil t)
+       (error "You need library `highlight.el' for this command"))
+     (let ((fac  (hlt-read-bg/face-name "Choose background color or face: "
+                                        (and (symbolp hlt-last-face)  
(symbol-name hlt-last-face))))
+           (var  (or (and current-prefix-arg  (zz-read-any-variable "Variable: 
" zz-izones-var))
+                     zz-izones-var)))
+       (if (hlt-nonempty-region-p)
+           (if (< (point) (mark)) (list (point) (mark) var t) (list (mark) 
(point) var t))
+         (list fac (point-min) (point-max) var t)))))
+  (unless (require 'highlight nil t)
+    (error "You need library `highlight.el' for this command"))
+  (unless (require 'isearch-prop nil t)
+    (error "You need library `isearch-prop.el' for this command"))
+  (unless (require 'zones nil t)
+    (error "You need library `zones' for this command"))
+  (font-lock-default-fontify-buffer)    ; Fontify the whole buffer.
+  (zz-set-zones-from-highlighting start end face nil 'text-prop)
+  (zz-unite-zones variable t))
+
+;;(@* "General Non-Interactive Functions")
 
-Optional arg VARIABLE is the izones variable to use.  If nil, use the
-value of `zz-izones-var'.  The variable is evaluated in each
-buffer (or in the current buffer, if BUFFERS is nil)."
-  (let ((limits  ()))
-    (dolist (buf  (or buffers  (list (current-buffer))))
-      (with-current-buffer buf
-        (setq limits  (nconc limits
-                             (zz-izone-limits (symbol-value (or variable  
zz-izones-var)) buf 'THISBUF)))))
-    limits))
+;;; General Non-Interactive Functions --------------------------------
 
-(defun zz-izone-limits (&optional izones buffer only-one-buffer-p)
-  "Return a list like IZONES, but with no identifiers.
-That is, return a list of zones, (LIMIT1 LIMIT2 . EXTRA).
+(defun zz-zone-abstract-function-default (izone)
+  "Default value of `zz-zone-abstract-function'.
+The abstract it produces for IZONE is (the absolute value of) the zone
+ID, followed by the first `zz-zone-abstract-limit' chars of the zone
+text.  The return value of the function is a cons, (ABSTRACT . IZONE),
+whose car is the abstract and whose cdr is the izone."
+  (let ((id   (abs (car izone)))
+        (beg  (cadr izone))
+        (end  (caddr izone)))
+    (cons (format "%d %s" id (buffer-substring beg (min (+ beg 
zz-zone-abstract-limit) end))) izone)))
 
-This is a non-destructive operation: A new list is returned.
+(defun zz-zone-ordered (zone)
+  "Return ZONE or ZONE with its car and cadr reversed, so car <= cadr.
+The cddr of ZONE remains as it was."
+  (let ((beg    (car  zone))
+        (end    (cadr zone))
+        (extra  (cddr zone)))
+    (when (zz-readable-marker-p beg) (setq beg  (nth 2 beg)))
+    (when (zz-readable-marker-p end) (setq end  (nth 2 end)))
+    (if (<= beg end) zone `(,end ,beg ,@extra))))
 
-Each limit can be a number or a marker (but see ONLY-ONE-BUFFER-P).
-The conses are new - they do not share with any conses with IZONES.
+(defun zz-zones-overlap-p (zone1 zone2)
+  "Return non-nil if ZONE1 and ZONE2 overlap.
+Assumes that each zone is ordered (its car <= its cadr).
+The cddrs are ignored.
 
-Optional input list IZONES has the same structure as `zz-izones'.  If
-IZONES is nil then the variable that is the value of `zz-izones-var'
-is used.  It is evaluated in BUFFER (default: current buffer) to
-obtain the izones.
+Zones that use markers do not overlap if the marker buffers differ."
+  (and (zz-zones-same-buffer-name-p zone1 zone2)
+       (progn (when (< (car zone2) (car zone1)) (setq zone1 (prog1 zone2 (setq 
zone2 zone1))))
+              (<= (car zone2) (cadr zone1)))))
 
-Non-nil optional arg ONLY-ONE-BUFFER-P means remove any izones that
-contain markers for a buffer other than BUFFER."
-  (unless buffer (setq buffer  (current-buffer)))
-  (let ((restrs  (or izones  (with-current-buffer buffer (symbol-value 
zz-izones-var)))))
-    (when only-one-buffer-p (setq restrs  
(zz-remove-izones-w-other-buffer-markers restrs)))
-    (delq nil (mapcar #'cdr restrs))))
+(defun zz-zones-same-buffer-name-p (zone1 zone2)
+  "Return non-nil if ZONE1 and ZONE2 apply to the same buffer.
+This is the case if `zz-zone-buffer-name' returns the same name for
+each.  (A buffer with that name need not exist.)"
+  (eq (zz-zone-buffer-name zone1) (zz-zone-buffer-name zone2)))
 
-;; Useful for commands that want to act on zones in multiple buffers.
-(defun zz-read-bufs ()
-  "Read names of buffers, one at a time.  `C-g' ends reading."
-  (let ((bufs  ())
-        buf)
-    (while (condition-case nil
-               (setq buf  (read-buffer "Buffer (C-g to end): "
-                                       (and (not (member (buffer-name 
(current-buffer)) bufs))
-                                            (current-buffer))
-                                       t))
-             (quit nil))
-      (push buf bufs))
-    (delq nil (mapcar #'get-buffer (nreverse bufs)))))
+(defun zz-zone-buffer-name (zone)
+  "Return the name of the buffer used by ZONE.
+If the two ZONE positions specify different buffers, or if either is a
+marker that points nowhere, then raise an error."
+  (let* ((lim1  (car zone))
+         (lim2  (cadr zone))
+         (buf1  (cond ((markerp lim1)               (and (marker-buffer lim1)
+                                                         (buffer-name 
(marker-buffer lim1))))
+                      ((zz-readable-marker-p lim1)  (cadr lim1))
+                      (t                            (buffer-name 
(current-buffer)))))
+         (buf2  (cond ((markerp lim2)               (and (marker-buffer lim2)
+                                                         (buffer-name 
(marker-buffer lim2))))
+                      ((zz-readable-marker-p lim2)  (cadr lim2))
+                      (t                            (buffer-name 
(current-buffer))))))
+    (unless (and buf1  buf2) (error "Zone has marker(s) that point nowhere: 
%S" zone))
+    (unless (equal buf1 buf2) (error "Zone has conflicting buffers: %S" zone))
+    buf1))
 
-(defun zz-remove-zones-w-other-buffer-markers (zones &optional buffer)
-  "Return ZONES, but remove any that use markers for another buffer.
-BUFFER is the buffer to compare with (default: current buffer).
-This is a non-destructive operation: a (shallow) copy is returned."
-  (unless buffer (setq buffer  (current-buffer)))
-  (zz-remove-if `(lambda (zone) (zz-zone-has-other-buffer-marker-p zone 
',buffer)) zones))
+(defun zz-choose-zone-by-id-and-text (&optional izones)
+  "Prompt for a zone from IZONES, completing against its ID and its text.
+Return the chosen zone.  If you hit `RET' with empty input then this
+is the first zone of IZONES.
+
+IZONES defaults to the value of the variable that is the value of
+`zz-izones-var'."
+  (setq izones  (or izones  (symbol-value zz-izones-var)))
+  (unless izones (zz-user-error "No zones defined"))
+  (let* ((abs-zones  (mapcar zz-zone-abstract-function izones))
+         (num        (string-to-number
+                      (completing-read "Zone: "
+                                       abs-zones nil t nil 'zz-zone-history 
(car abs-zones)))))
+    (assq (- num) izones)))
+
+(defun zz-do-zones (function &optional zones unite-p)
+  "Like `zz-map-zones', but without returning the result of mapping.
+The return value is undefined."
+  (when (functionp function)
+    (when (zz-izones-p zones) (setq zones  (zz-izone-limits zones nil 
'ONLY-THIS-BUFFER)))
+    (when unite-p (setq zones  (zz-zone-union zones)))
+    (dolist (zone  zones) (funcall function (car zone) (cadr zone)))))
 
-(defun zz-remove-izones-w-other-buffer-markers (izones &optional buffer)
-  "Return IZONES, but remove any that use markers for another buffer.
-BUFFER is the buffer to compare with (default: current buffer).
-This is a non-destructive operation: a (shallow) copy is returned."
-  (unless buffer (setq buffer  (current-buffer)))
-  (zz-remove-if `(lambda (izone) (zz-izone-has-other-buffer-marker-p izone 
',buffer)) izones))
+(defun zz-map-zones (function &optional zones unite-p)
+  "Map binary FUNCTION over ZONES, applying it to the limits of each zone.
+ZONES can be a list of basic zones or a list like `zz-izones', that
+is, zones that have identifiers.
+Non-nil optional arg UNITE-P means first unite the zones and then
+iterate over the resulting list."
+  (if (not (functionp function))
+      (or zones  zz-izones)
+    (when (zz-izones-p zones) (setq zones  (zz-izone-limits zones nil 
'ONLY-THIS-BUFFER)))
+    (when unite-p (setq zones  (zz-zone-union zones)))
+    (mapcar (lambda (zone) (funcall function (car zone) (cadr zone))) zones)))
 
-(defun zz-zone-has-other-buffer-marker-p (zone &optional buffer)
-  "Return non-nil if basic ZONE has a marker for another buffer.
-The first marker in the zone is returned.
-BUFFER is the buffer to compare with (default: current buffer)."
-  (unless buffer (setq buffer  (current-buffer)))
-  (let ((m1  (nth 0 zone))
-        (m2  (nth 1 zone)))
-    (or (and (markerp m1)  (not (eq buffer (marker-buffer m1)))  m1)
-        (and (markerp m2)  (not (eq buffer (marker-buffer m2)))  m2))))
+(defun zz-do-izones (function &optional izones unite-p)
+  "Like `zz-map-izones', but without returning the result of mapping.
+The return value is undefined."
+  (when (functionp function)
+    (when unite-p (setq izones  (zz-unite-zones izones)))
+    (dolist (izone  izones) (funcall function (car izone) (cadr izone) (caddr 
izone)))))
 
-(defun zz-izone-has-other-buffer-marker-p (izone &optional buffer)
-  "Return non-nil if IZONE has a marker for another buffer.
-The first marker in the izone is returned.
-BUFFER is the buffer to compare with (default: current buffer)."
-  (unless buffer (setq buffer  (current-buffer)))
-  (let ((m1  (nth 1 izone))
-        (m2  (nth 2 izone)))
-    (or (and (markerp m1)  (not (eq buffer (marker-buffer m1)))  m1)
-        (and (markerp m2)  (not (eq buffer (marker-buffer m2)))  m2))))
+(defun zz-map-izones (function &optional izones unite-p)
+  "Map FUNCTION over IZONES.
+Apply FUNCTION to the first three elements of each izone, that is, the
+ identifier and the zone limits.
+IZONES is a list like `zz-izones', that is, zones with identifiers.
+By default, IZONES is the value of `zz-izones'.
+Non-nil optional arg UNITE-P means first unite the zones and then
+iterate over the resulting list."
+  (if (not (functionp function))
+      (or izones  zz-izones)
+    (when unite-p (setq izones  (zz-unite-zones izones)))
+    (mapcar (lambda (izone) (funcall function (car izone) (cadr izone) (caddr 
izone))) izones)))
 
-(defun zz-remove-if (pred xs)
-  "A copy of list XS with no elements that satisfy predicate PRED."
-  (let ((result  ()))
-    (dolist (x  xs) (unless (funcall pred x) (push x result)))
-    (nreverse result)))
+(defun zz-order-zones (&optional zones _descendingp)
+  "Order each zone in ZONES, so that first limit is less than the second.
+ZONES can be a list of basic zones or a list like `zz-izones', that
+is, zones that have identifiers.
+Non-nil optional arg DESCENDINGP means put greater limit first."
+  (zz-map-zones (lambda (lim1 lim2) (if (> lim1 lim2) (list lim2 lim1) (list 
lim1 lim2))) zones))
 
-;; Useful for commands that want to act on zones in multiple buffers (e.g., 
visible buffers only).
-;;
-;; Same as `icicle-remove-if-not' etc.
-(defun zz-remove-if-not (pred xs)
-  "A copy of list XS with only elements that satisfy predicate PRED."
-  (let ((result  ()))
-    (dolist (x  xs) (when (funcall pred x) (push x result)))
-    (nreverse result)))
+(defun zz-zones-complement (zones &optional beg end)
+  "Return a list of zones that is the complement of ZONES, from BEG to END.
+ZONES is assumed to be a union, i.e., sorted by car, with no overlaps.
+Any extra info in a zone of ZONES, i.e., after the cadr, is ignored."
+  (setq beg  (zz-marker-from-object (or beg  (point-min)))
+        end  (zz-marker-from-object (or end  (point-max))))
+  (let ((res  ()))
+    (dolist (zone  zones)
+      (push (list beg (car zone)) res)
+      (setq beg  (cadr zone)))
+    (setq res  (nreverse (push (list beg end) res)))))
 
-;; Like `read-any-variable' in `strings.el', but passes REQUIRE-MATCH arg to 
`completing-read'.
-(defun zz-read-any-variable (prompt &optional default-value require-match)
-  "Read the name of a variable and return it as a symbol.
-Prompts with string PROMPT.  By default, returns DEFAULT-VALUE if
-non-nil.  If DEFAULT-VALUE is nil and the nearest symbol to the cursor
-is a variable, then return that by default.
+(defun zz-two-zone-union (zone1 zone2)
+  "Return the union of ZONE1 and ZONE2, or nil if they do not overlap.
+Assumes that each zone is ordered (its car <= its cadr).
 
-Unlike `read-variable', which reads only user options, this reads the
-name of any variable.  If optional arg REQUIRE-MATCH is nil then it
-reads any symbol, but it provides completion against variable names."
-  (let ((symb                          (cond ((fboundp 'symbol-nearest-point) 
(symbol-nearest-point))
-                                             ((fboundp 'symbol-at-point) 
(symbol-at-point))
-                                             (t nil)))
-        (enable-recursive-minibuffers  t))
-    (when (and default-value  (symbolp default-value))
-      (setq default-value  (symbol-name default-value)))
-    (intern (completing-read prompt obarray 'boundp require-match nil 
'minibuffer-history
-                             (let ((var-at-pt  (and symb  (boundp symb)  
(symbol-name symb))))
-                               (if (and default-value  var-at-pt  (> 
emacs-major-version 22))
-                                   (list default-value var-at-pt)
-                                 (or default-value  var-at-pt)))
-                             t))))
+The cddr of a non-nil result (its EXTRA information, which must be a
+list) is the union of the EXTRA information of each zone:
 
-(defalias 'zz-buffer-narrowed-p
-    (if (fboundp 'buffer-narrowed-p)
-        #'buffer-narrowed-p             ; Emacs 24+
-      (lambda () (/= (- (point-max) (point-min)) (buffer-size)))))
+ (zz-set-union (cddr zone1) (cddr zone2))
 
-(defalias 'zz-string-match-p
-  (if (fboundp 'string-match-p)
-      #'string-match-p                  ; Emacs 23+
-   (lambda (regexp string &optional start)
-     "Like `string-match', but this saves and restores the match data."
-      (save-match-data (string-match regexp string start)))))
+This is a non-destructive operation: The result is a new list."
+  (and (zz-zones-overlap-p zone1 zone2)  `(,(zz-min (car zone1)  (car zone2))
+                                            ,(zz-max (cadr zone1) (cadr zone2))
+                                            ,@(zz-set-union (cddr zone1) (cddr 
zone2)))))
 
-(defun zz-repeat-command (command)
-  "Repeat COMMAND."
-  (require 'repeat)                   ;Define its vars before we let-bind them!
-  (let ((repeat-previous-repeated-command  command)
-        (repeat-message-function           #'ignore)
-        (last-repeatable-command           'repeat))
-    (repeat nil)))
+(defun zz-zone-union (zones &optional buffer)
+  "Return the union (coalescence) of the zones in list ZONES.
+Each element of ZONES is a list of two zone limits, possibly followed
+by extra info: (LIMIT1 LIMIT2 . EXTRA), where EXTRA is a list.
+The limits need not be in numerical order.
 
-;;;###autoload
-(defun zz-narrow-repeat ()              ; Bound to `C-x n x'.
-  "Cycle to the next buffer restriction (narrowing).
-This is a repeatable version of `zz-narrow'.
+Each limit can be a number or a marker, but zones with markers for
+buffers other than BUFFER (default: current buffer) are ignored.
 
-Note that if the value of `zz-izones-var' is not buffer-local then you
-can use this command to cycle among zones in multiple buffers."
-  (interactive)
-  (zz-repeat-command 'zz-narrow))
+Any zones that use markers for a buffer other than BUFFER (default:
+current buffer) are excluded.
 
-;;;###autoload
-(defalias 'zz-select-region-repeat #'zz-select-zone-repeat)
-;;;###autoload
-(defun zz-select-zone-repeat ()         ; Bound to `C-x n C-x'.
-  "Cycle to the next zone, and make it the active region.
-Zones are cycled in chronological order of their recording.
-This is a repeatable version of `zz-select-zone'."
-  (interactive)
-  (zz-repeat-command 'zz-select-zone))
+Returns a new list, which is sorted by the lower limit of each zone,
+which is its car.  (This is a non-destructive operation.)
 
-(defun zz-izones-from-zones (basic-zones)
-  "Return a list of zones like `zz-izones', based on BASIC-ZONES.
-Each zone in the list BASIC-ZONES has form (LIMIT1 LIMIT2 . EXTRA),
-where each of the limits is a buffer position (a number or marker) and
-EXTRA is a list.
+Each zone in ZONES is first ordered, so that its car <= its cadr.
+The resulting zones are then sorted by their cars.
 
-This is a non-destructive operation.  A new list is returned.
+`zz-two-zone-union' is then applied recursively to coalesce
+overlapping or adjacent zones.  This means also that any EXTRA info is
+combined whenever zones are merged together."
+  (let* ((filtered-zones  (zz-remove-zones-w-other-buffer-markers zones 
buffer))
+         (flipped-zones   (mapcar #'zz-zone-ordered filtered-zones))
+         (sorted-zones    (sort flipped-zones #'zz-car-<)))
+    (zz-zone-union-1 sorted-zones)))
 
-\(zz-izone-limits (zz-izones-from-zones BASIC-ZONES)) = BASIC-ZONES
+(defun zz-zone-union-1 (zones)
+  "Helper for `zz-zone-union'."
+  (if (null (cdr zones))
+      zones
+    (let ((acc  ())
+          new)
+      (while zones
+        (setq new  (and (cdr zones)  (zz-two-zone-union (car zones) (cadr 
zones))))
+        (if new
+            (setq zones  (cons new (cddr zones)))
+          (setq acc    (cons (car zones) acc)
+                zones  (cdr zones))))
+      (setq acc  (nreverse acc)))))
 
-Also, (zz-izones-from-zones (zz-izone-limits)) returns the same set of
-izones as `zz-izones', but possibly with different IDs associated with
-the basic zones."
-  (let ((ii  0))
-    (nreverse (mapcar (lambda (zz) (cons (- (setq ii  (1+ ii))) zz)) (reverse 
basic-zones)))))
+(defun zz-car-< (zone1 zone2)
+  "Return non-nil if car of ZONE1 < car of ZONE2.
+Each car can be a number or a marker.
 
-;;;###autoload
-(defun zz-set-izones-var (variable &optional localp) ; Bound to `C-x n v'
-  "Set `zz-izones-var' to VARIABLE, for which you are prompted.
-With a prefix arg, make VARIABLE automatically be buffer-local."
-  (interactive (list (zz-read-any-variable "Variable: " zz-izones-var) 
current-prefix-arg))
-  (setq zz-izones-var  variable)
-  (when localp (make-variable-buffer-local variable)))
+* Two numbers or two markers in the same buffer: Use `<'.
+* Two markers in different buffers: Use `string<' of the buffer names.
+* Only one is a marker:
+  If its buffer is current then treat it as a number, using `<'.
+  Else return false if the marker is for ZONE1 and return true if it
+       is for ZONE2."
+  (let* ((p1  (car zone1))
+         (p2  (car zone2))
+         (m1  (markerp p1))
+         (m2  (markerp p2))
+         (b1  (and m1  (marker-buffer p1)))
+         (b2  (and m2  (marker-buffer p2))))
+    (cond ((and (not m1)  (not m2)) (< p1 p2))
+          ((and m1  m2)   (if (eq b1 b2) (< p1 p2) (string< (buffer-name b1) 
(buffer-name b2))))
+          (m1             (and (eq (current-buffer) b1)  (< p1 p2)))
+          (m2             (or (not (eq (current-buffer) b2))  (< p1 p2))))))
 
-;;;###autoload
-(defun zz-clone-zones (from-variable to-variable &optional msgp) ; Bound to 
`C-x n c'
-  "Clone FROM-VARIABLE to TO-VARIABLE.
-Return the new value of TO-VARIABLE.
-That is, copy the zones of FROM-VARIABLE to (emptied) TO-VARIABLE.
-A non-destructive operation: The value of TO-VARIABLE is a new list,
- with only the zones from FROM-VARIABLE.
-Return the value of TO-VARIABLE.
+(defun zz-two-zone-intersection (zone1 zone2)
+  "Return intersection of ZONE1 and ZONE2.
+\(The result is nil if they do not overlap.)
+Assumes that each zone is ordered (its car <= its cadr).
 
-You are prompted for FROM-VARIABLE and TO-VARIABLE.
+The cddr of a non-nil result (its list of EXTRA information) is the
+intersection of the EXTRA information of each zone:
 
-With a non-negative (>= 0) prefix arg, make TO-VARIABLE buffer-local.
-With a non-positive (<= 0) prefix arg, set `zz-izones-var' to the
-TO-VARIABLE symbol.  (Zero: do both.)
+ (zz-set-intersection (cddr zone1) (cddr zone2))
 
-FROM-VARIABLE defaults to the value of `zz-izones-var'.
+This is a non-destructive operation: The result is a new list."
+  (and (zz-zones-overlap-p zone1 zone2)  `(,(zz-max (car zone1)  (car zone2))
+                                            ,(zz-min (cadr zone1) (cadr zone2))
+                                            ,@(zz-set-intersection (cddr 
zone1) (cddr zone2)))))
 
-Non-interactively: Non-nil MSGP means show a status message."
-  (interactive
-   (let ((from-var  (zz-read-any-variable "Copy variable: " zz-izones-var t))
-         (to-var    (zz-read-any-variable "To variable: "))
-         (npref     (and current-prefix-arg  (prefix-numeric-value 
current-prefix-arg))))
-     (when (and npref  (>= npref 0)) (make-local-variable to-var))
-     (when (and npref  (<= npref 0)) (setq zz-izones-var to-var))
-     (list from-var to-var t)))
-  (prog1 (set to-variable (copy-sequence (symbol-value from-variable)))
-    (when msgp (message "Cloned `%s' to `%s'" from-variable to-variable))))
+(defun zz-zone-intersection (zones)
+  "Return the intersection of the zones in list ZONES.
+Each element of ZONES is a list of two zone limits, possibly followed
+by extra info: (LIMIT1 LIMIT2 . EXTRA), where EXTRA is a list.
 
-;;;###autoload
-(defalias 'zz-clone-and-coalesce-zones #'zz-clone-and-unite-zones)
-;;;###autoload
-(defun zz-clone-and-unite-zones (from-variable to-variable &optional msgp) ; 
Bound to `C-x n C'
-  "Clone FROM-VARIABLE to TO-VARIABLE, then unite (coalesce) TO-VARIABLE.
-That is, use`zz-clone-zones' to fill TO-VARIABLE, then use
-`zz-unite-zones' on TO-VARIABLE.
+The limits do not need to be in numerical order.
 
-Just as for `zz-clone-zones':
- With a non-negative (>= 0) prefix arg, make TO-VARIABLE buffer-local.
- With a non-positive (<= 0) prefix arg, set `zz-izones-var' to the
- TO-VARIABLE symbol.  (Zero: do both.)
+Returns a new list, which is sorted by the lower limit of each zone,
+which is its car.  (This is a non-destructive operation.)
 
-United zones are in ascending order of their cars.
-Return the new value of TO-VARIABLE.
+Each zone in ZONES is first ordered, so that its car <= its cadr.
+The resulting zones are then sorted by their cars.
 
-Use this when you do not want to unite the zones of FROM-VARIABLE (for
-example, you want to use them as possibly overlapping buffer
-narrowings), but you also want to act on the united zones (for
-example, to search them).
+`zz-two-zone-intersection' is then applied recursively to combine
+overlapping zones.  This means also that any EXTRA info is combined
+when zones are merged together."
+  (let* ((flipped-zones  (mapcar #'zz-zone-ordered zones))
+         (sorted-zones   (sort flipped-zones (lambda (z1 z2) (< (car z1) (car 
z2))))))
+    (zz-zone-intersection-1 sorted-zones)))
 
-FROM-VARIABLE defaults to the value of `zz-izones-var'.
+(defun zz-zone-intersection-1 (zones)
+  "Helper for `zz-zone-intersection'."
+  (if (null (cdr zones))
+      zones
+    (let ((new  (zz-two-zone-intersection (car zones) (cadr zones))))
+      (and new  (zz-zone-intersection-1 (cons new (cddr zones)))))))
+
+;; From `cl-seq.el', function `union', without keyword treatment.
+(defun zz-set-union (list1 list2)
+  "Combine LIST1 and LIST2 using a set-union operation.
+The result list contains all items that appear in either LIST1 or
+LIST2.  This is a non-destructive function: it copies the data if
+necessary."
+  (cond ((null list1)         list2)
+        ((null list2)         list1)
+        ((equal list1 list2)  list1)
+        (t
+         (unless (>= (length list1) (length list2)) (setq list1  (prog1 list2 
(setq list2  list1)))) ; Swap.
+         (while list2
+           (unless (member (car list2) list1) (setq list1  (cons (car list2) 
list1)))
+           (setq list2  (cdr list2)))
+         list1)))
 
-Non-interactively: Non-nil MSGP means show a status message."
-  (interactive
-   (let ((from-var  (zz-read-any-variable "Copy variable: " zz-izones-var t))
-         (to-var    (zz-read-any-variable "To variable: "))
-         (npref     (and current-prefix-arg  (prefix-numeric-value 
current-prefix-arg))))
-     (when (and npref  (>= npref 0)) (make-local-variable to-var))
-     (when (and npref  (<= npref 0)) (setq zz-izones-var to-var))
-     (list from-var to-var t)))
-  (set to-variable (copy-sequence (symbol-value from-variable)))
-  (prog1 (zz-unite-zones to-variable)
-    (when msgp (message "Cloned `%s' to `%s' and united `%s'" from-variable 
to-variable to-variable))))
+;; From `cl-seq.el', function `intersection', without keyword treatment.
+(defun zz-set-intersection (list1 list2)
+  "Set intersection of lists LIST1 and LIST2.
+This is a non-destructive operation: it copies the data if necessary."
+  (and list1  list2
+       (if (equal list1 list2)
+           list1
+         (let ((result  ()))
+           (unless (>= (length list1) (length list2)) (setq list1  (prog1 
list2 (setq list2  list1)))) ; Swap.
+           (while list2
+             (when (member (car list2) list1) (setq result  (cons (car list2) 
result)))
+             (setq list2  (cdr list2)))
+           result))))
 
-;;;###autoload
-(defalias 'zz-coalesce-zones #'zz-unite-zones)
-;;;###autoload
-(defun zz-unite-zones (&optional variable msgp) ; Bound to `C-x n u'
-  "Coalesce (unite) the izones of VARIABLE.
-A non-destructive operation: The new value of VARIABLE is a new list.
-Return the new value of VARIABLE.
+(defun zz-min (&rest ns)
+  "Like `min', but if the args include a marker then return a marker.
+Raise an error if the args include markers from different buffers."
+  (let ((buf  (zz-buffer-of-markers ns))
+        (min  (apply #'min ns)))
+    (if (not buf)
+        min
+      (with-current-buffer (get-buffer-create buf) (set-marker (copy-marker 
min) min buf)))))
 
-United zones are in ascending order of their cars.
+(defun zz-max (&rest ns)
+  "Like `max', but if the args include a marker then return a marker.
+Raise an error if the args include markers from different buffers."
+  (let ((buf  (zz-buffer-of-markers ns))
+        (max  (apply #'max ns)))
+    (if (not buf)
+        max
+      (with-current-buffer (get-buffer-create buf) (set-marker (copy-marker 
max) max buf)))))
 
-VARIABLE defaults to the value of `zz-izones-var'.
-With a prefix arg you are prompted for a different variable to use, in
-place of the current value of `zz-izones-var'.  If the prefix arg is
-non-negative (>= 0) then make the variable buffer-local.  If the
-prefix arg is non-positive (<= 0) then set `zz-izones-var' to that
-variable symbol.  (Zero: do both.)
+(defun zz-buffer-of-markers (ns)
+  "Return the buffer of the markers in list NS, or nil if no markers.
+Raise an error if NS contains markers from different buffers."
+  (let ((mkr  (car (zz-some #'markerp ns))))
+    (and mkr
+         (progn
+           (unless (zz-every (lambda (nn) (or (not (markerp nn)) (eq 
(marker-buffer nn) (marker-buffer mkr)))) ns)
+             (error "List contains markers from different buffers"))
+           t)
+         (marker-buffer mkr))))
 
-Non-interactively:
-* VARIABLE is the optional izones variable to use.
-* Non-nil MSGP means show a status message."
-  (interactive (let* ((var    (and current-prefix-arg  (zz-read-any-variable 
"Variable: " zz-izones-var t)))
-                      (npref  (prefix-numeric-value current-prefix-arg)))
-                 (when (and current-prefix-arg  (>= npref 0)) 
(make-local-variable var))
-                 (when (and current-prefix-arg  (<= npref 0)) (setq 
zz-izones-var var))
-                 (list var t)))
-  (let* ((var         (or variable  zz-izones-var))
-         (_IGNORE     (unless (boundp var) (set var ())))
-         (val         (symbol-value var))
-         (_IGNORE     (unless (zz-izones-p val) (error "Not an izones 
variable: `%s', value: `%S'" var val)))
-         (zone-union  (zz-zone-union (zz-izone-limits val))))
-    (set var  (zz-izones-from-zones zone-union))
-    (when msgp
-      (let ((len  (length (symbol-value var))))
-        (message "Zones united for variable `%s': %d zone%s now" var len (if 
(> len 1) "s" ""))))
-    (symbol-value var)))
+;; Similar to `every' in `cl-extra.el', without non-list sequences and multiple
+;; sequences.
+(defun zz-every (predicate list)
+  "Return t if PREDICATE is true for all elements of LIST; else nil."
+  (while (and list  (funcall predicate (car list)))  (setq list  (cdr list)))
+  (null list))
 
-;;;###autoload
-(defalias 'zz-add-zone-and-coalesce #'zz-add-zone-and-unite)
-;;;###autoload
-(defun zz-add-zone-and-unite (start end &optional variable msg) ; Bound to 
`C-x n A'.
-  "Add an izone from START to END to those of VARIABLE, and coalesce.
-Use `zz-add-zone', then apply `zz-unite-zones'.
-United zones are in ascending order of their cars.
-Return the new value of VARIABLE.
+;; Same as `bmkp-some' in `bookmark+-1.el'.
+;; This is NOT the same as `some' in `cl-extra.el', even without non-list 
sequences and multiple sequences.
+;;
+;; If PREDICATE is satisfied by a list element ELEMENT, so that it returns a 
non-nil value VALUE for ELEMENT,
+;; then this returns the cons (ELEMENT . VALUE).  It does not return just 
VALUE.
+(defun zz-some (predicate list)
+  "Return non-nil if PREDICATE applied to some element of LIST is true.
+The value returned is a cons, (ELEMENT . VALUE), where ELEMENT is the
+first list element that satisfies PREDICATE and VALUE is the value of
+PREDICATE applied to ELEMENT."
+  (let (elt val)
+    (catch 'zz-some
+      (while list
+        (when (setq val  (funcall predicate (setq elt  (pop list)))) (throw 
'zz-some (cons elt val))))
+      nil)))
 
-This is a destructive operation: The list structure of the variable
-value can be modified.
+(defun zz-narrowing-lighter ()
+  "Update minor-mode mode-line lighter to reflect narrowing/widening.
+Put `zz-narrow' on `mouse-2' for the lighter suffix."
+  (let* ((%n-cons  (zz-regexp-car-member "%n\\(.*\\)\\'" mode-line-modes)))
+    (when %n-cons
+      (setcar %n-cons (replace-regexp-in-string "%n\\(.*\\)"
+                                                (if (zz-buffer-narrowed-p) 
zz-lighter-narrowing-part "")
+                                                (car %n-cons) nil nil 1))
+      (when (> (length (car %n-cons)) 2)
+        (set-text-properties 2
+                             (length (car %n-cons))
+                             '(local-map (keymap (mode-line keymap (mouse-2 . 
zz-narrow)))
+                               mouse-face mode-line-highlight
+                               help-echo "mouse-2: Next Restriction")
+                             (car %n-cons)))
+      ;; Dunno why we need to do this.  Tried adjusting `rear-sticky' and 
`front-sticky',
+      ;; but without this the whole field (not just the suffix) gets changed, 
in effect, to the above spec.
+      (set-text-properties 0 2 '(local-map (keymap (mode-line keymap (mouse-2 
. mode-line-widen)))
+                                 mouse-face mode-line-highlight help-echo 
"mouse-2: Widen")
+                           (car %n-cons)))))
 
-VARIABLE defaults to the value of `zz-izones-var'.
-START and END are as for `narrow-to-region'.
+(defun zz-regexp-car-member (regexp xs)
+  "Like `member', but tests by matching REGEXP against cars."
+  (and (consp xs)  (if (and (stringp (car xs))  (zz-string-match-p regexp (car 
xs)))
+                       xs
+                     (zz-regexp-car-member regexp (cdr xs)))))
 
-With a prefix arg you are prompted for a different variable to use, in
-place of the current value of `zz-izones-var'.  If the prefix arg is
-non-negative (>= 0) then make the variable buffer-local.  If the
-prefix arg is non-positive (<= 0) then set `zz-izones-var' to that
-variable symbol.  (Zero: do both.)
+(defun zz-markerize (izone)
+  "Convert IZONE to use markers.
+IZONE is a list of an identifier (a number) and two buffer
+positions (numbers, markers, or readable-marker objects).  Positions
+that are numbers or readable-marker objects are converted to markers.
 
-Non-interactively:
-* VARIABLE is the optional izones variable to use.
-* Non-nil MSG means echo messages for adding the zone and uniting
-  zones.  In this case MSG is the message prefix for `zz-add-zone'."
-  (interactive (let ((beg    (region-beginning))
-                     (end    (region-end))
-                     (var    (or (and current-prefix-arg  
(zz-read-any-variable "Variable: " zz-izones-var))
-                                 zz-izones-var))
-                     (npref  (prefix-numeric-value current-prefix-arg)))
-                 (when (and current-prefix-arg  (>= npref 0)) 
(make-local-variable var))
-                 (when (and current-prefix-arg  (<= npref 0)) (setq 
zz-izones-var var))
-                 (list beg end var "Zone recorded: ")))
-  (unless variable (setq variable  zz-izones-var))
-  (zz-add-zone start end variable nil nil msg)
-  (zz-unite-zones variable msg)
-  (symbol-value variable))
+This is a non-destructive operation: it returns a new list."
+  (let ((ii   1)
+        posn)
+    (while (<  ii 3)
+      (setq posn  (nth ii izone))
+      (when (and (not (markerp posn))  (or (natnump posn)  
(zz-readable-marker-p posn)))
+        (setcar (nthcdr ii  izone) (zz-marker-from-object posn)))
+      (setq ii  (1+ ii))))
+  izone)
 
-;;;###autoload
-(defun zz-add-zones-matching-regexp (regexp ; Bound to `C-x n r'
-                                     &optional variable beg end 
not-buf-local-p set-var-p msgp)
-  "Add matches for REGEXP as zones to the izones of VARIABLE.
-If region is active, limit action to region.  Else, use whole buffer.
-Return the new value of VARIABLE.
+(defun zz-marker-from-object (object)
+  "Return an equivalent marker for OBJECT.
+This is a non-destructive operation: OBJECT is not modified.
 
-If `isearchp-dim-outside-search-area-flag' is non-nil then dim the
-non-contexts.  (You can use `\\[isearchp-remove-dimming]' or \
-`\\[isearchp-toggle-dimming-outside-search-area]' to remove the
-dimming.)
+If OBJECT is a marker then return it.
+If it is a number then return (copy-marker OBJECT).
+If it is a readable-marker sexp then return an equivalent real marker.
+Otherwise, return nil.
 
-See `zz-add-zone' for a description of VARIABLE, the use of a prefix
-arg, and the parameters when called from Lisp."
-  (interactive
-   (let* ((regx   (read-regexp "Add zones matching regexp: "))
-          (var    (or (and current-prefix-arg  (zz-read-any-variable 
"Variable: " zz-izones-var t))
-                      zz-izones-var))
-          (beg    (if (and transient-mark-mode  mark-active) 
(region-beginning) (point-min)))
-          (end    (if (and transient-mark-mode  mark-active) (region-end) 
(point-max)))
-          (npref  (prefix-numeric-value current-prefix-arg))
-          (nloc   (and current-prefix-arg  (<= npref 0)  (not (boundp var))))
-          (setv   (and current-prefix-arg  (or (consp current-prefix-arg)  (= 
npref 0)))))
-     (list regx var beg end nloc setv t)))
-  (unless (and beg  end) (setq beg  (point-min)
-                               end  (point-max)))
-  (unless (< beg end) (setq beg  (prog1 end (setq end  beg))))
-  (let ((last-beg  nil)
-        (num-hits  0))
-    (condition-case-unless-debug zz-add-zones-matching-regexp
-        (save-excursion
-          (goto-char (setq last-beg  beg))
-          (while (and beg  (< beg end)  (not (eobp))
-                      (progn (while (and (setq beg  (re-search-forward regexp 
end t))
-                                         (eq last-beg beg)
-                                         (not (eobp)))
-                               ;; Matched again, same place.  Advance 1 char.
-                               (forward-char) (setq beg  (1+ beg)))
-                             beg))      ; Stop if no more matches.
-            (setq num-hits  (1+ num-hits))
-            (let* ((hit-beg     (match-beginning 0))
-                   (hit-end     (match-end 0))
-                   (hit-string  (buffer-substring-no-properties hit-beg 
hit-end))
-                   (c-beg       last-beg)
-                   (c-end       (if beg (match-beginning 0) (min end 
(point-max)))) ; Truncate.
-                   end-marker)
-              (isearchp-add/remove-dim-overlay c-beg c-end 'ADD)
-              (cond ((not (string= "" hit-string))
-                     (zz-add-zone c-beg c-end variable not-buf-local-p 
set-var-p)
-                     (isearchp-add/remove-dim-overlay hit-beg hit-end nil))
-                    (t
-                     (isearchp-add/remove-dim-overlay hit-beg hit-end 'ADD))))
-            (goto-char (setq last-beg  beg))))
-      (error (error "%s" (error-message-string zz-add-zones-matching-regexp))))
-    (unless (> num-hits 0) (zz-user-error "No regexp matches"))
-    (when msgp
-      (let ((dim-msg  (if (not (bound-and-true-p
-                                isearchp-dim-outside-search-area-flag))
-                          ""
-                        (substitute-command-keys
-                         "; `\\[isearchp-remove-dimming]' or \
-`\\[isearchp-toggle-dimming-outside-search-area]' removes dimming"))))
-        (case num-hits
-          (1 (message "1 zone added%s" dim-msg))
-          (t (message "%d zones added or updated%s" num-hits dim-msg)))))
-    variable))
+A readable marker is a sexp of form (marker BUFFER POSITION), where
+BUFFER is a buffer name (string) and POSITION is a buffer position
+\(number)."
+  (cond ((markerp object) object)
+        ((numberp object) (copy-marker object))
+        ((zz-readable-marker-p object)
+         (with-current-buffer (get-buffer-create (nth 1 object)) (copy-marker 
(nth 2 object))))
+        (t nil)))
 
-;;;###autoload
-(defun zz-set-zones-matching-regexp (regexp ; Bound to `C-x n R'
-                                     &optional variable beg end 
not-buf-local-p set-var-p msgp)
-  "Replace value of izones variable with zones matching REGEXP.
-Like `zz-add-zones-matching-regexp' (which see), but it replaces any
-current zones instead of adding to them."
-  (interactive
-   (let* ((var    (or (and current-prefix-arg  (zz-read-any-variable 
"Variable: " zz-izones-var t))
-                      zz-izones-var))
-          (regx   (read-regexp (format "Set `%s' to zones matching regexp: " 
var)))
-          (beg    (if (and transient-mark-mode  mark-active) 
(region-beginning) (point-min)))
-          (end    (if (and transient-mark-mode  mark-active) (region-end) 
(point-max)))
-          (npref  (prefix-numeric-value current-prefix-arg))
-          (nloc   (and current-prefix-arg  (<= npref 0)  (not (boundp var))))
-          (setv   (and current-prefix-arg  (or (consp current-prefix-arg)  (= 
npref 0)))))
-     (list regx var beg end nloc setv t)))
-  (set variable ())
-  (zz-add-zones-matching-regexp regexp variable beg end not-buf-local-p 
set-var-p msgp))
+(defun zz-number-or-marker-p (position)
+  "Return non-nil if POSITION is a number, marker, or readable-marker object."
+  ;; Just like `number-or-marker-p', We don't check that a number arg is a 
positive integer.
+  (or (number-or-marker-p position)  (zz-readable-marker-p position)))
 
-;;;###autoload
-(defun zz-add-zones-from-highlighting ( ; Bound to `C-x n l'
-                                       &optional start end face only-hlt-face 
overlay/text fonk-lock-p msgp)
-  "Add highlighted areas as zones to izones variable.
-By default, the text used is that highlighted with `hlt-last-face'.
-With a non-negative prefix arg you are instead prompted for the face.
+(defun zz-readable-marker-p (object)
+  "Return non-nil if OBJECT is a readable marker.
+That is, it has form (marker BUFFER POSITION), where BUFFER is a
+buffer name (string), and POSITION is a buffer position (integer).
+OBJECT is returned."
+  (and (consp object)  (consp (cdr object))  (consp (cddr object))
+       (eq 'marker (nth 0 object))  (stringp (nth 1 object))  (integerp (nth 2 
object))
+       object))
 
-With a non-positive prefix arg use face property `font-lock-face'
-instead of property `face'.
+(defun zz-readable-marker (number-or-marker &optional num-buffer)
+  "Return a readable marker equivalent to NUMBER-OR-MARKER, or nil.
+Return nil if NUMBER-OR-MARKER is not `number-or-marker-p'.
+\(If NUMBER-OR-MARKER is already a readable marker then return it.)
 
-The izones variable to use is the value of `zz-izones-var'.  You can
-set this to a different variable anytime using `\\[zz-set-izones-var]'.
+A readable marker satisfies `zz-readable-marker-p'.  It has the form
+\(marker BUFFER POSITION), where BUFFER is a buffer name (string) and
+POSITION is a buffer position (number).
 
-All highlighting is checked, both overlays and face text properties.
+If NUMBER-OR-MARKER is itself a readable marker then return it.
 
-The number of highlighted areas added as zones is echoed in a message.
-This might be less than the number of zones added, because there can
-be multiple highlights with the same face for the same area.
+If NUMBER-OR-MARKER is a marker then use its buffer name as BUFFER.
 
-When called from Lisp:
+If NUMBER-OR-MARKER is a number then:
+ If   NUM-BUFFER names an existing buffer then use it as BUFFER.
+ Else use the name of the current buffer as BUFFER.
 
-* Non-nil START and END are the buffer limits to search.
-* Non-nil FACE is the highlighting face to look for.
-* Non-nil ONLY-HLT-FACE means check only `highlight.el' highlighting.
-  (By default, any highlighting is checked.)
-* If OVERLAY/TEXT is `text-prop' then only text-property highlighting
-  is checked. If it is `overlay' then only overlay highlighting is
-  checked.  (If nil then both are checked.)
-* Non-nil FONK-LOCK-P means check property `font-lock-face'.  By
-  default (nil), check property `face'."
-  (interactive
-   (let ((numarg  (and current-prefix-arg  (prefix-numeric-value 
current-prefix-arg))))
-     (unless (require 'highlight nil t) (zz-user-error "You need library 
`highlight.el' to use this command"))
-     `(,@(hlt-region-or-buffer-limits)
-         ,(if (natnump numarg)
-              (hlt-read-bg/face-name "Create zones highlighted with face: ")
-            hlt-last-face)
-         nil nil ,(and numarg  (<= numarg 0)) t)))
-  (require 'highlight)
-  (unless (and start  end) (let ((start-end  (hlt-region-or-buffer-limits)))
-                             (setq start  (car start-end)
-                                   end    (cadr start-end))))
-  (unless face (setq face  hlt-last-face))
-  (let ((hlt-use-overlays-flag     (case overlay/text
-                                     (text-prop  nil) ; Only text property
-                                     (overlay    'only) ; Only overlay
-                                     (t          t))) ; Default: both
-        (hlt-act-on-any-face-flag  (not only-hlt-face))
-        (hlt-face-prop             (if fonk-lock-p 'font-lock-face 'face))
-        (count                     0))
-    (save-excursion
-      (save-window-excursion
-        (goto-char start)
-        (let ((zone-beg  start)
-              zone-end zone)
-          (while (and zone-beg  (< zone-beg end))
-            (setq zone      (hlt-next-highlight zone-beg end face nil nil 
'no-error-msg)
-                  zone-beg  (car zone)
-                  zone-end  (cdr zone))
-            ;; Create zone from `zone-beg' to `zone-end' if highlighted.  Add 
it to zones list.
-            (when hlt-use-overlays-flag
-              (let ((overlays  (overlays-at zone-beg)))
-                (while overlays
-                  (when (and (or hlt-act-on-any-face-flag
-                                 (equal face (overlay-get (car overlays) 
'hlt-highlight)))
-                             (equal face (overlay-get (car overlays) 
hlt-face-prop)))
-                    (zz-add-zone zone-beg zone-end)
-                    (setq count  (1+ count)))
-                  (when overlays (setq overlays  (cdr overlays))))))
-            (when (and (not (eq hlt-use-overlays-flag 'only))
-                       (or hlt-act-on-any-face-flag  (equal face 
(get-text-property (point) 'hlt-highlight)))
-                       (let ((pt-faces  (get-text-property (point) 
hlt-face-prop)))
-                         (if (consp pt-faces) (memq face pt-faces) (equal face 
pt-faces))))
-              (zz-add-zone zone-beg zone-end)
-              (setq count  (1+ count)))))))
-    (when msgp
-      (case count
-        (0 (message "NO zones added or updated"))
-        (1 (message "1 zone added or updated"))
-        (t (message "%s highlighted areas added or updated as zones" 
count))))))
+This is a non-destructive operation."
+  ;; Just like `number-or-marker-p', We don't check that a number arg is a 
positive integer.
+  (cond ((zz-readable-marker-p number-or-marker) number-or-marker)
+        ((markerp number-or-marker)
+         `(marker ,(buffer-name (marker-buffer number-or-marker)) 
,(marker-position number-or-marker)))
+        ((numberp number-or-marker)
+         `(marker
+           ,(buffer-name (or (and (stringp num-buffer)  (get-buffer 
num-buffer))  (current-buffer)))
+           ,number-or-marker))
+        (t nil)))
 
-;;;###autoload
-(defun zz-set-zones-from-highlighting ( ; Bound to `C-x n L'
-                                       &optional start end face only-hlt-face 
overlay/text fonk-lock-p msgp)
-  "Replace value of izones variable with zones from the highlighted areas.
-Like `zz-add-zones-from-highlighting' (which see), but it replaces any
-current zones instead of adding to them."
-  (interactive
-   (let ((numarg  (and current-prefix-arg  (prefix-numeric-value 
current-prefix-arg))))
-     (unless (require 'highlight nil t) (zz-user-error "You need library 
`highlight.el' to use this command"))
-     `(,@(hlt-region-or-buffer-limits)
-         ,(if (natnump numarg)
-              (hlt-read-bg/face-name "Create zones highlighted with face: ")
-            hlt-last-face)
-         nil nil ,(and numarg  (<= numarg 0)) t)))
-  (set zz-izones-var ())
-  (zz-add-zones-from-highlighting start end face only-hlt-face overlay/text 
fonk-lock-p msgp))
+(defun zz-izones-p (value)
+  "Return non-nil if VALUE is a (possibly empty) list of izones.
+That is, non-nil means that VALUE has the form of `zz-izones'."
+  (and (listp value)  (listp (cdr (last value))) ; Proper list.
+       (let ((res  t))
+         (catch 'zz-izones-p
+           (dolist (xx  value) (unless (setq res  (zz-izone-p xx)) (throw 
'zz-izones-p nil))))
+         res)))
 
-;;;###autoload
-(defun zz-set-zones-from-face (face &optional start end variable _msgp) ; 
Bound to `C-x n f'
-  "Set an izones variable to (united) zones of a face or background color.
-You are prompted for a face name or a color name.  If you enter a
-color, it is used for the face background.  The face foreground is
-determined by the value of `hlt-auto-face-foreground'.
-The variable defaults to `zz-izones'.  With a prefix arg you are
-  prompted for a different izones variable."
-  (interactive
-   (progn
-     (unless (require 'highlight nil t)
-       (error "You need library `highlight.el' for this command"))
-     (let ((fac  (hlt-read-bg/face-name "Choose background color or face: "
-                                        (and (symbolp hlt-last-face)  
(symbol-name hlt-last-face))))
-           (var  (or (and current-prefix-arg  (zz-read-any-variable "Variable: 
" zz-izones-var))
-                     zz-izones-var)))
-       (if (hlt-nonempty-region-p)
-           (if (< (point) (mark)) (list (point) (mark) var t) (list (mark) 
(point) var t))
-         (list fac (point-min) (point-max) var t)))))
-  (unless (require 'highlight nil t)
-    (error "You need library `highlight.el' for this command"))
-  (unless (require 'isearch-prop nil t)
-    (error "You need library `isearch-prop.el' for this command"))
-  (unless (require 'zones nil t)
-    (error "You need library `zones' for this command"))
-  (font-lock-default-fontify-buffer)    ; Fontify the whole buffer.
-  (zz-set-zones-from-highlighting start end face nil 'text-prop)
-  (zz-unite-zones variable t))
+(defun zz-izone-p (value)
+  "Return non-nil if VALUE is an izone.
+That is, non-nil means it has the form (ID POS1 POS2 . EXTRA),
+where ID is a negative integer, and each POS<N> is a buffer-position
+representation (`zz-number-or-marker-p')."
+  (and (consp value)  (condition-case nil
+                          (and (integerp (nth 0 value))
+                               (< (nth 0 value) 0)
+                               (zz-number-or-marker-p (nth 1 value))
+                               (zz-number-or-marker-p (nth 2 value)))
+                        (error nil))))
+
+(defun zz-rassoc-delete-all (value alist)
+  "Delete from ALIST all elements whose cdr is `equal' to VALUE.
+Elements of ALIST that are not conses are ignored.
+Return the modified alist.
+This is a destructive operation."
+  (while (and (consp (car alist))  (equal (cdar alist) value)) (setq alist  
(cdr alist)))
+  (let ((tail  alist)
+        tail-cdr)
+    (while (setq tail-cdr  (cdr tail))
+      (if (and (consp (car tail-cdr))  (equal (cdar tail-cdr) value))
+          (setcdr tail (cdr tail-cdr))
+        (setq tail  tail-cdr))))
+  alist)
 
-;;---------------------
 
-;; Put all toggle commands on prefix key `M-='.
+(defun zz-izones-renumber (&optional variable)
+  "Renumber the izones of this buffer in the current `zz-izones-var'.
+This is a destructive operation: The list structure of the variable
+value can be modified."
+  (let* ((var   (or variable  zz-izones-var))
+         (orig  (symbol-value var)))
+    (set var ())
+    (dolist (iz  orig) (zz-add-zone (cadr iz) (car (cddr iz)) var))))
+
+;; Non-destructive version.
 ;;
-(defvar zz-toggles-map nil
-  "Keymap containing bindings for toggle commands for zones.")
-(define-prefix-command 'zz-toggles-map)
+;; (defun zz-izone-limits-in-bufs (buffers &optional variable)
+;;   "Return a list of all `zz-izone-limits' for each buffer in BUFFERS.
+;; That is, return a list of all recorded buffer zones for BUFFERS.
+;; If BUFFERS is nil, return the zones recorded for the current buffer.
+;;
+;; This is a non-destructive operation: The list returned is independent
+;; of the `zz-izone-limits' list in each of the buffers.
+;;
+;; Optional arg VARIABLE is the izones variable to use.  If nil,
+;; use the value of `zz-izones-var'.  The variable is evaluated in each
+;; buffer (or in the current buffer, if BUFFERS is nil)."
+;;
+;;   (let ((limits  ()))
+;;     (dolist (buf  (or (reverse buffers)  (list (current-buffer)))) ; 
Reverse so we keep the order.
+;;       (with-current-buffer buf
+;;         (setq limits  (append (zz-izone-limits (symbol-value (or variable  
zz-izones-var))
+;;                                                buf
+;;                                                'ONLY-THIS-BUFFER)
+;;                               limits))))
+;;     limits))
 
-(defun zz-add-key-bindings-to-narrow-map (bindings)
-  "Add BINDINGS to `narrow-map'.
-\(For Emacs prior to Emacs 24, add bindings to prefix key `C-x n'.)"
-  (let ((map  (if (boundp 'narrow-map) narrow-map (lookup-key ctl-x-map "n"))))
-    (when (keymapp map)
-      (dolist (binding  bindings)
-        (let ((kseq  (car binding))
-              (cmd   (cdr binding)))
-          (unless (lookup-key map kseq) (define-key map kseq cmd)))))))
+(defun zz-izone-limits-in-bufs (buffers &optional variable)
+  "Return a list of all `zz-izone-limits' for each buffer in BUFFERS.
+That is, return a list of all recorded buffer zones for BUFFERS.
+If BUFFERS is nil, return the zones recorded for the current buffer.
+
+This is a destructive operation: The list returned can have as
+sublists the `zz-izone-limits' lists of BUFFERS.
+
+Optional arg VARIABLE is the izones variable to use.  If nil, use the
+value of `zz-izones-var'.  The variable is evaluated in each
+buffer (or in the current buffer, if BUFFERS is nil)."
+  (let ((limits  ()))
+    (dolist (buf  (or buffers  (list (current-buffer))))
+      (with-current-buffer buf
+        (setq limits  (nconc limits (zz-izone-limits (symbol-value (or 
variable  zz-izones-var)) buf 'THISBUF)))))
+    limits))
 
-(zz-add-key-bindings-to-narrow-map '(("\M-=" . zz-toggles-map)
-                                     ("a"    . zz-add-zone)                    
                ; C-x n a
-                                     ("A"    . zz-add-zone-and-unite)          
                ; C-x n A
-                                     ("c"    . zz-clone-zones)                 
                ; C-x n c
-                                     ("C"    . zz-clone-and-unite-zones)       
                ; C-x n C
-                                     ("\C-d" . zz-delete-zone)                 
                ; C-x n C-d
-                                     ("\C-x" . zz-select-zone-repeat)          
                ; C-x n C-x
-                                     ("#"    . zz-select-zone-by-id-and-text)  
                ; C-x n #
-                                     ("u"    . zz-unite-zones)                 
                ; C-x n u
-                                     ("v"    . zz-set-izones-var)              
                ; C-x n v
-                                     ("x"    . zz-narrow-repeat)               
                ; C-x n x
-                                     ))
+(defun zz-izone-limits (izones &optional buffer only-one-buffer-p)
+  "Return a list like IZONES, but with no identifiers.
+That is, return a list of zones, (LIMIT1 LIMIT2 . EXTRA).
 
-(eval-after-load "highlight"
-  '(zz-add-key-bindings-to-narrow-map '(("h" . hlt-highlight-regions)          
                ; C-x n h
-                                        ("H" . 
hlt-highlight-regions-in-buffers)               ; C-x n H
-                                        ("l" . zz-add-zones-from-highlighting) 
                ; C-x n l
-                                        ("L" . zz-set-zones-from-highlighting) 
                ; C-x n L
-                                        )))
+This is a non-destructive operation: A new list is returned.
 
-(eval-after-load "isearch-prop"
-  '(progn
-    (zz-add-key-bindings-to-narrow-map `(("D"       . isearchp-remove-dimming) 
                ; C-x n D
-                                         ("P"       . 
isearchp-put-prop-on-zones)              ; C-x n P
-                                         ("r"       . 
zz-add-zones-matching-regexp)            ; C-x n r
-                                         ("R"       . 
zz-set-zones-matching-regexp)            ; C-x n R
-                                         ("\C-r"    . isearchp-zones-backward) 
                ; C-x n C-r
-                                         ("\C-\M-r" . 
isearchp-zones-backward-regexp)          ; C-x n C-M-r
-                                         ("\C-s"    . isearchp-zones-forward)  
                ; C-x n C-s
-                                         ("\C-\M-s" . 
isearchp-zones-forward-regexp)           ; C-x n C-M-s
-                                         ("\M-%"    . zz-query-replace-zones)  
                ; C-x n M-%
-                                         (,(kbd "C-M-%") . 
zz-query-replace-regexp-zones)      ; C-x n C-M-%
-;;                                       ("???" . zz-replace-regexp-zones)
-;;                                       ("???" . zz-replace-string-zones)
-;;                                       ("???" . 
zz-map-query-replace-regexp-zones)
-;;                                       ("???" . 
isearchp-make-anti-zones-invisible)
-;;                                       ("???" . 
isearchp-make-anti-zones-visible)
-;;                                       ("???" . 
isearchp-make-zones-invisible)
-;;                                       ("???" . isearchp-make-zones-visible)
-;;                                       ("???" . 
isearchp-toggle-zone/anti-zone-visibility)
-                                         ))
-    (define-key zz-toggles-map (kbd "d")     
'isearchp-toggle-dimming-outside-search-area)     ; C-x n M-= d
-    (define-key zz-toggles-map (kbd "v")     
'isearchp-toggle-anti-zones-invisible)            ; C-x n M-= v
-    (define-key zz-toggles-map (kbd "V")     'isearchp-toggle-zones-invisible) 
                ; C-x n M-= V
-    (define-key zz-toggles-map (kbd "~")     
'isearchp-toggle-complementing-domain)            ; C-x n M-= ~
-    ))
+Each limit can be a number or a marker (but see ONLY-ONE-BUFFER-P).
+The conses are new - they do not share with any conses with IZONES.
 
+IZONES has the same structure as `zz-izones'.
 
+The default value of IZONES is the value of the variable that is the
+value of `zz-izones-var'.  This variable is evaluated in BUFFER
+\(default: current buffer) to obtain the izones.
 
-;; Call `zz-add-zone' if interactive or if `zz-add-zone-anyway-p'.
+Non-nil optional arg ONLY-ONE-BUFFER-P means remove any izones that
+contain markers for a buffer other than BUFFER."
+  (let ((restrs  izones))
+    (when only-one-buffer-p
+      (setq restrs  (zz-remove-izones-w-other-buffer-markers restrs (or buffer 
 (current-buffer)))))
+    (delq nil (mapcar #'cdr restrs))))
 
-(defun zz-narrow-advice (interactive-p)
-  (when (or interactive-p  zz-add-zone-anyway-p)
-    (zz-add-zone (point-min) (point-max) nil nil nil "Narrowed, and recorded 
zone: ")))
+;; Useful for commands that want to act on zones in multiple buffers.
+(defun zz-read-bufs ()
+  "Read names of buffers, one at a time.  `C-g' ends reading."
+  (let ((bufs  ())
+        buf)
+    (while (condition-case nil
+               (setq buf  (read-buffer "Buffer (C-g to end): "
+                                       (and (not (member (buffer-name 
(current-buffer)) bufs))
+                                            (current-buffer))
+                                       t))
+             (quit nil))
+      (push buf bufs))
+    (delq nil (mapcar #'get-buffer (nreverse bufs)))))
 
-(defadvice narrow-to-region (after zz-add-zone--region activate)
-  "Push the region limits to the current `zz-izones-var'.
-You can use `C-x n x' to widen to a previous buffer restriction.
+(defun zz-remove-zones-w-other-buffer-markers (zones &optional buffer)
+  "Return ZONES, but remove any that use markers for another buffer.
+BUFFER is the buffer to compare with (default: current buffer).
+This is a non-destructive operation: a (shallow) copy is returned."
+  (unless buffer (setq buffer  (current-buffer)))
+  (zz-remove-if `(lambda (zone) (zz-zone-has-other-buffer-marker-p zone 
',buffer)) zones))
 
-This is a destructive operation. The list structure of the variable
-value can be modified."
-  (zz-narrow-advice (interactive-p)))
+(defun zz-remove-izones-w-other-buffer-markers (izones &optional buffer)
+  "Return IZONES, but remove any that use markers for another buffer.
+BUFFER is the buffer to compare with (default: current buffer).
+This is a non-destructive operation: a (shallow) copy is returned."
+  (unless buffer (setq buffer  (current-buffer)))
+  (zz-remove-if `(lambda (izone) (zz-izone-has-other-buffer-marker-p izone 
',buffer)) izones))
 
-(defadvice narrow-to-defun (after zz-add-zone--defun activate)
-  "Push the defun limits to the current `zz-izones-var'.
-You can use `C-x n x' to widen to a previous buffer restriction.
+(defun zz-zone-has-other-buffer-marker-p (zone &optional buffer)
+  "Return non-nil if basic ZONE has a marker for another buffer.
+The first marker in the zone is returned.
+BUFFER is the buffer to compare with (default: current buffer)."
+  (unless buffer (setq buffer  (current-buffer)))
+  (let ((m1  (nth 0 zone))
+        (m2  (nth 1 zone)))
+    (or (and (markerp m1)  (not (eq buffer (marker-buffer m1)))  m1)
+        (and (markerp m2)  (not (eq buffer (marker-buffer m2)))  m2))))
 
-This is a destructive operation. The list structure of the variable
-value can be modified."
-  (zz-narrow-advice (interactive-p)))
+(defun zz-izone-has-other-buffer-marker-p (izone &optional buffer)
+  "Return non-nil if IZONE has a marker for another buffer.
+The first marker in the izone is returned.
+BUFFER is the buffer to compare with (default: current buffer)."
+  (unless buffer (setq buffer  (current-buffer)))
+  (let ((m1  (nth 1 izone))
+        (m2  (nth 2 izone)))
+    (or (and (markerp m1)  (not (eq buffer (marker-buffer m1)))  m1)
+        (and (markerp m2)  (not (eq buffer (marker-buffer m2)))  m2))))
 
-;; Call `zz-add-zone' if interactive or `zz-add-zone-anyway-p'.
+(defun zz-remove-if (pred xs)
+  "A copy of list XS with no elements that satisfy predicate PRED."
+  (let ((result  ()))
+    (dolist (x  xs) (unless (funcall pred x) (push x result)))
+    (nreverse result)))
+
+;; Useful for commands that want to act on zones in multiple buffers (e.g., 
visible buffers only).
 ;;
-(defadvice narrow-to-page (after zz-add-zone--defun activate)
-  "Push the page limits to the current `zz-izones-var'.
-You can use `C-x n x' to widen to a previous buffer restriction.
+;; Same as `icicle-remove-if-not' etc.
+(defun zz-remove-if-not (pred xs)
+  "A copy of list XS with only elements that satisfy predicate PRED."
+  (let ((result  ()))
+    (dolist (x  xs) (when (funcall pred x) (push x result)))
+    (nreverse result)))
 
-This is a destructive operation. The list structure of the variable
-value can be modified."
-  (zz-narrow-advice (interactive-p)))
+;; Like `read-any-variable' in `strings.el', but passes REQUIRE-MATCH arg to 
`completing-read'.
+(defun zz-read-any-variable (prompt &optional default-value require-match)
+  "Read the name of a variable and return it as a symbol.
+Prompts with string PROMPT.  By default, returns DEFAULT-VALUE if
+non-nil.  If DEFAULT-VALUE is nil and the nearest symbol to the cursor
+is a variable, then return that by default.
+
+Unlike `read-variable', which reads only user options, this reads the
+name of any variable.  If optional arg REQUIRE-MATCH is nil then it
+reads any symbol, but it provides completion against variable names."
+  (let ((symb                          (cond ((fboundp 'symbol-nearest-point) 
(symbol-nearest-point))
+                                             ((fboundp 'symbol-at-point) 
(symbol-at-point))
+                                             (t nil)))
+        (enable-recursive-minibuffers  t))
+    (when (and default-value  (symbolp default-value))
+      (setq default-value  (symbol-name default-value)))
+    (intern (completing-read prompt obarray 'boundp require-match nil 
'minibuffer-history
+                             (let ((var-at-pt  (and symb  (boundp symb)  
(symbol-name symb))))
+                               (if (and default-value  var-at-pt  (> 
emacs-major-version 22))
+                                   (list default-value var-at-pt)
+                                 (or default-value  var-at-pt)))
+                             t))))
+
+(defun zz-repeat-command (command)
+  "Repeat COMMAND."
+  (require 'repeat)                   ;Define its vars before we let-bind them.
+  (let ((repeat-previous-repeated-command  command)
+        (repeat-message-function           #'ignore)
+        (last-repeatable-command           'repeat))
+    (repeat nil)))
 
 (when (> emacs-major-version 24)
 
@@ -2417,6 +2409,19 @@ The value of variable `zz-izones' defines the zones."
     )                                   ; Emacs 27+
   )                                     ; Emacs 25+
 
+(defun zz-dot-pairs (pairs)
+  "Dot PAIRS, a list of lists, each of which has at least two elements."
+  (mapcar (lambda (b-e) (cons (car b-e) (cadr b-e))) pairs))
+
+(defun zz-dotted-zones-from-izones (&optional variable)
+  "Return a list of dotted zones from value of value of VARIABLE.
+VARIABLE defaults to the value of `zz-izones-var'.
+
+This is similar to an Emacs \"noncontiguous region\" - entry pairs are
+dotted: `(beg . end)', not `(beg end)'.  But here the conses of zone
+limits are not united together - they can overlap."
+  (zz-dot-pairs (zz-izone-limits (symbol-value (or variable  zz-izones-var)))))
+
 (defun zz-noncontiguous-region-from-izones (&optional variable)
   "Return a noncontiguous region from value of value of VARIABLE.
 VARIABLE defaults to the value of `zz-izones-var'.  An Emacs
@@ -2434,10 +2439,6 @@ An Emacs \"noncontiguous region\" (Emacs 25+) is what 
the value of
 zones, but the entry pairs are dotted: `(beg . end)', not `(beg end)'."
   (zz-dot-pairs (zz-zone-union basic-zones)))
 
-(defun zz-dot-pairs (pairs)
-  "Dot PAIRS, a list of lists, each of which has at least two elements."
-  (mapcar (lambda (b-e) (cons (car b-e) (cadr b-e))) pairs))
-
 (defun zz-overlay-to-zone (overlay &optional pos-type)
   "Return a basic zone derived from OVERLAY.
 If OVERLAY is not an overlay or it has been deleted (has no buffer)
@@ -2532,6 +2533,90 @@ are included in the returned list."
         (push ov new-ovs)))             ; Add other-buffer overlays to return 
value.
     new-ovs))
 
+(defun zz-izones-from-zones (basic-zones)
+  "Return a list of zones like `zz-izones', based on BASIC-ZONES.
+Each zone in the list BASIC-ZONES has form (LIMIT1 LIMIT2 . EXTRA),
+where each of the limits is a buffer position (a number or marker) and
+EXTRA is a list.
+
+This is a non-destructive operation.  A new list is returned.
+
+\(zz-izone-limits (zz-izones-from-zones BASIC-ZONES)) = BASIC-ZONES
+
+Also, (zz-izones-from-zones (zz-izone-limits zz-izones)) returns the
+same set of izones as `zz-izones', but possibly with different IDs
+associated with the basic zones."
+  (let ((ii  0))
+    (nreverse (mapcar (lambda (zz) (cons (- (setq ii  (1+ ii))) zz)) (reverse 
basic-zones)))))
+
+
+;;(@* "Key Bindings)"
+
+;;; Key Bindings -----------------------------------------------------
+
+;; Put all toggle commands on prefix key `M-='.
+;;
+(defvar zz-toggles-map nil
+  "Keymap containing bindings for toggle commands for zones.")
+(define-prefix-command 'zz-toggles-map)
+
+(defun zz-add-key-bindings-to-narrow-map (bindings)
+  "Add BINDINGS to `narrow-map'.
+\(For Emacs prior to Emacs 24, add bindings to prefix key `C-x n'.)"
+  (let ((map  (if (boundp 'narrow-map) narrow-map (lookup-key ctl-x-map "n"))))
+    (when (keymapp map)
+      (dolist (binding  bindings)
+        (let ((kseq  (car binding))
+              (cmd   (cdr binding)))
+          (unless (lookup-key map kseq) (define-key map kseq cmd)))))))
+
+(zz-add-key-bindings-to-narrow-map '(("\M-=" . zz-toggles-map)
+                                     ("a"    . zz-add-zone)                    
                ; C-x n a
+                                     ("A"    . zz-add-zone-and-unite)          
                ; C-x n A
+                                     ("c"    . zz-clone-zones)                 
                ; C-x n c
+                                     ("C"    . zz-clone-and-unite-zones)       
                ; C-x n C
+                                     ("\C-d" . zz-delete-zone)                 
                ; C-x n C-d
+                                     ("\C-x" . zz-select-zone-repeat)          
                ; C-x n C-x
+                                     ("#"    . zz-select-zone-by-id-and-text)  
                ; C-x n #
+                                     ("u"    . zz-unite-zones)                 
                ; C-x n u
+                                     ("v"    . zz-set-izones-var)              
                ; C-x n v
+                                     ("x"    . zz-narrow-repeat)               
                ; C-x n x
+                                     ))
+
+(eval-after-load "highlight"
+  '(zz-add-key-bindings-to-narrow-map '(("h" . hlt-highlight-regions)          
                ; C-x n h
+                                        ("H" . 
hlt-highlight-regions-in-buffers)               ; C-x n H
+                                        ("l" . zz-add-zones-from-highlighting) 
                ; C-x n l
+                                        ("L" . zz-set-zones-from-highlighting) 
                ; C-x n L
+                                        )))
+
+(eval-after-load "isearch-prop"
+  '(progn
+    (zz-add-key-bindings-to-narrow-map `(("D"       . isearchp-remove-dimming) 
                ; C-x n D
+                                         ("P"       . 
isearchp-put-prop-on-zones)              ; C-x n P
+                                         ("r"       . 
zz-add-zones-matching-regexp)            ; C-x n r
+                                         ("R"       . 
zz-set-zones-matching-regexp)            ; C-x n R
+                                         ("\C-r"    . isearchp-zones-backward) 
                ; C-x n C-r
+                                         ("\C-\M-r" . 
isearchp-zones-backward-regexp)          ; C-x n C-M-r
+                                         ("\C-s"    . isearchp-zones-forward)  
                ; C-x n C-s
+                                         ("\C-\M-s" . 
isearchp-zones-forward-regexp)           ; C-x n C-M-s
+                                         ("\M-%"    . zz-query-replace-zones)  
                ; C-x n M-%
+                                         (,(kbd "C-M-%") . 
zz-query-replace-regexp-zones)      ; C-x n C-M-%
+;;                                       ("???" . zz-replace-regexp-zones)
+;;                                       ("???" . zz-replace-string-zones)
+;;                                       ("???" . 
zz-map-query-replace-regexp-zones)
+;;                                       ("???" . 
isearchp-make-anti-zones-invisible)
+;;                                       ("???" . 
isearchp-make-anti-zones-visible)
+;;                                       ("???" . 
isearchp-make-zones-invisible)
+;;                                       ("???" . isearchp-make-zones-visible)
+;;                                       ("???" . 
isearchp-toggle-zone/anti-zone-visibility)
+                                         ))
+    (define-key zz-toggles-map (kbd "d")     
'isearchp-toggle-dimming-outside-search-area)     ; C-x n M-= d
+    (define-key zz-toggles-map (kbd "v")     
'isearchp-toggle-anti-zones-invisible)            ; C-x n M-= v
+    (define-key zz-toggles-map (kbd "V")     'isearchp-toggle-zones-invisible) 
                ; C-x n M-= V
+    (define-key zz-toggles-map (kbd "~")     
'isearchp-toggle-complementing-domain)            ; C-x n M-= ~
+    ))
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (provide 'zones)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]