LCOV - code coverage report
Current view: top level - lisp/emacs-lisp - ewoc.el (source / functions) Hit Total Coverage
Test: tramp-tests.info Lines: 7 105 6.7 %
Date: 2017-08-27 09:44:50 Functions: 2 36 5.6 %

          Line data    Source code
       1             : ;;; ewoc.el --- utility to maintain a view of a list of objects in a buffer  -*- lexical-binding: t -*-
       2             : 
       3             : ;; Copyright (C) 1991-2017 Free Software Foundation, Inc.
       4             : 
       5             : ;; Author: Per Cederqvist <ceder@lysator.liu.se>
       6             : ;;      Inge Wallin <inge@lysator.liu.se>
       7             : ;; Maintainer: monnier@gnu.org
       8             : ;; Created: 3 Aug 1992
       9             : ;; Keywords: extensions, lisp
      10             : 
      11             : ;; This file is part of GNU Emacs.
      12             : 
      13             : ;; GNU Emacs is free software: you can redistribute it and/or modify
      14             : ;; it under the terms of the GNU General Public License as published by
      15             : ;; the Free Software Foundation, either version 3 of the License, or
      16             : ;; (at your option) any later version.
      17             : 
      18             : ;; GNU Emacs is distributed in the hope that it will be useful,
      19             : ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
      20             : ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      21             : ;; GNU General Public License for more details.
      22             : 
      23             : ;; You should have received a copy of the GNU General Public License
      24             : ;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
      25             : 
      26             : ;;; Commentary:
      27             : 
      28             : ;; Ewoc Was Once Cookie
      29             : ;; But now it's Emacs's Widget for Object Collections
      30             : 
      31             : ;; As the name implies this derives from the `cookie' package (part
      32             : ;; of Elib).  The changes are pervasive though mostly superficial:
      33             : 
      34             : ;; - uses CL (and its `defstruct')
      35             : ;; - separate from Elib.
      36             : ;; - uses its own version of a doubly-linked list which allows us
      37             : ;;   to merge the elib-wrapper and the elib-node structures into ewoc-node
      38             : ;; - dropping functions not used by PCL-CVS (the only client of ewoc at the
      39             : ;;   time of writing)
      40             : ;; - removing unused arguments
      41             : ;; - renaming:
      42             : ;;   elib-node  ==>  ewoc--node
      43             : ;;   collection ==>  ewoc
      44             : ;;   tin        ==>  ewoc--node
      45             : ;;   cookie     ==>  data or element or elem
      46             : 
      47             : ;;     Introduction
      48             : ;;     ============
      49             : ;;
      50             : ;; Ewoc is a package that implements a connection between an
      51             : ;; dll (a doubly linked list) and the contents of a buffer.
      52             : ;; Possible uses are dired (have all files in a list, and show them),
      53             : ;; buffer-list, kom-prioritize (in the LysKOM elisp client) and
      54             : ;; others.  pcl-cvs.el and vc.el use ewoc.el.
      55             : ;;
      56             : ;; Ewoc can be considered as the `view' part of a model-view-controller.
      57             : ;;
      58             : ;; A `element' can be any lisp object.  When you use the ewoc
      59             : ;; package you specify a pretty-printer, a function that inserts
      60             : ;; a printable representation of the element in the buffer.  (The
      61             : ;; pretty-printer should use "insert" and not
      62             : ;; "insert-before-markers").
      63             : ;;
      64             : ;; A `ewoc' consists of a doubly linked list of elements, a
      65             : ;; header, a footer and a pretty-printer.  It is displayed at a
      66             : ;; certain point in a certain buffer.  (The buffer and point are
      67             : ;; fixed when the ewoc is created).  The header and the footer
      68             : ;; are constant strings.  They appear before and after the elements.
      69             : ;;
      70             : ;; Ewoc does not affect the mode of the buffer in any way. It
      71             : ;; merely makes it easy to connect an underlying data representation
      72             : ;; to the buffer contents.
      73             : ;;
      74             : ;; A `ewoc--node' is an object that contains one element.  There are
      75             : ;; functions in this package that given an ewoc--node extract the data, or
      76             : ;; give the next or previous ewoc--node.  (All ewoc--nodes are linked together
      77             : ;; in a doubly linked list.  The `previous' ewoc--node is the one that appears
      78             : ;; before the other in the buffer.)  You should not do anything with
      79             : ;; an ewoc--node except pass it to the functions in this package.
      80             : ;;
      81             : ;; An ewoc is a very dynamic thing.  You can easily add or delete elements.
      82             : ;; You can apply a function to all elements in an ewoc, etc, etc.
      83             : ;;
      84             : ;; Remember that an element can be anything.  Your imagination is the
      85             : ;; limit!  It is even possible to have another ewoc as an
      86             : ;; element.  In that way some kind of tree hierarchy can be created.
      87             : ;;
      88             : ;; The Emacs Lisp Reference Manual documents ewoc.el's "public interface".
      89             : 
      90             : ;;     Coding conventions
      91             : ;;     ==================
      92             : ;;
      93             : ;; All functions of course start with `ewoc'.  Functions and macros
      94             : ;; starting with the prefix `ewoc--' are meant for internal use,
      95             : ;; while those starting with `ewoc-' are exported for public use.
      96             : 
      97             : ;;; Code:
      98             : 
      99             : (eval-when-compile (require 'cl-lib))
     100             : 
     101             : ;; The doubly linked list is implemented as a circular list with a dummy
     102             : ;; node first and last. The dummy node is used as "the dll".
     103             : (cl-defstruct (ewoc--node
     104             :             (:type vector)              ;ewoc--node-nth needs this
     105             :             (:constructor nil)
     106             :             (:constructor ewoc--node-create (start-marker data)))
     107             :   left right data start-marker)
     108             : 
     109             : (defun ewoc--node-next (dll node)
     110             :   "Return the node after NODE, or nil if NODE is the last node."
     111           0 :   (let ((R (ewoc--node-right node)))
     112           0 :     (unless (eq dll R) R)))
     113             : 
     114             : (defun ewoc--node-prev (dll node)
     115             :   "Return the node before NODE, or nil if NODE is the first node."
     116           0 :   (let ((L (ewoc--node-left node)))
     117           0 :     (unless (eq dll L) L)))
     118             : 
     119             : (defun ewoc--node-nth (dll n)
     120             :   "Return the Nth node from the doubly linked list `dll'.
     121             : N counts from zero.  If N is negative, return the -(N+1)th last element.
     122             : If N is out of range, return nil.
     123             : Thus, (ewoc--node-nth dll 0) returns the first node,
     124             : and (ewoc--node-nth dll -1) returns the last node."
     125             :   ;; Presuming a node is ":type vector", starting with `left' and `right':
     126             :   ;; Branch 0 ("follow left pointer") is used when n is negative.
     127             :   ;; Branch 1 ("follow right pointer") is used otherwise.
     128           0 :   (let* ((branch (if (< n 0) 0 1))
     129           0 :          (node   (aref dll branch)))
     130           0 :     (if (< n 0) (setq n (- -1 n)))
     131           0 :     (while (and (not (eq dll node)) (> n 0))
     132           0 :       (setq node (aref node branch))
     133           0 :       (setq n (1- n)))
     134           0 :     (unless (eq dll node) node)))
     135             : 
     136             : (defun ewoc-location (node)
     137             :   "Return the start location of NODE."
     138           0 :   (ewoc--node-start-marker node))
     139             : 
     140             : 
     141             : ;;; The ewoc data type
     142             : 
     143             : (cl-defstruct (ewoc
     144             :             (:constructor nil)
     145             :             (:constructor ewoc--create (buffer pretty-printer dll))
     146             :             (:conc-name ewoc--))
     147             :   buffer pretty-printer header footer dll last-node hf-pp)
     148             : 
     149             : (defmacro ewoc--set-buffer-bind-dll-let* (ewoc varlist &rest forms)
     150             :   "Execute FORMS with ewoc--buffer selected as current buffer,
     151             : `dll' bound to the dll, and VARLIST bound as in a let*.
     152             : `dll' will be bound when VARLIST is initialized, but
     153             : the current buffer will *not* have been changed.
     154             : Return value of last form in FORMS."
     155          16 :   (let ((hnd (make-symbol "ewoc")))
     156          16 :     `(let* ((,hnd ,ewoc)
     157          16 :             (dll (ewoc--dll ,hnd))
     158          16 :             ,@varlist)
     159          16 :        (with-current-buffer (ewoc--buffer ,hnd)
     160          16 :          ,@forms))))
     161             : 
     162             : (defmacro ewoc--set-buffer-bind-dll (ewoc &rest forms)
     163           7 :   `(ewoc--set-buffer-bind-dll-let* ,ewoc nil ,@forms))
     164             : 
     165             : (defsubst ewoc--filter-hf-nodes (ewoc node)
     166             :   "Evaluate NODE once and return it.
     167             : BUT if it is the header or the footer in EWOC return nil instead."
     168           0 :   (unless (or (eq node (ewoc--header ewoc))
     169           0 :               (eq node (ewoc--footer ewoc)))
     170           0 :     node))
     171             : 
     172             : (defun ewoc--adjust (beg end node dll)
     173             :   ;; "Manually reseat" markers for NODE and its successors (including footer
     174             :   ;; and dll), in the case where they originally shared start position with
     175             :   ;; BEG, to END.  BEG and END are buffer positions describing NODE's left
     176             :   ;; neighbor.  This operation is functionally equivalent to temporarily
     177             :   ;; setting these nodes' markers' insertion type to t around the pretty-print
     178             :   ;; call that precedes the call to `ewoc--adjust', and then changing them back
     179             :   ;; to nil.
     180           0 :   (when (< beg end)
     181           0 :     (let (m)
     182           0 :       (while (and (= beg (setq m (ewoc--node-start-marker node)))
     183             :                   ;; The "dummy" node `dll' actually holds the marker that
     184             :                   ;; points to the end of the footer, so we check `dll'
     185             :                   ;; *after* reseating the marker.
     186           0 :                   (progn
     187           0 :                     (set-marker m end)
     188           0 :                     (not (eq dll node))))
     189           0 :         (setq node (ewoc--node-right node))))))
     190             : 
     191             : (defun ewoc--insert-new-node (node data pretty-printer dll)
     192             :   "Insert before NODE a new node for DATA, displayed by PRETTY-PRINTER.
     193             : Fourth arg DLL -- from `(ewoc--dll EWOC)' -- is for internal purposes.
     194             : Call PRETTY-PRINTER with point at NODE's start, thus pushing back
     195             : NODE and leaving the new node's start there.  Return the new node."
     196           0 :   (save-excursion
     197           0 :     (let ((elemnode (ewoc--node-create
     198           0 :                      (copy-marker (ewoc--node-start-marker node)) data)))
     199           0 :       (setf (ewoc--node-left  elemnode) (ewoc--node-left node)
     200           0 :             (ewoc--node-right elemnode)                  node
     201           0 :             (ewoc--node-right (ewoc--node-left node)) elemnode
     202           0 :             (ewoc--node-left                   node)  elemnode)
     203           0 :       (ewoc--refresh-node pretty-printer elemnode dll)
     204           0 :       elemnode)))
     205             : 
     206             : (defun ewoc--refresh-node (pp node dll)
     207             :   "Redisplay the element represented by NODE using the pretty-printer PP."
     208           0 :   (let ((inhibit-read-only t)
     209           0 :         (m (ewoc--node-start-marker node))
     210           0 :         (R (ewoc--node-right node)))
     211             :     ;; First, remove the string from the buffer:
     212           0 :     (delete-region m (ewoc--node-start-marker R))
     213             :     ;; Calculate and insert the string.
     214           0 :     (goto-char m)
     215           0 :     (funcall pp (ewoc--node-data node))
     216           0 :     (ewoc--adjust m (point) R dll)))
     217             : 
     218             : (defun ewoc--wrap (func)
     219             :   (lambda (data)
     220           0 :     (funcall func data)
     221           0 :     (insert "\n")))
     222             : 
     223             : 
     224             : ;;; ===========================================================================
     225             : ;;;                  Public members of the Ewoc package
     226             : 
     227             : ;;;###autoload
     228             : (defun ewoc-create (pretty-printer &optional header footer nosep)
     229             :   "Create an empty ewoc.
     230             : 
     231             : The ewoc will be inserted in the current buffer at the current position.
     232             : 
     233             : PRETTY-PRINTER should be a function that takes one argument, an
     234             : element, and inserts a string representing it in the buffer (at
     235             : point).  The string PRETTY-PRINTER inserts may be empty or span
     236             : several lines.  The PRETTY-PRINTER should use `insert', and not
     237             : `insert-before-markers'.
     238             : 
     239             : Optional second and third arguments HEADER and FOOTER are strings,
     240             : possibly empty, that will always be present at the top and bottom,
     241             : respectively, of the ewoc.
     242             : 
     243             : Normally, a newline is automatically inserted after the header,
     244             : the footer and every node's printed representation.  Optional
     245             : fourth arg NOSEP non-nil inhibits this."
     246           0 :   (let* ((dummy-node (ewoc--node-create 'DL-LIST 'DL-LIST))
     247           0 :          (dll (progn (setf (ewoc--node-right dummy-node) dummy-node)
     248           0 :                      (setf (ewoc--node-left dummy-node) dummy-node)
     249           0 :                      dummy-node))
     250           0 :          (wrap (if nosep 'identity 'ewoc--wrap))
     251           0 :          (new-ewoc (ewoc--create (current-buffer)
     252           0 :                                  (funcall wrap pretty-printer)
     253           0 :                                  dll))
     254           0 :          (hf-pp (funcall wrap 'insert))
     255           0 :          (pos (point))
     256             :          head foot)
     257           0 :     (ewoc--set-buffer-bind-dll new-ewoc
     258             :       ;; Set default values
     259             :       (unless header (setq header ""))
     260             :       (unless footer (setq footer ""))
     261             :       (setf (ewoc--node-start-marker dll) (copy-marker pos)
     262             :             foot (ewoc--insert-new-node  dll footer hf-pp dll)
     263             :             head (ewoc--insert-new-node foot header hf-pp dll)
     264             :             (ewoc--hf-pp new-ewoc) hf-pp
     265             :             (ewoc--footer new-ewoc) foot
     266           0 :             (ewoc--header new-ewoc) head))
     267             :     ;; Return the ewoc
     268           0 :     new-ewoc))
     269             : 
     270             : (defalias 'ewoc-data 'ewoc--node-data
     271             :   "Extract the data encapsulated by NODE and return it.
     272             : 
     273             : \(fn NODE)")
     274             : 
     275             : (defun ewoc-set-data (node data)
     276             :   "Set NODE to encapsulate DATA."
     277           0 :   (setf (ewoc--node-data node) data))
     278             : 
     279             : (defun ewoc-enter-first (ewoc data)
     280             :   "Enter DATA first in EWOC.
     281             : Return the new node."
     282           0 :   (ewoc--set-buffer-bind-dll ewoc
     283           0 :     (ewoc-enter-after ewoc (ewoc--node-nth dll 0) data)))
     284             : 
     285             : (defun ewoc-enter-last (ewoc data)
     286             :   "Enter DATA last in EWOC.
     287             : Return the new node."
     288           0 :   (ewoc--set-buffer-bind-dll ewoc
     289           0 :     (ewoc-enter-before ewoc (ewoc--node-nth dll -1) data)))
     290             : 
     291             : (defun ewoc-enter-after (ewoc node data)
     292             :   "Enter a new element DATA after NODE in EWOC.
     293             : Return the new node."
     294           0 :   (ewoc--set-buffer-bind-dll ewoc
     295           0 :     (ewoc-enter-before ewoc (ewoc--node-next dll node) data)))
     296             : 
     297             : (defun ewoc-enter-before (ewoc node data)
     298             :   "Enter a new element DATA before NODE in EWOC.
     299             : Return the new node."
     300           0 :   (ewoc--set-buffer-bind-dll ewoc
     301           0 :     (ewoc--insert-new-node node data (ewoc--pretty-printer ewoc) dll)))
     302             : 
     303             : (defun ewoc-next (ewoc node)
     304             :   "Return the node in EWOC that follows NODE.
     305             : Return nil if NODE is nil or the last element."
     306           0 :   (when node
     307           0 :     (ewoc--filter-hf-nodes
     308           0 :      ewoc (ewoc--node-next (ewoc--dll ewoc) node))))
     309             : 
     310             : (defun ewoc-prev (ewoc node)
     311             :   "Return the node in EWOC that precedes NODE.
     312             : Return nil if NODE is nil or the first element."
     313           0 :   (when node
     314           0 :     (ewoc--filter-hf-nodes
     315           0 :      ewoc (ewoc--node-prev (ewoc--dll ewoc) node))))
     316             : 
     317             : (defun ewoc-nth (ewoc n)
     318             :   "Return the Nth node.
     319             : N counts from zero.  Return nil if there is less than N elements.
     320             : If N is negative, return the -(N+1)th last element.
     321             : Thus, (ewoc-nth ewoc 0) returns the first node,
     322             : and (ewoc-nth ewoc -1) returns the last node.
     323             : Use `ewoc-data' to extract the data from the node."
     324             :   ;; Skip the header (or footer, if n is negative).
     325           0 :   (setq n (if (< n 0) (1- n) (1+ n)))
     326           0 :   (ewoc--filter-hf-nodes ewoc
     327           0 :                          (ewoc--node-nth (ewoc--dll ewoc) n)))
     328             : 
     329             : (defun ewoc-map (map-function ewoc &rest args)
     330             :   "Apply MAP-FUNCTION to all elements in EWOC.
     331             : MAP-FUNCTION is applied to the first element first.
     332             : If MAP-FUNCTION returns non-nil the element will be refreshed (its
     333             : pretty-printer will be called once again).
     334             : 
     335             : Note that the buffer for EWOC will be the current buffer when
     336             : MAP-FUNCTION is called.  MAP-FUNCTION must restore the current
     337             : buffer before it returns, if it changes it.
     338             : 
     339             : If more than two arguments are given, the remaining
     340             : arguments will be passed to MAP-FUNCTION."
     341           0 :   (ewoc--set-buffer-bind-dll-let* ewoc
     342             :       ((footer (ewoc--footer ewoc))
     343             :        (pp (ewoc--pretty-printer ewoc))
     344             :        (node (ewoc--node-nth dll 1)))
     345             :     (save-excursion
     346             :       (while (not (eq node footer))
     347             :         (if (apply map-function (ewoc--node-data node) args)
     348             :             (ewoc--refresh-node pp node dll))
     349           0 :         (setq node (ewoc--node-next dll node))))))
     350             : 
     351             : (defun ewoc-delete (ewoc &rest nodes)
     352             :   "Delete NODES from EWOC."
     353           0 :   (ewoc--set-buffer-bind-dll-let* ewoc
     354             :       ((L nil) (R nil) (last (ewoc--last-node ewoc)))
     355             :     (dolist (node nodes)
     356             :       ;; If we are about to delete the node pointed at by last-node,
     357             :       ;; set last-node to nil.
     358             :       (when (eq last node)
     359             :         (setf last nil (ewoc--last-node ewoc) nil))
     360             :       (delete-region (ewoc--node-start-marker node)
     361             :                      (ewoc--node-start-marker (ewoc--node-next dll node)))
     362             :       (set-marker (ewoc--node-start-marker node) nil)
     363             :       (setf L (ewoc--node-left  node)
     364             :             R (ewoc--node-right node)
     365             :             ;; Link neighbors to each other.
     366             :             (ewoc--node-right L) R
     367             :             (ewoc--node-left  R) L
     368             :             ;; Forget neighbors.
     369             :             (ewoc--node-left  node) nil
     370           0 :             (ewoc--node-right node) nil))))
     371             : 
     372             : (defun ewoc-filter (ewoc predicate &rest args)
     373             :   "Remove all elements in EWOC for which PREDICATE returns nil.
     374             : Note that the buffer for EWOC will be current-buffer when PREDICATE
     375             : is called.  PREDICATE must restore the current buffer before it returns
     376             : if it changes it.
     377             : The PREDICATE is called with the element as its first argument.  If any
     378             : ARGS are given they will be passed to the PREDICATE."
     379           0 :   (ewoc--set-buffer-bind-dll-let* ewoc
     380             :       ((node (ewoc--node-nth dll 1))
     381             :        (footer (ewoc--footer ewoc))
     382             :        (goodbye nil)
     383             :        (inhibit-read-only t))
     384             :     (while (not (eq node footer))
     385             :       (unless (apply predicate (ewoc--node-data node) args)
     386             :         (push node goodbye))
     387             :       (setq node (ewoc--node-next dll node)))
     388           0 :     (apply 'ewoc-delete ewoc goodbye)))
     389             : 
     390             : (defun ewoc-locate (ewoc &optional pos guess)
     391             :   "Return the node that POS (a buffer position) is within.
     392             : POS may be a marker or an integer.  It defaults to point.
     393             : GUESS should be a node that it is likely to be near POS.
     394             : 
     395             : If POS points before the first element, the first node is returned.
     396             : If POS points after the last element, the last node is returned.
     397             : If the EWOC is empty, nil is returned."
     398           0 :   (unless pos (setq pos (point)))
     399           0 :   (ewoc--set-buffer-bind-dll ewoc
     400             : 
     401             :     (cond
     402             :      ;; Nothing present?
     403             :      ((eq (ewoc--node-nth dll 1) (ewoc--node-nth dll -1))
     404             :       nil)
     405             : 
     406             :      ;; Before second elem?
     407             :      ((< pos (ewoc--node-start-marker (ewoc--node-nth dll 2)))
     408             :       (ewoc--node-nth dll 1))
     409             : 
     410             :      ;; After one-before-last elem?
     411             :      ((>= pos (ewoc--node-start-marker (ewoc--node-nth dll -2)))
     412             :       (ewoc--node-nth dll -2))
     413             : 
     414             :      ;; We now know that pos is within a elem.
     415             :      (t
     416             :       ;; Make an educated guess about which of the three known
     417             :       ;; node'es (the first, the last, or GUESS) is nearest.
     418             :       (let* ((best-guess (ewoc--node-nth dll 1))
     419             :              (distance (abs (- pos (ewoc--node-start-marker best-guess)))))
     420             :         (when guess
     421             :           (let ((d (abs (- pos (ewoc--node-start-marker guess)))))
     422             :             (when (< d distance)
     423             :               (setq distance d)
     424             :               (setq best-guess guess))))
     425             : 
     426             :         (let* ((g (ewoc--node-nth dll -1))      ;Check the last elem
     427             :                (d (abs (- pos (ewoc--node-start-marker g)))))
     428             :           (when (< d distance)
     429             :             (setq distance d)
     430             :             (setq best-guess g)))
     431             : 
     432             :         (when (ewoc--last-node ewoc)    ;Check "previous".
     433             :           (let* ((g (ewoc--last-node ewoc))
     434             :                  (d (abs (- pos (ewoc--node-start-marker g)))))
     435             :             (when (< d distance)
     436             :               (setq distance d)
     437             :               (setq best-guess g))))
     438             : 
     439             :         ;; best-guess is now a "best guess".
     440             :         ;; Find the correct node. First determine in which direction
     441             :         ;; it lies, and then move in that direction until it is found.
     442             : 
     443             :         (cond
     444             :          ;; Is pos after the guess?
     445             :          ((>= pos
     446             :               (ewoc--node-start-marker best-guess))
     447             :           ;; Loop until we are exactly one node too far down...
     448             :           (while (>= pos (ewoc--node-start-marker best-guess))
     449             :             (setq best-guess (ewoc--node-next dll best-guess)))
     450             :           ;; ...and return the previous node.
     451             :           (ewoc--node-prev dll best-guess))
     452             : 
     453             :          ;; Pos is before best-guess
     454             :          (t
     455             :           (while (< pos (ewoc--node-start-marker best-guess))
     456             :             (setq best-guess (ewoc--node-prev dll best-guess)))
     457           0 :           best-guess)))))))
     458             : 
     459             : (defun ewoc-invalidate (ewoc &rest nodes)
     460             :   "Call EWOC's pretty-printer for each element in NODES.
     461             : Delete current text first, thus effecting a \"refresh\"."
     462           0 :   (ewoc--set-buffer-bind-dll-let* ewoc
     463             :       ((pp (ewoc--pretty-printer ewoc)))
     464             :     (save-excursion
     465             :       (dolist (node nodes)
     466           0 :         (ewoc--refresh-node pp node dll)))))
     467             : 
     468             : (defun ewoc-goto-prev (ewoc arg)
     469             :   "Move point to the ARGth previous element in EWOC.
     470             : Don't move if we are at the first element, or if EWOC is empty.
     471             : Return the node we moved to."
     472           0 :   (ewoc--set-buffer-bind-dll-let* ewoc
     473             :       ((node (ewoc-locate ewoc (point))))
     474             :     (when node
     475             :       ;; If we were past the last element, first jump to it.
     476             :       (when (>= (point) (ewoc--node-start-marker (ewoc--node-right node)))
     477             :         (setq arg (1- arg)))
     478             :       (while (and node (> arg 0))
     479             :         (setq arg (1- arg))
     480             :         (setq node (ewoc--node-prev dll node)))
     481             :       ;; Never step above the first element.
     482             :       (unless (ewoc--filter-hf-nodes ewoc node)
     483             :         (setq node (ewoc--node-nth dll 1)))
     484           0 :       (ewoc-goto-node ewoc node))))
     485             : 
     486             : (defun ewoc-goto-next (ewoc arg)
     487             :   "Move point to the ARGth next element in EWOC.
     488             : Return the node (or nil if we just passed the last node)."
     489           0 :   (ewoc--set-buffer-bind-dll-let* ewoc
     490             :       ((node (ewoc-locate ewoc (point))))
     491             :     (while (and node (> arg 0))
     492             :       (setq arg (1- arg))
     493             :       (setq node (ewoc--node-next dll node)))
     494             :     ;; Never step below the first element.
     495             :     ;; (unless (ewoc--filter-hf-nodes ewoc node)
     496             :     ;;   (setq node (ewoc--node-nth dll -2)))
     497             :     (unless node
     498             :       (error "No next"))
     499           0 :     (ewoc-goto-node ewoc node)))
     500             : 
     501             : (defun ewoc-goto-node (ewoc node)
     502             :   "Move point to NODE in EWOC."
     503           0 :   (ewoc--set-buffer-bind-dll ewoc
     504             :     (goto-char (ewoc--node-start-marker node))
     505             :     (if goal-column (move-to-column goal-column))
     506           0 :     (setf (ewoc--last-node ewoc) node)))
     507             : 
     508             : (defun ewoc-refresh (ewoc)
     509             :   "Refresh all data in EWOC.
     510             : The pretty-printer that was specified when the EWOC was created
     511             : will be called for all elements in EWOC.
     512             : Note that `ewoc-invalidate' is more efficient if only a small
     513             : number of elements needs to be refreshed."
     514           0 :   (ewoc--set-buffer-bind-dll-let* ewoc
     515             :       ((footer (ewoc--footer ewoc)))
     516             :     (let ((inhibit-read-only t))
     517             :       (delete-region (ewoc--node-start-marker (ewoc--node-nth dll 1))
     518             :                      (ewoc--node-start-marker footer))
     519             :       (goto-char (ewoc--node-start-marker footer))
     520             :       (let ((pp (ewoc--pretty-printer ewoc))
     521             :             (node (ewoc--node-nth dll 1)))
     522             :         (while (not (eq node footer))
     523             :           (set-marker (ewoc--node-start-marker node) (point))
     524             :           (funcall pp (ewoc--node-data node))
     525             :           (setq node (ewoc--node-next dll node)))))
     526           0 :     (set-marker (ewoc--node-start-marker footer) (point))))
     527             : 
     528             : (defun ewoc-collect (ewoc predicate &rest args)
     529             :   "Select elements from EWOC using PREDICATE.
     530             : Return a list of all selected data elements.
     531             : PREDICATE is a function that takes a data element as its first
     532             : argument.  The elements on the returned list will appear in the
     533             : same order as in the buffer.  You should not rely on the order of
     534             : calls to PREDICATE.
     535             : Note that the buffer the EWOC is displayed in is the current
     536             : buffer when PREDICATE is called.  PREDICATE must restore it if it
     537             : changes it.
     538             : If more than two arguments are given the
     539             : remaining arguments will be passed to PREDICATE."
     540           0 :   (ewoc--set-buffer-bind-dll-let* ewoc
     541             :       ((header (ewoc--header ewoc))
     542             :        (node (ewoc--node-nth dll -2))
     543             :        result)
     544             :     (while (not (eq node header))
     545             :       (if (apply predicate (ewoc--node-data node) args)
     546             :           (push (ewoc--node-data node) result))
     547             :       (setq node (ewoc--node-prev dll node)))
     548           0 :     result))
     549             : 
     550             : (defun ewoc-buffer (ewoc)
     551             :   "Return the buffer that is associated with EWOC.
     552             : Return nil if the buffer has been deleted."
     553           0 :   (let ((buf (ewoc--buffer ewoc)))
     554           0 :     (when (buffer-name buf) buf)))
     555             : 
     556             : (defun ewoc-get-hf (ewoc)
     557             :   "Return a cons cell containing the (HEADER . FOOTER) of EWOC."
     558           0 :   (cons (ewoc--node-data (ewoc--header ewoc))
     559           0 :         (ewoc--node-data (ewoc--footer ewoc))))
     560             : 
     561             : (defun ewoc-set-hf (ewoc header footer)
     562             :   "Set the HEADER and FOOTER of EWOC."
     563           0 :   (ewoc--set-buffer-bind-dll-let* ewoc
     564             :       ((head (ewoc--header ewoc))
     565             :        (foot (ewoc--footer ewoc))
     566             :        (hf-pp (ewoc--hf-pp ewoc)))
     567             :     (setf (ewoc--node-data head) header
     568             :           (ewoc--node-data foot) footer)
     569             :     (save-excursion
     570             :       (ewoc--refresh-node hf-pp head dll)
     571           0 :       (ewoc--refresh-node hf-pp foot dll))))
     572             : 
     573             : 
     574             : (provide 'ewoc)
     575             : 
     576             : ;; Local Variables:
     577             : ;; eval: (put 'ewoc--set-buffer-bind-dll 'lisp-indent-hook 1)
     578             : ;; eval: (put 'ewoc--set-buffer-bind-dll-let* 'lisp-indent-hook 2)
     579             : ;; End:
     580             : 
     581             : ;;; ewoc.el ends here

Generated by: LCOV version 1.12