autoloading eval-when forms
[bpt/emacs.git] / lisp / emacs-lisp / ewoc.el
CommitLineData
e95a67dc 1;;; ewoc.el --- utility to maintain a view of a list of objects in a buffer -*- lexical-binding: t -*-
5b467bf4 2
ba318903 3;; Copyright (C) 1991-2014 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
44e97401 29;; But now it's Emacs's Widget for Object Collections
5b467bf4
SM
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
f80efb86 99(eval-when-compile (require 'cl-lib))
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".
f80efb86 103(cl-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
f80efb86 143(cl-defstruct (ewoc
5b467bf4 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)))
2ee3d7f0
SM
199 (setf (ewoc--node-left elemnode) (ewoc--node-left node)
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)
e95a67dc
SM
219 (lambda (data)
220 (funcall func data)
221 (insert "\n")))
2bbacc0e 222
5b467bf4
SM
223\f
224;;; ===========================================================================
225;;; Public members of the Ewoc package
226
3fe35897 227;;;###autoload
2bbacc0e 228(defun ewoc-create (pretty-printer &optional header footer nosep)
5b467bf4
SM
229 "Create an empty ewoc.
230
cb3430a1 231The ewoc will be inserted in the current buffer at the current position.
5b467bf4
SM
232
233PRETTY-PRINTER should be a function that takes one argument, an
234element, and inserts a string representing it in the buffer (at
0111ab41 235point). The string PRETTY-PRINTER inserts may be empty or span
60eae434 236several lines. The PRETTY-PRINTER should use `insert', and not
0111ab41
JB
237`insert-before-markers'.
238
60eae434
TTN
239Optional second and third arguments HEADER and FOOTER are strings,
240possibly empty, that will always be present at the top and bottom,
2bbacc0e
TTN
241respectively, of the ewoc.
242
243Normally, a newline is automatically inserted after the header,
244the footer and every node's printed representation. Optional
245fourth arg NOSEP non-nil inhibits this."
2c246c9f 246 (let* ((dummy-node (ewoc--node-create 'DL-LIST 'DL-LIST))
2ee3d7f0
SM
247 (dll (progn (setf (ewoc--node-right dummy-node) dummy-node)
248 (setf (ewoc--node-left dummy-node) dummy-node)
2c246c9f 249 dummy-node))
2bbacc0e 250 (wrap (if nosep 'identity 'ewoc--wrap))
f860b721 251 (new-ewoc (ewoc--create (current-buffer)
2bbacc0e 252 (funcall wrap pretty-printer)
f860b721 253 dll))
2bbacc0e 254 (hf-pp (funcall wrap 'insert))
7f0ea399
TTN
255 (pos (point))
256 head foot)
5b467bf4
SM
257 (ewoc--set-buffer-bind-dll new-ewoc
258 ;; Set default values
259 (unless header (setq header ""))
260 (unless footer (setq footer ""))
2ee3d7f0
SM
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 (ewoc--header new-ewoc) head))
5b467bf4
SM
267 ;; Return the ewoc
268 new-ewoc))
269
8d1bec8d
TTN
270(defalias 'ewoc-data 'ewoc--node-data
271 "Extract the data encapsulated by NODE and return it.
272
273\(fn NODE)")
5b467bf4 274
bb8d35a2
TTN
275(defun ewoc-set-data (node data)
276 "Set NODE to encapsulate DATA."
2ee3d7f0 277 (setf (ewoc--node-data node) data))
bb8d35a2 278
5b467bf4 279(defun ewoc-enter-first (ewoc data)
d4ddf783
TTN
280 "Enter DATA first in EWOC.
281Return the new node."
5b467bf4 282 (ewoc--set-buffer-bind-dll ewoc
bb7a346f 283 (ewoc-enter-after ewoc (ewoc--node-nth dll 0) data)))
5b467bf4
SM
284
285(defun ewoc-enter-last (ewoc data)
d4ddf783
TTN
286 "Enter DATA last in EWOC.
287Return the new node."
5b467bf4 288 (ewoc--set-buffer-bind-dll ewoc
bb7a346f 289 (ewoc-enter-before ewoc (ewoc--node-nth dll -1) data)))
5b467bf4 290
5b467bf4 291(defun ewoc-enter-after (ewoc node data)
10c471e6 292 "Enter a new element DATA after NODE in EWOC.
d4ddf783 293Return the new node."
5b467bf4 294 (ewoc--set-buffer-bind-dll ewoc
bb7a346f 295 (ewoc-enter-before ewoc (ewoc--node-next dll node) data)))
5b467bf4
SM
296
297(defun ewoc-enter-before (ewoc node data)
10c471e6 298 "Enter a new element DATA before NODE in EWOC.
d4ddf783 299Return the new node."
5b467bf4 300 (ewoc--set-buffer-bind-dll ewoc
f718c2fc 301 (ewoc--insert-new-node node data (ewoc--pretty-printer ewoc) dll)))
5b467bf4
SM
302
303(defun ewoc-next (ewoc node)
d4ddf783
TTN
304 "Return the node in EWOC that follows NODE.
305Return nil if NODE is nil or the last element."
5b467bf4
SM
306 (when node
307 (ewoc--filter-hf-nodes
bb7a346f 308 ewoc (ewoc--node-next (ewoc--dll ewoc) node))))
5b467bf4
SM
309
310(defun ewoc-prev (ewoc node)
d4ddf783
TTN
311 "Return the node in EWOC that precedes NODE.
312Return nil if NODE is nil or the first element."
5b467bf4
SM
313 (when node
314 (ewoc--filter-hf-nodes
bb7a346f 315 ewoc (ewoc--node-prev (ewoc--dll ewoc) node))))
5b467bf4 316
5b467bf4
SM
317(defun ewoc-nth (ewoc n)
318 "Return the Nth node.
f0529b5b 319N counts from zero. Return nil if there is less than N elements.
5b467bf4 320If N is negative, return the -(N+1)th last element.
7dd2e64c
TTN
321Thus, (ewoc-nth ewoc 0) returns the first node,
322and (ewoc-nth ewoc -1) returns the last node.
8d1bec8d 323Use `ewoc-data' to extract the data from the node."
5b467bf4
SM
324 ;; Skip the header (or footer, if n is negative).
325 (setq n (if (< n 0) (1- n) (1+ n)))
326 (ewoc--filter-hf-nodes ewoc
bb7a346f 327 (ewoc--node-nth (ewoc--dll ewoc) n)))
5b467bf4
SM
328
329(defun ewoc-map (map-function ewoc &rest args)
330 "Apply MAP-FUNCTION to all elements in EWOC.
331MAP-FUNCTION is applied to the first element first.
332If MAP-FUNCTION returns non-nil the element will be refreshed (its
333pretty-printer will be called once again).
334
0111ab41
JB
335Note that the buffer for EWOC will be the current buffer when
336MAP-FUNCTION is called. MAP-FUNCTION must restore the current
337buffer before it returns, if it changes it.
5b467bf4
SM
338
339If more than two arguments are given, the remaining
340arguments will be passed to MAP-FUNCTION."
341 (ewoc--set-buffer-bind-dll-let* ewoc
342 ((footer (ewoc--footer ewoc))
8433d470 343 (pp (ewoc--pretty-printer ewoc))
bb7a346f 344 (node (ewoc--node-nth dll 1)))
bfbdb5ca
TTN
345 (save-excursion
346 (while (not (eq node footer))
347 (if (apply map-function (ewoc--node-data node) args)
bb7a346f
SM
348 (ewoc--refresh-node pp node dll))
349 (setq node (ewoc--node-next dll node))))))
5b467bf4 350
f569c26e
TTN
351(defun ewoc-delete (ewoc &rest nodes)
352 "Delete NODES from EWOC."
353 (ewoc--set-buffer-bind-dll-let* ewoc
ec491f90 354 ((L nil) (R nil) (last (ewoc--last-node ewoc)))
f569c26e
TTN
355 (dolist (node nodes)
356 ;; If we are about to delete the node pointed at by last-node,
357 ;; set last-node to nil.
ec491f90 358 (when (eq last node)
2ee3d7f0 359 (setf last nil (ewoc--last-node ewoc) nil))
f569c26e 360 (delete-region (ewoc--node-start-marker node)
bb7a346f 361 (ewoc--node-start-marker (ewoc--node-next dll node)))
f569c26e 362 (set-marker (ewoc--node-start-marker node) nil)
2ee3d7f0
SM
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 (ewoc--node-right node) nil))))
f569c26e 371
5b467bf4
SM
372(defun ewoc-filter (ewoc predicate &rest args)
373 "Remove all elements in EWOC for which PREDICATE returns nil.
a1506d29 374Note that the buffer for EWOC will be current-buffer when PREDICATE
0111ab41 375is called. PREDICATE must restore the current buffer before it returns
5b467bf4 376if it changes it.
0111ab41 377The PREDICATE is called with the element as its first argument. If any
5b467bf4
SM
378ARGS are given they will be passed to the PREDICATE."
379 (ewoc--set-buffer-bind-dll-let* ewoc
bb7a346f 380 ((node (ewoc--node-nth dll 1))
5b467bf4 381 (footer (ewoc--footer ewoc))
f569c26e 382 (goodbye nil)
2c246c9f 383 (inhibit-read-only t))
5b467bf4 384 (while (not (eq node footer))
5b467bf4 385 (unless (apply predicate (ewoc--node-data node) args)
f569c26e 386 (push node goodbye))
bb7a346f 387 (setq node (ewoc--node-next dll node)))
f569c26e 388 (apply 'ewoc-delete ewoc goodbye)))
5b467bf4 389
44946a4c 390(defun ewoc-locate (ewoc &optional pos guess)
5b467bf4 391 "Return the node that POS (a buffer position) is within.
44946a4c 392POS may be a marker or an integer. It defaults to point.
0111ab41 393GUESS should be a node that it is likely to be near POS.
5b467bf4
SM
394
395If POS points before the first element, the first node is returned.
396If POS points after the last element, the last node is returned.
397If the EWOC is empty, nil is returned."
44946a4c 398 (unless pos (setq pos (point)))
bb7a346f 399 (ewoc--set-buffer-bind-dll ewoc
5b467bf4
SM
400
401 (cond
402 ;; Nothing present?
bb7a346f 403 ((eq (ewoc--node-nth dll 1) (ewoc--node-nth dll -1))
5b467bf4
SM
404 nil)
405
406 ;; Before second elem?
bb7a346f
SM
407 ((< pos (ewoc--node-start-marker (ewoc--node-nth dll 2)))
408 (ewoc--node-nth dll 1))
5b467bf4
SM
409
410 ;; After one-before-last elem?
bb7a346f
SM
411 ((>= pos (ewoc--node-start-marker (ewoc--node-nth dll -2)))
412 (ewoc--node-nth dll -2))
5b467bf4
SM
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.
bb7a346f 418 (let* ((best-guess (ewoc--node-nth dll 1))
5b467bf4
SM
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
bb7a346f 426 (let* ((g (ewoc--node-nth dll -1)) ;Check the last elem
5b467bf4
SM
427 (d (abs (- pos (ewoc--node-start-marker g)))))
428 (when (< d distance)
429 (setq distance d)
430 (setq best-guess g)))
431
7dd2e64c 432 (when (ewoc--last-node ewoc) ;Check "previous".
5b467bf4
SM
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.
a1506d29 442
5b467bf4
SM
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))
bb7a346f 449 (setq best-guess (ewoc--node-next dll best-guess)))
5b467bf4 450 ;; ...and return the previous node.
bb7a346f 451 (ewoc--node-prev dll best-guess))
5b467bf4
SM
452
453 ;; Pos is before best-guess
454 (t
455 (while (< pos (ewoc--node-start-marker best-guess))
bb7a346f 456 (setq best-guess (ewoc--node-prev dll best-guess)))
5b467bf4
SM
457 best-guess)))))))
458
459(defun ewoc-invalidate (ewoc &rest nodes)
d4ddf783
TTN
460 "Call EWOC's pretty-printer for each element in NODES.
461Delete current text first, thus effecting a \"refresh\"."
8433d470
TTN
462 (ewoc--set-buffer-bind-dll-let* ewoc
463 ((pp (ewoc--pretty-printer ewoc)))
bfbdb5ca
TTN
464 (save-excursion
465 (dolist (node nodes)
bb7a346f 466 (ewoc--refresh-node pp node dll)))))
5b467bf4 467
44946a4c 468(defun ewoc-goto-prev (ewoc arg)
d4ddf783 469 "Move point to the ARGth previous element in EWOC.
5b467bf4 470Don't move if we are at the first element, or if EWOC is empty.
d4ddf783 471Return the node we moved to."
5b467bf4 472 (ewoc--set-buffer-bind-dll-let* ewoc
6d84ac85 473 ((node (ewoc-locate ewoc (point))))
5b467bf4 474 (when node
44946a4c
SM
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)))
5b467bf4
SM
478 (while (and node (> arg 0))
479 (setq arg (1- arg))
bb7a346f 480 (setq node (ewoc--node-prev dll node)))
5b467bf4
SM
481 ;; Never step above the first element.
482 (unless (ewoc--filter-hf-nodes ewoc node)
bb7a346f 483 (setq node (ewoc--node-nth dll 1)))
5b467bf4
SM
484 (ewoc-goto-node ewoc node))))
485
44946a4c 486(defun ewoc-goto-next (ewoc arg)
d4ddf783
TTN
487 "Move point to the ARGth next element in EWOC.
488Return the node (or nil if we just passed the last node)."
5b467bf4 489 (ewoc--set-buffer-bind-dll-let* ewoc
6d84ac85 490 ((node (ewoc-locate ewoc (point))))
5b467bf4
SM
491 (while (and node (> arg 0))
492 (setq arg (1- arg))
bb7a346f 493 (setq node (ewoc--node-next dll node)))
5b467bf4 494 ;; Never step below the first element.
44946a4c 495 ;; (unless (ewoc--filter-hf-nodes ewoc node)
bb7a346f 496 ;; (setq node (ewoc--node-nth dll -2)))
a918ed9b
BR
497 (unless node
498 (error "No next"))
5b467bf4
SM
499 (ewoc-goto-node ewoc node)))
500
501(defun ewoc-goto-node (ewoc node)
d4ddf783 502 "Move point to NODE in EWOC."
5b467bf4
SM
503 (ewoc--set-buffer-bind-dll ewoc
504 (goto-char (ewoc--node-start-marker node))
505 (if goal-column (move-to-column goal-column))
2ee3d7f0 506 (setf (ewoc--last-node ewoc) node)))
5b467bf4
SM
507
508(defun ewoc-refresh (ewoc)
509 "Refresh all data in EWOC.
510The pretty-printer that was specified when the EWOC was created
511will be called for all elements in EWOC.
512Note that `ewoc-invalidate' is more efficient if only a small
513number of elements needs to be refreshed."
514 (ewoc--set-buffer-bind-dll-let* ewoc
cb3430a1 515 ((footer (ewoc--footer ewoc)))
5b467bf4 516 (let ((inhibit-read-only t))
bb7a346f 517 (delete-region (ewoc--node-start-marker (ewoc--node-nth dll 1))
5b467bf4
SM
518 (ewoc--node-start-marker footer))
519 (goto-char (ewoc--node-start-marker footer))
340d9945 520 (let ((pp (ewoc--pretty-printer ewoc))
bb7a346f 521 (node (ewoc--node-nth dll 1)))
5b467bf4
SM
522 (while (not (eq node footer))
523 (set-marker (ewoc--node-start-marker node) (point))
340d9945 524 (funcall pp (ewoc--node-data node))
bb7a346f 525 (setq node (ewoc--node-next dll node)))))
5b467bf4
SM
526 (set-marker (ewoc--node-start-marker footer) (point))))
527
528(defun ewoc-collect (ewoc predicate &rest args)
529 "Select elements from EWOC using PREDICATE.
530Return a list of all selected data elements.
0111ab41
JB
531PREDICATE is a function that takes a data element as its first
532argument. The elements on the returned list will appear in the
533same order as in the buffer. You should not rely on the order of
534calls to PREDICATE.
535Note that the buffer the EWOC is displayed in is the current
536buffer when PREDICATE is called. PREDICATE must restore it if it
537changes it.
5b467bf4
SM
538If more than two arguments are given the
539remaining arguments will be passed to PREDICATE."
540 (ewoc--set-buffer-bind-dll-let* ewoc
541 ((header (ewoc--header ewoc))
bb7a346f 542 (node (ewoc--node-nth dll -2))
5b467bf4
SM
543 result)
544 (while (not (eq node header))
545 (if (apply predicate (ewoc--node-data node) args)
546 (push (ewoc--node-data node) result))
bb7a346f 547 (setq node (ewoc--node-prev dll node)))
d5337506 548 result))
5b467bf4
SM
549
550(defun ewoc-buffer (ewoc)
551 "Return the buffer that is associated with EWOC.
d4ddf783 552Return nil if the buffer has been deleted."
5b467bf4
SM
553 (let ((buf (ewoc--buffer ewoc)))
554 (when (buffer-name buf) buf)))
555
cb3430a1
SM
556(defun ewoc-get-hf (ewoc)
557 "Return a cons cell containing the (HEADER . FOOTER) of EWOC."
558 (cons (ewoc--node-data (ewoc--header ewoc))
559 (ewoc--node-data (ewoc--footer ewoc))))
560
561(defun ewoc-set-hf (ewoc header footer)
562 "Set the HEADER and FOOTER of EWOC."
60eae434
TTN
563 (ewoc--set-buffer-bind-dll-let* ewoc
564 ((head (ewoc--header ewoc))
2bbacc0e
TTN
565 (foot (ewoc--footer ewoc))
566 (hf-pp (ewoc--hf-pp ewoc)))
2ee3d7f0
SM
567 (setf (ewoc--node-data head) header
568 (ewoc--node-data foot) footer)
60eae434 569 (save-excursion
bb7a346f
SM
570 (ewoc--refresh-node hf-pp head dll)
571 (ewoc--refresh-node hf-pp foot dll))))
cb3430a1 572
5b467bf4
SM
573\f
574(provide 'ewoc)
575
7ece7aba
SM
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:
5b467bf4
SM
580
581;;; ewoc.el ends here