(ewoc--current-dll): New var.
(ewoc--node-next, ewoc--node-prev, ewoc--node-nth): Don't take DLL arg. Instead, use `ewoc--current-dll'. Update all callers. (ewoc--set-buffer-bind-dll-let*): Bind `ewoc--current-dll', not `dll'. (ewoc--adjust): Use `ewoc--current-dll'. (ewoc-next, ewoc-prev, ewoc-nth): Bind `ewoc--current-dll'.
This commit is contained in:
parent
07a7837c9f
commit
7dd2e64c5d
2 changed files with 69 additions and 54 deletions
|
@ -134,7 +134,9 @@
|
|||
|
||||
;; 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).
|
||||
;; "the dll" (or rather the dynamically bound `ewoc--current-dll').
|
||||
|
||||
(defvar ewoc--current-dll)
|
||||
|
||||
(defstruct (ewoc--node
|
||||
(:type vector) ;required for ewoc--node-branch hack
|
||||
|
@ -146,29 +148,31 @@
|
|||
|
||||
\(fn NODE CHILD)")
|
||||
|
||||
(defun ewoc--node-next (dll node)
|
||||
(defun ewoc--node-next (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)))
|
||||
(let ((R (ewoc--node-right node)))
|
||||
(unless (eq ewoc--current-dll R) R)))
|
||||
|
||||
(defun ewoc--node-prev (dll node)
|
||||
(defun ewoc--node-prev (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)))
|
||||
(let ((L (ewoc--node-left node)))
|
||||
(unless (eq ewoc--current-dll L) L)))
|
||||
|
||||
(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."
|
||||
(defun ewoc--node-nth (n)
|
||||
"Return the Nth node from the doubly linked list `ewoc--current-dll'.
|
||||
N counts from zero. If N is negative, return the -(N+1)th last element.
|
||||
If N is out of range, return nil.
|
||||
Thus, (ewoc--node-nth 0) returns the first node,
|
||||
and (ewoc--node-nth -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)))
|
||||
(node (ewoc--node-branch ewoc--current-dll branch)))
|
||||
(if (< n 0) (setq n (- -1 n)))
|
||||
(while (and (not (eq dll node)) (> n 0))
|
||||
(while (and (not (eq ewoc--current-dll node)) (> n 0))
|
||||
(setq node (ewoc--node-branch node branch))
|
||||
(setq n (1- n)))
|
||||
(unless (eq dll node) node)))
|
||||
(unless (eq ewoc--current-dll node) node)))
|
||||
|
||||
(defun ewoc-location (node)
|
||||
"Return the start location of NODE."
|
||||
|
@ -186,13 +190,13 @@ and (ewoc--node-nth dll -1) returns the 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.
|
||||
`ewoc--current-dll' bound to the dll, and VARLIST bound as in a let*.
|
||||
`ewoc--current-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 ((hnd (make-symbol "ewoc")))
|
||||
`(let* ((,hnd ,ewoc)
|
||||
(dll (ewoc--dll ,hnd))
|
||||
(ewoc--current-dll (ewoc--dll ,hnd))
|
||||
,@varlist)
|
||||
(with-current-buffer (ewoc--buffer ,hnd)
|
||||
,@forms))))
|
||||
|
@ -213,14 +217,14 @@ BUT if it is the header or the footer in EWOC return nil instead."
|
|||
;; BEG, to END. BEG and END are buffer positions describing NODE's left
|
||||
;; neighbor. This operation is functionally equivalent to temporarily
|
||||
;; setting these nodes' markers' insertion type to t around the pretty-print
|
||||
;; call that precedes the call to `ewoc-adjust', and then changing them back
|
||||
;; call that precedes the call to `ewoc--adjust', and then changing them back
|
||||
;; to nil.
|
||||
(when (< beg end)
|
||||
(let (m)
|
||||
(while (and (= beg (setq m (ewoc--node-start-marker node)))
|
||||
(progn
|
||||
(set-marker m end)
|
||||
(not (eq dll node))))
|
||||
(not (eq ewoc--current-dll node))))
|
||||
(setq node (ewoc--node-right node))))))
|
||||
|
||||
(defun ewoc--insert-new-node (node data pretty-printer)
|
||||
|
@ -306,20 +310,20 @@ respectively, of the ewoc."
|
|||
"Enter DATA first in EWOC.
|
||||
Return the new node."
|
||||
(ewoc--set-buffer-bind-dll ewoc
|
||||
(ewoc-enter-after ewoc (ewoc--node-nth dll 0) data)))
|
||||
(ewoc-enter-after ewoc (ewoc--node-nth 0) data)))
|
||||
|
||||
(defun ewoc-enter-last (ewoc data)
|
||||
"Enter DATA last in EWOC.
|
||||
Return the new node."
|
||||
(ewoc--set-buffer-bind-dll ewoc
|
||||
(ewoc-enter-before ewoc (ewoc--node-nth dll -1) data)))
|
||||
(ewoc-enter-before ewoc (ewoc--node-nth -1) data)))
|
||||
|
||||
|
||||
(defun ewoc-enter-after (ewoc node data)
|
||||
"Enter a new element DATA after NODE in EWOC.
|
||||
Return the new node."
|
||||
(ewoc--set-buffer-bind-dll ewoc
|
||||
(ewoc-enter-before ewoc (ewoc--node-next dll node) data)))
|
||||
(ewoc-enter-before ewoc (ewoc--node-next node) data)))
|
||||
|
||||
(defun ewoc-enter-before (ewoc node data)
|
||||
"Enter a new element DATA before NODE in EWOC.
|
||||
|
@ -332,28 +336,30 @@ Return the new node."
|
|||
Return nil if NODE is nil or the last element."
|
||||
(when node
|
||||
(ewoc--filter-hf-nodes
|
||||
ewoc (ewoc--node-next (ewoc--dll ewoc) node))))
|
||||
ewoc (let ((ewoc--current-dll (ewoc--dll ewoc)))
|
||||
(ewoc--node-next node)))))
|
||||
|
||||
(defun ewoc-prev (ewoc node)
|
||||
"Return the node in EWOC that precedes NODE.
|
||||
Return nil if NODE is nil or the first element."
|
||||
(when node
|
||||
(ewoc--filter-hf-nodes
|
||||
ewoc
|
||||
(ewoc--node-prev (ewoc--dll ewoc) node))))
|
||||
ewoc (let ((ewoc--current-dll (ewoc--dll ewoc)))
|
||||
(ewoc--node-prev node)))))
|
||||
|
||||
|
||||
(defun ewoc-nth (ewoc n)
|
||||
"Return the Nth node.
|
||||
N counts from zero. Return nil 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.
|
||||
Thus, (ewoc-nth ewoc 0) returns the first node,
|
||||
and (ewoc-nth ewoc -1) returns the last node.
|
||||
Use `ewoc-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)))
|
||||
(let ((ewoc--current-dll (ewoc--dll ewoc)))
|
||||
(ewoc--node-nth n))))
|
||||
|
||||
(defun ewoc-map (map-function ewoc &rest args)
|
||||
"Apply MAP-FUNCTION to all elements in EWOC.
|
||||
|
@ -370,12 +376,12 @@ arguments will be passed to MAP-FUNCTION."
|
|||
(ewoc--set-buffer-bind-dll-let* ewoc
|
||||
((footer (ewoc--footer ewoc))
|
||||
(pp (ewoc--pretty-printer ewoc))
|
||||
(node (ewoc--node-nth dll 1)))
|
||||
(node (ewoc--node-nth 1)))
|
||||
(save-excursion
|
||||
(while (not (eq node footer))
|
||||
(if (apply map-function (ewoc--node-data node) args)
|
||||
(ewoc--refresh-node pp node))
|
||||
(setq node (ewoc--node-next dll node))))))
|
||||
(setq node (ewoc--node-next node))))))
|
||||
|
||||
(defun ewoc-delete (ewoc &rest nodes)
|
||||
"Delete NODES from EWOC."
|
||||
|
@ -387,7 +393,7 @@ arguments will be passed to MAP-FUNCTION."
|
|||
(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)))
|
||||
(ewoc--node-start-marker (ewoc--node-next node)))
|
||||
(set-marker (ewoc--node-start-marker node) nil)
|
||||
(setf L (ewoc--node-left node)
|
||||
R (ewoc--node-right node)
|
||||
|
@ -406,14 +412,14 @@ 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))
|
||||
((node (ewoc--node-nth 1))
|
||||
(footer (ewoc--footer ewoc))
|
||||
(goodbye nil)
|
||||
(inhibit-read-only t))
|
||||
(while (not (eq node footer))
|
||||
(unless (apply predicate (ewoc--node-data node) args)
|
||||
(push node goodbye))
|
||||
(setq node (ewoc--node-next dll node)))
|
||||
(setq node (ewoc--node-next node)))
|
||||
(apply 'ewoc-delete ewoc goodbye)))
|
||||
|
||||
(defun ewoc-locate (ewoc &optional pos guess)
|
||||
|
@ -430,22 +436,22 @@ If the EWOC is empty, nil is returned."
|
|||
|
||||
(cond
|
||||
;; Nothing present?
|
||||
((eq (ewoc--node-nth dll 1) (ewoc--node-nth dll -1))
|
||||
((eq (ewoc--node-nth 1) (ewoc--node-nth -1))
|
||||
nil)
|
||||
|
||||
;; Before second elem?
|
||||
((< pos (ewoc--node-start-marker (ewoc--node-nth dll 2)))
|
||||
(ewoc--node-nth dll 1))
|
||||
((< pos (ewoc--node-start-marker (ewoc--node-nth 2)))
|
||||
(ewoc--node-nth 1))
|
||||
|
||||
;; After one-before-last elem?
|
||||
((>= pos (ewoc--node-start-marker (ewoc--node-nth dll -2)))
|
||||
(ewoc--node-nth dll -2))
|
||||
((>= pos (ewoc--node-start-marker (ewoc--node-nth -2)))
|
||||
(ewoc--node-nth -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))
|
||||
(let* ((best-guess (ewoc--node-nth 1))
|
||||
(distance (abs (- pos (ewoc--node-start-marker best-guess)))))
|
||||
(when guess
|
||||
(let ((d (abs (- pos (ewoc--node-start-marker guess)))))
|
||||
|
@ -453,13 +459,13 @@ If the EWOC is empty, nil is returned."
|
|||
(setq distance d)
|
||||
(setq best-guess guess))))
|
||||
|
||||
(let* ((g (ewoc--node-nth dll -1)) ;Check the last elem
|
||||
(let* ((g (ewoc--node-nth -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".
|
||||
(when (ewoc--last-node ewoc) ;Check "previous".
|
||||
(let* ((g (ewoc--last-node ewoc))
|
||||
(d (abs (- pos (ewoc--node-start-marker g)))))
|
||||
(when (< d distance)
|
||||
|
@ -476,14 +482,14 @@ If the EWOC is empty, nil is returned."
|
|||
(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)))
|
||||
(setq best-guess (ewoc--node-next best-guess)))
|
||||
;; ...and return the previous node.
|
||||
(ewoc--node-prev dll best-guess))
|
||||
(ewoc--node-prev 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)))
|
||||
(setq best-guess (ewoc--node-prev best-guess)))
|
||||
best-guess)))))))
|
||||
|
||||
(defun ewoc-invalidate (ewoc &rest nodes)
|
||||
|
@ -507,10 +513,10 @@ Return the node we moved to."
|
|||
(setq arg (1- arg)))
|
||||
(while (and node (> arg 0))
|
||||
(setq arg (1- arg))
|
||||
(setq node (ewoc--node-prev dll node)))
|
||||
(setq node (ewoc--node-prev node)))
|
||||
;; Never step above the first element.
|
||||
(unless (ewoc--filter-hf-nodes ewoc node)
|
||||
(setq node (ewoc--node-nth dll 1)))
|
||||
(setq node (ewoc--node-nth 1)))
|
||||
(ewoc-goto-node ewoc node))))
|
||||
|
||||
(defun ewoc-goto-next (ewoc arg)
|
||||
|
@ -520,10 +526,10 @@ Return the node (or nil if we just passed the last node)."
|
|||
((node (ewoc-locate ewoc (point))))
|
||||
(while (and node (> arg 0))
|
||||
(setq arg (1- arg))
|
||||
(setq node (ewoc--node-next dll node)))
|
||||
(setq node (ewoc--node-next node)))
|
||||
;; Never step below the first element.
|
||||
;; (unless (ewoc--filter-hf-nodes ewoc node)
|
||||
;; (setq node (ewoc--node-nth dll -2)))
|
||||
;; (setq node (ewoc--node-nth -2)))
|
||||
(ewoc-goto-node ewoc node)))
|
||||
|
||||
(defun ewoc-goto-node (ewoc node)
|
||||
|
@ -542,15 +548,15 @@ number of elements needs to be refreshed."
|
|||
(ewoc--set-buffer-bind-dll-let* ewoc
|
||||
((footer (ewoc--footer ewoc)))
|
||||
(let ((inhibit-read-only t))
|
||||
(delete-region (ewoc--node-start-marker (ewoc--node-nth dll 1))
|
||||
(delete-region (ewoc--node-start-marker (ewoc--node-nth 1))
|
||||
(ewoc--node-start-marker footer))
|
||||
(goto-char (ewoc--node-start-marker footer))
|
||||
(let ((pp (ewoc--pretty-printer ewoc))
|
||||
(node (ewoc--node-nth dll 1)))
|
||||
(node (ewoc--node-nth 1)))
|
||||
(while (not (eq node footer))
|
||||
(set-marker (ewoc--node-start-marker node) (point))
|
||||
(funcall pp (ewoc--node-data node))
|
||||
(setq node (ewoc--node-next dll node)))))
|
||||
(setq node (ewoc--node-next node)))))
|
||||
(set-marker (ewoc--node-start-marker footer) (point))))
|
||||
|
||||
(defun ewoc-collect (ewoc predicate &rest args)
|
||||
|
@ -567,12 +573,12 @@ 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))
|
||||
(node (ewoc--node-nth -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)))
|
||||
(setq node (ewoc--node-prev node)))
|
||||
(nreverse result)))
|
||||
|
||||
(defun ewoc-buffer (ewoc)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue