diff options
author | Stefan Monnier <monnier@iro.umontreal.ca> | 2000-03-11 03:51:31 +0000 |
---|---|---|
committer | Stefan Monnier <monnier@iro.umontreal.ca> | 2000-03-11 03:51:31 +0000 |
commit | 5b467bf4e2787e3290280cadbae9e915df88dacd (patch) | |
tree | 83e838669d3052e213f8f518602bae5ec0cf0a15 /lisp/emacs-lisp/ewoc.el | |
parent | afa18a4e5d28a418fa9374c96be75a8e20f5fe08 (diff) | |
download | emacs-5b467bf4e2787e3290280cadbae9e915df88dacd.tar.gz |
*** empty log message ***
Diffstat (limited to 'lisp/emacs-lisp/ewoc.el')
-rw-r--r-- | lisp/emacs-lisp/ewoc.el | 620 |
1 files changed, 620 insertions, 0 deletions
diff --git a/lisp/emacs-lisp/ewoc.el b/lisp/emacs-lisp/ewoc.el new file mode 100644 index 00000000000..2af8dd49298 --- /dev/null +++ b/lisp/emacs-lisp/ewoc.el @@ -0,0 +1,620 @@ +;;; ewoc.el -- Utility to maintain a view of a list of objects in a buffer + +;; Copyright (C) 1991-2000 Free Software Foundation + +;; Author: Per Cederqvist <ceder@lysator.liu.se> +;; Inge Wallin <inge@lysator.liu.se> +;; Maintainer: monnier@gnu.org +;; Created: 3 Aug 1992 +;; Keywords: extensions, lisp + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; Ewoc Was Once Cookie +;; But now it's Emacs' Widget for Object Collections + +;; As the name implies this derives from the `cookie' package (part +;; of Elib). The changes are mostly superficial: + +;; - uses CL (and its `defstruct' +;; - separate from Elib. +;; - uses its own version of a doubly-linked list which allows us +;; to merge the elib-wrapper and the elib-node structures into ewoc-node +;; - dropping functions not used by PCL-CVS (the only client of ewoc at the +;; time of writing) +;; - removing unused arguments +;; - renaming: +;; elib-node ==> ewoc--node +;; collection ==> ewoc +;; tin ==> ewoc--node +;; cookie ==> data or element or elem + +;; Introduction +;; ============ +;; +;; Ewoc is a package that implements a connection between an +;; dll (a doubly linked list) and the contents of a buffer. +;; Possible uses are dired (have all files in a list, and show them), +;; buffer-list, kom-prioritize (in the LysKOM elisp client) and +;; others. pcl-cvs.el uses ewoc.el. +;; +;; Ewoc can be considered as the `view' part of a model-view-controller. +;; +;; A `element' can be any lisp object. When you use the ewoc +;; package you specify a pretty-printer, a function that inserts +;; a printable representation of the element in the buffer. (The +;; pretty-printer should use "insert" and not +;; "insert-before-markers"). +;; +;; A `ewoc' consists of a doubly linked list of elements, a +;; header, a footer and a pretty-printer. It is displayed at a +;; certain point in a certain buffer. (The buffer and point are +;; fixed when the ewoc is created). The header and the footer +;; are constant strings. They appear before and after the elements. +;; (Currently, once set, they can not be changed). +;; +;; Ewoc does not affect the mode of the buffer in any way. It +;; merely makes it easy to connect an underlying data representation +;; to the buffer contents. +;; +;; A `ewoc--node' is an object that contains one element. There are +;; functions in this package that given an ewoc--node extracts the data, or +;; gives the next or previous ewoc--node. (All ewoc--nodes are linked together +;; in a doubly linked list. The 'previous' ewoc--node is the one that appears +;; before the other in the buffer.) You should not do anything with +;; an ewoc--node except pass it to the functions in this package. +;; +;; An ewoc is a very dynamic thing. You can easily add or delete elements. +;; You can apply a function to all elements in an ewoc, etc, etc. +;; +;; Remember that an element can be anything. Your imagination is the +;; limit! It is even possible to have another ewoc as an +;; element. In that way some kind of tree hierarchy can be created. +;; +;; Full documentation will, God willing, soon be available in a +;; Texinfo manual. + +;; In the mean time `grep '^(.*ewoc-[^-]' emacs-lisp/ewoc.el' can help +;; you find all the exported functions: +;; +;; (defun ewoc-create (buffer pretty-printer &optional header footer pos) +;; (defalias 'ewoc-data 'ewoc--node-data) +;; (defun ewoc-enter-first (ewoc data) +;; (defun ewoc-enter-last (ewoc data) +;; (defun ewoc-enter-after (ewoc node data) +;; (defun ewoc-enter-before (ewoc node data) +;; (defun ewoc-next (ewoc node) +;; (defun ewoc-prev (ewoc node) +;; (defun ewoc-nth (ewoc n) +;; (defun ewoc-map (map-function ewoc &rest args) +;; (defun ewoc-filter (ewoc predicate &rest args) +;; (defun ewoc-locate (ewoc pos &optional guess) +;; (defun ewoc-invalidate (ewoc &rest nodes) +;; (defun ewoc-goto-prev (ewoc pos arg) +;; (defun ewoc-goto-next (ewoc pos arg) +;; (defun ewoc-goto-node (ewoc node) +;; (defun ewoc-refresh (ewoc) +;; (defun ewoc-collect (ewoc predicate &rest args) +;; (defun ewoc-buffer (ewoc) + + +;; Coding conventions +;; ================== +;; +;; All functions of course start with `ewoc'. Functions and macros +;; starting with the prefix `ewoc--' are meant for internal use, +;; while those starting with `ewoc-' are exported for public use. +;; There are currently no global or buffer-local variables used. + + +;;; Code: + +(eval-when-compile (require 'cl)) ;because of CL compiler macros + +;; The doubly linked list is implemented as a circular list +;; with a dummy node first and last. The dummy node is used as +;; "the dll" (or rather is the dll handle passed around). + +(defstruct (ewoc--node + (:type vector) ;required for ewoc--node-branch hack + (:constructor ewoc--node-create (start-marker data))) + left right data start-marker) + +(defalias 'ewoc--node-branch 'aref) + +(defun ewoc--dll-create () + "Create an empty doubly linked list." + (let ((dummy-node (ewoc--node-create 'DL-LIST 'DL-LIST))) + (setf (ewoc--node-right dummy-node) dummy-node) + (setf (ewoc--node-left dummy-node) dummy-node) + dummy-node)) + +(defun ewoc--node-enter-before (node elemnode) + "Insert ELEMNODE before NODE in a DLL." + (assert (and (null (ewoc--node-left elemnode)) (null (ewoc--node-right elemnode)))) + (setf (ewoc--node-left elemnode) (ewoc--node-left node)) + (setf (ewoc--node-right elemnode) node) + (setf (ewoc--node-right (ewoc--node-left node)) elemnode) + (setf (ewoc--node-left node) elemnode)) + +(defun ewoc--node-enter-first (dll node) + "Add a free floating NODE first in DLL." + (ewoc--node-enter-before (ewoc--node-right dll) node)) + +(defun ewoc--node-enter-last (dll node) + "Add a free floating NODE last in DLL." + (ewoc--node-enter-before dll node)) + +(defun ewoc--node-next (dll node) + "Return the node after NODE, or nil if NODE is the last node." + (unless (eq (ewoc--node-right node) dll) (ewoc--node-right node))) + +(defun ewoc--node-prev (dll node) + "Return the node before NODE, or nil if NODE is the first node." + (unless (eq (ewoc--node-left node) dll) (ewoc--node-left node))) + +(defun ewoc--node-delete (node) + "Unbind NODE from its doubly linked list and return it." + ;; This is a no-op when applied to the dummy node. This will return + ;; nil if applied to the dummy node since it always contains nil. + (setf (ewoc--node-right (ewoc--node-left node)) (ewoc--node-right node)) + (setf (ewoc--node-left (ewoc--node-right node)) (ewoc--node-left node)) + (setf (ewoc--node-left node) nil) + (setf (ewoc--node-right node) nil) + node) + +(defun ewoc--node-nth (dll n) + "Return the Nth node from the doubly linked list DLL. +N counts from zero. If DLL is not that long, nil is returned. +If N is negative, return the -(N+1)th last element. +Thus, (ewoc--node-nth dll 0) returns the first node, +and (ewoc--node-nth dll -1) returns the last node." + ;; Branch 0 ("follow left pointer") is used when n is negative. + ;; Branch 1 ("follow right pointer") is used otherwise. + (let* ((branch (if (< n 0) 0 1)) + (node (ewoc--node-branch dll branch))) + (if (< n 0) (setq n (- -1 n))) + (while (and (not (eq dll node)) (> n 0)) + (setq node (ewoc--node-branch node branch)) + (setq n (1- n))) + (unless (eq dll node) node))) + + +;;; The ewoc data type + +(defstruct (ewoc + (:constructor nil) + (:constructor ewoc--create + (buffer pretty-printer header footer dll)) + (:conc-name ewoc--)) + buffer pretty-printer header footer dll last-node) + +(defmacro ewoc--set-buffer-bind-dll-let* (ewoc varlist &rest forms) + "Execute FORMS with ewoc--buffer selected as current buffer, +dll bound to ewoc--dll, and VARLIST bound as in a let*. +dll will be bound when VARLIST is initialized, but the current +buffer will *not* have been changed. +Return value of last form in FORMS." + (let ((old-buffer (make-symbol "old-buffer")) + (hnd (make-symbol "ewoc"))) + (` (let* (((, old-buffer) (current-buffer)) + ((, hnd) (, ewoc)) + (dll (ewoc--dll (, hnd))) + (,@ varlist)) + (set-buffer (ewoc--buffer (, hnd))) + (unwind-protect + (progn (,@ forms)) + (set-buffer (, old-buffer))))))) + +(defmacro ewoc--set-buffer-bind-dll (ewoc &rest forms) + `(ewoc--set-buffer-bind-dll-let* ,ewoc nil ,@forms)) + +(defsubst ewoc--filter-hf-nodes (ewoc node) + "Evaluate NODE once and return it. +BUT if it is the header or the footer in EWOC return nil instead." + (unless (or (eq node (ewoc--header ewoc)) + (eq node (ewoc--footer ewoc))) + node)) + + +(defun ewoc--create-special-node (data string pos) + "Insert STRING at POS in current buffer. Remember the start +position. Create a wrapper containing that start position and the +element DATA." + (save-excursion + ;; Remember the position as a number so that it doesn't move + ;; when we insert the string. + (when (markerp pos) (setq pos (marker-position pos))) + (goto-char pos) + (let ((inhibit-read-only t)) + ;; Use insert-before-markers so that the marker for the + ;; next element is updated. + (insert-before-markers string) + ;; Always insert a newline. You want invisible elements? You + ;; lose. (At least in this version). FIXME-someday. (It is + ;; harder to fix than it might seem. All markers have to point + ;; to the right place all the time...) + (insert-before-markers ?\n) + (ewoc--node-create (copy-marker pos) data)))) + + +(defun ewoc--create-node (data pretty-printer pos) + "Call PRETTY-PRINTER with point set at POS in current buffer. +Remember the start position. Create a wrapper containing that +start position and the element DATA." + (save-excursion + ;; Remember the position as a number so that it doesn't move + ;; when we insert the string. + (when (markerp pos) (setq pos (marker-position pos))) + (goto-char pos) + (let ((inhibit-read-only t)) + ;; Insert the trailing newline using insert-before-markers + ;; so that the start position for the next element is updated. + (insert-before-markers ?\n) + ;; Move back, and call the pretty-printer. + (backward-char 1) + (funcall pretty-printer data) + (ewoc--node-create (copy-marker pos) data)))) + + +(defun ewoc--delete-node-internal (ewoc node) + "Delete a data string from EWOC. +Can not be used on the footer. Returns the wrapper that is deleted. +The start-marker in the wrapper is set to nil, so that it doesn't +consume any more resources." + (let ((dll (ewoc--dll ewoc)) + (inhibit-read-only t)) + ;; If we are about to delete the node pointed at by last-node, + ;; set last-node to nil. + (if (eq (ewoc--last-node ewoc) node) + (setf (ewoc--last-node ewoc) nil)) + + (delete-region (ewoc--node-start-marker node) + (ewoc--node-start-marker (ewoc--node-next dll node))) + (set-marker (ewoc--node-start-marker node) nil) + ;; Delete the node, and return the wrapper. + (ewoc--node-delete node))) + + +(defvar dll) ;passed by dynamic binding + +(defun ewoc--refresh-node (ewoc node) + "Redisplay the element represented by NODE. +Can not be used on the footer. dll *must* be bound to +\(ewoc--dll ewoc)." + (let ((inhibit-read-only t)) + (save-excursion + ;; First, remove the string from the buffer: + (delete-region (ewoc--node-start-marker node) + (1- (marker-position + (ewoc--node-start-marker (ewoc--node-next dll node))))) + ;; Calculate and insert the string. + (goto-char (ewoc--node-start-marker node)) + (funcall (ewoc--pretty-printer ewoc) + (ewoc--node-data node))))) + +;;; =========================================================================== +;;; Public members of the Ewoc package + + +(defun ewoc-create (buffer pretty-printer &optional header footer pos) + "Create an empty ewoc. + +The ewoc will be inserted in BUFFER. BUFFER may be a +buffer or a buffer name. It is created if it does not exist. + +PRETTY-PRINTER should be a function that takes one argument, an +element, and inserts a string representing it in the buffer (at +point). The string PRETTY-PRINTER inserts may be empty or span +several linse. A trailing newline will always be inserted +automatically. The PRETTY-PRINTER should use insert, and not +insert-before-markers. + +Optional third argument HEADER is a string that will always be +present at the top of the ewoc. HEADER should end with a +newline. Optionaly fourth argument FOOTER is similar, and will +always be inserted at the bottom of the ewoc. + +Optional fifth argument POS is a buffer position, specifying +where the ewoc will be inserted. It defaults to the +beginning of the buffer." + (let ((new-ewoc + (ewoc--create (get-buffer-create buffer) + pretty-printer nil nil (ewoc--dll-create)))) + (ewoc--set-buffer-bind-dll new-ewoc + ;; Set default values + (unless header (setq header "")) + (unless footer (setq footer "")) + (unless pos (setq pos (point-min))) + ;; Force header to be above footer. + (if (markerp pos) (setq pos (marker-position pos))) + (let ((foot (ewoc--create-special-node footer footer pos)) + (head (ewoc--create-special-node header header pos))) + (ewoc--node-enter-first dll head) + (ewoc--node-enter-last dll foot) + (setf (ewoc--header new-ewoc) (ewoc--node-nth dll 0)) + (setf (ewoc--footer new-ewoc) (ewoc--node-nth dll -1)))) + ;; Return the ewoc + new-ewoc)) + +(defalias 'ewoc-data 'ewoc--node-data) + +(defun ewoc-enter-first (ewoc data) + "Enter DATA first in EWOC." + (ewoc--set-buffer-bind-dll ewoc + (ewoc-enter-after ewoc (ewoc--node-nth dll 0) data))) + +(defun ewoc-enter-last (ewoc data) + "Enter DATA last in EWOC." + (ewoc--set-buffer-bind-dll ewoc + (ewoc-enter-before ewoc (ewoc--node-nth dll -1) data))) + + +(defun ewoc-enter-after (ewoc node data) + "Enter a new element DATA after NODE in EWOC." + (ewoc--set-buffer-bind-dll ewoc + (ewoc-enter-before ewoc (ewoc--node-next dll node) data))) + +(defun ewoc-enter-before (ewoc node data) + "Enter a new element DATA before NODE in EWOC." + (ewoc--set-buffer-bind-dll ewoc + (ewoc--node-enter-before + node + (ewoc--create-node + data + (ewoc--pretty-printer ewoc) + (ewoc--node-start-marker node))))) + +(defun ewoc-next (ewoc node) + "Get the next node. +Returns nil if NODE is nil or the last element." + (when node + (ewoc--filter-hf-nodes + ewoc (ewoc--node-next (ewoc--dll ewoc) node)))) + +(defun ewoc-prev (ewoc node) + "Get the previous node. +Returns nil if NODE is nil or the first element." + (when node + (ewoc--filter-hf-nodes + ewoc + (ewoc--node-prev (ewoc--dll ewoc) node)))) + + +(defun ewoc-nth (ewoc n) + "Return the Nth node. +N counts from zero. Nil is returned if there is less than N elements. +If N is negative, return the -(N+1)th last element. +Thus, (ewoc-nth dll 0) returns the first node, +and (ewoc-nth dll -1) returns the last node. +Use `ewoc--node-data' to extract the data from the node." + ;; Skip the header (or footer, if n is negative). + (setq n (if (< n 0) (1- n) (1+ n))) + (ewoc--filter-hf-nodes ewoc + (ewoc--node-nth (ewoc--dll ewoc) n))) + +(defun ewoc-map (map-function ewoc &rest args) + "Apply MAP-FUNCTION to all elements in EWOC. +MAP-FUNCTION is applied to the first element first. +If MAP-FUNCTION returns non-nil the element will be refreshed (its +pretty-printer will be called once again). + +Note that the buffer for EWOC will be current buffer when MAP-FUNCTION +is called. MAP-FUNCTION must restore the current buffer to BUFFER before +it returns, if it changes it. + +If more than two arguments are given, the remaining +arguments will be passed to MAP-FUNCTION." + (ewoc--set-buffer-bind-dll-let* ewoc + ((footer (ewoc--footer ewoc)) + (node (ewoc--node-nth dll 1))) + (while (not (eq node footer)) + (if (apply map-function (ewoc--node-data node) args) + (ewoc--refresh-node ewoc node)) + (setq node (ewoc--node-next dll node))))) + +(defun ewoc-filter (ewoc predicate &rest args) + "Remove all elements in EWOC for which PREDICATE returns nil. +Note that the buffer for EWOC will be current-buffer when PREDICATE +is called. PREDICATE must restore the current buffer before it returns +if it changes it. +The PREDICATE is called with the element as its first argument. If any +ARGS are given they will be passed to the PREDICATE." + (ewoc--set-buffer-bind-dll-let* ewoc + ((node (ewoc--node-nth dll 1)) + (footer (ewoc--footer ewoc)) + (next nil)) + (while (not (eq node footer)) + (setq next (ewoc--node-next dll node)) + (unless (apply predicate (ewoc--node-data node) args) + (ewoc--delete-node-internal ewoc node)) + (setq node next)))) + +(defun ewoc-locate (ewoc pos &optional guess) + "Return the node that POS (a buffer position) is within. +POS may be a marker or an integer. +GUESS should be a node that it is likely that POS is near. + +If POS points before the first element, the first node is returned. +If POS points after the last element, the last node is returned. +If the EWOC is empty, nil is returned." + (ewoc--set-buffer-bind-dll-let* ewoc + ((footer (ewoc--footer ewoc))) + + (cond + ;; Nothing present? + ((eq (ewoc--node-nth dll 1) (ewoc--node-nth dll -1)) + nil) + + ;; Before second elem? + ((< pos (ewoc--node-start-marker (ewoc--node-nth dll 2))) + (ewoc--node-nth dll 1)) + + ;; After one-before-last elem? + ((>= pos (ewoc--node-start-marker (ewoc--node-nth dll -2))) + (ewoc--node-nth dll -2)) + + ;; We now know that pos is within a elem. + (t + ;; Make an educated guess about which of the three known + ;; node'es (the first, the last, or GUESS) is nearest. + (let* ((best-guess (ewoc--node-nth dll 1)) + (distance (abs (- pos (ewoc--node-start-marker best-guess))))) + (when guess + (let ((d (abs (- pos (ewoc--node-start-marker guess))))) + (when (< d distance) + (setq distance d) + (setq best-guess guess)))) + + (let* ((g (ewoc--node-nth dll -1)) ;Check the last elem + (d (abs (- pos (ewoc--node-start-marker g))))) + (when (< d distance) + (setq distance d) + (setq best-guess g))) + + (when (ewoc--last-node ewoc) ;Check "previous". + (let* ((g (ewoc--last-node ewoc)) + (d (abs (- pos (ewoc--node-start-marker g))))) + (when (< d distance) + (setq distance d) + (setq best-guess g)))) + + ;; best-guess is now a "best guess". + ;; Find the correct node. First determine in which direction + ;; it lies, and then move in that direction until it is found. + + (cond + ;; Is pos after the guess? + ((>= pos + (ewoc--node-start-marker best-guess)) + ;; Loop until we are exactly one node too far down... + (while (>= pos (ewoc--node-start-marker best-guess)) + (setq best-guess (ewoc--node-next dll best-guess))) + ;; ...and return the previous node. + (ewoc--node-prev dll best-guess)) + + ;; Pos is before best-guess + (t + (while (< pos (ewoc--node-start-marker best-guess)) + (setq best-guess (ewoc--node-prev dll best-guess))) + best-guess))))))) + +(defun ewoc-invalidate (ewoc &rest nodes) + "Refresh some elements. +The pretty-printer that for EWOC will be called for all NODES." + (ewoc--set-buffer-bind-dll ewoc + (dolist (node nodes) + (ewoc--refresh-node ewoc node)))) + +(defun ewoc-goto-prev (ewoc pos arg) + "Move point to the ARGth previous element. +Don't move if we are at the first element, or if EWOC is empty. +Returns the node we moved to." + (ewoc--set-buffer-bind-dll-let* ewoc + ((node (ewoc-locate ewoc pos (ewoc--last-node ewoc)))) + (when node + (while (and node (> arg 0)) + (setq arg (1- arg)) + (setq node (ewoc--node-prev dll node))) + ;; Never step above the first element. + (unless (ewoc--filter-hf-nodes ewoc node) + (setq node (ewoc--node-nth dll 1))) + (ewoc-goto-node ewoc node)))) + +(defun ewoc-goto-next (ewoc pos arg) + "Move point to the ARGth next element. +Don't move if we are at the last element. +Returns the node." + (ewoc--set-buffer-bind-dll-let* ewoc + ((node (ewoc-locate ewoc pos (ewoc--last-node ewoc)))) + (while (and node (> arg 0)) + (setq arg (1- arg)) + (setq node (ewoc--node-next dll node))) + ;; Never step below the first element. + (unless (ewoc--filter-hf-nodes ewoc node) + (setq node (ewoc--node-nth dll -2))) + (ewoc-goto-node ewoc node))) + +(defun ewoc-goto-node (ewoc node) + "Move point to NODE." + (ewoc--set-buffer-bind-dll ewoc + (goto-char (ewoc--node-start-marker node)) + (if goal-column (move-to-column goal-column)) + (setf (ewoc--last-node ewoc) node))) + +(defun ewoc-refresh (ewoc) + "Refresh all data in EWOC. +The pretty-printer that was specified when the EWOC was created +will be called for all elements in EWOC. +Note that `ewoc-invalidate' is more efficient if only a small +number of elements needs to be refreshed." + (ewoc--set-buffer-bind-dll-let* ewoc + ((header (ewoc--header ewoc)) + (footer (ewoc--footer ewoc))) + (let ((inhibit-read-only t)) + (delete-region (ewoc--node-start-marker (ewoc--node-nth dll 1)) + (ewoc--node-start-marker footer)) + (goto-char (ewoc--node-start-marker footer)) + (let ((node (ewoc--node-nth dll 1))) + (while (not (eq node footer)) + (set-marker (ewoc--node-start-marker node) (point)) + (funcall (ewoc--pretty-printer ewoc) + (ewoc--node-data node)) + (insert "\n") + (setq node (ewoc--node-next dll node))))) + (set-marker (ewoc--node-start-marker footer) (point)))) + +(defun ewoc-collect (ewoc predicate &rest args) + "Select elements from EWOC using PREDICATE. +Return a list of all selected data elements. +PREDICATE is a function that takes a data element as its first argument. +The elements on the returned list will appear in the same order as in +the buffer. You should not rely on in which order PREDICATE is +called. +Note that the buffer the EWOC is displayed in is current-buffer +when PREDICATE is called. If PREDICATE must restore current-buffer if +it changes it. +If more than two arguments are given the +remaining arguments will be passed to PREDICATE." + (ewoc--set-buffer-bind-dll-let* ewoc + ((header (ewoc--header ewoc)) + (node (ewoc--node-nth dll -2)) + result) + (while (not (eq node header)) + (if (apply predicate (ewoc--node-data node) args) + (push (ewoc--node-data node) result)) + (setq node (ewoc--node-prev dll node))) + result)) + +(defun ewoc-buffer (ewoc) + "Return the buffer that is associated with EWOC. +Returns nil if the buffer has been deleted." + (let ((buf (ewoc--buffer ewoc))) + (when (buffer-name buf) buf))) + + +(provide 'ewoc) + +;;; Local Variables: +;;; eval: (put 'ewoc--set-buffer-bind-dll 'lisp-indent-hook 1) +;;; eval: (put 'ewoc--set-buffer-bind-dll-let* 'lisp-indent-hook 2) +;;; End: + +;;; ewoc.el ends here |