Changeset 4098 for trunk/lisp/emacs-lisp/ewoc.el
- Timestamp:
- 07/01/06 08:27:06 (2 years ago)
- Files:
-
- trunk/lisp/emacs-lisp/ewoc.el (modified) (29 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/lisp/emacs-lisp/ewoc.el
r4091 r4098 89 89 ;; element. In that way some kind of tree hierarchy can be created. 90 90 ;; 91 ;; Full documentation will, God willing, soon be available in a 92 ;; Texinfo manual. 93 94 ;; In the mean time `grep '^(.*ewoc-[^-]' emacs-lisp/ewoc.el' can help 95 ;; you find all the exported functions: 96 ;; 97 ;; (defun ewoc-create (pretty-printer &optional header footer) 98 ;; (defalias 'ewoc-data 'ewoc--node-data) 99 ;; (defun ewoc-set-data (node data) 100 ;; (defun ewoc-location (node) 101 ;; (defun ewoc-enter-first (ewoc data) 102 ;; (defun ewoc-enter-last (ewoc data) 103 ;; (defun ewoc-enter-after (ewoc node data) 104 ;; (defun ewoc-enter-before (ewoc node data) 105 ;; (defun ewoc-next (ewoc node) 106 ;; (defun ewoc-prev (ewoc node) 107 ;; (defun ewoc-nth (ewoc n) 108 ;; (defun ewoc-map (map-function ewoc &rest args) 109 ;; (defun ewoc-filter (ewoc predicate &rest args) 110 ;; (defun ewoc-delete (ewoc &rest nodes) 111 ;; (defun ewoc-locate (ewoc &optional pos guess) 112 ;; (defun ewoc-invalidate (ewoc &rest nodes) 113 ;; (defun ewoc-goto-prev (ewoc arg) 114 ;; (defun ewoc-goto-next (ewoc arg) 115 ;; (defun ewoc-goto-node (ewoc node) 116 ;; (defun ewoc-refresh (ewoc) 117 ;; (defun ewoc-collect (ewoc predicate &rest args) 118 ;; (defun ewoc-buffer (ewoc) 119 ;; (defun ewoc-get-hf (ewoc) 120 ;; (defun ewoc-set-hf (ewoc header footer) 91 ;; The Emacs Lisp Reference Manual documents ewoc.el's "public interface". 121 92 122 93 ;; Coding conventions … … 126 97 ;; starting with the prefix `ewoc--' are meant for internal use, 127 98 ;; while those starting with `ewoc-' are exported for public use. 128 ;; There are currently no global or buffer-local variables used.129 130 99 131 100 ;;; Code: 132 101 133 (eval-when-compile (require 'cl)) ;because of CL compiler macros 134 135 ;; The doubly linked list is implemented as a circular list 136 ;; with a dummy node first and last. The dummy node is used as 137 ;; "the dll" (or rather the dynamically bound `ewoc--current-dll'). 138 139 (defvar ewoc--current-dll) 140 102 (eval-when-compile (require 'cl)) 103 104 ;; The doubly linked list is implemented as a circular list with a dummy 105 ;; node first and last. The dummy node is used as "the dll". 141 106 (defstruct (ewoc--node 142 (:type vector) ;required for ewoc--node-branch hack 107 (:type vector) ;ewoc--node-nth needs this 108 (:constructor nil) 143 109 (:constructor ewoc--node-create (start-marker data))) 144 110 left right data start-marker) 145 111 146 (defalias 'ewoc--node-branch 'aref 147 "Get the left (CHILD=0) or right (CHILD=1) child of the NODE. 148 149 \(fn NODE CHILD)") 150 151 (defun ewoc--node-next (node) 112 (defun ewoc--node-next (dll node) 152 113 "Return the node after NODE, or nil if NODE is the last node." 153 114 (let ((R (ewoc--node-right node))) 154 (unless (eq ewoc--current-dll R) R)))155 156 (defun ewoc--node-prev ( node)115 (unless (eq dll R) R))) 116 117 (defun ewoc--node-prev (dll node) 157 118 "Return the node before NODE, or nil if NODE is the first node." 158 119 (let ((L (ewoc--node-left node))) 159 (unless (eq ewoc--current-dll L) L)))160 161 (defun ewoc--node-nth ( n)162 "Return the Nth node from the doubly linked list ` ewoc--current-dll'.120 (unless (eq dll L) L))) 121 122 (defun ewoc--node-nth (dll n) 123 "Return the Nth node from the doubly linked list `dll'. 163 124 N counts from zero. If N is negative, return the -(N+1)th last element. 164 125 If N is out of range, return nil. 165 Thus, (ewoc--node-nth 0) returns the first node, 166 and (ewoc--node-nth -1) returns the last node." 126 Thus, (ewoc--node-nth dll 0) returns the first node, 127 and (ewoc--node-nth dll -1) returns the last node." 128 ;; Presuming a node is ":type vector", starting with `left' and `right': 167 129 ;; Branch 0 ("follow left pointer") is used when n is negative. 168 130 ;; Branch 1 ("follow right pointer") is used otherwise. 169 131 (let* ((branch (if (< n 0) 0 1)) 170 (node ( ewoc--node-branch ewoc--current-dll branch)))132 (node (aref dll branch))) 171 133 (if (< n 0) (setq n (- -1 n))) 172 (while (and (not (eq ewoc--current-dll node)) (> n 0))173 (setq node ( ewoc--node-branchnode branch))134 (while (and (not (eq dll node)) (> n 0)) 135 (setq node (aref node branch)) 174 136 (setq n (1- n))) 175 (unless (eq ewoc--current-dll node) node)))137 (unless (eq dll node) node))) 176 138 177 139 (defun ewoc-location (node) … … 184 146 (defstruct (ewoc 185 147 (:constructor nil) 186 (:constructor ewoc--create 187 (buffer pretty-printer header footer dll)) 148 (:constructor ewoc--create (buffer pretty-printer dll)) 188 149 (:conc-name ewoc--)) 189 buffer pretty-printer header footer dll last-node )150 buffer pretty-printer header footer dll last-node hf-pp) 190 151 191 152 (defmacro ewoc--set-buffer-bind-dll-let* (ewoc varlist &rest forms) 192 153 "Execute FORMS with ewoc--buffer selected as current buffer, 193 ` ewoc--current-dll' bound to the dll, and VARLIST bound as in a let*.194 ` ewoc--current-dll' will be bound when VARLIST is initialized, but154 `dll' bound to the dll, and VARLIST bound as in a let*. 155 `dll' will be bound when VARLIST is initialized, but 195 156 the current buffer will *not* have been changed. 196 157 Return value of last form in FORMS." 197 158 (let ((hnd (make-symbol "ewoc"))) 198 159 `(let* ((,hnd ,ewoc) 199 ( ewoc--current-dll (ewoc--dll ,hnd))160 (dll (ewoc--dll ,hnd)) 200 161 ,@varlist) 201 162 (with-current-buffer (ewoc--buffer ,hnd) … … 212 173 node)) 213 174 214 (defun ewoc--adjust (beg end node )175 (defun ewoc--adjust (beg end node dll) 215 176 ;; "Manually reseat" markers for NODE and its successors (including footer 216 177 ;; and dll), in the case where they originally shared start position with … … 223 184 (let (m) 224 185 (while (and (= beg (setq m (ewoc--node-start-marker node))) 186 ;; The "dummy" node `dll' actually holds the marker that 187 ;; points to the end of the footer, so we check `dll' 188 ;; *after* reseating the marker. 225 189 (progn 226 190 (set-marker m end) 227 (not (eq ewoc--current-dll node))))191 (not (eq dll node)))) 228 192 (setq node (ewoc--node-right node)))))) 229 193 … … 233 197 NODE and leaving the new node's start there. Return the new node." 234 198 (save-excursion 235 (let* ((inhibit-read-only t) 236 (m (copy-marker (ewoc--node-start-marker node))) 237 (pos (marker-position m)) 238 (elemnode (ewoc--node-create m data))) 239 (goto-char pos) 240 (funcall pretty-printer data) 241 (setf (marker-position m) pos 242 (ewoc--node-left elemnode) (ewoc--node-left node) 199 (let ((elemnode (ewoc--node-create 200 (copy-marker (ewoc--node-start-marker node)) data))) 201 (setf (ewoc--node-left elemnode) (ewoc--node-left node) 243 202 (ewoc--node-right elemnode) node 244 203 (ewoc--node-right (ewoc--node-left node)) elemnode 245 204 (ewoc--node-left node) elemnode) 246 (ewoc-- adjust pos (point) node)205 (ewoc--refresh-node pretty-printer elemnode dll) 247 206 elemnode))) 248 207 249 (defun ewoc--refresh-node (pp node )208 (defun ewoc--refresh-node (pp node dll) 250 209 "Redisplay the element represented by NODE using the pretty-printer PP." 251 210 (let ((inhibit-read-only t) … … 257 216 (goto-char m) 258 217 (funcall pp (ewoc--node-data node)) 259 (ewoc--adjust m (point) R))) 218 (ewoc--adjust m (point) R dll))) 219 220 (defun ewoc--wrap (func) 221 (lexical-let ((ewoc--user-pp func)) 222 (lambda (data) 223 (funcall ewoc--user-pp data) 224 (insert "\n")))) 225 260 226 261 227 ;;; =========================================================================== … … 263 229 264 230 ;;;###autoload 265 (defun ewoc-create (pretty-printer &optional header footer )231 (defun ewoc-create (pretty-printer &optional header footer nosep) 266 232 "Create an empty ewoc. 267 233 … … 276 242 Optional second and third arguments HEADER and FOOTER are strings, 277 243 possibly empty, that will always be present at the top and bottom, 278 respectively, of the ewoc." 244 respectively, of the ewoc. 245 246 Normally, a newline is automatically inserted after the header, 247 the footer and every node's printed representation. Optional 248 fourth arg NOSEP non-nil inhibits this." 279 249 (let* ((dummy-node (ewoc--node-create 'DL-LIST 'DL-LIST)) 280 250 (dll (progn (setf (ewoc--node-right dummy-node) dummy-node) 281 251 (setf (ewoc--node-left dummy-node) dummy-node) 282 252 dummy-node)) 283 (new-ewoc 284 (ewoc--create (current-buffer) 285 pretty-printer nil nil dll)) 253 (wrap (if nosep 'identity 'ewoc--wrap)) 254 (new-ewoc (ewoc--create (current-buffer) 255 (funcall wrap pretty-printer) 256 dll)) 257 (hf-pp (funcall wrap 'insert)) 286 258 (pos (point)) 287 259 head foot) … … 291 263 (unless footer (setq footer "")) 292 264 (setf (ewoc--node-start-marker dll) (copy-marker pos) 293 foot (ewoc--insert-new-node dll footer 'insert) 294 head (ewoc--insert-new-node foot header 'insert) 265 foot (ewoc--insert-new-node dll footer hf-pp) 266 head (ewoc--insert-new-node foot header hf-pp) 267 (ewoc--hf-pp new-ewoc) hf-pp 295 268 (ewoc--footer new-ewoc) foot 296 269 (ewoc--header new-ewoc) head)) … … 311 284 Return the new node." 312 285 (ewoc--set-buffer-bind-dll ewoc 313 (ewoc-enter-after ewoc (ewoc--node-nth 0) data)))286 (ewoc-enter-after ewoc (ewoc--node-nth dll 0) data))) 314 287 315 288 (defun ewoc-enter-last (ewoc data) … … 317 290 Return the new node." 318 291 (ewoc--set-buffer-bind-dll ewoc 319 (ewoc-enter-before ewoc (ewoc--node-nth -1) data))) 320 292 (ewoc-enter-before ewoc (ewoc--node-nth dll -1) data))) 321 293 322 294 (defun ewoc-enter-after (ewoc node data) … … 324 296 Return the new node." 325 297 (ewoc--set-buffer-bind-dll ewoc 326 (ewoc-enter-before ewoc (ewoc--node-next node) data)))298 (ewoc-enter-before ewoc (ewoc--node-next dll node) data))) 327 299 328 300 (defun ewoc-enter-before (ewoc node data) … … 337 309 (when node 338 310 (ewoc--filter-hf-nodes 339 ewoc (let ((ewoc--current-dll (ewoc--dll ewoc))) 340 (ewoc--node-next node))))) 311 ewoc (ewoc--node-next (ewoc--dll ewoc) node)))) 341 312 342 313 (defun ewoc-prev (ewoc node) … … 345 316 (when node 346 317 (ewoc--filter-hf-nodes 347 ewoc (let ((ewoc--current-dll (ewoc--dll ewoc))) 348 (ewoc--node-prev node))))) 349 318 ewoc (ewoc--node-prev (ewoc--dll ewoc) node)))) 350 319 351 320 (defun ewoc-nth (ewoc n) … … 359 328 (setq n (if (< n 0) (1- n) (1+ n))) 360 329 (ewoc--filter-hf-nodes ewoc 361 (let ((ewoc--current-dll (ewoc--dll ewoc))) 362 (ewoc--node-nth n)))) 330 (ewoc--node-nth (ewoc--dll ewoc) n))) 363 331 364 332 (defun ewoc-map (map-function ewoc &rest args) … … 377 345 ((footer (ewoc--footer ewoc)) 378 346 (pp (ewoc--pretty-printer ewoc)) 379 (node (ewoc--node-nth 1)))347 (node (ewoc--node-nth dll 1))) 380 348 (save-excursion 381 349 (while (not (eq node footer)) 382 350 (if (apply map-function (ewoc--node-data node) args) 383 (ewoc--refresh-node pp node ))384 (setq node (ewoc--node-next node))))))351 (ewoc--refresh-node pp node dll)) 352 (setq node (ewoc--node-next dll node)))))) 385 353 386 354 (defun ewoc-delete (ewoc &rest nodes) 387 355 "Delete NODES from EWOC." 388 356 (ewoc--set-buffer-bind-dll-let* ewoc 389 ((L nil) (R nil) )357 ((L nil) (R nil) (last (ewoc--last-node ewoc))) 390 358 (dolist (node nodes) 391 359 ;; If we are about to delete the node pointed at by last-node, 392 360 ;; set last-node to nil. 393 ( if (eq (ewoc--last-node ewoc)node)394 (setf(ewoc--last-node ewoc) nil))361 (when (eq last node) 362 (setf last nil (ewoc--last-node ewoc) nil)) 395 363 (delete-region (ewoc--node-start-marker node) 396 (ewoc--node-start-marker (ewoc--node-next node)))364 (ewoc--node-start-marker (ewoc--node-next dll node))) 397 365 (set-marker (ewoc--node-start-marker node) nil) 398 366 (setf L (ewoc--node-left node) … … 413 381 ARGS are given they will be passed to the PREDICATE." 414 382 (ewoc--set-buffer-bind-dll-let* ewoc 415 ((node (ewoc--node-nth 1))383 ((node (ewoc--node-nth dll 1)) 416 384 (footer (ewoc--footer ewoc)) 417 385 (goodbye nil) … … 420 388 (unless (apply predicate (ewoc--node-data node) args) 421 389 (push node goodbye)) 422 (setq node (ewoc--node-next node)))390 (setq node (ewoc--node-next dll node))) 423 391 (apply 'ewoc-delete ewoc goodbye))) 424 392 … … 432 400 If the EWOC is empty, nil is returned." 433 401 (unless pos (setq pos (point))) 434 (ewoc--set-buffer-bind-dll-let* ewoc 435 ((footer (ewoc--footer ewoc))) 402 (ewoc--set-buffer-bind-dll ewoc 436 403 437 404 (cond 438 405 ;; Nothing present? 439 ((eq (ewoc--node-nth 1) (ewoc--node-nth-1))406 ((eq (ewoc--node-nth dll 1) (ewoc--node-nth dll -1)) 440 407 nil) 441 408 442 409 ;; Before second elem? 443 ((< pos (ewoc--node-start-marker (ewoc--node-nth 2)))444 (ewoc--node-nth 1))410 ((< pos (ewoc--node-start-marker (ewoc--node-nth dll 2))) 411 (ewoc--node-nth dll 1)) 445 412 446 413 ;; After one-before-last elem? 447 ((>= pos (ewoc--node-start-marker (ewoc--node-nth -2)))448 (ewoc--node-nth -2))414 ((>= pos (ewoc--node-start-marker (ewoc--node-nth dll -2))) 415 (ewoc--node-nth dll -2)) 449 416 450 417 ;; We now know that pos is within a elem. … … 452 419 ;; Make an educated guess about which of the three known 453 420 ;; node'es (the first, the last, or GUESS) is nearest. 454 (let* ((best-guess (ewoc--node-nth 1))421 (let* ((best-guess (ewoc--node-nth dll 1)) 455 422 (distance (abs (- pos (ewoc--node-start-marker best-guess))))) 456 423 (when guess … … 460 427 (setq best-guess guess)))) 461 428 462 (let* ((g (ewoc--node-nth -1)) ;Check the last elem429 (let* ((g (ewoc--node-nth dll -1)) ;Check the last elem 463 430 (d (abs (- pos (ewoc--node-start-marker g))))) 464 431 (when (< d distance) … … 483 450 ;; Loop until we are exactly one node too far down... 484 451 (while (>= pos (ewoc--node-start-marker best-guess)) 485 (setq best-guess (ewoc--node-next best-guess)))452 (setq best-guess (ewoc--node-next dll best-guess))) 486 453 ;; ...and return the previous node. 487 (ewoc--node-prev best-guess))454 (ewoc--node-prev dll best-guess)) 488 455 489 456 ;; Pos is before best-guess 490 457 (t 491 458 (while (< pos (ewoc--node-start-marker best-guess)) 492 (setq best-guess (ewoc--node-prev best-guess)))459 (setq best-guess (ewoc--node-prev dll best-guess))) 493 460 best-guess))))))) 494 461 … … 500 467 (save-excursion 501 468 (dolist (node nodes) 502 (ewoc--refresh-node pp node )))))469 (ewoc--refresh-node pp node dll))))) 503 470 504 471 (defun ewoc-goto-prev (ewoc arg) … … 514 481 (while (and node (> arg 0)) 515 482 (setq arg (1- arg)) 516 (setq node (ewoc--node-prev node)))483 (setq node (ewoc--node-prev dll node))) 517 484 ;; Never step above the first element. 518 485 (unless (ewoc--filter-hf-nodes ewoc node) 519 (setq node (ewoc--node-nth 1)))486 (setq node (ewoc--node-nth dll 1))) 520 487 (ewoc-goto-node ewoc node)))) 521 488 … … 527 494 (while (and node (> arg 0)) 528 495 (setq arg (1- arg)) 529 (setq node (ewoc--node-next node)))496 (setq node (ewoc--node-next dll node))) 530 497 ;; Never step below the first element. 531 498 ;; (unless (ewoc--filter-hf-nodes ewoc node) 532 ;; (setq node (ewoc--node-nth -2)))499 ;; (setq node (ewoc--node-nth dll -2))) 533 500 (ewoc-goto-node ewoc node))) 534 501 … … 549 516 ((footer (ewoc--footer ewoc))) 550 517 (let ((inhibit-read-only t)) 551 (delete-region (ewoc--node-start-marker (ewoc--node-nth 1))518 (delete-region (ewoc--node-start-marker (ewoc--node-nth dll 1)) 552 519 (ewoc--node-start-marker footer)) 553 520 (goto-char (ewoc--node-start-marker footer)) 554 521 (let ((pp (ewoc--pretty-printer ewoc)) 555 (node (ewoc--node-nth 1)))522 (node (ewoc--node-nth dll 1))) 556 523 (while (not (eq node footer)) 557 524 (set-marker (ewoc--node-start-marker node) (point)) 558 525 (funcall pp (ewoc--node-data node)) 559 (setq node (ewoc--node-next node)))))526 (setq node (ewoc--node-next dll node))))) 560 527 (set-marker (ewoc--node-start-marker footer) (point)))) 561 528 … … 574 541 (ewoc--set-buffer-bind-dll-let* ewoc 575 542 ((header (ewoc--header ewoc)) 576 (node (ewoc--node-nth -2))543 (node (ewoc--node-nth dll -2)) 577 544 result) 578 545 (while (not (eq node header)) 579 546 (if (apply predicate (ewoc--node-data node) args) 580 547 (push (ewoc--node-data node) result)) 581 (setq node (ewoc--node-prev node)))548 (setq node (ewoc--node-prev dll node))) 582 549 (nreverse result))) 583 550 … … 597 564 (ewoc--set-buffer-bind-dll-let* ewoc 598 565 ((head (ewoc--header ewoc)) 599 (foot (ewoc--footer ewoc))) 566 (foot (ewoc--footer ewoc)) 567 (hf-pp (ewoc--hf-pp ewoc))) 600 568 (setf (ewoc--node-data head) header 601 569 (ewoc--node-data foot) footer) 602 570 (save-excursion 603 (ewoc--refresh-node 'insert head)604 (ewoc--refresh-node 'insert foot))))571 (ewoc--refresh-node hf-pp head dll) 572 (ewoc--refresh-node hf-pp foot dll)))) 605 573 606 574 607 575 (provide 'ewoc) 608 576 609 ;; ;Local Variables:610 ;; ;eval: (put 'ewoc--set-buffer-bind-dll 'lisp-indent-hook 1)611 ;; ;eval: (put 'ewoc--set-buffer-bind-dll-let* 'lisp-indent-hook 2)612 ;; ;End:613 614 ;; ;arch-tag: d78915b9-9a07-44bf-aac6-04a1fc1bd6d4577 ;; 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: 581 582 ;; arch-tag: d78915b9-9a07-44bf-aac6-04a1fc1bd6d4 615 583 ;;; ewoc.el ends here
