From a965c062133dea33dfddb5e3eabf373e2084b466 Mon Sep 17 00:00:00 2001 From: Nicolas Goaziou Date: Sun, 24 Feb 2013 13:49:29 +0100 Subject: [PATCH] ox: Use tabulated list mode for asynchronous stack * lisp/ox.el (org-export-stack): Rewrite. (org-export-stack-refresh): Refactor. (org-export-stack-remove, org-export-stack-view): Apply renaming. (org-export-stack-mode-map): Use tabulated list map as a basis. (org-export-stack--generate, org-export-stack--num-predicate): New function. --- lisp/ox.el | 142 +++++++++++++++++++++++++++-------------------------- 1 file changed, 73 insertions(+), 69 deletions(-) diff --git a/lisp/ox.el b/lisp/ox.el index 996106368..aa8bfa891 100644 --- a/lisp/ox.el +++ b/lisp/ox.el @@ -77,6 +77,7 @@ ;;; Code: (eval-when-compile (require 'cl)) +(require 'tabulated-list) (require 'org-element) (require 'org-macro) (require 'ob-exp) @@ -5142,74 +5143,27 @@ 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 dummy) - "Refresh the asynchronous export stack. -DUMMY is ignored. Unavailable sources are removed from the list. -Return the new stack." - (let ((inhibit-read-only t)) - (org-preserve-lc - (erase-buffer) - (insert (concat - (let ((counter 0)) - (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. - (org-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 - (org-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 asynchronous export stack." + (interactive) + (tabulated-list-print t)) (defun org-export-stack-remove (&optional source) "Remove export results at point from stack. If optional argument SOURCE is non-nil, remove it instead." (interactive) - (let ((source (or source (org-export--stack-source-at-point)))) + (let ((source (or source (org-export-stack--source-at-point)))) (setq org-export-stack-contents (org-remove-if (lambda (el) (equal (car el) source)) org-export-stack-contents)))) @@ -5219,7 +5173,7 @@ If optional argument SOURCE is non-nil, remove it instead." With an optional prefix argument IN-EMACS, force viewing files within Emacs." (interactive "P") - (let ((source (org-export--stack-source-at-point))) + (let ((source (org-export-stack--source-at-point))) (cond ((processp source) (org-switch-to-buffer-other-window (process-buffer source))) ((bufferp source) (org-switch-to-buffer-other-window source)) @@ -5227,11 +5181,10 @@ within Emacs." (defconst 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) @@ -5239,10 +5192,11 @@ within Emacs." (define-key km "v" 'org-export-stack-view) (define-key km (kbd "RET") 'org-export-stack-view) (define-key km "d" 'org-export-stack-remove) + (define-key km "r" 'org-export-stack-refresh) 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 @@ -5256,17 +5210,67 @@ Removing entries in an Org Export Stack buffer doesn't affect files or buffers, only the 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"))) + (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) - (set (make-local-variable 'revert-buffer-function) - 'org-export-stack-refresh)) + (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 + (org-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 (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)) + (org-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 (concat ".* +" (regexp-quote source-name) "$"))) + source + ;; SOURCE is not consistent with current line. The stack + ;; view is outdated. + (error "Source unavailable; type `r' to refresh buffer"))))))