Changeset 4091 for trunk/lisp/emacs-lisp/ewoc.el
- Timestamp:
- 05/27/06 10:35:24 (2 years ago)
- Files:
-
- trunk/lisp/emacs-lisp/ewoc.el (modified) (27 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/lisp/emacs-lisp/ewoc.el
r4085 r4091 97 97 ;; (defun ewoc-create (pretty-printer &optional header footer) 98 98 ;; (defalias 'ewoc-data 'ewoc--node-data) 99 ;; (defun ewoc-set-data (node data) 99 100 ;; (defun ewoc-location (node) 100 101 ;; (defun ewoc-enter-first (ewoc data) … … 107 108 ;; (defun ewoc-map (map-function ewoc &rest args) 108 109 ;; (defun ewoc-filter (ewoc predicate &rest args) 110 ;; (defun ewoc-delete (ewoc &rest nodes) 109 111 ;; (defun ewoc-locate (ewoc &optional pos guess) 110 112 ;; (defun ewoc-invalidate (ewoc &rest nodes) … … 133 135 ;; The doubly linked list is implemented as a circular list 134 136 ;; with a dummy node first and last. The dummy node is used as 135 ;; "the dll" (or rather is the dll handle passed around). 137 ;; "the dll" (or rather the dynamically bound `ewoc--current-dll'). 138 139 (defvar ewoc--current-dll) 136 140 137 141 (defstruct (ewoc--node … … 145 149 \(fn NODE CHILD)") 146 150 147 (defun ewoc--node-next ( dllnode)151 (defun ewoc--node-next (node) 148 152 "Return the node after NODE, or nil if NODE is the last node." 149 (unless (eq (ewoc--node-right node) dll) (ewoc--node-right node))) 150 151 (defun ewoc--node-prev (dll node) 153 (let ((R (ewoc--node-right node))) 154 (unless (eq ewoc--current-dll R) R))) 155 156 (defun ewoc--node-prev (node) 152 157 "Return the node before NODE, or nil if NODE is the first node." 153 (unless (eq (ewoc--node-left node) dll) (ewoc--node-left node))) 154 155 (defun ewoc--node-nth (dll n) 156 "Return the Nth node from the doubly linked list DLL. 157 N counts from zero. If DLL is not that long, nil is returned. 158 If N is negative, return the -(N+1)th last element. 159 Thus, (ewoc--node-nth dll 0) returns the first node, 160 and (ewoc--node-nth dll -1) returns the last node." 158 (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'. 163 N counts from zero. If N is negative, return the -(N+1)th last element. 164 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." 161 167 ;; Branch 0 ("follow left pointer") is used when n is negative. 162 168 ;; Branch 1 ("follow right pointer") is used otherwise. 163 169 (let* ((branch (if (< n 0) 0 1)) 164 (node (ewoc--node-branch dll branch)))170 (node (ewoc--node-branch ewoc--current-dll branch))) 165 171 (if (< n 0) (setq n (- -1 n))) 166 (while (and (not (eq dll node)) (> n 0))172 (while (and (not (eq ewoc--current-dll node)) (> n 0)) 167 173 (setq node (ewoc--node-branch node branch)) 168 174 (setq n (1- n))) 169 (unless (eq dll node) node)))175 (unless (eq ewoc--current-dll node) node))) 170 176 171 177 (defun ewoc-location (node) … … 185 191 (defmacro ewoc--set-buffer-bind-dll-let* (ewoc varlist &rest forms) 186 192 "Execute FORMS with ewoc--buffer selected as current buffer, 187 dll bound to ewoc--dll, and VARLIST bound as in a let*.188 dll will be bound when VARLIST is initialized, but the current189 buffer will *not* have been changed.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, but 195 the current buffer will *not* have been changed. 190 196 Return value of last form in FORMS." 191 197 (let ((hnd (make-symbol "ewoc"))) 192 198 `(let* ((,hnd ,ewoc) 193 ( dll (ewoc--dll ,hnd))199 (ewoc--current-dll (ewoc--dll ,hnd)) 194 200 ,@varlist) 195 201 (with-current-buffer (ewoc--buffer ,hnd) … … 205 211 (eq node (ewoc--footer ewoc))) 206 212 node)) 213 214 (defun ewoc--adjust (beg end node) 215 ;; "Manually reseat" markers for NODE and its successors (including footer 216 ;; and dll), in the case where they originally shared start position with 217 ;; BEG, to END. BEG and END are buffer positions describing NODE's left 218 ;; neighbor. This operation is functionally equivalent to temporarily 219 ;; setting these nodes' markers' insertion type to t around the pretty-print 220 ;; call that precedes the call to `ewoc--adjust', and then changing them back 221 ;; to nil. 222 (when (< beg end) 223 (let (m) 224 (while (and (= beg (setq m (ewoc--node-start-marker node))) 225 (progn 226 (set-marker m end) 227 (not (eq ewoc--current-dll node)))) 228 (setq node (ewoc--node-right node)))))) 207 229 208 230 (defun ewoc--insert-new-node (node data pretty-printer) … … 216 238 (elemnode (ewoc--node-create m data))) 217 239 (goto-char pos) 218 ;; Insert the trailing newline using insert-before-markers219 ;; so that the start position for the next element is updated.220 (insert-before-markers ?\n)221 ;; Move back, and call the pretty-printer.222 (backward-char 1)223 240 (funcall pretty-printer data) 224 241 (setf (marker-position m) pos … … 227 244 (ewoc--node-right (ewoc--node-left node)) elemnode 228 245 (ewoc--node-left node) elemnode) 246 (ewoc--adjust pos (point) node) 229 247 elemnode))) 230 248 231 249 (defun ewoc--refresh-node (pp node) 232 250 "Redisplay the element represented by NODE using the pretty-printer PP." 233 (let ((inhibit-read-only t)) 251 (let ((inhibit-read-only t) 252 (m (ewoc--node-start-marker node)) 253 (R (ewoc--node-right node))) 234 254 ;; First, remove the string from the buffer: 235 (delete-region (ewoc--node-start-marker node) 236 (1- (marker-position 237 (ewoc--node-start-marker (ewoc--node-right node))))) 255 (delete-region m (ewoc--node-start-marker R)) 238 256 ;; Calculate and insert the string. 239 (goto-char (ewoc--node-start-marker node)) 240 (funcall pp (ewoc--node-data node)))) 257 (goto-char m) 258 (funcall pp (ewoc--node-data node)) 259 (ewoc--adjust m (point) R))) 241 260 242 261 ;;; =========================================================================== 243 262 ;;; Public members of the Ewoc package 244 263 245 264 ;;;###autoload 246 265 (defun ewoc-create (pretty-printer &optional header footer) 247 266 "Create an empty ewoc. … … 252 271 element, and inserts a string representing it in the buffer (at 253 272 point). The string PRETTY-PRINTER inserts may be empty or span 254 several lines. A trailing newline will always be inserted 255 automatically. The PRETTY-PRINTER should use `insert', and not 273 several lines. The PRETTY-PRINTER should use `insert', and not 256 274 `insert-before-markers'. 257 275 258 Optional second argument HEADER is a string that will always be 259 present at the top of the ewoc. HEADER should end with a 260 newline. Optional third argument FOOTER is similar, and will 261 be inserted at the bottom of the ewoc." 276 Optional second and third arguments HEADER and FOOTER are strings, 277 possibly empty, that will always be present at the top and bottom, 278 respectively, of the ewoc." 262 279 (let* ((dummy-node (ewoc--node-create 'DL-LIST 'DL-LIST)) 263 280 (dll (progn (setf (ewoc--node-right dummy-node) dummy-node) … … 286 303 \(fn NODE)") 287 304 305 (defun ewoc-set-data (node data) 306 "Set NODE to encapsulate DATA." 307 (setf (ewoc--node-data node) data)) 308 288 309 (defun ewoc-enter-first (ewoc data) 289 310 "Enter DATA first in EWOC. 290 311 Return the new node." 291 312 (ewoc--set-buffer-bind-dll ewoc 292 (ewoc-enter-after ewoc (ewoc--node-nth dll0) data)))313 (ewoc-enter-after ewoc (ewoc--node-nth 0) data))) 293 314 294 315 (defun ewoc-enter-last (ewoc data) … … 296 317 Return the new node." 297 318 (ewoc--set-buffer-bind-dll ewoc 298 (ewoc-enter-before ewoc (ewoc--node-nth dll-1) data)))319 (ewoc-enter-before ewoc (ewoc--node-nth -1) data))) 299 320 300 321 … … 303 324 Return the new node." 304 325 (ewoc--set-buffer-bind-dll ewoc 305 (ewoc-enter-before ewoc (ewoc--node-next dllnode) data)))326 (ewoc-enter-before ewoc (ewoc--node-next node) data))) 306 327 307 328 (defun ewoc-enter-before (ewoc node data) … … 316 337 (when node 317 338 (ewoc--filter-hf-nodes 318 ewoc (ewoc--node-next (ewoc--dll ewoc) node)))) 339 ewoc (let ((ewoc--current-dll (ewoc--dll ewoc))) 340 (ewoc--node-next node))))) 319 341 320 342 (defun ewoc-prev (ewoc node) … … 323 345 (when node 324 346 (ewoc--filter-hf-nodes 325 ewoc 326 (ewoc--node-prev (ewoc--dll ewoc) node))))347 ewoc (let ((ewoc--current-dll (ewoc--dll ewoc))) 348 (ewoc--node-prev node))))) 327 349 328 350 … … 331 353 N counts from zero. Return nil if there is less than N elements. 332 354 If N is negative, return the -(N+1)th last element. 333 Thus, (ewoc-nth dll0) returns the first node,334 and (ewoc-nth dll-1) returns the last node.355 Thus, (ewoc-nth ewoc 0) returns the first node, 356 and (ewoc-nth ewoc -1) returns the last node. 335 357 Use `ewoc-data' to extract the data from the node." 336 358 ;; Skip the header (or footer, if n is negative). 337 359 (setq n (if (< n 0) (1- n) (1+ n))) 338 360 (ewoc--filter-hf-nodes ewoc 339 (ewoc--node-nth (ewoc--dll ewoc) n))) 361 (let ((ewoc--current-dll (ewoc--dll ewoc))) 362 (ewoc--node-nth n)))) 340 363 341 364 (defun ewoc-map (map-function ewoc &rest args) … … 354 377 ((footer (ewoc--footer ewoc)) 355 378 (pp (ewoc--pretty-printer ewoc)) 356 (node (ewoc--node-nth dll1)))379 (node (ewoc--node-nth 1))) 357 380 (save-excursion 358 381 (while (not (eq node footer)) 359 382 (if (apply map-function (ewoc--node-data node) args) 360 383 (ewoc--refresh-node pp node)) 361 (setq node (ewoc--node-next dll node)))))) 384 (setq node (ewoc--node-next node)))))) 385 386 (defun ewoc-delete (ewoc &rest nodes) 387 "Delete NODES from EWOC." 388 (ewoc--set-buffer-bind-dll-let* ewoc 389 ((L nil) (R nil)) 390 (dolist (node nodes) 391 ;; If we are about to delete the node pointed at by last-node, 392 ;; set last-node to nil. 393 (if (eq (ewoc--last-node ewoc) node) 394 (setf (ewoc--last-node ewoc) nil)) 395 (delete-region (ewoc--node-start-marker node) 396 (ewoc--node-start-marker (ewoc--node-next node))) 397 (set-marker (ewoc--node-start-marker node) nil) 398 (setf L (ewoc--node-left node) 399 R (ewoc--node-right node) 400 ;; Link neighbors to each other. 401 (ewoc--node-right L) R 402 (ewoc--node-left R) L 403 ;; Forget neighbors. 404 (ewoc--node-left node) nil 405 (ewoc--node-right node) nil)))) 362 406 363 407 (defun ewoc-filter (ewoc predicate &rest args) … … 369 413 ARGS are given they will be passed to the PREDICATE." 370 414 (ewoc--set-buffer-bind-dll-let* ewoc 371 ((node (ewoc--node-nth dll1))415 ((node (ewoc--node-nth 1)) 372 416 (footer (ewoc--footer ewoc)) 373 (next nil) 374 (L nil) (R nil) 417 (goodbye nil) 375 418 (inhibit-read-only t)) 376 419 (while (not (eq node footer)) 377 (setq next (ewoc--node-next dll node))378 420 (unless (apply predicate (ewoc--node-data node) args) 379 ;; If we are about to delete the node pointed at by last-node, 380 ;; set last-node to nil. 381 (if (eq (ewoc--last-node ewoc) node) 382 (setf (ewoc--last-node ewoc) nil)) 383 (delete-region (ewoc--node-start-marker node) 384 (ewoc--node-start-marker (ewoc--node-next dll node))) 385 (set-marker (ewoc--node-start-marker node) nil) 386 (setf L (ewoc--node-left node) 387 R (ewoc--node-right node) 388 ;; Link neighbors to each other. 389 (ewoc--node-right L) R 390 (ewoc--node-left R) L 391 ;; Forget neighbors. 392 (ewoc--node-left node) nil 393 (ewoc--node-right node) nil)) 394 (setq node next)))) 421 (push node goodbye)) 422 (setq node (ewoc--node-next node))) 423 (apply 'ewoc-delete ewoc goodbye))) 395 424 396 425 (defun ewoc-locate (ewoc &optional pos guess) … … 408 437 (cond 409 438 ;; Nothing present? 410 ((eq (ewoc--node-nth dll 1) (ewoc--node-nth dll-1))439 ((eq (ewoc--node-nth 1) (ewoc--node-nth -1)) 411 440 nil) 412 441 413 442 ;; Before second elem? 414 ((< pos (ewoc--node-start-marker (ewoc--node-nth dll2)))415 (ewoc--node-nth dll1))443 ((< pos (ewoc--node-start-marker (ewoc--node-nth 2))) 444 (ewoc--node-nth 1)) 416 445 417 446 ;; After one-before-last elem? 418 ((>= pos (ewoc--node-start-marker (ewoc--node-nth dll-2)))419 (ewoc--node-nth dll-2))447 ((>= pos (ewoc--node-start-marker (ewoc--node-nth -2))) 448 (ewoc--node-nth -2)) 420 449 421 450 ;; We now know that pos is within a elem. … … 423 452 ;; Make an educated guess about which of the three known 424 453 ;; node'es (the first, the last, or GUESS) is nearest. 425 (let* ((best-guess (ewoc--node-nth dll1))454 (let* ((best-guess (ewoc--node-nth 1)) 426 455 (distance (abs (- pos (ewoc--node-start-marker best-guess))))) 427 456 (when guess … … 431 460 (setq best-guess guess)))) 432 461 433 (let* ((g (ewoc--node-nth dll-1)) ;Check the last elem462 (let* ((g (ewoc--node-nth -1)) ;Check the last elem 434 463 (d (abs (- pos (ewoc--node-start-marker g))))) 435 464 (when (< d distance) … … 437 466 (setq best-guess g))) 438 467 439 (when (ewoc--last-node ewoc) ;Check "previous".468 (when (ewoc--last-node ewoc) ;Check "previous". 440 469 (let* ((g (ewoc--last-node ewoc)) 441 470 (d (abs (- pos (ewoc--node-start-marker g))))) … … 454 483 ;; Loop until we are exactly one node too far down... 455 484 (while (>= pos (ewoc--node-start-marker best-guess)) 456 (setq best-guess (ewoc--node-next dllbest-guess)))485 (setq best-guess (ewoc--node-next best-guess))) 457 486 ;; ...and return the previous node. 458 (ewoc--node-prev dllbest-guess))487 (ewoc--node-prev best-guess)) 459 488 460 489 ;; Pos is before best-guess 461 490 (t 462 491 (while (< pos (ewoc--node-start-marker best-guess)) 463 (setq best-guess (ewoc--node-prev dllbest-guess)))492 (setq best-guess (ewoc--node-prev best-guess))) 464 493 best-guess))))))) 465 494 … … 485 514 (while (and node (> arg 0)) 486 515 (setq arg (1- arg)) 487 (setq node (ewoc--node-prev dllnode)))516 (setq node (ewoc--node-prev node))) 488 517 ;; Never step above the first element. 489 518 (unless (ewoc--filter-hf-nodes ewoc node) 490 (setq node (ewoc--node-nth dll1)))519 (setq node (ewoc--node-nth 1))) 491 520 (ewoc-goto-node ewoc node)))) 492 521 … … 498 527 (while (and node (> arg 0)) 499 528 (setq arg (1- arg)) 500 (setq node (ewoc--node-next dllnode)))529 (setq node (ewoc--node-next node))) 501 530 ;; Never step below the first element. 502 531 ;; (unless (ewoc--filter-hf-nodes ewoc node) 503 ;; (setq node (ewoc--node-nth dll-2)))532 ;; (setq node (ewoc--node-nth -2))) 504 533 (ewoc-goto-node ewoc node))) 505 534 … … 520 549 ((footer (ewoc--footer ewoc))) 521 550 (let ((inhibit-read-only t)) 522 (delete-region (ewoc--node-start-marker (ewoc--node-nth dll1))551 (delete-region (ewoc--node-start-marker (ewoc--node-nth 1)) 523 552 (ewoc--node-start-marker footer)) 524 553 (goto-char (ewoc--node-start-marker footer)) 525 554 (let ((pp (ewoc--pretty-printer ewoc)) 526 (node (ewoc--node-nth dll1)))555 (node (ewoc--node-nth 1))) 527 556 (while (not (eq node footer)) 528 557 (set-marker (ewoc--node-start-marker node) (point)) 529 558 (funcall pp (ewoc--node-data node)) 530 (insert "\n") 531 (setq node (ewoc--node-next dll node))))) 559 (setq node (ewoc--node-next node))))) 532 560 (set-marker (ewoc--node-start-marker footer) (point)))) 533 561 … … 546 574 (ewoc--set-buffer-bind-dll-let* ewoc 547 575 ((header (ewoc--header ewoc)) 548 (node (ewoc--node-nth dll-2))576 (node (ewoc--node-nth -2)) 549 577 result) 550 578 (while (not (eq node header)) 551 579 (if (apply predicate (ewoc--node-data node) args) 552 580 (push (ewoc--node-data node) result)) 553 (setq node (ewoc--node-prev dllnode)))581 (setq node (ewoc--node-prev node))) 554 582 (nreverse result))) 555 583 … … 567 595 (defun ewoc-set-hf (ewoc header footer) 568 596 "Set the HEADER and FOOTER of EWOC." 569 (setf (ewoc--node-data (ewoc--header ewoc)) header) 570 (setf (ewoc--node-data (ewoc--footer ewoc)) footer) 571 (save-excursion 572 (ewoc--refresh-node 'insert (ewoc--header ewoc)) 573 (ewoc--refresh-node 'insert (ewoc--footer ewoc)))) 597 (ewoc--set-buffer-bind-dll-let* ewoc 598 ((head (ewoc--header ewoc)) 599 (foot (ewoc--footer ewoc))) 600 (setf (ewoc--node-data head) header 601 (ewoc--node-data foot) footer) 602 (save-excursion 603 (ewoc--refresh-node 'insert head) 604 (ewoc--refresh-node 'insert foot)))) 574 605 575 606
