ox: Use tabulated lists for export stack display

* lisp/ox.el (org-export-stack):
(org-export-stack-mode):
(org-export--stack-generate):
(org-export--stack-num-predicate):
(org-export--stack-source-at-point): Use tabulated lists.
This commit is contained in:
Nicolas Goaziou 2016-09-07 18:05:19 +02:00
parent d1c1b7f8fa
commit d66721f6b0
1 changed files with 80 additions and 71 deletions

View File

@ -72,9 +72,10 @@
;;; Code:
(require 'cl-lib)
(require 'ob-exp)
(require 'org-element)
(require 'org-macro)
(require 'ob-exp)
(require 'tabulated-list)
(declare-function org-publish "ox-publish" (project &optional force async))
(declare-function org-publish-all "ox-publish" (&optional force async))
@ -6112,66 +6113,21 @@ removed beforehand. Return the new stack."
"Menu for asynchronous export results and running processes."
(interactive)
(let ((buffer (get-buffer-create "*Org Export Stack*")))
(set-buffer buffer)
(when (zerop (buffer-size)) (org-export-stack-mode))
(org-export-stack-refresh)
(with-current-buffer buffer
(org-export-stack-mode)
(tabulated-list-print t))
(pop-to-buffer buffer))
(message "Type \"q\" to quit, \"?\" for help"))
(defun org-export--stack-source-at-point ()
"Return source from export results at point in stack."
(let ((source (car (nth (1- (org-current-line)) org-export-stack-contents))))
(if (not source) (error "Source unavailable, please refresh buffer")
(let ((source-name (if (stringp source) source (buffer-name source))))
(if (save-excursion
(beginning-of-line)
(looking-at (concat ".* +" (regexp-quote source-name) "$")))
source
;; SOURCE is not consistent with current line. The stack
;; view is outdated.
(error "Source unavailable; type `g' to update buffer"))))))
(defun org-export-stack-clear ()
"Remove all entries from export stack."
(interactive)
(setq org-export-stack-contents nil))
(defun org-export-stack-refresh (&rest _)
"Refresh the asynchronous export stack.
Unavailable sources are removed from the list. Return the new
stack."
(let ((inhibit-read-only t))
(org-preserve-lc
(erase-buffer)
(insert (concat
(mapconcat
(lambda (entry)
(let ((proc-p (processp (nth 2 entry))))
(concat
;; Back-end.
(format " %-12s " (or (nth 1 entry) ""))
;; Age.
(let ((data (nth 2 entry)))
(if proc-p (format " %6s " (process-status data))
;; Compute age of the results.
(format-seconds "%4h:%.2m "
(float-time (time-since data)))))
;; Source.
(format " %s"
(let ((source (car entry)))
(if (stringp source) source
(buffer-name source)))))))
;; Clear stack from exited processes, dead buffers or
;; non-existent files.
(setq org-export-stack-contents
(cl-remove-if-not
(lambda (el)
(if (processp (nth 2 el))
(buffer-live-p (process-buffer (nth 2 el)))
(let ((source (car el)))
(if (bufferp source) (buffer-live-p source)
(file-exists-p source)))))
org-export-stack-contents)) "\n"))))))
(defun org-export-stack-refresh ()
"Refresh the export stack."
(interactive)
(tabulated-list-print t))
(defun org-export-stack-remove (&optional source)
"Remove export results at point from stack.
@ -6195,11 +6151,10 @@ within Emacs."
(defvar org-export-stack-mode-map
(let ((km (make-sparse-keymap)))
(set-keymap-parent km tabulated-list-mode-map)
(define-key km " " 'next-line)
(define-key km "n" 'next-line)
(define-key km "\C-n" 'next-line)
(define-key km [down] 'next-line)
(define-key km "p" 'previous-line)
(define-key km "\C-p" 'previous-line)
(define-key km "\C-?" 'previous-line)
(define-key km [up] 'previous-line)
@ -6210,31 +6165,85 @@ within Emacs."
km)
"Keymap for Org Export Stack.")
(define-derived-mode org-export-stack-mode special-mode "Org-Stack"
(define-derived-mode org-export-stack-mode tabulated-list-mode "Org-Stack"
"Mode for displaying asynchronous export stack.
Type \\[org-export-stack] to visualize the asynchronous export
stack.
In an Org Export Stack buffer, use \\<org-export-stack-mode-map>\\[org-export-stack-view] to view export output
on current line, \\[org-export-stack-remove] to remove it from the stack and \\[org-export-stack-clear] to clear
In an Org Export Stack buffer, use \
\\<org-export-stack-mode-map>\\[org-export-stack-view] to view export output
on current line, \\[org-export-stack-remove] to remove it from the stack and \
\\[org-export-stack-clear] to clear
stack completely.
Removing entries in an Org Export Stack buffer doesn't affect
files or buffers, only the display.
Removing entries in a stack buffer does not affect files
or buffers, only display.
\\{org-export-stack-mode-map}"
(abbrev-mode 0)
(auto-fill-mode 0)
(setq buffer-read-only t
buffer-undo-list t
truncate-lines t
header-line-format
'(:eval
(format " %-12s | %6s | %s" "Back-End" "Age" "Source")))
(add-hook 'post-command-hook 'org-export-stack-refresh nil t)
(setq-local revert-buffer-function
'org-export-stack-refresh))
(setq tabulated-list-format
(vector (list "#" 4 #'org-export--stack-num-predicate)
(list "Back-End" 12 t)
(list "Age" 6 nil)
(list "Source" 0 nil)))
(setq tabulated-list-sort-key (cons "#" nil))
(setq tabulated-list-entries #'org-export--stack-generate)
(add-hook 'tabulated-list-revert-hook #'org-export--stack-generate nil t)
(add-hook 'post-command-hook #'org-export-stack-refresh nil t)
(tabulated-list-init-header))
(defun org-export--stack-generate ()
"Generate the asynchronous export stack for display.
Unavailable sources are removed from the list. Return a list
appropriate for `tabulated-list-print'."
;; Clear stack from exited processes, dead buffers or non-existent
;; files.
(setq org-export-stack-contents
(cl-remove-if-not
(lambda (el)
(if (processp (nth 2 el))
(buffer-live-p (process-buffer (nth 2 el)))
(let ((source (car el)))
(if (bufferp source) (buffer-live-p source)
(file-exists-p source)))))
org-export-stack-contents))
;; Update `tabulated-list-entries'.
(let ((counter 0))
(mapcar
(lambda (entry)
(let ((source (car entry)))
(list source
(vector
;; Counter.
(number-to-string (cl-incf counter))
;; Back-End.
(if (nth 1 entry) (symbol-name (nth 1 entry)) "")
;; Age.
(let ((info (nth 2 entry)))
(if (processp info) (symbol-name (process-status info))
(format-seconds "%h:%.2m" (float-time (time-since info)))))
;; Source.
(if (stringp source) source (buffer-name source))))))
org-export-stack-contents)))
(defun org-export--stack-num-predicate (a b)
(< (string-to-number (aref (nth 1 a) 0))
(string-to-number (aref (nth 1 b) 0))))
(defun org-export--stack-source-at-point ()
"Return source from export results at point in stack."
(let ((source (car (nth (1- (org-current-line)) org-export-stack-contents))))
(if (not source) (error "Source unavailable, please refresh buffer")
(let ((source-name (if (stringp source) source (buffer-name source))))
(if (save-excursion
(beginning-of-line)
(looking-at-p (concat ".* +" (regexp-quote source-name) "$")))
source
;; SOURCE is not consistent with current line. The stack
;; view is outdated.
(error (substitute-command-keys
"Source unavailable; type \\[org-export-stack-refresh] \
to refresh buffer")))))))