branch: elpa/php-mode
commit af6913519cdd9781dab2ad655821dc99e75c8e4e
Author: USAMI Kenta <[email protected]>
Commit: USAMI Kenta <[email protected]>

    Improve project.el and Projectile interoperability in php-project
    
    `php-project-project-find-function` built a `(vc . ROOT)` cons, which is
    only valid on Emacs 27.  Since Emacs 28 the VC project is the 3-element
    `(vc BACKEND ROOT)` form, so `project-root` (which reads `(nth 2 ...)`)
    signalled `wrong-type-argument` on the returned value.  Delegate to
    `project-try-vc`, which yields the representation the running Emacs
    expects, and fall back to a `transient` project otherwise.
    
    Let `php-project-get-root-dir` fall back to `project-current` when no
    PHP-specific marker is found.  This lets any project.el backend
    contribute detection -- Projectile 3 (which registers itself on
    `project-find-functions'), `project-vc-extra-root-markers', and other
    VCS -- while keeping the composer.json-first precedence that matters for
    monorepos.  `php-project-project-find-function' is removed from the hook
    during the fallback to avoid recursing back into detection.
    
    Deprecate `php-project-use-projectile-to-detect-root': Projectile 3 is
    now consulted automatically through the project.el fallback, so the
    dedicated option is redundant.
    
    Drop the load-time `(require 'projectile nil t)'; Projectile is only
    touched behind `fboundp'/`projectile-mode' guards, and an active
    `projectile-mode' already implies the library is loaded.
    
    Document the integration and the low-priority `project-find-functions'
    registration in both READMEs.
---
 CHANGELOG.md        | 12 +++++++++++
 README.ja.md        | 18 +++++++++++++++++
 README.md           | 18 +++++++++++++++++
 lisp/php-project.el | 57 ++++++++++++++++++++++++++++++++++++++++++++---------
 4 files changed, 96 insertions(+), 9 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 115ef78d60..727c9f3186 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,12 +4,24 @@ All notable changes of the PHP Mode 1.19.1 release series are 
documented in this
 
 ## Unreleased
 
+### Added
+
+ * `php-project-get-root-dir` falls back to `project-current` when no 
PHP-specific marker is found, so `project.el` backends (Projectile 3, 
`project-vc-extra-root-markers`, etc.) can contribute project detection
+
 ### Changed
 
  * Add `readonly` class modifier to [Imenu] ([#802])
  * Add `enum` support to `php-current-class` ([#802])
  * Remove hardcoding of implicit paths in `php` that are not guaranteed to 
exist ([#803])
 
+### Fixed
+
+ * `php-project-project-find-function` now returns a `project.el` value valid 
on Emacs 28+; it previously built a `(vc . ROOT)` cons that broke the 3-element 
`(vc BACKEND ROOT)` representation and made `project-root` signal an error
+
+### Deprecated
+
+ * `php-project-use-projectile-to-detect-root` is obsolete; Projectile 3 
registers itself on `project-find-functions`, which `php-project-get-root-dir` 
now consults automatically
+
 [Imenu]: https://www.gnu.org/software/emacs/manual/html_node/emacs/Imenu.html
 [#802]: https://github.com/emacs-php/php-mode/pull/802
 [#803]: https://github.com/emacs-php/php-mode/pull/803
diff --git a/README.ja.md b/README.ja.md
index 2222cbb379..d9bc528f37 100644
--- a/README.ja.md
+++ b/README.ja.md
@@ -75,6 +75,24 @@ M-x package-install php-mode
   (php-project-coding-style . psr2)))
 ```
 
+### `project.el`・Projectileとの連携
+
+`php-project-get-root-dir`は、まずPHP固有のマーカー(`.projectile`、`composer.json`/`composer.lock`、続いてVCSディレクトリ)を探索します。モノレポではパッケージ単位の`vendor/autoload.php`やコーディングスタイルが`php-mode`にとって重要なため、VCSルートより`composer.json`を優先します。これらのマーカーが見つからない場合は`project-current`にフォールバックするので、任意の[`project.el`](https://www.gnu.org/software/emacs/manual/html_node/emacs/Projects.html)バックエンドが検出に寄与できます。
+
+* **Projectile 
3**は`projectile-mode`有効時に自身を`project-find-functions`へ登録するため、その検出結果が自動的に利用されます。従来の`php-project-use-projectile-to-detect-root`オプションはこのため廃止予定です。
+* Projectileなしでも`project-vc-extra-root-markers`(Emacs 
29以降)で追加のルートマーカーを宣言できます。例えば`.dir-locals.el`に次のように記述します。
+
+  ```lisp
+  ((nil
+    (project-vc-extra-root-markers . ("composer.json"))))
+  ```
+
+逆に、PHP固有の検出(上記の`composer.json`優先ルール)をEglotや`project-find-file`などの`project.el`利用側に見せたい場合は、組み込みのVC検出を補完するだけになるよう、低い優先度で`php-project-project-find-function`を登録します。
+
+```lisp
+(add-hook 'project-find-functions #'php-project-project-find-function 90)
+```
+
 ## HTMLとPHPが混在するファイルの編集
 
 
`php-mode`は純粋なPHPスクリプトのためのメジャーモードです。テンプレートのようにHTMLの中にPHPを埋め込んだファイルは、両方の言語を理解するメジャーモードで編集するほうが適しています。特にインデントは、HTML部分を素の`php-mode`で編集すると正しく動作しません。
diff --git a/README.md b/README.md
index 94421fb85b..178257b862 100644
--- a/README.md
+++ b/README.md
@@ -77,6 +77,24 @@ You can add project-specific settings by creating a 
`.dir-locals.el` or `.dir-lo
   (php-project-coding-style . psr2)))
 ```
 
+### Integration with `project.el` and Projectile
+
+`php-project-get-root-dir` first looks for a PHP-specific marker 
(`.projectile`, `composer.json`/`composer.lock`, then a VCS directory).  
Preferring `composer.json` over the VCS root matters in monorepos, where 
per-package `vendor/autoload.php` and coding styles are what `php-mode` cares 
about.  When none of those markers is found, it now falls back to 
`project-current`, so any 
[`project.el`](https://www.gnu.org/software/emacs/manual/html_node/emacs/Projects.html)
 backend can contribute  [...]
+
+* **Projectile 3** registers itself on `project-find-functions` when 
`projectile-mode` is enabled, so its detection is picked up automatically.  The 
old `php-project-use-projectile-to-detect-root` option is therefore obsolete.
+* **Extra root markers** can be declared without Projectile via 
`project-vc-extra-root-markers` (Emacs 29+), for example in `.dir-locals.el`:
+
+  ```lisp
+  ((nil
+    (project-vc-extra-root-markers . ("composer.json"))))
+  ```
+
+Conversely, to expose PHP-specific detection (the `composer.json`-first 
precedence above) to `project.el` consumers such as Eglot or 
`project-find-file`, register `php-project-project-find-function` with a low 
priority so it only supplements the built-in VC detection:
+
+```lisp
+(add-hook 'project-find-functions #'php-project-project-find-function 90)
+```
+
 ## Editing files that mix HTML and PHP
 
 `php-mode` is designed for pure PHP scripts.  Files that embed PHP inside 
HTML, such as templates, are better edited in a major mode that understands 
both languages.  Indentation in particular is unreliable when the HTML part of 
a file is edited in plain `php-mode`.
diff --git a/lisp/php-project.el b/lisp/php-project.el
index e057b5fe6a..57e5ae33d9 100644
--- a/lisp/php-project.el
+++ b/lisp/php-project.el
@@ -59,7 +59,10 @@
 (eval-when-compile
   (require 'cl-lib))
 (require 'php-core)
-(require 'projectile nil t)
+(require 'project)
+;; Projectile is optional and only used at runtime through `fboundp' guards.
+;; `projectile-mode' being active already implies the library is loaded, so we
+;; deliberately avoid pulling in the whole of Projectile just by requiring us.
 
 ;; Constants
 (defconst php-project-composer-autoloader "vendor/autoload.php")
@@ -77,9 +80,18 @@
   :type 'boolean)
 
 (defcustom php-project-use-projectile-to-detect-root nil
-  "If `T' and projectile-mode is activated, use Projectile for root detection."
+  "If `T' and projectile-mode is activated, use Projectile for root detection.
+
+This option predates Projectile 3, which registers itself on
+`project-find-functions'.  `php-project-get-root-dir' now falls back to
+`project-current' when no PHP marker is found, so Projectile (and any other
+`project.el' backend) is consulted automatically.  Prefer that path instead."
   :tag "PHP Project Use Projectile To Detect Root"
   :type 'boolean)
+(make-obsolete-variable 'php-project-use-projectile-to-detect-root
+                        "rely on `project-find-functions'; \
+`php-project-get-root-dir' falls back to `project-current' automatically."
+                        "1.28.0")
 
 ;; Variables
 (defvar php-project-available-root-files
@@ -260,14 +272,24 @@ Typically it is `pear', `drupal', `wordpress', `symfony2' 
and `psr2'.")
 
 ;;;###autoload
 (defun php-project-project-find-function (dir)
-  "Return path to current PHP project from DIR.
+  "Return the PHP project containing DIR.
+
+This function is compatible with `project-find-functions'.  Register it with a
+low priority so that it only supplements the built-in detection, for example:
+
+    (add-hook \\='project-find-functions 
#\\='php-project-project-find-function 90)
 
-This function is compatible with `project-find-functions'."
+When the detected root is under version control the result is delegated to
+`project-try-vc', which yields the representation expected by the running
+Emacs (a plain \\='(vc . ROOT) cons is only valid on Emacs 27 and breaks the
+3-element \\='(vc BACKEND ROOT) form used since Emacs 28).  Otherwise a
+`transient' project rooted at the PHP project directory is returned."
   (let ((default-directory dir))
     (when-let* ((root (php-project-get-root-dir)))
-      (if (file-exists-p (expand-file-name ".git" root))
-          (cons 'vc root)
-        (cons 'transient root)))))
+      (or (and (file-exists-p (expand-file-name ".git" root))
+               (fboundp 'project-try-vc)
+               (project-try-vc root))
+          (cons 'transient root)))))
 
 (defun php-project--detect-root-dir ()
   "Return detected project root."
@@ -282,8 +304,25 @@ This function is compatible with `project-find-functions'."
              (cl-loop for m in php-project-available-root-files
                       append (cdr m)))
             (t (cdr-safe (assq php-project-root 
php-project-available-root-files))))))
-      (cl-loop for m in detect-method
-               thereis (locate-dominating-file default-directory m)))))
+      (or (cl-loop for m in detect-method
+                   thereis (locate-dominating-file default-directory m))
+          (php-project--detect-root-by-project-el)))))
+
+(defun php-project--detect-root-by-project-el ()
+  "Return the root reported by `project.el', or nil.
+
+Used as a last resort when no PHP-specific marker is found.  This lets
+`project.el' backends contribute their own detection, including Projectile 3
+\(which registers itself on `project-find-functions') and
+`project-vc-extra-root-markers'.  `php-project-project-find-function' is
+temporarily removed from the hook to avoid recursing back into this function."
+  ;; `project-root' only exists on Emacs 28.1+; on Emacs 27 there is no
+  ;; non-obsolete accessor, so the fallback simply does nothing there.
+  (when (fboundp 'project-root)
+    (let ((project-find-functions
+           (remq #'php-project-project-find-function project-find-functions)))
+      (when-let* ((project (project-current)))
+        (project-root project)))))
 
 (provide 'php-project)
 ;;; php-project.el ends here

Reply via email to