diff --git a/modules/lang/emacs-lisp/autoload.el b/modules/lang/emacs-lisp/autoload.el index b2e650320..a94b8e4b2 100644 --- a/modules/lang/emacs-lisp/autoload.el +++ b/modules/lang/emacs-lisp/autoload.el @@ -277,25 +277,81 @@ https://emacs.stackexchange.com/questions/10230/how-to-indent-keywords-aligned" file-base))))))) (not (locate-dominating-file default-directory ".doommodule"))))) -;;;###autoload -(define-minor-mode +emacs-lisp-non-package-mode - "Reduce flycheck verbosity where it is appropriate. +(defvar-local +emacs-lisp-reduced-flymake-byte-compile--process nil) -Essentially, this means in any elisp file that either: -- Is not a theme in `custom-theme-load-path', -- Lacks a `provide' statement, -- Lives in a project with a .doommodule file, -- Is a dotfile (like .dir-locals.el or .doomrc). +(defun +emacs-lisp-reduced-flymake-byte-compile (report-fn &rest _args) + "A Flymake backend for byte compilation in non-package elisp files. -This generally applies to your private config (`doom-user-dir') or Doom's source -\(`doom-emacs-dir')." +This checker reduces the amount of false positives the byte compiler throws off +compared to `elisp-flymake-byte-compile'. The linter warnings that are enabled +are set by `+emacs-lisp-linter-warnings' + +This backend does not need to be added directly +as `+emacs-lisp-non-package-mode' will enable it and disable the other checkers." + ;; if a process already exists. kill it. + (when (and +emacs-lisp-reduced-flymake-byte-compile--process + (process-live-p +emacs-lisp-reduced-flymake-byte-compile--process)) + (kill-process +emacs-lisp-reduced-flymake-byte-compile--process)) + (let ((source (current-buffer)) + (tmp-file (make-temp-file "+emacs-lisp-byte-compile-src")) + (out-buf (generate-new-buffer "+emacs-lisp-byte-compile-out"))) + ;; write the content to a temp file + (save-restriction + (widen) + (write-region nil nil tmp-file nil 'nomessage)) + ;; make the process + (setq +emacs-lisp-reduced-flymake-byte-compile--process + (make-process + :name "+emacs-reduced-flymake" + :noquery t + :connection-type 'pipe + :buffer out-buf + :command `(,(expand-file-name invocation-name invocation-directory) + "-Q" + "--batch" + ,@(mapcan (lambda (p) (list "-L" p)) elisp-flymake-byte-compile-load-path) + ;; this is what silences the byte compiler + "--eval" ,(prin1-to-string `(setq doom-modules ',doom-modules + doom-disabled-packages ',doom-disabled-packages + byte-compile-warnings ',+emacs-lisp-linter-warnings)) + "-f" "elisp-flymake--batch-compile-for-flymake" + ,tmp-file) + :stderr "*stderr of +elisp-flymake-byte-compile-out*" + :sentinel + ;; deal with the process when it exits + (lambda (proc _event) + (when (memq (process-status proc) '(exit signal)) + (unwind-protect + (cond + ;; if the buffer is dead or the process is not the same, log the process as old. + ((or (not (buffer-live-p source)) + (not (with-current-buffer source (eq proc +emacs-lisp-reduced-flymake-byte-compile--process)))) + (flymake-log :warning "byte compile process %s is old" proc)) + ;; if the process exited without problem process the buffer + ((zerop (process-exit-status proc)) + (elisp-flymake--byte-compile-done report-fn source out-buf)) + ;; otherwise something else horrid has gone wrong and we panic + (t (funcall report-fn :panic + :explanation + (format "byte compile process %s died" proc)))) + ;; cleanup + (ignore-errors (delete-file tmp-file)) + (kill-buffer out-buf)))))))) + +(define-minor-mode +emacs-lisp--flymake-non-package-mode + "" :since "3.0.0" - (unless (and (bound-and-true-p flycheck-mode) - (not (+emacs-lisp--in-package-buffer-p))) - (setq +emacs-lisp-non-package-mode nil)) - (when (derived-mode-p 'emacs-lisp-mode) - (add-hook 'after-save-hook #'+emacs-lisp-non-package-mode nil t)) - (if (not +emacs-lisp-non-package-mode) + (if +emacs-lisp--flymake-non-package-mode + (progn + (remove-hook! 'flymake-diagnostic-functions :local #'elisp-flymake-checkdoc #'elisp-flymake-byte-compile) + (add-hook 'flymake-diagnostic-functions #'+emacs-lisp-reduced-flymake-byte-compile nil t)) + (add-hook! 'flymake-diagnostic-functions :local #'elisp-flymake-checkdoc #'elisp-flymake-byte-compile) + (remove-hook 'flymake-diagnostic-functions #'+emacs-lisp-reduced-flymake-byte-compile t))) + +(define-minor-mode +emacs-lisp--flycheck-non-package-mode + "" + :since "3.0.0" + (if (not +emacs-lisp--flycheck-non-package-mode) (when (get 'flycheck-disabled-checkers 'initial-value) (setq-local flycheck-disabled-checkers (get 'flycheck-disabled-checkers 'initial-value)) (kill-local-variable 'flycheck-emacs-lisp-check-form)) @@ -323,6 +379,29 @@ This generally applies to your private config (`doom-user-dir') or Doom's source ,(read (default-toplevel-value 'flycheck-emacs-lisp-check-form)))) flycheck-disabled-checkers (cons 'emacs-lisp-checkdoc flycheck-disabled-checkers)))) +;;;###autoload +(define-minor-mode +emacs-lisp-non-package-mode + "Reduce flycheck/flymake verbosity where it is appropriate. + +Essentially, this means in any elisp file that either: +- Is not a theme in `custom-theme-load-path', +- Lacks a `provide' statement, +- Lives in a project with a .doommodule file, +- Is a dotfile (like .dir-locals.el or .doomrc). + +This generally applies to your private config (`doom-user-dir') or Doom's source +\(`doom-emacs-dir')." + :since "3.0.0" + (unless (and (or (bound-and-true-p flycheck-mode) + (bound-and-true-p flymake-mode)) + (not (+emacs-lisp--in-package-buffer-p))) + (setq +emacs-lisp-non-package-mode nil)) + (when (derived-mode-p 'emacs-lisp-mode) + (add-hook 'after-save-hook #'+emacs-lisp-non-package-mode nil t)) + (let ((toggle (if +emacs-lisp-non-package-mode +1 -1))) + (if (modulep! :checkers syntax +flymake) + (+emacs-lisp--flymake-non-package-mode toggle) + (+emacs-lisp--flycheck-non-package-mode toggle)))) ;; diff --git a/modules/lang/emacs-lisp/config.el b/modules/lang/emacs-lisp/config.el index 34c88ed16..90c613053 100644 --- a/modules/lang/emacs-lisp/config.el +++ b/modules/lang/emacs-lisp/config.el @@ -95,11 +95,11 @@ See `+emacs-lisp-non-package-mode' for details.") ;; Ensure straight sees modifications to installed packages #'+emacs-lisp-init-straight-maybe-h) - ;; UX: Flycheck's two emacs-lisp checkers produce a *lot* of false positives - ;; in non-packages (like Emacs configs or elisp scripts), so I disable - ;; `emacs-lisp-checkdoc' and set `byte-compile-warnings' to a subset of the - ;; original in the flycheck instance (see `+emacs-lisp-linter-warnings'). - (add-hook 'flycheck-mode-hook #'+emacs-lisp-non-package-mode) + ;; UX: Both Flycheck's and Flymake's two + ;; emacs-lisp checkers produce a *lot* of false positives in non-packages + ;; (like Emacs configs or elisp scripts), so I disable `checkdoc' (`emacs-lisp-checkdoc', `elisp-flymake-checkdoc') + ;; and set `byte-compile-warnings' to a subset that makes more sense (see `+emacs-lisp-linter-warnings') + (add-hook! '(flycheck-mode-hook flymake-mode-hook) #'+emacs-lisp-non-package-mode) (defadvice! +syntax--fix-elisp-flymake-load-path (orig-fn &rest args) "Set load path for elisp byte compilation Flymake backend"