radian-software / apheleia

🌷 Run code formatter on buffer contents without moving point, using RCS patches and dynamic programming.
MIT License
570 stars 80 forks source link

Closing a file after editing causes error "selecting deleted buffer" #91

Open philipsd6 opened 2 years ago

philipsd6 commented 2 years ago

A typical workflow for me is:

emacsclient filename.yaml

Then editing it... followed by C-x C-s C-x # to save and close the server edit buffer, or just C-x # and y when prompted to save. In either case, unless there is a brief pause after saving, I receive the following error:

error in process sentinel: Selecting deleted buffer

If I have (setq debug-on-error t) then I see all of this:

Debugger entered--Lisp error: (error "Selecting deleted buffer")
  #f(compiled-function (formatted-buffer) #<bytecode -0x12a58b9977bc0ba3>)(#<buffer  *apheleia-prettier-stdout*>)
  #f(compiled-function (stdout) #<bytecode -0x1001ef31becdbbf4>)(#<buffer  *apheleia-prettier-stdout*>)
  #f(compiled-function (stdout) #<bytecode -0x135790d5b55c2f90>)(#<buffer  *apheleia-prettier-stdout*>)
  #f(compiled-function (proc event) #<bytecode 0x1697bb085bc189a9>)(#<process apheleia-prettier> "finished\n")

Without debug-on-error it's only mildly distracting, but still I was wondering if there was some way to avoid this error for what seems a normal usage pattern?

raxod502 commented 2 years ago

I've been getting that Selecting deleted buffer issue for some time now occasionally, but I haven't yet been able to get to the bottom of what's happening :/

I think it may be a subtle bug introduced with some of the recent refactoring to allow formatters to be chained together.

mohkale commented 2 years ago

Interesting. Sadly I can't reproduce a backtrace with the instructions you've shared.

@philipsd6 Could you do M-x find-library apheliea and M-x eval-buffer and produce and share the stack trace again? Everything being byte-compiled makes it hard to really see what's going on.

philipsd6 commented 2 years ago

Done! I just upgraded my VM to Ubuntu 22.04 LTS and recompiled Emacs from the latest HEAD, and I can still reproduce the issue as I described earlier. Here's the new stacktrace:

