aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Kost <alezost@gmail.com>2015-09-15 21:27:44 +0300
committerAlex Kost <alezost@gmail.com>2015-09-18 21:41:23 +0300
commiteda1cc8b5d68189166e1d61142aa84e5af4187c7 (patch)
tree356dfd1bde69199f0d102c94655ac2d0a8065c8f
parentc093f9f63a57ae8fa9d230249f0b724f80763dc5 (diff)
downloadpatches-eda1cc8b5d68189166e1d61142aa84e5af4187c7.tar
patches-eda1cc8b5d68189166e1d61142aa84e5af4187c7.tar.gz
emacs: Add commands to show/hide build log phases.
Suggested by Ludovic Courtès <ludo@gnu.org>. * emacs/guix-build-log.el (guix-build-log-phase-end-regexp): New variable. (guix-build-log-phase-start, guix-build-log-phase-end, guix-build-log-phase-hide, guix-build-log-phase-show, guix-build-log-phase-hidden-p, guix-build-log-phase-toggle-function, guix-build-log-phase-toggle, guix-build-log-phase-toggle-all): New functions. (guix-build-log-mode-map): Add 'TAB'/'S-TAB' key bindings. * doc/emacs.texi (Emacs Build Log): Document them.
-rw-r--r--doc/emacs.texi6
-rw-r--r--emacs/guix-build-log.el81
2 files changed, 87 insertions, 0 deletions
diff --git a/doc/emacs.texi b/doc/emacs.texi
index 33bdbd23d9..67773466a4 100644
--- a/doc/emacs.texi
+++ b/doc/emacs.texi
@@ -591,6 +591,12 @@ Move to the next build phase.
@item M-p
Move to the previous build phase.
+@item @key{TAB}
+Toggle (show/hide) the body of the current build phase.
+
+@item S-@key{TAB}
+Toggle (show/hide) the bodies of all build phases.
+
@end table
There is also @kbd{M-x guix-build-log-minor-mode} which also provides
diff --git a/emacs/guix-build-log.el b/emacs/guix-build-log.el
index 6d71521a86..6faa37c311 100644
--- a/emacs/guix-build-log.el
+++ b/emacs/guix-build-log.el
@@ -144,6 +144,12 @@ STATE is a symbol denoting how a build phase was ended. It should be
(group (1+ digit)) " seconds")
t)))
+(defvar guix-build-log-phase-end-regexp
+ ;; For efficiency, it is better to have a regexp for the general line
+ ;; of the phase end, then to call the function all the time.
+ (guix-build-log-phase-end-regexp)
+ "Regexp for the end line of a 'build' phase.")
+
(defvar guix-build-log-font-lock-keywords
`((,(guix-build-log-title-regexp 'start)
(1 'guix-build-log-title-head)
@@ -177,9 +183,84 @@ STATE is a symbol denoting how a build phase was ended. It should be
(set-keymap-parent map special-mode-map)
(define-key map (kbd "M-n") 'guix-build-log-next-phase)
(define-key map (kbd "M-p") 'guix-build-log-previous-phase)
+ (define-key map (kbd "TAB") 'guix-build-log-phase-toggle)
+ (define-key map (kbd "<tab>") 'guix-build-log-phase-toggle)
+ (define-key map (kbd "<backtab>") 'guix-build-log-phase-toggle-all)
+ (define-key map [(shift tab)] 'guix-build-log-phase-toggle-all)
map)
"Keymap for `guix-build-log-mode' buffers.")
+(defun guix-build-log-phase-start (&optional with-header?)
+ "Return the start point of the current build phase.
+If WITH-HEADER? is non-nil, do not skip 'starting phase ...' header.
+Return nil, if there is no phase start before the current point."
+ (save-excursion
+ (end-of-line)
+ (when (re-search-backward guix-build-log-phase-start-regexp nil t)
+ (unless with-header? (end-of-line))
+ (point))))
+
+(defun guix-build-log-phase-end ()
+ "Return the end point of the current build phase."
+ (save-excursion
+ (beginning-of-line)
+ (when (re-search-forward guix-build-log-phase-end-regexp nil t)
+ (point))))
+
+(defun guix-build-log-phase-hide ()
+ "Hide the body of the current build phase."
+ (interactive)
+ (let ((beg (guix-build-log-phase-start))
+ (end (guix-build-log-phase-end)))
+ (when (and beg end)
+ ;; If not on the header line, move to it.
+ (when (and (> (point) beg)
+ (< (point) end))
+ (goto-char (guix-build-log-phase-start t)))
+ (remove-overlays beg end 'invisible t)
+ (let ((o (make-overlay beg end)))
+ (overlay-put o 'evaporate t)
+ (overlay-put o 'invisible t)))))
+
+(defun guix-build-log-phase-show ()
+ "Show the body of the current build phase."
+ (interactive)
+ (let ((beg (guix-build-log-phase-start))
+ (end (guix-build-log-phase-end)))
+ (when (and beg end)
+ (remove-overlays beg end 'invisible t))))
+
+(defun guix-build-log-phase-hidden-p ()
+ "Return non-nil, if the body of the current build phase is hidden."
+ (let ((beg (guix-build-log-phase-start)))
+ (and beg
+ (cl-some (lambda (o)
+ (overlay-get o 'invisible))
+ (overlays-at beg)))))
+
+(defun guix-build-log-phase-toggle-function ()
+ "Return a function to toggle the body of the current build phase."
+ (if (guix-build-log-phase-hidden-p)
+ #'guix-build-log-phase-show
+ #'guix-build-log-phase-hide))
+
+(defun guix-build-log-phase-toggle ()
+ "Show/hide the body of the current build phase."
+ (interactive)
+ (funcall (guix-build-log-phase-toggle-function)))
+
+(defun guix-build-log-phase-toggle-all ()
+ "Show/hide the bodies of all build phases."
+ (interactive)
+ (save-excursion
+ ;; Some phases may be hidden, and some shown. Whether to hide or to
+ ;; show them, it is determined by the state of the first phase here.
+ (goto-char (point-min))
+ (guix-build-log-next-phase)
+ (let ((fun (guix-build-log-phase-toggle-function)))
+ (while (re-search-forward guix-build-log-phase-start-regexp nil t)
+ (funcall fun)))))
+
(defun guix-build-log-next-phase (&optional arg)
"Move to the next build phase.
With ARG, do it that many times. Negative ARG means move