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.
This commit is contained in:
Alex Kost 2015-09-15 21:27:44 +03:00
parent c093f9f63a
commit eda1cc8b5d
2 changed files with 87 additions and 0 deletions

View File

@ -591,6 +591,12 @@ Move to the next build phase.
@item M-p @item M-p
Move to the previous build phase. 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 @end table
There is also @kbd{M-x guix-build-log-minor-mode} which also provides There is also @kbd{M-x guix-build-log-minor-mode} which also provides

View File

@ -144,6 +144,12 @@ STATE is a symbol denoting how a build phase was ended. It should be
(group (1+ digit)) " seconds") (group (1+ digit)) " seconds")
t))) 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 (defvar guix-build-log-font-lock-keywords
`((,(guix-build-log-title-regexp 'start) `((,(guix-build-log-title-regexp 'start)
(1 'guix-build-log-title-head) (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) (set-keymap-parent map special-mode-map)
(define-key map (kbd "M-n") 'guix-build-log-next-phase) (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 "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) map)
"Keymap for `guix-build-log-mode' buffers.") "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) (defun guix-build-log-next-phase (&optional arg)
"Move to the next build phase. "Move to the next build phase.
With ARG, do it that many times. Negative ARG means move With ARG, do it that many times. Negative ARG means move