]> git.eshelyaron.com Git - emacs.git/commitdiff
* lisp/emacs-lisp/tabulated-list.el: New optional print method
authorArtur Malabarba <bruce.connor.am@gmail.com>
Sun, 24 May 2015 22:38:53 +0000 (23:38 +0100)
committerArtur Malabarba <bruce.connor.am@gmail.com>
Sun, 24 May 2015 22:45:46 +0000 (23:45 +0100)
(tabulated-list-print): New optional argument, UPDATE.  If
non-nil, the list is printed by only adding and deleting the
changed entries, instead of erasing the whole buffer.  This method
is much faster when few or no entries have changed.

* doc/lispref/modes.texi (Tabulated List Mode): Document it.

* etc/NEWS: Document it.

doc/lispref/modes.texi
etc/NEWS
lisp/emacs-lisp/tabulated-list.el

index c325506da114ac41bfc4048c4c679d77377c92d2..a8b6bb19c5f1586a5764f5968fa509b457d59b18 100644 (file)
@@ -1055,7 +1055,7 @@ the above variables (in particular, only after setting
 @code{tabulated-list-format}).
 @end defun
 
-@defun tabulated-list-print &optional remember-pos
+@defun tabulated-list-print &optional remember-pos update
 This function populates the current buffer with entries.  It should be
 called by the listing command.  It erases the buffer, sorts the entries
 specified by @code{tabulated-list-entries} according to
@@ -1065,6 +1065,13 @@ specified by @code{tabulated-list-entries} according to
 If the optional argument @var{remember-pos} is non-@code{nil}, this
 function looks for the @var{id} element on the current line, if any, and
 tries to move to that entry after all the entries are (re)inserted.
+
+If the optional argument @var{update} is non-@code{nil}, this function
+will only erase or add entries that have changed since the last print.
+This is several times faster if most entries haven't changed since the
+last time this function was called.  The only difference in outcome is
+that tags placed via @code{tabulated-list-put-tag} will not be removed
+from entries that haven't changed (normally all tags are removed).
 @end defun
 
 @node Generic Modes
index 7ad85bae5b23c78da567683dcd132a429508fc8d..b922a276e0518e772810ff63bcd23bf5c086e1a9 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -205,10 +205,16 @@ font, and (iii) the specified window.
    `message' and related functions from displaying messages the Echo
    Area.  The output is still logged to the *Messages* buffer.
 
++++
 ** It is now safe for a mode that derives `tabulated-list-mode' to not
 call `tabulated-list-init-header', in which case it will have no
 header.
 
++++
+** `tabulated-list-print' takes a second optional argument, update,
+which specifies an alternative printing method which is faster when
+few or no entries have changed.
+
 \f
 * Editing Changes in Emacs 25.1
 
index 9d55ab8f533eaa55fa610f7c4cddf0b143c212eb..58b8fd62d2f8c0d86e9cad8e69f77aa344dadaed 100644 (file)
@@ -298,7 +298,7 @@ column.  Negate the predicate that would be returned if
           (lambda (a b) (not (funcall sorter a b)))
         sorter))))
 
-(defun tabulated-list-print (&optional remember-pos)
+(defun tabulated-list-print (&optional remember-pos update)
   "Populate the current Tabulated List mode buffer.
 This sorts the `tabulated-list-entries' list if sorting is
 specified by `tabulated-list-sort-key'.  It then erases the
@@ -306,7 +306,14 @@ buffer and inserts the entries with `tabulated-list-printer'.
 
 Optional argument REMEMBER-POS, if non-nil, means to move point
 to the entry with the same ID element as the current line and
-recenter window line accordingly."
+recenter window line accordingly.
+
+Non-nil UPDATE argument means to use an alternative printing
+method which is faster if most entries haven't changed since the
+last print.  The only difference in outcome is that tags will not
+be removed from entries that haven't changed (see
+`tabulated-list-put-tag').  Don't use this immediately after
+changing `tabulated-list-sort-key'."
   (let ((inhibit-read-only t)
        (entries (if (functionp tabulated-list-entries)
                     (funcall tabulated-list-entries)
@@ -319,18 +326,47 @@ recenter window line accordingly."
                  (count-screen-lines (window-start) (point))))
         (setq entry-id (tabulated-list-get-id))
         (setq saved-col (current-column)))
-    (erase-buffer)
-    (unless tabulated-list-use-header-line
-      (tabulated-list-print-fake-header))
     ;; Sort the entries, if necessary.
     (setq entries (sort entries sorter))
     (unless (functionp tabulated-list-entries)
       (setq tabulated-list-entries entries))
+    ;; Without a sorter, we have no way to just update.
+    (when (and update (not sorter))
+      (setq update nil))
+    (if update (goto-char (point-min))
+      ;; Redo the buffer, unless we're just updating.
+      (erase-buffer)
+      (unless tabulated-list-use-header-line
+        (tabulated-list-print-fake-header)))
+    ;; Finally, print the resulting list.
     (dolist (elt entries)
-      (and entry-id
-          (equal entry-id (car elt))
-          (setq saved-pt (point)))
-      (apply tabulated-list-printer elt))
+      (let ((id (car elt)))
+        (and entry-id
+             (equal entry-id id)
+             (setq entry-id nil
+                   saved-pt (point)))
+        ;; If the buffer this empty, simply print each elt.
+        (if (eobp)
+            (apply tabulated-list-printer elt)
+          (while (let ((local-id (tabulated-list-get-id)))
+                   ;; If we find id, then nothing to update.
+                   (cond ((equal id local-id)
+                          (forward-line 1)
+                          nil)
+                         ;; If this entry sorts after id (or it's the
+                         ;; end), then just insert id and move on.
+                         ((funcall sorter elt
+                                   ;; FIXME: Might be faster if
+                                   ;; don't construct this list.
+                                   (list local-id (tabulated-list-get-entry)))
+                          (apply tabulated-list-printer elt)
+                          nil)
+                         ;; We find an entry that sorts before id,
+                         ;; it needs to be deleted.
+                         (t t)))
+            (let ((old (point)))
+              (forward-line 1)
+              (delete-region old (point)))))))
     (set-buffer-modified-p nil)
     ;; If REMEMBER-POS was specified, move to the "old" location.
     (if saved-pt