Add 2012 to FSF copyright years for Emacs files
[bpt/emacs.git] / lisp / emacs-lisp / ewoc.el
CommitLineData
e8af40ee 1;;; ewoc.el --- utility to maintain a view of a list of objects in a buffer
5b467bf4 2
acaf905b 3;; Copyright (C) 1991-2012 Free Software Foundation, Inc.
5b467bf4
SM
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
d6cba7ae 13;; GNU Emacs is free software: you can redistribute it and/or modify
5b467bf4 14;; it under the terms of the GNU General Public License as published by
d6cba7ae
GM
15;; the Free Software Foundation, either version 3 of the License, or
16;; (at your option) any later version.
5b467bf4
SM
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
d6cba7ae 24;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
5b467bf4
SM
25
26;;; Commentary:
27
28;; Ewoc Was Once Cookie
29;; But now it's Emacs' Widget for Object Collections
30
31;; As the name implies this derives from the `cookie' package (part
10c471e6 32;; of Elib). The changes are pervasive though mostly superficial:
5b467bf4 33
10c471e6 34;; - uses CL (and its `defstruct')
5b467bf4
SM
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
83370e6b 54;; others. pcl-cvs.el and vc.el use ewoc.el.
5b467bf4
SM
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.
5b467bf4
SM
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
10c471e6
SM
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
5b467bf4
SM
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;;
0741626e 88;; The Emacs Lisp Reference Manual documents ewoc.el's "public interface".
5b467bf4
SM
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.
5b467bf4
SM
96
97;;; Code:
98
7ece7aba 99(eval-when-compile (require 'cl))
5b467bf4 100
bb7a346f
SM
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".
5b467bf4 103(defstruct (ewoc--node
63910b23 104 (:type vector) ;ewoc--node-nth needs this
7f934f3d 105 (:constructor nil)
5b467bf4
SM
106 (:constructor ewoc--node-create (start-marker data)))
107 left right data start-marker)
108
bb7a346f 109(defun ewoc--node-next (dll node)
5b467bf4 110 "Return the node after NODE, or nil if NODE is the last node."
7dd2e64c 111 (let ((R (ewoc--node-right node)))
bb7a346f 112 (unless (eq dll R) R)))
5b467bf4 113
bb7a346f 114(defun ewoc--node-prev (dll node)
5b467bf4 115 "Return the node before NODE, or nil if NODE is the first node."
7dd2e64c 116 (let ((L (ewoc--node-left node)))
bb7a346f 117 (unless (eq dll L) L)))
7dd2e64c 118
bb7a346f
SM
119(defun ewoc--node-nth (dll n)
120 "Return the Nth node from the doubly linked list `dll'.
7dd2e64c
TTN
121N counts from zero. If N is negative, return the -(N+1)th last element.
122If N is out of range, return nil.
bb7a346f
SM
123Thus, (ewoc--node-nth dll 0) returns the first node,
124and (ewoc--node-nth dll -1) returns the last node."
63910b23 125 ;; Presuming a node is ":type vector", starting with `left' and `right':
5b467bf4
SM
126 ;; Branch 0 ("follow left pointer") is used when n is negative.
127 ;; Branch 1 ("follow right pointer") is used otherwise.
128 (let* ((branch (if (< n 0) 0 1))
bb7a346f 129 (node (aref dll branch)))
5b467bf4 130 (if (< n 0) (setq n (- -1 n)))
bb7a346f 131 (while (and (not (eq dll node)) (> n 0))
63910b23 132 (setq node (aref node branch))
5b467bf4 133 (setq n (1- n)))
bb7a346f 134 (unless (eq dll node) node)))
5b467bf4 135
10c471e6
SM
136(defun ewoc-location (node)
137 "Return the start location of NODE."
138 (ewoc--node-start-marker node))
139
5b467bf4
SM
140\f
141;;; The ewoc data type
142
143(defstruct (ewoc
144 (:constructor nil)
f860b721 145 (:constructor ewoc--create (buffer pretty-printer dll))
5b467bf4 146 (:conc-name ewoc--))
2bbacc0e 147 buffer pretty-printer header footer dll last-node hf-pp)
5b467bf4
SM
148
149(defmacro ewoc--set-buffer-bind-dll-let* (ewoc varlist &rest forms)
150 "Execute FORMS with ewoc--buffer selected as current buffer,
bb7a346f
SM
151`dll' bound to the dll, and VARLIST bound as in a let*.
152`dll' will be bound when VARLIST is initialized, but
7dd2e64c 153the current buffer will *not* have been changed.
5b467bf4 154Return value of last form in FORMS."
b1c36c0f
TTN
155 (let ((hnd (make-symbol "ewoc")))
156 `(let* ((,hnd ,ewoc)
bb7a346f 157 (dll (ewoc--dll ,hnd))
8a946354 158 ,@varlist)
b1c36c0f
TTN
159 (with-current-buffer (ewoc--buffer ,hnd)
160 ,@forms))))
5b467bf4
SM
161
162(defmacro ewoc--set-buffer-bind-dll (ewoc &rest forms)
163 `(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.
167BUT if it is the header or the footer in EWOC return nil instead."
168 (unless (or (eq node (ewoc--header ewoc))
169 (eq node (ewoc--footer ewoc)))
170 node))
171
bb7a346f 172(defun ewoc--adjust (beg end node dll)
60eae434
TTN
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
7dd2e64c 178 ;; call that precedes the call to `ewoc--adjust', and then changing them back
60eae434
TTN
179 ;; to nil.
180 (when (< beg end)
181 (let (m)
182 (while (and (= beg (setq m (ewoc--node-start-marker node)))
bb7a346f
SM
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.
60eae434
TTN
186 (progn
187 (set-marker m end)
bb7a346f 188 (not (eq dll node))))
60eae434
TTN
189 (setq node (ewoc--node-right node))))))
190
f718c2fc 191(defun ewoc--insert-new-node (node data pretty-printer dll)
7f0ea399 192 "Insert before NODE a new node for DATA, displayed by PRETTY-PRINTER.
f718c2fc 193Fourth arg DLL -- from `(ewoc--dll EWOC)' -- is for internal purposes.
7f0ea399
TTN
194Call PRETTY-PRINTER with point at NODE's start, thus pushing back
195NODE and leaving the new node's start there. Return the new node."
5b467bf4 196 (save-excursion
7ece7aba
SM
197 (let ((elemnode (ewoc--node-create
198 (copy-marker (ewoc--node-start-marker node)) data)))
199 (setf (ewoc--node-left elemnode) (ewoc--node-left node)
7f0ea399
TTN
200 (ewoc--node-right elemnode) node
201 (ewoc--node-right (ewoc--node-left node)) elemnode
202 (ewoc--node-left node) elemnode)
bb7a346f 203 (ewoc--refresh-node pretty-printer elemnode dll)
7f0ea399 204 elemnode)))
5b467bf4 205
bb7a346f 206(defun ewoc--refresh-node (pp node dll)
cb3430a1 207 "Redisplay the element represented by NODE using the pretty-printer PP."
60eae434
TTN
208 (let ((inhibit-read-only t)
209 (m (ewoc--node-start-marker node))
210 (R (ewoc--node-right node)))
bfbdb5ca 211 ;; First, remove the string from the buffer:
60eae434 212 (delete-region m (ewoc--node-start-marker R))
bfbdb5ca 213 ;; Calculate and insert the string.
60eae434
TTN
214 (goto-char m)
215 (funcall pp (ewoc--node-data node))
bb7a346f 216 (ewoc--adjust m (point) R dll)))
2bbacc0e
TTN
217
218(defun ewoc--wrap (func)
219 (lexical-let ((ewoc--user-pp func))
220 (lambda (data)
221 (funcall ewoc--user-pp data)
222 (insert "\n"))))
223
5b467bf4
SM
224\f
225;;; ===========================================================================
226;;; Public members of the Ewoc package
227
3fe35897 228;;;###autoload
2bbacc0e 229(defun ewoc-create (pretty-printer &optional header footer nosep)
5b467bf4
SM
230 "Create an empty ewoc.
231
cb3430a1 232The ewoc will be inserted in the current buffer at the current position.
5b467bf4
SM
233
234PRETTY-PRINTER should be a function that takes one argument, an
235element, and inserts a string representing it in the buffer (at
0111ab41 236point). The string PRETTY-PRINTER inserts may be empty or span
60eae434 237several lines. The PRETTY-PRINTER should use `insert', and not
0111ab41
JB
238`insert-before-markers'.
239
60eae434
TTN
240Optional second and third arguments HEADER and FOOTER are strings,
241possibly empty, that will always be present at the top and bottom,
2bbacc0e
TTN
242respectively, of the ewoc.
243
244Normally, a newline is automatically inserted after the header,
245the footer and every node's printed representation. Optional
246fourth arg NOSEP non-nil inhibits this."
2c246c9f
TTN
247 (let* ((dummy-node (ewoc--node-create 'DL-LIST 'DL-LIST))
248 (dll (progn (setf (ewoc--node-right dummy-node) dummy-node)
249 (setf (ewoc--node-left dummy-node) dummy-node)
250 dummy-node))
2bbacc0e 251 (wrap (if nosep 'identity 'ewoc--wrap))
f860b721 252 (new-ewoc (ewoc--create (current-buffer)
2bbacc0e 253 (funcall wrap pretty-printer)
f860b721 254 dll))
2bbacc0e 255 (hf-pp (funcall wrap 'insert))
7f0ea399
TTN
256 (pos (point))
257 head foot)
5b467bf4
SM
258 (ewoc--set-buffer-bind-dll new-ewoc
259 ;; Set default values
260 (unless header (setq header ""))
261 (unless footer (setq footer ""))
7f0ea399 262 (setf (ewoc--node-start-marker dll) (copy-marker pos)
f718c2fc
TTN
263 foot (ewoc--insert-new-node dll footer hf-pp dll)
264 head (ewoc--insert-new-node foot header hf-pp dll)
2bbacc0e 265 (ewoc--hf-pp new-ewoc) hf-pp
7f0ea399
TTN
266 (ewoc--footer new-ewoc) foot
267 (ewoc--header new-ewoc) head))
5b467bf4
SM
268 ;; Return the ewoc
269 new-ewoc))
270
8d1bec8d
TTN
271(defalias 'ewoc-data 'ewoc--node-data
272 "Extract the data encapsulated by NODE and return it.
273
274\(fn NODE)")
5b467bf4 275
bb8d35a2
TTN
276(defun ewoc-set-data (node data)
277 "Set NODE to encapsulate DATA."
278 (setf (ewoc--node-data node) data))
279
5b467bf4 280(defun ewoc-enter-first (ewoc data)
d4ddf783
TTN
281 "Enter DATA first in EWOC.
282Return the new node."
5b467bf4 283 (ewoc--set-buffer-bind-dll ewoc
bb7a346f 284 (ewoc-enter-after ewoc (ewoc--node-nth dll 0) data)))
5b467bf4
SM
285
286(defun ewoc-enter-last (ewoc data)
d4ddf783
TTN
287 "Enter DATA last in EWOC.
288Return the new node."
5b467bf4 289 (ewoc--set-buffer-bind-dll ewoc
bb7a346f 290 (ewoc-enter-before ewoc (ewoc--node-nth dll -1) data)))
5b467bf4 291
5b467bf4 292(defun ewoc-enter-after (ewoc node data)
10c471e6 293 "Enter a new element DATA after NODE in EWOC.
d4ddf783 294Return the new node."
5b467bf4 295 (ewoc--set-buffer-bind-dll ewoc
bb7a346f 296 (ewoc-enter-before ewoc (ewoc--node-next dll node) data)))
5b467bf4
SM
297
298(defun ewoc-enter-before (ewoc node data)
10c471e6 299 "Enter a new element DATA before NODE in EWOC.
d4ddf783 300Return the new node."
5b467bf4 301 (ewoc--set-buffer-bind-dll ewoc
f718c2fc 302 (ewoc--insert-new-node node data (ewoc--pretty-printer ewoc) dll)))
5b467bf4
SM
303
304(defun ewoc-next (ewoc node)
d4ddf783
TTN
305 "Return the node in EWOC that follows NODE.
306Return nil if NODE is nil or the last element."
5b467bf4
SM
307 (when node
308 (ewoc--filter-hf-nodes
bb7a346f 309 ewoc (ewoc--node-next (ewoc--dll ewoc) node))))
5b467bf4
SM
310
311(defun ewoc-prev (ewoc node)
d4ddf783
TTN
312 "Return the node in EWOC that precedes NODE.
313Return nil if NODE is nil or the first element."
5b467bf4
SM
314 (when node
315 (ewoc--filter-hf-nodes
bb7a346f 316 ewoc (ewoc--node-prev (ewoc--dll ewoc) node))))
5b467bf4 317
5b467bf4
SM
318(defun ewoc-nth (ewoc n)
319 "Return the Nth node.
f0529b5b 320N counts from zero. Return nil if there is less than N elements.
5b467bf4 321If N is negative, return the -(N+1)th last element.
7dd2e64c
TTN
322Thus, (ewoc-nth ewoc 0) returns the first node,
323and (ewoc-nth ewoc -1) returns the last node.
8d1bec8d 324Use `ewoc-data' to extract the data from the node."
5b467bf4
SM
325 ;; Skip the header (or footer, if n is negative).
326 (setq n (if (< n 0) (1- n) (1+ n)))
327 (ewoc--filter-hf-nodes ewoc
bb7a346f 328 (ewoc--node-nth (ewoc--dll ewoc) n)))
5b467bf4
SM
329
330(defun ewoc-map (map-function ewoc &rest args)
331 "Apply MAP-FUNCTION to all elements in EWOC.
332MAP-FUNCTION is applied to the first element first.
333If MAP-FUNCTION returns non-nil the element will be refreshed (its
334pretty-printer will be called once again).
335
0111ab41
JB
336Note that the buffer for EWOC will be the current buffer when
337MAP-FUNCTION is called. MAP-FUNCTION must restore the current
338buffer before it returns, if it changes it.
5b467bf4
SM
339
340If more than two arguments are given, the remaining
341arguments will be passed to MAP-FUNCTION."
342 (ewoc--set-buffer-bind-dll-let* ewoc
343 ((footer (ewoc--footer ewoc))
8433d470 344 (pp (ewoc--pretty-printer ewoc))
bb7a346f 345 (node (ewoc--node-nth dll 1)))
bfbdb5ca
TTN
346 (save-excursion
347 (while (not (eq node footer))
348 (if (apply map-function (ewoc--node-data node) args)
bb7a346f
SM
349 (ewoc--refresh-node pp node dll))
350 (setq node (ewoc--node-next dll node))))))
5b467bf4 351
f569c26e
TTN
352(defun ewoc-delete (ewoc &rest nodes)
353 "Delete NODES from EWOC."
354 (ewoc--set-buffer-bind-dll-let* ewoc
ec491f90 355 ((L nil) (R nil) (last (ewoc--last-node ewoc)))
f569c26e
TTN
356 (dolist (node nodes)
357 ;; If we are about to delete the node pointed at by last-node,
358 ;; set last-node to nil.
ec491f90
TTN
359 (when (eq last node)
360 (setf last nil (ewoc--last-node ewoc) nil))
f569c26e 361 (delete-region (ewoc--node-start-marker node)
bb7a346f 362 (ewoc--node-start-marker (ewoc--node-next dll node)))
f569c26e
TTN
363 (set-marker (ewoc--node-start-marker node) nil)
364 (setf L (ewoc--node-left node)
365 R (ewoc--node-right node)
366 ;; Link neighbors to each other.
367 (ewoc--node-right L) R
368 (ewoc--node-left R) L
369 ;; Forget neighbors.
370 (ewoc--node-left node) nil
371 (ewoc--node-right node) nil))))
372
5b467bf4
SM
373(defun ewoc-filter (ewoc predicate &rest args)
374 "Remove all elements in EWOC for which PREDICATE returns nil.
a1506d29 375Note that the buffer for EWOC will be current-buffer when PREDICATE
0111ab41 376is called. PREDICATE must restore the current buffer before it returns
5b467bf4 377if it changes it.
0111ab41 378The PREDICATE is called with the element as its first argument. If any
5b467bf4
SM
379ARGS are given they will be passed to the PREDICATE."
380 (ewoc--set-buffer-bind-dll-let* ewoc
bb7a346f 381 ((node (ewoc--node-nth dll 1))
5b467bf4 382 (footer (ewoc--footer ewoc))
f569c26e 383 (goodbye nil)
2c246c9f 384 (inhibit-read-only t))
5b467bf4 385 (while (not (eq node footer))
5b467bf4 386 (unless (apply predicate (ewoc--node-data node) args)
f569c26e 387 (push node goodbye))
bb7a346f 388 (setq node (ewoc--node-next dll node)))
f569c26e 389 (apply 'ewoc-delete ewoc goodbye)))
5b467bf4 390
44946a4c 391(defun ewoc-locate (ewoc &optional pos guess)
5b467bf4 392 "Return the node that POS (a buffer position) is within.
44946a4c 393POS may be a marker or an integer. It defaults to point.
0111ab41 394GUESS should be a node that it is likely to be near POS.
5b467bf4
SM
395
396If POS points before the first element, the first node is returned.
397If POS points after the last element, the last node is returned.
398If the EWOC is empty, nil is returned."
44946a4c 399 (unless pos (setq pos (point)))
bb7a346f 400 (ewoc--set-buffer-bind-dll ewoc
5b467bf4
SM
401
402 (cond
403 ;; Nothing present?
bb7a346f 404 ((eq (ewoc--node-nth dll 1) (ewoc--node-nth dll -1))
5b467bf4
SM
405 nil)
406
407 ;; Before second elem?
bb7a346f
SM
408 ((< pos (ewoc--node-start-marker (ewoc--node-nth dll 2)))
409 (ewoc--node-nth dll 1))
5b467bf4
SM
410
411 ;; After one-before-last elem?
bb7a346f
SM
412 ((>= pos (ewoc--node-start-marker (ewoc--node-nth dll -2)))
413 (ewoc--node-nth dll -2))
5b467bf4
SM
414
415 ;; We now know that pos is within a elem.
416 (t
417 ;; Make an educated guess about which of the three known
418 ;; node'es (the first, the last, or GUESS) is nearest.
bb7a346f 419 (let* ((best-guess (ewoc--node-nth dll 1))
5b467bf4
SM
420 (distance (abs (- pos (ewoc--node-start-marker best-guess)))))
421 (when guess
422 (let ((d (abs (- pos (ewoc--node-start-marker guess)))))
423 (when (< d distance)
424 (setq distance d)
425 (setq best-guess guess))))
426
bb7a346f 427 (let* ((g (ewoc--node-nth dll -1)) ;Check the last elem
5b467bf4
SM
428 (d (abs (- pos (ewoc--node-start-marker g)))))
429 (when (< d distance)
430 (setq distance d)
431 (setq best-guess g)))
432
7dd2e64c 433 (when (ewoc--last-node ewoc) ;Check "previous".
5b467bf4
SM
434 (let* ((g (ewoc--last-node ewoc))
435 (d (abs (- pos (ewoc--node-start-marker g)))))
436 (when (< d distance)
437 (setq distance d)
438 (setq best-guess g))))
439
440 ;; best-guess is now a "best guess".
441 ;; Find the correct node. First determine in which direction
442 ;; it lies, and then move in that direction until it is found.
a1506d29 443
5b467bf4
SM
444 (cond
445 ;; Is pos after the guess?
446 ((>= pos
447 (ewoc--node-start-marker best-guess))
448 ;; Loop until we are exactly one node too far down...
449 (while (>= pos (ewoc--node-start-marker best-guess))
bb7a346f 450 (setq best-guess (ewoc--node-next dll best-guess)))
5b467bf4 451 ;; ...and return the previous node.
bb7a346f 452 (ewoc--node-prev dll best-guess))
5b467bf4
SM
453
454 ;; Pos is before best-guess
455 (t
456 (while (< pos (ewoc--node-start-marker best-guess))
bb7a346f 457 (setq best-guess (ewoc--node-prev dll best-guess)))
5b467bf4
SM
458 best-guess)))))))
459
460(defun ewoc-invalidate (ewoc &rest nodes)
d4ddf783
TTN
461 "Call EWOC's pretty-printer for each element in NODES.
462Delete current text first, thus effecting a \"refresh\"."
8433d470
TTN
463 (ewoc--set-buffer-bind-dll-let* ewoc
464 ((pp (ewoc--pretty-printer ewoc)))
bfbdb5ca
TTN
465 (save-excursion
466 (dolist (node nodes)
bb7a346f 467 (ewoc--refresh-node pp node dll)))))
5b467bf4 468
44946a4c 469(defun ewoc-goto-prev (ewoc arg)
d4ddf783 470 "Move point to the ARGth previous element in EWOC.
5b467bf4 471Don't move if we are at the first element, or if EWOC is empty.
d4ddf783 472Return the node we moved to."
5b467bf4 473 (ewoc--set-buffer-bind-dll-let* ewoc
6d84ac85 474 ((node (ewoc-locate ewoc (point))))
5b467bf4 475 (when node
44946a4c
SM
476 ;; If we were past the last element, first jump to it.
477 (when (>= (point) (ewoc--node-start-marker (ewoc--node-right node)))
478 (setq arg (1- arg)))
5b467bf4
SM
479 (while (and node (> arg 0))
480 (setq arg (1- arg))
bb7a346f 481 (setq node (ewoc--node-prev dll node)))
5b467bf4
SM
482 ;; Never step above the first element.
483 (unless (ewoc--filter-hf-nodes ewoc node)
bb7a346f 484 (setq node (ewoc--node-nth dll 1)))
5b467bf4
SM
485 (ewoc-goto-node ewoc node))))
486
44946a4c 487(defun ewoc-goto-next (ewoc arg)
d4ddf783
TTN
488 "Move point to the ARGth next element in EWOC.
489Return the node (or nil if we just passed the last node)."
5b467bf4 490 (ewoc--set-buffer-bind-dll-let* ewoc
6d84ac85 491 ((node (ewoc-locate ewoc (point))))
5b467bf4
SM
492 (while (and node (> arg 0))
493 (setq arg (1- arg))
bb7a346f 494 (setq node (ewoc--node-next dll node)))
5b467bf4 495 ;; Never step below the first element.
44946a4c 496 ;; (unless (ewoc--filter-hf-nodes ewoc node)
bb7a346f 497 ;; (setq node (ewoc--node-nth dll -2)))
a918ed9b
BR
498 (unless node
499 (error "No next"))
5b467bf4
SM
500 (ewoc-goto-node ewoc node)))
501
502(defun ewoc-goto-node (ewoc node)
d4ddf783 503 "Move point to NODE in EWOC."
5b467bf4
SM
504 (ewoc--set-buffer-bind-dll ewoc
505 (goto-char (ewoc--node-start-marker node))
506 (if goal-column (move-to-column goal-column))
507 (setf (ewoc--last-node ewoc) node)))
508
509(defun ewoc-refresh (ewoc)
510 "Refresh all data in EWOC.
511The pretty-printer that was specified when the EWOC was created
512will be called for all elements in EWOC.
513Note that `ewoc-invalidate' is more efficient if only a small
514number of elements needs to be refreshed."
515 (ewoc--set-buffer-bind-dll-let* ewoc
cb3430a1 516 ((footer (ewoc--footer ewoc)))
5b467bf4 517 (let ((inhibit-read-only t))
bb7a346f 518 (delete-region (ewoc--node-start-marker (ewoc--node-nth dll 1))
5b467bf4
SM
519 (ewoc--node-start-marker footer))
520 (goto-char (ewoc--node-start-marker footer))
340d9945 521 (let ((pp (ewoc--pretty-printer ewoc))
bb7a346f 522 (node (ewoc--node-nth dll 1)))
5b467bf4
SM
523 (while (not (eq node footer))
524 (set-marker (ewoc--node-start-marker node) (point))
340d9945 525 (funcall pp (ewoc--node-data node))
bb7a346f 526 (setq node (ewoc--node-next dll node)))))
5b467bf4
SM
527 (set-marker (ewoc--node-start-marker footer) (point))))
528
529(defun ewoc-collect (ewoc predicate &rest args)
530 "Select elements from EWOC using PREDICATE.
531Return a list of all selected data elements.
0111ab41
JB
532PREDICATE is a function that takes a data element as its first
533argument. The elements on the returned list will appear in the
534same order as in the buffer. You should not rely on the order of
535calls to PREDICATE.
536Note that the buffer the EWOC is displayed in is the current
537buffer when PREDICATE is called. PREDICATE must restore it if it
538changes it.
5b467bf4
SM
539If more than two arguments are given the
540remaining arguments will be passed to PREDICATE."
541 (ewoc--set-buffer-bind-dll-let* ewoc
542 ((header (ewoc--header ewoc))
bb7a346f 543 (node (ewoc--node-nth dll -2))
5b467bf4
SM
544 result)
545 (while (not (eq node header))
546 (if (apply predicate (ewoc--node-data node) args)
547 (push (ewoc--node-data node) result))
bb7a346f 548 (setq node (ewoc--node-prev dll node)))
d5337506 549 result))
5b467bf4
SM
550
551(defun ewoc-buffer (ewoc)
552 "Return the buffer that is associated with EWOC.
d4ddf783 553Return nil if the buffer has been deleted."
5b467bf4
SM
554 (let ((buf (ewoc--buffer ewoc)))
555 (when (buffer-name buf) buf)))
556
cb3430a1
SM
557(defun ewoc-get-hf (ewoc)
558 "Return a cons cell containing the (HEADER . FOOTER) of EWOC."
559 (cons (ewoc--node-data (ewoc--header ewoc))
560 (ewoc--node-data (ewoc--footer ewoc))))
561
562(defun ewoc-set-hf (ewoc header footer)
563 "Set the HEADER and FOOTER of EWOC."
60eae434
TTN
564 (ewoc--set-buffer-bind-dll-let* ewoc
565 ((head (ewoc--header ewoc))
2bbacc0e
TTN
566 (foot (ewoc--footer ewoc))
567 (hf-pp (ewoc--hf-pp ewoc)))
60eae434
TTN
568 (setf (ewoc--node-data head) header
569 (ewoc--node-data foot) footer)
570 (save-excursion
bb7a346f
SM
571 (ewoc--refresh-node hf-pp head dll)
572 (ewoc--refresh-node hf-pp foot dll))))
cb3430a1 573
5b467bf4
SM
574\f
575(provide 'ewoc)
576
7ece7aba
SM
577;; Local Variables:
578;; eval: (put 'ewoc--set-buffer-bind-dll 'lisp-indent-hook 1)
579;; eval: (put 'ewoc--set-buffer-bind-dll-let* 'lisp-indent-hook 2)
580;; End:
5b467bf4
SM
581
582;;; ewoc.el ends here