From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Thien-Thi Nguyen Newsgroups: gmane.emacs.devel Subject: Re: PATCH: ewoc.el to permit node representation abutment Date: 08 May 2006 04:48:05 -0400 Message-ID: References: <8764kkty67.fsf-monnier+emacs@gnu.org> NNTP-Posting-Host: main.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: sea.gmane.org 1147078139 8291 80.91.229.2 (8 May 2006 08:48:59 GMT) X-Complaints-To: usenet@sea.gmane.org NNTP-Posting-Date: Mon, 8 May 2006 08:48:59 +0000 (UTC) Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Mon May 08 10:48:56 2006 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by ciao.gmane.org with esmtp (Exim 4.43) id 1Fd1QC-0001nY-P5 for ged-emacs-devel@m.gmane.org; Mon, 08 May 2006 10:48:53 +0200 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Fd1QB-0002jU-Qx for ged-emacs-devel@m.gmane.org; Mon, 08 May 2006 04:48:51 -0400 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1Fd1PV-0002h1-MW for emacs-devel@gnu.org; Mon, 08 May 2006 04:48:09 -0400 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1Fd1PT-0002eO-Hj for emacs-devel@gnu.org; Mon, 08 May 2006 04:48:09 -0400 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Fd1PS-0002dx-Ua for emacs-devel@gnu.org; Mon, 08 May 2006 04:48:07 -0400 Original-Received: from [67.59.132.6] (helo=mail.agora-net.com) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA:32) (Exim 4.52) id 1Fd1QG-0000s8-6l for emacs-devel@gnu.org; Mon, 08 May 2006 04:48:56 -0400 Original-Received: from ttn by mail.agora-net.com with local (Exim 4.50) id 1Fd1PR-0004dh-Pt for emacs-devel@gnu.org; Mon, 08 May 2006 04:48:05 -0400 Original-To: emacs-devel@gnu.org In-Reply-To: Original-Lines: 296 User-Agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.4 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:54071 Archived-At: i've revised the patch (please see below) to handle empty representations. this was tested by modifying `cvs-fileinfo-pp' to output empty string for a certain hardcoded filename in my local repo, making the empty string conditional on a variable and toggling the variable followed by either `ewoc-refresh' or `ewoc-invalidate' calls. (this description omits several steps for preparing the testing framework, but you get the idea.) * emacs-lisp/ewoc.el (ewoc--create-node): Don't insert trailing newline. Also, create marker with insertion type t. (ewoc--refresh-node): Delete all text from current node's start marker to the next one's. Also, make the marker "stay put" before calling the pretty-printer, and return it. (ewoc--init-stay-put-list, ewoc--reset-marker-types): New funcs. (ewoc-create): Use marker insertion type t. (ewoc-map): Collect "stay put" markers; reset them when done. (ewoc-invalidate): Rewrite. (ewoc-refresh): Don't insert newline. Collect "stay put" markers; reset them when done. (ewoc-set-hf): Reset header and footer markers when done. * pcvs-info.el (cvs-fileinfo-pp): Insert trailing newline. note that ewoc.el is 1.19 from cvs. thi _________________________________________________________ diff -c -F '^(' ewoc.el ewoc.el.NEW *** ewoc.el Mon May 8 10:00:48 2006 --- ewoc.el.NEW Mon May 8 10:11:45 2006 *************** (defun ewoc--create-node (data pretty-pr *** 249,261 **** (when (markerp pos) (setq pos (marker-position pos))) (goto-char pos) (let ((inhibit-read-only t)) - ;; Insert the trailing newline using insert-before-markers - ;; so that the start position for the next element is updated. - (insert-before-markers ?\n) - ;; Move back, and call the pretty-printer. - (backward-char 1) (funcall pretty-printer data) ! (ewoc--node-create (copy-marker pos) data)))) (defun ewoc--delete-node-internal (ewoc node) --- 249,256 ---- (when (markerp pos) (setq pos (marker-position pos))) (goto-char pos) (let ((inhibit-read-only t)) (funcall pretty-printer data) ! (ewoc--node-create (copy-marker pos t) data)))) (defun ewoc--delete-node-internal (ewoc node) *************** (defun ewoc--delete-node-internal (ewoc *** 276,293 **** ;; Delete the node, and return the wrapper. (ewoc--node-delete node))) (defun ewoc--refresh-node (pp node) ! "Redisplay the element represented by NODE using the pretty-printer PP." (let ((inhibit-read-only t)) (save-excursion ;; First, remove the string from the buffer: (delete-region (ewoc--node-start-marker node) ! (1- (marker-position ! (ewoc--node-start-marker (ewoc--node-right node))))) ;; Calculate and insert the string. ! (goto-char (ewoc--node-start-marker node)) ! (funcall pp (ewoc--node-data node))))) ;;; =========================================================================== ;;; Public members of the Ewoc package --- 271,317 ---- ;; Delete the node, and return the wrapper. (ewoc--node-delete node))) + ;; Refresh protocol + ;; + ;; Refresh requires essentially two passes. The first collects info on which + ;; nodes have been visited. The header is always visited, the footer never. + ;; For each node visited in order of increasing position: (1a) set marker + ;; insertion type to nil; (1b) do the pretty-printing (if necessary). Then, + ;; when all pretty-printing is done: (2) reset all insertion types to t. + ;; + ;; This approach ensures that a series of prior nodes (including the header) + ;; can insert nothing (empty string) and maintain their start markers (aka + ;; "stay put") should a later node insert something (non-empty string) at the + ;; same position. Note: "series" for prior and "a" for later because when + ;; something is inserted, that changes the position. This property explains + ;; the "if necessary" in the previous paragraph; for partial refresh (i.e., + ;; `ewoc-invalidate') we must visit those nodes prior to the ones requested + ;; iff they have the same position even though we do not pretty-print them. (defun ewoc--refresh-node (pp node) ! "Redisplay the element represented by NODE using the pretty-printer PP. ! Set NODE's start marker's insertion type to nil and return it." (let ((inhibit-read-only t)) (save-excursion ;; First, remove the string from the buffer: (delete-region (ewoc--node-start-marker node) ! (ewoc--node-start-marker (ewoc--node-right node))) ;; Calculate and insert the string. ! (let ((m (ewoc--node-start-marker node))) ! (goto-char m) ! (set-marker-insertion-type m nil) ! (funcall pp (ewoc--node-data node)) ! m)))) ! ! (defun ewoc--init-stay-put-list (ewoc) ! (let ((m (ewoc--node-start-marker (ewoc--header ewoc)))) ! (set-marker-insertion-type m nil) ! (list m))) ! ! (defsubst ewoc--reset-marker-types (list) ! (dolist (m list) ! (set-marker-insertion-type m t))) ! ;;; =========================================================================== ;;; Public members of the Ewoc package *************** (defun ewoc-create (pretty-printer &opti *** 301,308 **** PRETTY-PRINTER should be a function that takes one argument, an element, and inserts a string representing it in the buffer (at point). The string PRETTY-PRINTER inserts may be empty or span ! several lines. A trailing newline will always be inserted ! automatically. The PRETTY-PRINTER should use `insert', and not `insert-before-markers'. Optional second argument HEADER is a string that will always be --- 325,331 ---- PRETTY-PRINTER should be a function that takes one argument, an element, and inserts a string representing it in the buffer (at point). The string PRETTY-PRINTER inserts may be empty or span ! several lines. The PRETTY-PRINTER should use `insert', and not `insert-before-markers'. Optional second argument HEADER is a string that will always be *************** (defun ewoc-create (pretty-printer &opti *** 317,323 **** ;; Set default values (unless header (setq header "")) (unless footer (setq footer "")) ! (setf (ewoc--node-start-marker dll) (copy-marker pos)) (let ((foot (ewoc--create-node footer 'insert pos)) (head (ewoc--create-node header 'insert pos))) (ewoc--node-enter-first dll head) --- 340,346 ---- ;; Set default values (unless header (setq header "")) (unless footer (setq footer "")) ! (setf (ewoc--node-start-marker dll) (copy-marker pos t)) (let ((foot (ewoc--create-node footer 'insert pos)) (head (ewoc--create-node header 'insert pos))) (ewoc--node-enter-first dll head) *************** (defun ewoc-map (map-function ewoc &rest *** 400,411 **** If more than two arguments are given, the remaining arguments will be passed to MAP-FUNCTION." (ewoc--set-buffer-bind-dll-let* ewoc ! ((footer (ewoc--footer ewoc)) ! (node (ewoc--node-nth dll 1))) (while (not (eq node footer)) (if (apply map-function (ewoc--node-data node) args) ! (ewoc--refresh-node (ewoc--pretty-printer ewoc) node)) ! (setq node (ewoc--node-next dll node))))) (defun ewoc-filter (ewoc predicate &rest args) "Remove all elements in EWOC for which PREDICATE returns nil. --- 423,437 ---- If more than two arguments are given, the remaining arguments will be passed to MAP-FUNCTION." (ewoc--set-buffer-bind-dll-let* ewoc ! ((pp (ewoc--pretty-printer ewoc)) ! (footer (ewoc--footer ewoc)) ! (node (ewoc--node-nth dll 1)) ! (stay-put (ewoc--init-stay-put-list ewoc))) (while (not (eq node footer)) (if (apply map-function (ewoc--node-data node) args) ! (push (ewoc--refresh-node pp node) stay-put)) ! (setq node (ewoc--node-next dll node))) ! (ewoc--reset-marker-types stay-put))) (defun ewoc-filter (ewoc predicate &rest args) "Remove all elements in EWOC for which PREDICATE returns nil. *************** (defun ewoc-locate (ewoc &optional pos g *** 497,505 **** (defun ewoc-invalidate (ewoc &rest nodes) "Call EWOC's pretty-printer for each element in NODES. Delete current text first, thus effecting a \"refresh\"." ! (ewoc--set-buffer-bind-dll ewoc ! (dolist (node nodes) ! (ewoc--refresh-node (ewoc--pretty-printer ewoc) node)))) (defun ewoc-goto-prev (ewoc arg) "Move point to the ARGth previous element in EWOC. --- 523,562 ---- (defun ewoc-invalidate (ewoc &rest nodes) "Call EWOC's pretty-printer for each element in NODES. Delete current text first, thus effecting a \"refresh\"." ! (ewoc--set-buffer-bind-dll-let* ewoc ! ((pp (ewoc--pretty-printer ewoc)) ! (header (ewoc--header ewoc)) ! (stay-put (ewoc--init-stay-put-list ewoc))) ! (setq nodes ! (sort nodes ! (lambda (a b) ! (let ((am (ewoc--node-start-marker a)) ! (bm (ewoc--node-start-marker b))) ! (cond ((> am bm) nil) ! ((< am bm) t) ! (t ;; i.e., (= am bm) ! ;; Maintain DLL ordering: A is "less than" B ! ;; if is found closer to the header than B. ! (let (donep lessp) ! (while (not (or donep ! (eq header ! (setq b (ewoc--node-left ! b))))) ! (when (eq a b) ! (setq lessp t donep t))) ! lessp))))))) ! (let ((stop (ewoc--header ewoc)) ! node-m mid mid-m) ! (dolist (node nodes) ! (setq node-m (ewoc--node-start-marker node) ! mid node) ! (while (and (not (eq stop (setq mid (ewoc--node-left mid)))) ! (= node-m (setq mid-m (ewoc--node-start-marker mid)))) ! (set-marker-insertion-type mid-m nil) ! (push mid-m stay-put)) ! (push (ewoc--refresh-node pp node) stay-put) ! (setq stop node))) ! (ewoc--reset-marker-types stay-put))) (defun ewoc-goto-prev (ewoc arg) "Move point to the ARGth previous element in EWOC. *************** (defun ewoc-refresh (ewoc) *** 551,563 **** (delete-region (ewoc--node-start-marker (ewoc--node-nth dll 1)) (ewoc--node-start-marker footer)) (goto-char (ewoc--node-start-marker footer)) ! (let ((node (ewoc--node-nth dll 1))) (while (not (eq node footer)) ! (set-marker (ewoc--node-start-marker node) (point)) ! (funcall (ewoc--pretty-printer ewoc) ! (ewoc--node-data node)) ! (insert "\n") ! (setq node (ewoc--node-next dll node))))) (set-marker (ewoc--node-start-marker footer) (point)))) (defun ewoc-collect (ewoc predicate &rest args) --- 608,625 ---- (delete-region (ewoc--node-start-marker (ewoc--node-nth dll 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)) ! (stay-put (ewoc--init-stay-put-list ewoc)) ! m) (while (not (eq node footer)) ! (setq m (ewoc--node-start-marker node)) ! (set-marker m (point)) ! (set-marker-insertion-type m nil) ! (push m stay-put) ! (funcall pp (ewoc--node-data node)) ! (setq node (ewoc--node-next dll node))) ! (ewoc--reset-marker-types stay-put))) (set-marker (ewoc--node-start-marker footer) (point)))) (defun ewoc-collect (ewoc predicate &rest args) *************** (defun ewoc-set-hf (ewoc header footer) *** 597,604 **** "Set the HEADER and FOOTER of EWOC." (setf (ewoc--node-data (ewoc--header ewoc)) header) (setf (ewoc--node-data (ewoc--footer ewoc)) footer) ! (ewoc--refresh-node 'insert (ewoc--header ewoc)) ! (ewoc--refresh-node 'insert (ewoc--footer ewoc))) (provide 'ewoc) --- 659,668 ---- "Set the HEADER and FOOTER of EWOC." (setf (ewoc--node-data (ewoc--header ewoc)) header) (setf (ewoc--node-data (ewoc--footer ewoc)) footer) ! (let ((stay-put (list ! (ewoc--refresh-node 'insert (ewoc--header ewoc)) ! (ewoc--refresh-node 'insert (ewoc--footer ewoc))))) ! (ewoc--reset-marker-types stay-put))) (provide 'ewoc)