Skip to content

Commit 1d5e4e4

Browse files
committed
plugin/emacs: recover from quick-lint-js crashes in Flymake plugin
Signed-off-by: wagner riffel <[email protected]>
1 parent 88a9792 commit 1d5e4e4

File tree

2 files changed

+78
-35
lines changed

2 files changed

+78
-35
lines changed

plugin/emacs/flymake-quicklintjs.el

Lines changed: 77 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -40,47 +40,89 @@ Return a list of Flymake diagnostic objects in source buffer SRC-BUF."
4040
(if (= sev 0) :error :warning) msg)))
4141
quicklintjs-output-alist))
4242

43+
(defun flymake-quicklintjs--report-with-crash (qljs-stdout-buf
44+
qljs-stderr-buf
45+
src-buf report-fn)
46+
"Similar to `flymake-quicklintjs--report' but tries to recover errors from
47+
quick-lint-js crashes and logs whatever is in QLJS-STDERR-BUF"
48+
(flymake-log :warning
49+
"quick-lint-js exited with a deadly signal.\n\
50+
Please consider filing a bug at\
51+
https://github.com/quick-lint/quick-lint-js/issues/new\n\
52+
qjls-stderr-buf:\n\
53+
%s\n"
54+
(with-current-buffer qljs-stderr-buf
55+
(buffer-substring-no-properties (point-min) (point-max))))
56+
(with-current-buffer qljs-stdout-buf
57+
(save-excursion
58+
;; a crash without any previous issue, try to fix an empty buffer
59+
(when (zerop (buffer-size))
60+
(goto-char (point-min))
61+
(insert-char ?\())
62+
;; the above left a '(' danlging or crashed and
63+
;; emacs_lisp_error_reporter::finish() haven't been called yet
64+
(goto-char (point-min))
65+
(when (eq (char-after 1) ?\()
66+
(goto-char (point-max))
67+
(insert-char ?\)))))
68+
(condition-case nil
69+
(flymake-quicklintjs--report qljs-stdout-buf src-buf report-fn)
70+
(funcall report-fn '())))
71+
72+
(defun flymake-quicklintjs--report (qljs-stdout-buf src-buf report-fn)
73+
"Call REPORT-FN to highlight reports in SRC_BUF reported in QLJS-STDOUT-BUF.
74+
QLJS-STDOUT-BUF is entirely read and it's expected to be in
75+
QUICKLINTJS-OUTPUT-ALIST format."
76+
(with-current-buffer qljs-stdout-buf
77+
(funcall report-fn
78+
(flymake-quicklintjs--make-diagnostics
79+
src-buf
80+
(car (read-from-string
81+
(buffer-substring-no-properties (point-min)
82+
(point-max))))))))
83+
4384
;;;###autoload
4485
(defun flymake-quicklintjs (report-fn &rest _args)
4586
"Flymake backend for quick-lint-js linter.
46-
This backend uses `flymake-quicklintjs-program' (which see) to launch a
47-
quick-lint-js process that is passed the current buffer's contents via stdin.
87+
This backend uses `quicklintjs-find-program' to find and launch a quick-lint-js
88+
process that is passed the current buffer's contents via stdin.
4889
REPORT-FN is Flymake's callback."
4990
(when (process-live-p flymake-quicklintjs--proc)
5091
(kill-process flymake-quicklintjs--proc))
51-
(let ((src-buf (current-buffer)))
52-
(setq flymake-quicklintjs--proc
53-
(make-process
54-
:name "flymake-quicklintjs"
55-
:connection-type 'pipe
56-
:noquery t
57-
:buffer (get-buffer-create " *flymake-quicklintjs*")
58-
:command (quicklintjs-find-program
59-
(let ((file (buffer-file-name)))
60-
(when file (concat "--path-for-config-search=" file)))
61-
"--stdin" "--output-format=emacs-lisp")
62-
:sentinel
63-
(lambda (p _ev)
64-
(unwind-protect
65-
(when (and (eq 'exit (process-status p))
66-
(eq p flymake-quicklintjs--proc))
67-
(with-current-buffer (process-buffer p)
68-
(let ((diags (flymake-quicklintjs--make-diagnostics
69-
src-buf
70-
(car (read-from-string
71-
(buffer-substring-no-properties
72-
(point-min) (point-max)))))))
73-
(if (or diags (zerop (process-exit-status p)))
74-
(funcall report-fn diags)
75-
(funcall report-fn
76-
:panic :explanation
77-
(buffer-substring
78-
(point-min) (progn (goto-char (point-min))
79-
(line-end-position))))))))
80-
(unless (process-live-p p)
81-
(kill-buffer (process-buffer p)))))))
82-
(process-send-region flymake-quicklintjs--proc (point-min) (point-max))
83-
(process-send-eof flymake-quicklintjs--proc)))
92+
(let ((src-buf (current-buffer))
93+
(stdout-buf (generate-new-buffer " *flymake-quicklintjs-stdout*"))
94+
(stderr-buf (generate-new-buffer " *flymake-quicklintjs-stderr*")))
95+
(save-restriction
96+
(widen)
97+
(setq flymake-quicklintjs--proc
98+
(make-process
99+
:name "flymake-quicklintjs"
100+
:connection-type 'pipe
101+
:noquery t
102+
:buffer stdout-buf
103+
:stderr stderr-buf
104+
:command (quicklintjs-find-program
105+
(let ((file (buffer-file-name)))
106+
(when file (concat "--path-for-config-search=" file)))
107+
"--stdin" "--output-format=emacs-lisp")
108+
:sentinel
109+
(lambda (p _ev)
110+
(let ((proc-status (process-status p)))
111+
(unwind-protect
112+
(when (and (or (eq proc-status 'exit)
113+
(eq proc-status 'signal))
114+
(with-current-buffer src-buf
115+
(eq p flymake-quicklintjs--proc)))
116+
(if (zerop (process-exit-status p))
117+
(flymake-quicklintjs--report stdout-buf
118+
src-buf
119+
report-fn)
120+
(flymake-quicklintjs--report-with-crash
121+
stdout-buf stderr-buf src-buf report-fn)))
122+
(progn (kill-buffer stdout-buf)
123+
(kill-buffer stderr-buf)))))))
124+
(process-send-region flymake-quicklintjs--proc (point-min) (point-max))
125+
(process-send-eof flymake-quicklintjs--proc))))
84126

85127
(provide 'flymake-quicklintjs)
86128

src/emacs-lisp-error-reporter.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ void emacs_lisp_error_formatter::write_after_message(severity sev,
8282
return;
8383
}
8484
this->output_ << "\")";
85+
this->output_.flush();
8586
}
8687
}
8788

0 commit comments

Comments
 (0)