Debugger entered--Lisp error: (error "Selecting deleted buffer")
  set-buffer(#<killed buffer>)
  (save-current-buffer (set-buffer cur-buffer) (if (equal apheleia--buffer-hash (apheleia--buffer-hash)) (progn (apheleia--create-rcs-patch (current-buffer) formatted-buffer #'(lambda (patch-buffer) (save-current-buffer (set-buffer cur-buffer) (if ... ...)))))))
  (closure ((cur-buffer . #<killed buffer>) (formatters prettier) (callback closure ((formatters prettier) t) nil (condition-case err (progn (if buffer-file-name (progn ...)) (run-hooks 'apheleia-post-format-hook)) ((debug error) (message "Apheleia: %s" err) nil))) (formatter prettier) t) (formatted-buffer) (save-current-buffer (set-buffer cur-buffer) (if (equal apheleia--buffer-hash (apheleia--buffer-hash)) (progn (apheleia--create-rcs-patch (current-buffer) formatted-buffer #'(lambda ... ...))))))(#<buffer  *apheleia-prettier-stdout*>)
  funcall((closure ((cur-buffer . #<killed buffer>) (formatters prettier) (callback closure ((formatters prettier) t) nil (condition-case err (progn (if buffer-file-name (progn ...)) (run-hooks 'apheleia-post-format-hook)) ((debug error) (message "Apheleia: %s" err) nil))) (formatter prettier) t) (formatted-buffer) (save-current-buffer (set-buffer cur-buffer) (if (equal apheleia--buffer-hash (apheleia--buffer-hash)) (progn (apheleia--create-rcs-patch (current-buffer) formatted-buffer #'(lambda ... ...)))))) #<buffer  *apheleia-prettier-stdout*>)
  (if (cdr formatters) (apheleia--run-formatters (cdr formatters) buffer callback stdout) (funcall callback stdout))
  (closure ((command npx "prettier" "--stdin-filepath" filepath) (stdin) (callback closure ((cur-buffer . #<killed buffer>) (formatters prettier) (callback closure ((formatters prettier) t) nil (condition-case err (progn ... ...) (... ... nil))) (formatter prettier) t) (formatted-buffer) (save-current-buffer (set-buffer cur-buffer) (if (equal apheleia--buffer-hash (apheleia--buffer-hash)) (progn (apheleia--create-rcs-patch ... formatted-buffer ...))))) (buffer . #<killed buffer>) (formatters prettier) t) (stdout) (if (cdr formatters) (apheleia--run-formatters (cdr formatters) buffer callback stdout) (funcall callback stdout)))(#<buffer  *apheleia-prettier-stdout*>)
  funcall((closure ((command npx "prettier" "--stdin-filepath" filepath) (stdin) (callback closure ((cur-buffer . #<killed buffer>) (formatters prettier) (callback closure ((formatters prettier) t) nil (condition-case err (progn ... ...) (... ... nil))) (formatter prettier) t) (formatted-buffer) (save-current-buffer (set-buffer cur-buffer) (if (equal apheleia--buffer-hash (apheleia--buffer-hash)) (progn (apheleia--create-rcs-patch ... formatted-buffer ...))))) (buffer . #<killed buffer>) (formatters prettier) t) (stdout) (if (cdr formatters) (apheleia--run-formatters (cdr formatters) buffer callback stdout) (funcall callback stdout))) #<buffer  *apheleia-prettier-stdout*>)
  (closure ((stdin . #<killed buffer>) (output-fname) (input-fname) (command "prettier" "--stdin-filepath" "/home/philipd/devel/e2e-automation/e2e-lz-gitops-a...") (ret nil nil #<killed buffer> "prettier" "--stdin-filepath" "/home/philipd/devel/e2e-automation/e2e-lz-gitops-a...") (formatter . prettier) (stdin) (callback closure ((command npx "prettier" "--stdin-filepath" filepath) (stdin) (callback closure ((cur-buffer . #<killed buffer>) (formatters prettier) (callback closure ... nil ...) (formatter prettier) t) (formatted-buffer) (save-current-buffer (set-buffer cur-buffer) (if ... ...))) (buffer . #<killed buffer>) (formatters prettier) t) (stdout) (if (cdr formatters) (apheleia--run-formatters (cdr formatters) buffer callback stdout) (funcall callback stdout))) (buffer . #<killed buffer>) (command npx "prettier" "--stdin-filepath" filepath) t) (stdout) (if output-fname (progn (erase-buffer) (insert-file-contents-literally output-fname))) (funcall callback stdout))(#<buffer  *apheleia-prettier-stdout*>)
  funcall((closure ((stdin . #<killed buffer>) (output-fname) (input-fname) (command "prettier" "--stdin-filepath" "/home/philipd/devel/e2e-automation/e2e-lz-gitops-a...") (ret nil nil #<killed buffer> "prettier" "--stdin-filepath" "/home/philipd/devel/e2e-automation/e2e-lz-gitops-a...") (formatter . prettier) (stdin) (callback closure ((command npx "prettier" "--stdin-filepath" filepath) (stdin) (callback closure ((cur-buffer . #<killed buffer>) (formatters prettier) (callback closure ... nil ...) (formatter prettier) t) (formatted-buffer) (save-current-buffer (set-buffer cur-buffer) (if ... ...))) (buffer . #<killed buffer>) (formatters prettier) t) (stdout) (if (cdr formatters) (apheleia--run-formatters (cdr formatters) buffer callback stdout) (funcall callback stdout))) (buffer . #<killed buffer>) (command npx "prettier" "--stdin-filepath" filepath) t) (stdout) (if output-fname (progn (erase-buffer) (insert-file-contents-literally output-fname))) (funcall callback stdout)) #<buffer  *apheleia-prettier-stdout*>)
  (progn (funcall callback stdout))
  (if callback (progn (funcall callback stdout)))
  (if exit-ok (if callback (progn (funcall callback stdout))) (message (concat "Failed to run %s: exit status %s " "(see %s %s)") (car command) (process-exit-status proc) (if (string-prefix-p " " log-name) "hidden buffer" "buffer") (string-trim log-name)))
  (unwind-protect (if exit-ok (if callback (progn (funcall callback stdout))) (message (concat "Failed to run %s: exit status %s " "(see %s %s)") (car command) (process-exit-status proc) (if (string-prefix-p " " log-name) "hidden buffer" "buffer") (string-trim log-name))) (if ensure (progn (funcall ensure))) (condition-case nil (progn (kill-buffer stdout)) (error nil)) (condition-case nil (progn (kill-buffer stderr)) (error nil)))
  (let ((exit-ok (funcall (or exit-status #'zerop) (process-exit-status proc)))) (if (and exit-ok apheleia-log-only-errors) nil (save-current-buffer (set-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 (save-current-buffer ... ...))) (goto-char (point-max)) (skip-chars-backward "\n") (delete-region (point) (point-max)) (if (bobp) nil (insert "\n\n\f\n")) (if exit-ok nil (if apheleia--last-error-marker nil (setq apheleia--last-error-marker ...) (move-marker apheleia--last-error-marker ...))) (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") (goto-char (if keep-at-end (point-max) (min ... orig-point))) (goto-char (point-max)))))) (if formatter (progn (run-hook-with-args 'apheleia-formatter-exited-hook :formatter formatter :error (not exit-ok) :log (get-buffer log-name)))) (unwind-protect (if exit-ok (if callback (progn (funcall callback stdout))) (message (concat "Failed to run %s: exit status %s " "(see %s %s)") (car command) (process-exit-status proc) (if (string-prefix-p " " log-name) "hidden buffer" "buffer") (string-trim log-name))) (if ensure (progn (funcall ensure))) (condition-case nil (progn (kill-buffer stdout)) (error nil)) (condition-case nil (progn (kill-buffer stderr)) (error nil))))
  (if (process-live-p proc) nil (let ((exit-ok (funcall (or exit-status #'zerop) (process-exit-status proc)))) (if (and exit-ok apheleia-log-only-errors) nil (save-current-buffer (set-buffer (get-buffer-create log-name)) (special-mode) (save-restriction (widen) (let ((inhibit-read-only t) (orig-point ...) (keep-at-end ...) (stderr-string ...)) (goto-char (point-max)) (skip-chars-backward "\n") (delete-region (point) (point-max)) (if (bobp) nil (insert "\n\n\f\n")) (if exit-ok nil (if apheleia--last-error-marker nil ... ...)) (insert (current-time-string) " :: " (buffer-local-value ... stdout) "\n$ " (mapconcat ... command " ") "\n\n" (if ... "(no output on stderr)" stderr-string) "\n\n" "Command " (if exit-ok "succeeded" "failed") " with exit code " (number-to-string ...) ".\n") (goto-char (if keep-at-end ... ...)) (goto-char (point-max)))))) (if formatter (progn (run-hook-with-args 'apheleia-formatter-exited-hook :formatter formatter :error (not exit-ok) :log (get-buffer log-name)))) (unwind-protect (if exit-ok (if callback (progn (funcall callback stdout))) (message (concat "Failed to run %s: exit status %s " "(see %s %s)") (car command) (process-exit-status proc) (if (string-prefix-p " " log-name) "hidden buffer" "buffer") (string-trim log-name))) (if ensure (progn (funcall ensure))) (condition-case nil (progn (kill-buffer stdout)) (error nil)) (condition-case nil (progn (kill-buffer stderr)) (error nil)))))
  (closure ((log-name . "*apheleia-prettier-log*") (stderr . #<buffer  *apheleia-prettier-stderr*>) (stdout . #<buffer  *apheleia-prettier-stdout*>) (name . "prettier") (formatter . prettier) (exit-status) (ensure closure ((stdin . #<killed buffer>) (output-fname) (input-fname) (command "prettier" "--stdin-filepath" "/home/philipd/devel/e2e-automation/e...") (ret nil nil #<killed buffer> "prettier" "--stdin-filepath" "/home/philipd/devel/e2e-automation/e...") (formatter . prettier) (stdin) (callback closure ... ... ...) (buffer . #<killed buffer>) (command npx "prettier" "--stdin-filepath" filepath) t) nil (condition-case nil (progn ... ...) (error nil))) (callback closure ((stdin . #<killed buffer>) (output-fname) (input-fname) (command "prettier" "--stdin-filepath" "/home/philipd/devel/e2e-automation/e...") (ret nil nil #<killed buffer> "prettier" "--stdin-filepath" "/home/philipd/devel/e2e-automation/e...") (formatter . prettier) (stdin) (callback closure ... ... ...) (buffer . #<killed buffer>) (command npx "prettier" "--stdin-filepath" filepath) t) (stdout) (if output-fname (progn ... ...)) (funcall callback stdout)) (stdin . #<killed buffer>) (command "prettier" "--stdin-filepath" "/home/philipd/devel/e2e-automation/e...") (--cl-rest-- :command ("prettier" "--stdin-filepath" "/home/philipd/devel/e2e-automation/e...") :stdin #<killed buffer> :callback (closure (... ... ... ... ... ... ... ... ... ... t) (stdout) (if output-fname ...) (funcall callback stdout)) :ensure (closure (... ... ... ... ... ... ... ... ... ... t) nil (condition-case nil ... ...)) :formatter prettier) t) (proc _event) (if (process-live-p proc) nil (let ((exit-ok ...)) (if (and exit-ok apheleia-log-only-errors) nil (save-current-buffer ... ... ...)) (if formatter (progn ...)) (unwind-protect (if exit-ok ... ...) (if ensure ...) (condition-case nil ... ...) (condition-case nil ... ...)))))(#<process apheleia-prettier> "finished\n")