branch: elpa/flycheck
commit 422e216065d554ef1d4f6613891dd1bab84a86bc
Merge: 77c100c380 43be6c3110
Author: Bozhidar Batsov <[email protected]>
Commit: GitHub <[email protected]>

    Merge pull request #2146 from takeokunn/fix/issue-2144
    
    Rewrite org-lint checker to run in current Emacs process
---
 CHANGES.rst                      |  3 ++
 doc/languages.rst                | 18 +++-----
 flycheck.el                      | 92 ++++++++++++++--------------------------
 test/specs/test-checker-api.el   | 12 +++---
 test/specs/test-customization.el | 15 ++++---
 5 files changed, 57 insertions(+), 83 deletions(-)

diff --git a/CHANGES.rst b/CHANGES.rst
index e247dc35eb..2f8730959a 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -17,6 +17,9 @@ Bugs fixed
 
 - [#2086]: Fix the name of the PyMarkdown config.
 - [#2036]: Fix ``awk-gawk`` checker passing spurious quotes to ``gawk 
--source``.
+- [#2144]: Rewrite ``org-lint`` checker to run in the current Emacs process
+  instead of a ``-Q --batch`` subprocess. This eliminates false "Unknown source
+  block language" warnings for languages from external packages.
 
 35.0 (2025-04-23)
 ======================
diff --git a/doc/languages.rst b/doc/languages.rst
index b2ad07558e..eea8661c2d 100644
--- a/doc/languages.rst
+++ b/doc/languages.rst
@@ -924,8 +924,8 @@ to view the docstring of the syntax checker.  Likewise, you 
may use
 
       An Org mode syntax and style checker using ``org-lint``.
 
-      The checker runs ``org-lint`` in an Emacs subprocess to detect issues 
such
-      as:
+      The checker runs ``org-lint`` in the current Emacs process to detect
+      issues such as:
 
       - Invalid links
       - Dead links
@@ -934,11 +934,9 @@ to view the docstring of the syntax checker.  Likewise, 
you may use
       - Special characters in links
       - And more...
 
-      The checker automatically inherits your Org mode configuration, including
-      ``org-directory`` and ``org-id-locations-file``. Note that ``load-path`` 
is
-      not inherited for security reasons to prevent potential code injection.
-      Org should be installed in a standard location that Emacs can find 
without
-      a custom ``load-path``.
+      Because the checker runs in the current Emacs process, it has access to
+      all installed packages and user configuration, avoiding false positives
+      for source block languages provided by external packages.
 
       The checker is enabled by default when ``org-lint`` is available (Org 
mode
       9.0 or later).
@@ -946,12 +944,6 @@ to view the docstring of the syntax checker.  Likewise, 
you may use
       See the ``org-lint`` documentation in Org mode for details about the 
checks
       performed.
 
-      .. note::
-
-         The checker does not inherit ``org-id-locations`` because this 
variable
-         can contain thousands of entries and exceed shell argument limits. The
-         ``org-id-locations-file`` is used instead.
-
 .. supported-language:: Opam
 
    .. syntax-checker:: opam
diff --git a/flycheck.el b/flycheck.el
index f290da5aba..32f162e875 100644
--- a/flycheck.el
+++ b/flycheck.el
@@ -91,6 +91,7 @@
 
 ;; Tell the byte compiler about autoloaded functions from packages
 (declare-function pkg-info-version-info "pkg-info" (package))
+(declare-function org-lint "org-lint" (&optional arg))
 
 
 ;;; Customization
@@ -8979,23 +8980,10 @@ Variables are taken from 
`flycheck-emacs-lisp-checkdoc-variables'."
      ,@(seq-map (lambda (opt) `(setq-default ,opt ',(symbol-value opt)))
                 (seq-filter #'boundp flycheck-emacs-lisp-checkdoc-variables))))
 
-(defconst flycheck-org-lint-variables
-  '(org-directory
-    org-id-locations-file)  ; File path only, not contents
-  "Variables inherited by the org-lint subprocess.
-
-Note: We do NOT include `load-path' to prevent potential code injection
-and information disclosure. Org should be installed in a standard
-location that Emacs can find without a custom load-path.
-
-We also do not include `org-id-locations' because it can contain
-thousands of entries and exceed shell argument limits (ARG_MAX).")
-
-(defun flycheck-org-lint-variables-form ()
-  "Make a sexp to pass relevant variables to an org-lint subprocess."
-  `(progn
-     ,@(seq-map (lambda (opt) `(setq-default ,opt ',(symbol-value opt)))
-                (seq-filter #'boundp flycheck-org-lint-variables))))
+(defun flycheck-org-lint-available-p ()
+  "Check if org-lint is available."
+  (and (fboundp 'org-lint)
+       (require 'org nil 'no-error)))
 
 (flycheck-define-checker emacs-lisp-checkdoc
   "An Emacs Lisp style checker using CheckDoc.
@@ -9011,61 +8999,47 @@ The checker runs `checkdoc-current-buffer'."
   :modes (emacs-lisp-mode)
   :enabled flycheck--emacs-lisp-checkdoc-enabled-p)
 
-(defconst flycheck-org-lint-form
-  (flycheck-prepare-emacs-lisp-form
-    (with-demoted-errors "Org-lint error: %S"
-      (require 'org)
-      (let ((source (car command-line-args-left))
-            (process-default-directory default-directory))
-        (with-temp-buffer
-          (insert-file-contents source 'visit)
-          (setq buffer-file-name source)
-          (setq default-directory process-default-directory)
-          (delay-mode-hooks (org-mode))
-          (setq delayed-mode-hooks nil)
-          (dolist (err (org-lint))
-            (pcase err
-              (`(,_n [,line ,_trust ,desc ,_checker])
-               (princ (format "%s:%s: %s\n" source line desc)))
-              (_
-               (princ (format "%s:1: Unexpected org-lint format: %S\n" source 
err))))))))))
-
-(defun flycheck-org-lint-available-p ()
-  "Check if org-lint is available."
-  (and (fboundp 'org-lint)
-       (require 'org nil 'no-error)))
-
 (dolist (checker '(emacs-lisp emacs-lisp-checkdoc))
   (setf (car (flycheck-checker-get checker 'command))
         flycheck-this-emacs-executable))
 
-(flycheck-define-checker org-lint
+(flycheck-define-generic-checker 'org-lint
   "An Org mode syntax checker using `org-lint'.
 
-The checker runs `org-lint' in an Emacs subprocess."
-  :command ("emacs" (eval flycheck-emacs-args)
-            "--eval" (eval (flycheck-sexp-to-string
-                            (flycheck-org-lint-variables-form)))
-            "--eval" (eval flycheck-org-lint-form)
-            "--" source)
-  :error-patterns
-  ((info line-start (file-name) ":" line ": " (message) line-end))
-  :modes (org-mode)
-  :enabled (lambda () (flycheck-org-lint-available-p))
+The checker runs `org-lint' in the current Emacs process, so it
+has access to all installed packages and user configuration."
+  :start (lambda (checker callback)
+           (condition-case err
+               (let ((errors
+                      (delq nil
+                            (mapcar
+                             (lambda (e)
+                               (pcase e
+                                 (`(,_n [,line ,_trust ,desc ,_checker])
+                                  (flycheck-error-new-at
+                                   line nil 'info desc
+                                   :checker checker))
+                                 (_
+                                  (flycheck-error-new-at
+                                   1 nil 'warning
+                                   (format "Unexpected org-lint format: %S" e)
+                                   :checker checker))))
+                             (org-lint)))))
+                 (funcall callback 'finished errors))
+             (error (funcall callback 'errored
+                             (error-message-string err)))))
+  :modes '(org-mode)
+  :enabled #'flycheck-org-lint-available-p
   :verify (lambda (_)
             (let ((org-version (when (require 'org nil 'no-error)
-                                  (org-version))))
+                                 (org-version))))
               (list (flycheck-verification-result-new
                      :label "Org-lint available"
                      :message (if (fboundp 'org-lint)
-                                 (format "yes (Org %s)" org-version)
-                               "no")
+                                  (format "yes (Org %s)" org-version)
+                                "no")
                      :face (if (fboundp 'org-lint) 'success 'warning))))))
 
-;; Set org-lint to use the current Emacs
-(setf (car (flycheck-checker-get 'org-lint 'command))
-      flycheck-this-emacs-executable)
-
 (defun flycheck-ember-template--check-for-config (&rest _ignored)
   "Check the required config file is available up the file system."
   (and buffer-file-name
diff --git a/test/specs/test-checker-api.el b/test/specs/test-checker-api.el
index 8f95a641a6..f7c7225cb7 100644
--- a/test/specs/test-checker-api.el
+++ b/test/specs/test-checker-api.el
@@ -78,14 +78,16 @@
   (describe "flycheck-checker-executable"
     (it "is-string"
       (dolist (checker flycheck-checkers)
-        (expect (stringp (flycheck-checker-executable checker)) 
:to-be-truthy)))
+        (when (flycheck-checker-get checker 'command)
+          (expect (stringp (flycheck-checker-executable checker)) 
:to-be-truthy))))
 
     (it "override-the-executable"
       (dolist (checker flycheck-checkers)
-        (let ((variable (flycheck-checker-executable-variable checker)))
-          (expect (eval `(let ((,variable "some-nice-executable"))
-                           (flycheck-checker-executable ',checker)))
-                  :to-equal "some-nice-executable")))))
+        (when (flycheck-checker-get checker 'command)
+          (let ((variable (flycheck-checker-executable-variable checker)))
+            (expect (eval `(let ((,variable "some-nice-executable"))
+                             (flycheck-checker-executable ',checker)))
+                    :to-equal "some-nice-executable"))))))
 
   (describe "flycheck-checker-get"
     (it "modes"
diff --git a/test/specs/test-customization.el b/test/specs/test-customization.el
index 70f8e9322e..83ffdd4c26 100644
--- a/test/specs/test-customization.el
+++ b/test/specs/test-customization.el
@@ -112,18 +112,21 @@
 
     (it "is a special variable"
       (dolist (checker flycheck-checkers)
-        (let ((variable (flycheck-checker-executable-variable checker)))
-          (expect (custom-variable-p variable) :to-be-truthy))))
+        (when (flycheck-checker-get checker 'command)
+          (let ((variable (flycheck-checker-executable-variable checker)))
+            (expect (custom-variable-p variable) :to-be-truthy)))))
 
     (it "is customizable"
       (dolist (checker flycheck-checkers)
-        (let ((variable (flycheck-checker-executable-variable checker)))
-          (expect (custom-variable-p variable) :to-be-truthy))))
+        (when (flycheck-checker-get checker 'command)
+          (let ((variable (flycheck-checker-executable-variable checker)))
+            (expect (custom-variable-p variable) :to-be-truthy)))))
 
     (it "defaults to nil"
       (dolist (checker flycheck-checkers)
-        (let ((variable (flycheck-checker-executable-variable checker)))
-          (expect (null (symbol-value variable)) :to-be-truthy)))))
+        (when (flycheck-checker-get checker 'command)
+          (let ((variable (flycheck-checker-executable-variable checker)))
+            (expect (null (symbol-value variable)) :to-be-truthy))))))
 
   (describe "flycheck-keymap-prefix"
 

Reply via email to