* lisp/emacs-lisp/tabulated-list.el: New optional print method

(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.
This commit is contained in:
Artur Malabarba 2015-05-24 23:38:53 +01:00
parent d38350984e
commit c205098b6a
3 changed files with 59 additions and 10 deletions

View 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