From 54844c3988c88535186d0b89e7d44fdfbbcc63ae Mon Sep 17 00:00:00 2001 From: Radon Rosborough Date: Mon, 3 Jan 2022 20:07:44 -0800 Subject: [PATCH] [#69] Improvements to Apheleia logging * Rename apheleia-hide-log-buffer to apheleia-hide-log-buffers. * Rename apheleia-verbose to apheleia-log-only-errors (note, meaning is inverted). * Add apheleia-hide-old-log-entries. * Include more information in log and format it more neatly. * Convert log buffer to special-mode and attempt to keep point at the end (although this is not working for an undetermined reason). --- CHANGELOG.md | 10 +++--- README.md | 17 ++++++++++ apheleia.el | 95 ++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 92 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index febead0..90b9b94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,10 +13,12 @@ The format is based on [Keep a Changelog]. ## Changes * Stdout and stderr buffers are no longer retained after running a formatter. Instead, the stderr is appended into an - `*apheleia-whatever-log*` buffer if it fails, or unconditionally if - the new user option `apheleia-verbose` is set to non-nil. See [#64], - [#65]. The log buffer is not hidden by default, and this can be - changed via the new user option `apheleia-hide-log-buffer` ([#69]). + `*apheleia-cmdname-log*` buffer if it fails, or unconditionally if + the new user option `apheleia-log-only-errors` is set to nil. See + [#64], [#65]. The log buffer is not hidden by default, and shows all + command output rather than just the latest run. These behaviors can + be customized using the new user options `apheleia-hide-log-buffers` + and `apheleia-hide-old-log-entries` ([#69]). ## Formatters * [fish\_indent](https://fishshell.com/docs/current/cmds/fish_indent.html) diff --git a/README.md b/README.md index be22b9f..23e4d41 100644 --- a/README.md +++ b/README.md @@ -169,6 +169,23 @@ run. Apheleia does not currently support TRAMP, and is therefore automatically disabled for remote files. +You can configure error reporting using the following user options: + +* `apheleia-hide-log-buffers`: By default, errors from formatters are + put in buffers named like `*apheleia-cmdname-log*`. If you customize + this user option to non-nil then a space is prepended to the names + of these buffers, hiding them by default in `switch-to-buffer` (you + must type a space to see them). +* `apheleia-log-only-errors`: By default, only failed formatter runs + are logged. If you customize this user option to nil then all runs + are logged, along with whether or not they succeeded. +* `apheleia-hide-old-log-entries`: By default, all failed formatter + runs are appended to the log. It is intended that point stay at the + end of the buffer by default, but due to an unknown bug this is not + currently the case. By customizing this user option to non-nil, you + can cause only the most recent failure for a formatter to be + retained in its log buffer. + The following user options are also available: * `apheleia-post-format-hook`: Normal hook run after Apheleia formats diff --git a/apheleia.el b/apheleia.el index 5c9769c..bb3ff91 100644 --- a/apheleia.el +++ b/apheleia.el @@ -36,13 +36,24 @@ :link '(url-link :tag "GitHub" "https://github.com/raxod502/apheleia") :link '(emacs-commentary-link :tag "Commentary" "apheleia")) -(defcustom apheleia-hide-log-buffer nil +(defcustom apheleia-hide-log-buffers nil "Non-nil means log buffers will be hidden. Hidden buffers have names that begin with a space, and do not appear in `switch-to-buffer' unless you type in a space manually." :type 'boolean) +(defcustom apheleia-log-only-errors t + "Non-nil means Apheleia will only log when an error occurs. +Otherwise, Apheleia will log every time a formatter is run, even +if it is successful." + :type 'boolean) + +(defcustom apheleia-hide-old-log-entries nil + "Non-nil means only the most recent log entry will be retained. +This is on a per-formatter basis." + :type 'boolean) + (cl-defun apheleia--edit-distance-table (s1 s2) "Align strings S1 and S2 for minimum edit distance. Return the dynamic programming table as has table which maps cons @@ -261,11 +272,6 @@ contains the patch." Keeping track of this helps avoid running more than one process at once.") -(defvar apheleia-verbose nil - "When true `apheleia' produces richer log buffers. -Specifically, formatter stderr is appended to the log buffer even -if there is no error.") - (cl-defun apheleia--make-process (&key command stdin callback ensure exit-status) "Wrapper for `make-process' that behaves a bit more nicely. @@ -289,12 +295,11 @@ command succeeds provided that its exit status is 0." (format " *apheleia-%s-stdout*" name))) (stderr (generate-new-buffer (format " *apheleia-%s-stderr*" name))) - (log (get-buffer-create - (format "%s*apheleia-%s-log*" - (if apheleia-hide-log-buffer - " " - "") - name)))) + (log-name (format "%s*apheleia-%s-log*" + (if apheleia-hide-log-buffers + " " + "") + name))) (condition-case-unless-debug e (progn (setq apheleia--current-process @@ -308,22 +313,60 @@ command succeeds provided that its exit status is 0." (lambda (proc _event) (unless (process-live-p proc) (let ((exit-ok (funcall - (or exit-status - (lambda (status) - (= 0 status))) + (or exit-status #'zerop) (process-exit-status proc)))) ;; Append standard-error from current formatter - ;; to log buffer when `apheleia-verbose' or the + ;; to log buffer when + ;; `apheleia-log-only-errors' is nil or the ;; formatter failed. Every process output is ;; delimited by a line-feed character. - (with-current-buffer log - (when (or apheleia-verbose - (not exit-ok)) - (if (= 0 (with-current-buffer stderr - (buffer-size))) - (insert "[No output received on stderr]") - (insert-buffer-substring stderr)) - (insert "\n\C-l\n"))) + (unless (and exit-ok apheleia-log-only-errors) + (with-current-buffer (get-buffer-create log-name) + (special-mode) + (save-restriction + (widen) + (let ((inhibit-read-only t) + (orig-point (point)) + (keep-at-end (eobp)) + (stderr-string + (with-current-buffer stderr + (string-trim (buffer-string))))) + (when apheleia-hide-old-log-entries + (erase-buffer)) + (goto-char (point-max)) + (skip-chars-backward "\n") + (delete-region (point) (point-max)) + (unless (bobp) + (insert + "\n\n\C-l\n")) + (insert + (current-time-string) + " :: " + (buffer-local-value 'default-directory stdout) + "\n$ " + (mapconcat #'shell-quote-argument command " ") + "\n\n" + (if (string-empty-p stderr-string) + "(no output on stderr)" + stderr-string) + "\n\n" + "Command " + (if exit-ok "succeeded" "failed") + " with exit code " + (number-to-string (process-exit-status proc)) + ".\n") + ;; Known issue: this does not actually + ;; work; point is left at the end of + ;; the previous command output, instead + ;; of being moved to the end of the + ;; buffer for some reason. + (goto-char + (if keep-at-end + (point-max) + (min + (point-max) + orig-point))) + (goto-char (point-max)))))) (unwind-protect (if exit-ok (when callback @@ -334,10 +377,10 @@ command succeeds provided that its exit status is 0." "(see %s %s)") (car command) (process-exit-status proc) - (if (string-prefix-p " " (buffer-name log)) + (if (string-prefix-p " " log-name) "hidden buffer" "buffer") - (string-trim (buffer-name log)))) + (string-trim log-name))) (when ensure (funcall ensure)) (kill-buffer stdout)