Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 27 additions & 11 deletions flycheck-eldev.el
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
;;; flycheck-eldev.el --- Eldev support in Flycheck -*- lexical-binding: t -*-

;;; Copyright (C) 2020-2023 Paul Pogonyshev
;;; Copyright (C) 2020-2025 Paul Pogonyshev

;; Author: Paul Pogonyshev <pogonyshev@gmail.com>
;; Maintainer: Paul Pogonyshev <pogonyshev@gmail.com>
Expand Down Expand Up @@ -120,6 +120,19 @@ concerns when checking Eldev (or any Elisp) projects."
(const :tag "Don't trust" dont-trust)
(const :tag "Trust if ever initialized" trust-if-ever-initialized)))

(defcustom flycheck-eldev-outside-temp-files t
"Normally, Flycheck creates visible files in project directory.
This sometimes leads to various annoying side effects, for example
interference with Git or file watchers on project directory. For this
reason, `flycheck-eldev' puts such files in `temporary-file-directory'
by default (utilizing built-in Flycheck capability, that is simply not
used for Elisp).

However, if this causes any issues, you can revert to the standard
Flycheck behavior by setting this to nil."
:group 'flycheck-eldev
:type 'boolean)


(defvar flycheck-eldev-active t
"Whether Eldev extension to Flycheck is active.")
Expand Down Expand Up @@ -207,8 +220,15 @@ If FROM is nil, search from `default-directory'."
;; rewrite the command line provided by the standard checker, so we get any
;; future improvements for free.
(let* ((super (let ((flycheck-emacs-lisp-load-path nil)
(flycheck-emacs-lisp-initialize-packages nil))
(flycheck-checker-substituted-arguments 'emacs-lisp)))
(flycheck-emacs-lisp-initialize-packages nil)
(original-command-template (flycheck-checker-get 'emacs-lisp 'command)))
(unwind-protect
(progn
(when flycheck-eldev-outside-temp-files
(setf (flycheck-checker-get 'emacs-lisp 'command)
(mapcar (lambda (x) (if (eq x 'source-inplace) 'source x)) original-command-template)))
(flycheck-checker-substituted-arguments 'emacs-lisp))
(setf (flycheck-checker-get 'emacs-lisp 'command) original-command-template))))
(head (-drop-last 2 super))
(tail (-take-last 2 super))
(filename (cadr tail))
Expand Down Expand Up @@ -237,20 +257,16 @@ If FROM is nil, search from `default-directory'."
;; `eldev-project-main-file' is specified, this does nothing.
"--setup-first"
,(flycheck-sexp-to-string
`(advice-add #'eldev--package-dir-info :around
`(advice-add #'eldev-package-descriptor :around
(lambda (original)
(eldev-advised
(#'insert-file-contents
:around (lambda (original filename &rest arguments)
(unless (file-equal-p filename ,real-filename)
(if (file-equal-p filename ,real-filename)
;; Load the temp file instead.
(apply original ,filename arguments)
(apply original filename arguments))))
(funcall original)))))
;; When checking project's main file, use the temporary as the main file
;; instead.
"--setup"
,(flycheck-sexp-to-string
`(when (and eldev-project-main-file (file-equal-p eldev-project-main-file ,real-filename))
(setf eldev-project-main-file ,filename)))
;; Special handling for test files: load extra dependencies as if testing
;; now. Likewise for loading roots.
"--setup"
Expand Down
52 changes: 31 additions & 21 deletions test/flycheck-eldev-test.el
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,26 @@
(:unknown-projects (setf flycheck-eldev-unknown-projects (pop body)))
(:enable-checkdoc (if (pop body)
(push 'emacs-lisp-checkdoc enabled-checkers)
;; We don't use `emacs-lisp-checkdoc' unless explicitly enabled.
(setf enabled-checkers (delq 'emacs-lisp-checkdoc enabled-checkers))))))
;; Don't use `emacs-lisp-checkdoc'.
`(let ((flycheck-checkers (--filter (memq it ',enabled-checkers) flycheck-checkers))
(flycheck-disabled-checkers nil)
(flycheck-check-syntax-automatically nil)
(flycheck-eldev-whitelist ',flycheck-eldev-whitelist)
(flycheck-eldev-blacklist ',flycheck-eldev-blacklist)
(flycheck-eldev-unknown-projects ',flycheck-eldev-unknown-projects)
(file (expand-file-name ,file flycheck-eldev--test-dir)))
(with-temp-buffer
(insert-file-contents file t)
(setf default-directory (file-name-directory file))
(emacs-lisp-mode)
(flycheck-mode 1)
,@body))))
;; Currently not testing if `flycheck-eldev-outside-temp-files' actually achieves what it promises, but at
;; least make sure that everything works regardless if that is set to t or nil.
`(dolist (outside-temp-files '(nil t))
(ert-info ((format "flycheck-eldev-outside-temp-files = %s" outside-temp-files))
(let ((flycheck-checkers (--filter (memq it ',enabled-checkers) flycheck-checkers))
(flycheck-disabled-checkers nil)
(flycheck-check-syntax-automatically nil)
(flycheck-eldev-whitelist ',flycheck-eldev-whitelist)
(flycheck-eldev-blacklist ',flycheck-eldev-blacklist)
(flycheck-eldev-unknown-projects ',flycheck-eldev-unknown-projects)
(flycheck-eldev-outside-temp-files outside-temp-files)
(file (expand-file-name ,file flycheck-eldev--test-dir)))
(with-temp-buffer
(insert-file-contents file t)
(setf default-directory (file-name-directory file))
(emacs-lisp-mode)
(flycheck-mode 1)
,@body))))))

(defmacro flycheck-eldev--test-with-temp-file (file content-creation &rest body)
(declare (indent 2) (debug (sexp form body)))
Expand Down Expand Up @@ -96,13 +101,13 @@


(flycheck-eldev-ert-defargtest flycheck-eldev-basics-1 (file)
("project-a/project-a.el" "project-b/project-b.el" "project-b/project-b-util.el")
("project-a/project-a.el" "project-b/project-b.el" "project-b/project-b-util.el" "project-c/project-c.el" "project-c/project-c-util.el")
(flycheck-eldev--test file
(flycheck-eldev--test-recheck)
(flycheck-eldev--test-expect-no-errors)))

(flycheck-eldev-ert-defargtest flycheck-eldev-basics-2 (file)
("project-a/Eldev" "project-b/Eldev")
("project-a/Eldev" "project-b/Eldev" "project-c/Eldev")
(flycheck-eldev--test file
;; Enable `checkdoc'. Must be disabled at runtime (currently through our own hack)
;; for the test to pass.
Expand Down Expand Up @@ -132,7 +137,9 @@
(flycheck-eldev--test-expect-no-errors)))

(flycheck-eldev-ert-defargtest flycheck-eldev-test-file-1 (file)
("project-a/test/project-a.el" "project-b/test/project-b.el" "project-b/test/project-b-util.el")
("project-a/test/project-a.el"
"project-b/test/project-b.el" "project-b/test/project-b-util.el"
"project-c/test/project-c.el" "project-c/test/project-c-util.el")
(flycheck-eldev--test file
(flycheck-eldev--test-recheck)
(flycheck-eldev--test-expect-no-errors)))
Expand All @@ -144,12 +151,15 @@
(flycheck-eldev--test-expect-errors '(:matches "dependency-a")))))

;; Test that removing dependencies gives errors immediately.
(ert-deftest flycheck-eldev-remove-dependency-1 ()
(flycheck-eldev--test "project-a/project-a.el"
(search-forward "(dependency-a \"1.0\")")
(flycheck-eldev-ert-defargtest flycheck-eldev-remove-dependency-1 (file dependency)
(("project-a/project-a.el" 'dependency-a)
("project-b/project-b.el" 'dependency-b)
("project-c/project-c.el" 'dependency-b))
(flycheck-eldev--test file
(re-search-forward (format "(%s \"[^\"]+\")" dependency))
(replace-match "")
(flycheck-eldev--test-recheck)
(flycheck-eldev--test-expect-errors '(:matches "dependency-a"))))
(flycheck-eldev--test-expect-errors `(:matches ,(symbol-name dependency)))))

;; Test that adding unaccessible dependencies gives errors immediately.
(ert-deftest flycheck-eldev-add-dependency-1 ()
Expand Down
7 changes: 7 additions & 0 deletions test/project-c/Eldev
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
; -*- mode: emacs-lisp; lexical-binding: t -*-

(eldev-use-package-archive `("archive-a" . ,(expand-file-name "../package-archive-a")))

;; The point of this test project is to verify that explicitly set `eldev-project-main-file' still works as
;; expected.
(setf eldev-project-main-file "project-c.el")
9 changes: 9 additions & 0 deletions test/project-c/project-c-util.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
;;; -*- lexical-binding: t; -*-

(require 'dependency-a)
(require 'dependency-b)

(defun project-c-do-hello ()
(dependency-a-hello))

(provide 'project-c-util)
24 changes: 24 additions & 0 deletions test/project-c/project-c.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
;;; project-c.el --- Exactly like `project-b', but with explicitly set `eldev-project-main-file' -*- lexical-binding: t; -*-

;; Version: 1.0
;; Homepage: https://example.com/
;; Package-Requires: ((dependency-a "1.0") (dependency-b "1.0"))

;;; Commentary:

;; Comments to make linters happy.

;;; Code:

(require 'project-c-util)
(require 'dependency-a)
(require 'dependency-b)

(defun project-c-hello ()
"Invoke `project-c-do-hello' from `project-c-util'.
This docstring exists to make linters happy."
(project-c-do-hello))

(provide 'project-c)

;;; project-c.el ends here
6 changes: 6 additions & 0 deletions test/project-c/test/project-c-util.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
;; -*- lexical-binding: t; -*-

(require 'project-c)
(require 'ert)

(provide 'test/project-c-util)
6 changes: 6 additions & 0 deletions test/project-c/test/project-c.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
;; -*- lexical-binding: t; -*-

(require 'test/project-c-util)

(ert-deftest project-c-test-hello ()
(should (string= (project-c-hello) "Hello")))
Loading