From b0088be396edb7a569ab5486df9d37d9df1cd432 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Sun, 10 Jul 2022 18:34:03 +0900 Subject: [PATCH 01/71] Add phpstan-analyze-this-file --- CHANGELOG.md | 9 +++++++++ phpstan.el | 9 ++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..8c9d053 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,9 @@ +# Changelog + +All notable changes of the phpactor.el are documented in this file using the [Keep a Changelog](https://keepachangelog.com/) principles. + +## Unreleased + +### Added + +* Add `phpstan-analyze-this-file` command diff --git a/phpstan.el b/phpstan.el index b05f3dd..143ab94 100644 --- a/phpstan.el +++ b/phpstan.el @@ -283,8 +283,15 @@ it returns the value of `SOURCE' as it is." "Return --memory-limit value." phpstan-memory-limit) +(defun phpstan-analyze-this-file () + "Analyze current buffer-file using PHPStan." + (interactive) + (let ((file (expand-file-name (or buffer-file-name + (read-file-name "Choose a PHP script: "))))) + (compile (mapconcat #'shell-quote-argument (append (phpstan-get-command-args t) (list file)) " ")))) + (defun phpstan-analyze-file (file) - "Analyze a PHPScript FILE using PHPStan." + "Analyze a PHP script FILE using PHPStan." (interactive (list (expand-file-name (read-file-name "Choose a PHP script: ")))) (compile (mapconcat #'shell-quote-argument (append (phpstan-get-command-args t) (list file)) " "))) From 02bb760c523265e293305737c95f7d62b7fdd3b9 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Sat, 23 Jul 2022 13:01:23 +0900 Subject: [PATCH 02/71] Fix doc comments --- phpstan.el | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/phpstan.el b/phpstan.el index 143ab94..7b00645 100644 --- a/phpstan.el +++ b/phpstan.el @@ -58,9 +58,8 @@ ;; Variables: - (defgroup phpstan nil - "Interaface to PHPStan" + "Interaface to PHPStan." :tag "PHPStan" :prefix "phpstan-" :group 'tools @@ -229,7 +228,7 @@ NIL (php-project-get-root-dir))))) (defun phpstan-get-config-file () - "Return path to phpstan configure file or `NIL'." + "Return path to phpstan configure file or NIL." (if phpstan-config-file (if (and (consp phpstan-config-file) (eq 'root (car phpstan-config-file))) @@ -252,7 +251,7 @@ NIL phpstan-autoload-file))) (defun phpstan-normalize-path (source-original &optional source) - "Return normalized source file path to pass by `SOURCE-ORIGINAL' OR `SOURCE'. + "Return normalized source file path to pass by SOURCE-ORIGINAL or SOURCE. If neither `phpstan-replace-path-prefix' nor executable docker is set, it returns the value of `SOURCE' as it is." @@ -272,7 +271,7 @@ it returns the value of `SOURCE' as it is." (or source source-original)))) (defun phpstan-get-level () - "Return path to phpstan configure file or `NIL'." + "Return path to phpstan configure file or NIL." (cond ((null phpstan-level) nil) ((integerp phpstan-level) (int-to-string phpstan-level)) From 45709136f1060252d04756f9e58dd2c35725797f Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Sat, 23 Jul 2022 13:16:08 +0900 Subject: [PATCH 03/71] Add phpstan.dist.neon to phpstan-get-config-file --- CHANGELOG.md | 1 + phpstan.el | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c9d053..b8d4951 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,3 +7,4 @@ All notable changes of the phpactor.el are documented in this file using the [Ke ### Added * Add `phpstan-analyze-this-file` command +* Add `phpstan.dist.neon` to `phpstan-get-config-file` as PHPStan config files. diff --git a/phpstan.el b/phpstan.el index 7b00645..f241977 100644 --- a/phpstan.el +++ b/phpstan.el @@ -237,8 +237,8 @@ NIL phpstan-config-file) (let ((working-directory (phpstan-get-working-dir))) (when working-directory - (cl-loop for name in '("phpstan.neon" "phpstan.neon.dist") - for dir = (locate-dominating-file working-directory name) + (cl-loop for name in '("phpstan.neon" "phpstan.neon.dist" "phpstan.dist.neon") + for dir = (locate-dominating-file working-directory name) if dir return (expand-file-name name dir)))))) From a9eb3e44c89922f6b752117f53da1bcca6022bb7 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Sat, 23 Jul 2022 13:16:47 +0900 Subject: [PATCH 04/71] Add (require 'php) in eval-when-compile --- phpstan.el | 2 ++ 1 file changed, 2 insertions(+) diff --git a/phpstan.el b/phpstan.el index f241977..250fac3 100644 --- a/phpstan.el +++ b/phpstan.el @@ -56,6 +56,8 @@ (require 'cl-lib) (require 'php-project) +(eval-when-compile + (require 'php)) ;; Variables: (defgroup phpstan nil From 8928206e16d7408f80d6987390fcebe26e3d30dd Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Sat, 23 Jul 2022 15:04:04 +0900 Subject: [PATCH 05/71] Make flycheck analyze the original directly instead of temporary --- CHANGELOG.md | 4 ++++ flycheck-phpstan.el | 7 ++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8d4951..a0cfe26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,3 +8,7 @@ All notable changes of the phpactor.el are documented in this file using the [Ke * Add `phpstan-analyze-this-file` command * Add `phpstan.dist.neon` to `phpstan-get-config-file` as PHPStan config files. + +### Changed + +* Make flycheck analyze the original file directly instead of temporary files when there are no changes to the file. diff --git a/flycheck-phpstan.el b/flycheck-phpstan.el index 35af909..a4256b1 100644 --- a/flycheck-phpstan.el +++ b/flycheck-phpstan.el @@ -63,9 +63,10 @@ (flycheck-define-checker phpstan "PHP static analyzer based on PHPStan." :command ("php" (eval (phpstan-get-command-args)) - (eval (phpstan-normalize-path - (flycheck-save-buffer-to-temp #'flycheck-temp-file-inplace) - (flycheck-save-buffer-to-temp #'flycheck-temp-file-system)))) + (eval (if (or (buffer-modified-p) (not buffer-file-name)) + (phpstan-normalize-path + (flycheck-save-buffer-to-temp #'flycheck-temp-file-inplace)) + buffer-file-name))) :working-directory (lambda (_) (phpstan-get-working-dir)) :enabled (lambda () (flycheck-phpstan--enabled-and-set-variable)) :error-patterns From 220079133946b961c91b54c739b55d46f46798e8 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Sat, 23 Jul 2022 18:29:38 +0900 Subject: [PATCH 06/71] Add autoload cookies to interactive commands --- phpstan.el | 2 ++ 1 file changed, 2 insertions(+) diff --git a/phpstan.el b/phpstan.el index 250fac3..e902f5f 100644 --- a/phpstan.el +++ b/phpstan.el @@ -284,6 +284,7 @@ it returns the value of `SOURCE' as it is." "Return --memory-limit value." phpstan-memory-limit) +;;;###autoload (defun phpstan-analyze-this-file () "Analyze current buffer-file using PHPStan." (interactive) @@ -291,6 +292,7 @@ it returns the value of `SOURCE' as it is." (read-file-name "Choose a PHP script: "))))) (compile (mapconcat #'shell-quote-argument (append (phpstan-get-command-args t) (list file)) " ")))) +;;;###autoload (defun phpstan-analyze-file (file) "Analyze a PHP script FILE using PHPStan." (interactive (list (expand-file-name (read-file-name "Choose a PHP script: ")))) From fb5a48912f38a0aa08824265604b4c3da03167a7 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Sat, 23 Jul 2022 23:09:31 +0900 Subject: [PATCH 07/71] Use cl-defun php-stan-get-command-args instead of defun --- phpstan.el | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/phpstan.el b/phpstan.el index e902f5f..b390a31 100644 --- a/phpstan.el +++ b/phpstan.el @@ -290,13 +290,15 @@ it returns the value of `SOURCE' as it is." (interactive) (let ((file (expand-file-name (or buffer-file-name (read-file-name "Choose a PHP script: "))))) - (compile (mapconcat #'shell-quote-argument (append (phpstan-get-command-args t) (list file)) " ")))) + (compile (mapconcat #'shell-quote-argument + (append (phpstan-get-command-args :include-executable t) (list file)) " ")))) ;;;###autoload (defun phpstan-analyze-file (file) "Analyze a PHP script FILE using PHPStan." (interactive (list (expand-file-name (read-file-name "Choose a PHP script: ")))) - (compile (mapconcat #'shell-quote-argument (append (phpstan-get-command-args t) (list file)) " "))) + (compile (mapconcat #'shell-quote-argument + (append (phpstan-get-command-args :include-executable t) (list file)) " "))) (defun phpstan-get-executable-and-args () "Return PHPStan excutable file and arguments." @@ -335,7 +337,7 @@ it returns the value of `SOURCE' as it is." ((executable-find "phpstan") (list (executable-find "phpstan"))) (t (error "PHPStan executable not found"))))))) -(defun phpstan-get-command-args (&optional include-executable) +(cl-defun phpstan-get-command-args (&key include-executable use-pro) "Return command line argument for PHPStan." (let ((executable-and-args (phpstan-get-executable-and-args)) (path (phpstan-normalize-path (phpstan-get-config-file))) From e229e990e36a2bfb88503bfe2bb6f2836eaa2874 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Sat, 23 Jul 2022 23:49:59 +0900 Subject: [PATCH 08/71] Add phpstan-pro command to launch PHPStan Pro --- CHANGELOG.md | 3 +++ phpstan.el | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0cfe26..d6ec178 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ All notable changes of the phpactor.el are documented in this file using the [Ke * Add `phpstan-analyze-this-file` command * Add `phpstan.dist.neon` to `phpstan-get-config-file` as PHPStan config files. +* Add `phpstan-pro` command to launch [PHPStan Pro]. + +[PHPStan Pro]: https://phpstan.org/blog/introducing-phpstan-pro ### Changed diff --git a/phpstan.el b/phpstan.el index b390a31..3185f0c 100644 --- a/phpstan.el +++ b/phpstan.el @@ -300,6 +300,15 @@ it returns the value of `SOURCE' as it is." (compile (mapconcat #'shell-quote-argument (append (phpstan-get-command-args :include-executable t) (list file)) " "))) +;;;###autoload +(defun phpstan-pro () + "Analyze current PHP project using PHPStan Pro." + (interactive) + (let ((compilation-buffer-name-function (lambda (_) "*PHPStan Pro*")) + (command (mapconcat #'shell-quote-argument + (phpstan-get-command-args :include-executable t :use-pro t) " "))) + (compile command t))) + (defun phpstan-get-executable-and-args () "Return PHPStan excutable file and arguments." (cond @@ -347,6 +356,7 @@ it returns the value of `SOURCE' as it is." (append (if include-executable (list (car executable-and-args)) nil) (cdr executable-and-args) (list "analyze" "--error-format=raw" "--no-progress" "--no-interaction") + (and use-pro (list "--pro" "--no-ansi")) (and path (list "-c" path)) (and autoload (list "-a" autoload)) (and memory-limit (list "--memory-limit" memory-limit)) From 8b4be09defe5856a1855c976474ada67557780cd Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Sun, 6 Nov 2022 06:12:17 +0900 Subject: [PATCH 09/71] Add :args option to phpstan-get-command-args and use nconc for optimization --- phpstan.el | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/phpstan.el b/phpstan.el index 3185f0c..b67e2b4 100644 --- a/phpstan.el +++ b/phpstan.el @@ -291,14 +291,14 @@ it returns the value of `SOURCE' as it is." (let ((file (expand-file-name (or buffer-file-name (read-file-name "Choose a PHP script: "))))) (compile (mapconcat #'shell-quote-argument - (append (phpstan-get-command-args :include-executable t) (list file)) " ")))) + (phpstan-get-command-args :include-executable t :args (list file)) " ")))) ;;;###autoload (defun phpstan-analyze-file (file) "Analyze a PHP script FILE using PHPStan." (interactive (list (expand-file-name (read-file-name "Choose a PHP script: ")))) (compile (mapconcat #'shell-quote-argument - (append (phpstan-get-command-args :include-executable t) (list file)) " "))) + (phpstan-get-command-args :include-executable t :args (list file)) " "))) ;;;###autoload (defun phpstan-pro () @@ -346,22 +346,23 @@ it returns the value of `SOURCE' as it is." ((executable-find "phpstan") (list (executable-find "phpstan"))) (t (error "PHPStan executable not found"))))))) -(cl-defun phpstan-get-command-args (&key include-executable use-pro) +(cl-defun phpstan-get-command-args (&key include-executable use-pro args) "Return command line argument for PHPStan." (let ((executable-and-args (phpstan-get-executable-and-args)) (path (phpstan-normalize-path (phpstan-get-config-file))) (autoload (phpstan-get-autoload-file)) (memory-limit (phpstan-get-memory-limit)) (level (phpstan-get-level))) - (append (if include-executable (list (car executable-and-args)) nil) - (cdr executable-and-args) - (list "analyze" "--error-format=raw" "--no-progress" "--no-interaction") - (and use-pro (list "--pro" "--no-ansi")) - (and path (list "-c" path)) - (and autoload (list "-a" autoload)) - (and memory-limit (list "--memory-limit" memory-limit)) - (and level (list "-l" level)) - (list "--")))) + (nconc (if include-executable (list (car executable-and-args)) nil) + (cdr executable-and-args) + (list "analyze" "--error-format=raw" "--no-progress" "--no-interaction") + (and use-pro (list "--pro" "--no-ansi")) + (and path (list "-c" path)) + (and autoload (list "-a" autoload)) + (and memory-limit (list "--memory-limit" memory-limit)) + (and level (list "-l" level)) + (list "--") + args))) (provide 'phpstan) ;;; phpstan.el ends here From cce2b02a7f91525423b14dbdae304c1c6b8a1817 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Sun, 6 Nov 2022 06:14:19 +0900 Subject: [PATCH 10/71] composer require phpstan/phpstan:^1.9 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 3dc0dd8..8787e56 100644 --- a/composer.json +++ b/composer.json @@ -3,6 +3,6 @@ "description": "Emacs interface to PHPStan", "license": "GPL-3.0-or-later", "require": { - "phpstan/phpstan": "^0.12.92" + "phpstan/phpstan": "^1.9" } } From 497ac27d2bb11bf62f56977259f9a6d6b0862d9b Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Thu, 30 Mar 2023 09:55:41 +0900 Subject: [PATCH 11/71] Add automatically --xdebug option support --- phpstan.el | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/phpstan.el b/phpstan.el index b67e2b4..3cb5520 100644 --- a/phpstan.el +++ b/phpstan.el @@ -7,7 +7,7 @@ ;; Version: 0.6.0 ;; Keywords: tools, php ;; Homepage: https://github.com/emacs-php/phpstan.el -;; Package-Requires: ((emacs "24.3") (php-mode "1.22.3")) +;; Package-Requires: ((emacs "24.3") (php-mode "1.22.3") (php-runtime "0.2")) ;; License: GPL-3.0-or-later ;; This program is free software; you can redistribute it and/or modify @@ -55,6 +55,7 @@ ;;; Code: (require 'cl-lib) (require 'php-project) +(require 'php-runtime) (eval-when-compile (require 'php)) @@ -98,6 +99,15 @@ :safe (lambda (v) (or (null v) (stringp v))) :group 'phpstan) +(defcustom phpstan-use-xdebug-option 'auto + "Set --xdebug option." + :type '(choice (const :tag "Set --xdebug option dynamically" 'auto) + (const :tag "Add --xdebug option" t) + (const :tag "No --xdebug option" nil)) + :group 'phpstan) + +(defvar-local phpstan--use-xdebug-option nil) + ;;;###autoload (progn (defvar phpstan-working-dir nil @@ -361,6 +371,14 @@ it returns the value of `SOURCE' as it is." (and autoload (list "-a" autoload)) (and memory-limit (list "--memory-limit" memory-limit)) (and level (list "-l" level)) + (cond + (phpstan--use-xdebug-option (list phpstan--use-xdebug-option)) + ((eq phpstan-use-xdebug-option 'auto) + (setq-local phpstan--use-xdebug-option + (when (string= "1" (php-runtime-expr "extension_loaded('xdebug')")) + "--xdebug")) + (list phpstan--use-xdebug-option)) + (phpstan-use-xdebug-option (list "--xdebug"))) (list "--") args))) From 3248a0504a01ab77849b6176bdf96e60fea86865 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Thu, 30 Mar 2023 09:59:12 +0900 Subject: [PATCH 12/71] Add JSON support --- phpstan.el | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/phpstan.el b/phpstan.el index 3cb5520..277c71e 100644 --- a/phpstan.el +++ b/phpstan.el @@ -58,7 +58,8 @@ (require 'php-runtime) (eval-when-compile - (require 'php)) + (require 'php) + (require 'json)) ;; Variables: (defgroup phpstan nil @@ -294,6 +295,17 @@ it returns the value of `SOURCE' as it is." "Return --memory-limit value." phpstan-memory-limit) +(defun phpstan--parse-json (buffer) + "Read JSON string from BUFFER." + (with-current-buffer buffer + (goto-char (point-min)) + (if (eval-when-compile (and (fboundp 'json-serialize) + (fboundp 'json-parse-buffer))) + (with-no-warnings + (json-parse-buffer :object-type 'plist :array-type 'list)) + (let ((json-object-type 'plist) (json-array-type 'list)) + (json-read-object))))) + ;;;###autoload (defun phpstan-analyze-this-file () "Analyze current buffer-file using PHPStan." From e245f87e3ec4a1776037f3295d17be8a1c5abf9f Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Thu, 30 Mar 2023 10:14:09 +0900 Subject: [PATCH 13/71] Add format option to phpstan-get-command-args --- phpstan.el | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/phpstan.el b/phpstan.el index 277c71e..c0564a2 100644 --- a/phpstan.el +++ b/phpstan.el @@ -368,7 +368,7 @@ it returns the value of `SOURCE' as it is." ((executable-find "phpstan") (list (executable-find "phpstan"))) (t (error "PHPStan executable not found"))))))) -(cl-defun phpstan-get-command-args (&key include-executable use-pro args) +(cl-defun phpstan-get-command-args (&key include-executable use-pro args format) "Return command line argument for PHPStan." (let ((executable-and-args (phpstan-get-executable-and-args)) (path (phpstan-normalize-path (phpstan-get-config-file))) @@ -377,7 +377,9 @@ it returns the value of `SOURCE' as it is." (level (phpstan-get-level))) (nconc (if include-executable (list (car executable-and-args)) nil) (cdr executable-and-args) - (list "analyze" "--error-format=raw" "--no-progress" "--no-interaction") + (list "analyze" + (format "--error-format=%s" (or format "raw")) + "--no-progress" "--no-interaction") (and use-pro (list "--pro" "--no-ansi")) (and path (list "-c" path)) (and autoload (list "-a" autoload)) From 864e8faefc9cc351ec566b2b332438e54c1568a1 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Thu, 30 Mar 2023 10:15:48 +0900 Subject: [PATCH 14/71] Make flycheck-phpstan use --error-format=json instead of "raw" --- flycheck-phpstan.el | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/flycheck-phpstan.el b/flycheck-phpstan.el index a4256b1..09e3ce3 100644 --- a/flycheck-phpstan.el +++ b/flycheck-phpstan.el @@ -43,6 +43,7 @@ ;; Usually it is defined dynamically by flycheck (defvar flycheck-phpstan-executable) +(defvar flycheck-phpstan--temp-buffer-name "*Flycheck PHPStan*") (defun flycheck-phpstan--enabled-and-set-variable () "Return path to phpstan configure file, and set buffer execute in side effect." @@ -60,17 +61,48 @@ (null phpstan-executable))) (setq-local flycheck-phpstan-executable (car (phpstan-get-executable-and-args))))))) +(defun flycheck-phpstan-parse-output (output &optional _checker _buffer) + "Parse PHPStan errors from OUTPUT." + (with-current-buffer (flycheck-phpstan--temp-buffer) + (erase-buffer) + (insert output)) + (flycheck-phpstan-parse-json (flycheck-phpstan--temp-buffer))) + +(defun flycheck-phpstan--temp-buffer () + "Return a temporary buffer for decode JSON." + (get-buffer-create flycheck-phpstan--temp-buffer-name)) + +(defun flycheck-phpstan-parse-json (json-buffer) + "Parse PHPStan errors from JSON-BUFFER." + (let ((data (phpstan--parse-json json-buffer))) + (cl-loop for (file . entry) in (flycheck-phpstan--plist-to-alist (plist-get data :files)) + append (cl-loop for messages in (plist-get entry :messages) + for text = (let ((msg (plist-get messages :message)) + (tip (plist-get messages :tip))) + (if tip + (concat msg "\n" phpstan-tip-message-prefix tip) + msg)) + collect (flycheck-error-new-at (plist-get messages :line) + nil 'error text + :filename file))))) + +(defun flycheck-phpstan--plist-to-alist (plist) + "Convert PLIST to association list." + (let (alist) + (while plist + (push (cons (substring-no-properties (symbol-name (pop plist)) 1) (pop plist)) alist)) + (nreverse alist))) + (flycheck-define-checker phpstan "PHP static analyzer based on PHPStan." - :command ("php" (eval (phpstan-get-command-args)) + :command ("php" (eval (phpstan-get-command-args :format "json")) (eval (if (or (buffer-modified-p) (not buffer-file-name)) (phpstan-normalize-path (flycheck-save-buffer-to-temp #'flycheck-temp-file-inplace)) buffer-file-name))) :working-directory (lambda (_) (phpstan-get-working-dir)) :enabled (lambda () (flycheck-phpstan--enabled-and-set-variable)) - :error-patterns - ((error line-start (1+ (not (any ":"))) ":" line ":" (message) line-end)) + :error-parser flycheck-phpstan-parse-output :modes (php-mode phps-mode)) (add-to-list 'flycheck-checkers 'phpstan t) From fdccb9b3abda4be2fe78c190920ccbdc72ad5062 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Thu, 30 Mar 2023 10:16:53 +0900 Subject: [PATCH 15/71] Fix link to PHPStan docker image --- README.org | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.org b/README.org index 620fe2c..818f4a9 100644 --- a/README.org +++ b/README.org @@ -29,7 +29,7 @@ Emacs interface to [[https://github.com/phpstan/phpstan][PHPStan]], includes che #+END_SRC *** Using Docker (phpstan/docker-image) -Install [[https://www.docker.com/get-started][Docker]] and [[https://hub.docker.com/r/phpstan/phpstan][phpstan/phpstan image]]. +Install [[https://www.docker.com/get-started][Docker]] and [[https://github.com/phpstan/phpstan/pkgs/container/phpstan][phpstan/phpstan image]]. If you always use Docker for PHPStan, add the following into your ~.emacs~ file (~~/.emacs.d/init.el~) #+BEGIN_SRC emacs-lisp From 9edd6ddad65d91b77b1cd17062063d465b91de44 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Thu, 30 Mar 2023 21:35:01 +0900 Subject: [PATCH 16/71] Add :options keyword to phpstan-get-command-args --- phpstan.el | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/phpstan.el b/phpstan.el index c0564a2..5c53dca 100644 --- a/phpstan.el +++ b/phpstan.el @@ -368,7 +368,7 @@ it returns the value of `SOURCE' as it is." ((executable-find "phpstan") (list (executable-find "phpstan"))) (t (error "PHPStan executable not found"))))))) -(cl-defun phpstan-get-command-args (&key include-executable use-pro args format) +(cl-defun phpstan-get-command-args (&key include-executable use-pro args format options) "Return command line argument for PHPStan." (let ((executable-and-args (phpstan-get-executable-and-args)) (path (phpstan-normalize-path (phpstan-get-config-file))) @@ -393,8 +393,8 @@ it returns the value of `SOURCE' as it is." "--xdebug")) (list phpstan--use-xdebug-option)) (phpstan-use-xdebug-option (list "--xdebug"))) - (list "--") - args))) + options + (and args (cons "--" args))))) (provide 'phpstan) ;;; phpstan.el ends here From 4645ff02afd184eda9e61616231e6aac4317b517 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Thu, 30 Mar 2023 21:37:04 +0900 Subject: [PATCH 17/71] Add phpstan-analyze-project and phpstan-generate-baseline --- phpstan.el | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/phpstan.el b/phpstan.el index 5c53dca..7a292fb 100644 --- a/phpstan.el +++ b/phpstan.el @@ -322,6 +322,19 @@ it returns the value of `SOURCE' as it is." (compile (mapconcat #'shell-quote-argument (phpstan-get-command-args :include-executable t :args (list file)) " "))) +;;;###autoload +(defun phpstan-analyze-project () + "Analyze a PHP project using PHPStan." + (interactive) + (compile (mapconcat #'shell-quote-argument (phpstan-get-command-args :include-executable t) " "))) + +;;;###autoload +(defun phpstan-generate-baseline () + "Generate PHPStan baseline file." + (interactive) + (compile (mapconcat #'shell-quote-argument + (phpstan-get-command-args :include-executable t :options '("--generate-baseline")) " "))) + ;;;###autoload (defun phpstan-pro () "Analyze current PHP project using PHPStan Pro." From b4baa1b731e3affaa379cb46beff10792349a63f Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Fri, 31 Mar 2023 01:50:46 +0900 Subject: [PATCH 18/71] Add depends on compat --- Cask | 1 + phpstan.el | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Cask b/Cask index ed6cb9e..582b115 100644 --- a/Cask +++ b/Cask @@ -1,5 +1,6 @@ (package "phpstan" "0.6.0" "Interface to PHPStan (PHP static analyzer)") (source "melpa" "https://melpa.org/packages/") +(source "gnu" "https://elpa.gnu.org/packages/") (package-file "phpstan.el") (package-file "flycheck-phpstan.el") diff --git a/phpstan.el b/phpstan.el index 7a292fb..5e3bae4 100644 --- a/phpstan.el +++ b/phpstan.el @@ -7,7 +7,7 @@ ;; Version: 0.6.0 ;; Keywords: tools, php ;; Homepage: https://github.com/emacs-php/phpstan.el -;; Package-Requires: ((emacs "24.3") (php-mode "1.22.3") (php-runtime "0.2")) +;; Package-Requires: ((emacs "24.3") (compat "29") (php-mode "1.22.3") (php-runtime "0.2")) ;; License: GPL-3.0-or-later ;; This program is free software; you can redistribute it and/or modify @@ -58,6 +58,7 @@ (require 'php-runtime) (eval-when-compile + (require 'compat) (require 'php) (require 'json)) From 7ab85a495cd8f49c011d4a9c27b292dfaf473c95 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Fri, 31 Mar 2023 02:01:24 +0900 Subject: [PATCH 19/71] Add phpstan-baseline-file command --- phpstan.el | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/phpstan.el b/phpstan.el index 5e3bae4..e81c5cd 100644 --- a/phpstan.el +++ b/phpstan.el @@ -108,6 +108,12 @@ (const :tag "No --xdebug option" nil)) :group 'phpstan) +(defcustom phpstan-baseline-file "phpstan-baseline.neon" + "File name of PHPStan baseline file." + :type 'string + :safe #'stringp + :group 'phpstan) + (defvar-local phpstan--use-xdebug-option nil) ;;;###autoload @@ -336,6 +342,14 @@ it returns the value of `SOURCE' as it is." (compile (mapconcat #'shell-quote-argument (phpstan-get-command-args :include-executable t :options '("--generate-baseline")) " "))) +;;;###autoload +(defun phpstan-find-baseline-file () + "Find PHPStan baseline file of current project." + (interactive) + (if-let ((path (locate-dominating-file default-directory phpstan-baseline-file))) + (find-file (expand-file-name phpstan-baseline-file path)) + (user-error "Baseline file not found. Try running M-x phpstan-generate-baseline"))) + ;;;###autoload (defun phpstan-pro () "Analyze current PHP project using PHPStan Pro." From a4193de889c68d195a109fc239857f70728bce4e Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Fri, 31 Mar 2023 21:30:26 +0900 Subject: [PATCH 20/71] Add missing phpstan-tip-message-prefix custom variable --- phpstan.el | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/phpstan.el b/phpstan.el index e81c5cd..3d5f15c 100644 --- a/phpstan.el +++ b/phpstan.el @@ -114,6 +114,12 @@ :safe #'stringp :group 'phpstan) +(defcustom phpstan-tip-message-prefix "💡 " + "Prefix of PHPStan tip message." + :type 'string + :safe #'stringp + :group 'phpstan) + (defvar-local phpstan--use-xdebug-option nil) ;;;###autoload From e55df7527a322cc965c5aa952708ea55d3d3052b Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Tue, 4 Apr 2023 20:06:49 +0900 Subject: [PATCH 21/71] (require 'compat nil t) --- phpstan.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpstan.el b/phpstan.el index 3d5f15c..5245954 100644 --- a/phpstan.el +++ b/phpstan.el @@ -58,7 +58,7 @@ (require 'php-runtime) (eval-when-compile - (require 'compat) + (require 'compat nil t) (require 'php) (require 'json)) From 8650aa94674c04b01970c0d90602c77e7a22e8a3 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Tue, 4 Apr 2023 20:07:19 +0900 Subject: [PATCH 22/71] Ignore error output in JSON --- phpstan.el | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/phpstan.el b/phpstan.el index 5245954..f6ce712 100644 --- a/phpstan.el +++ b/phpstan.el @@ -312,6 +312,11 @@ it returns the value of `SOURCE' as it is." "Read JSON string from BUFFER." (with-current-buffer buffer (goto-char (point-min)) + ;; Ignore STDERR + (save-match-data + (when (search-forward-regexp "^{" nil t) + (backward-char 1) + (delete-region (point-min) (point)))) (if (eval-when-compile (and (fboundp 'json-serialize) (fboundp 'json-parse-buffer))) (with-no-warnings From 0d2907abaca61235c2ff8181135b9acc48f8d3cf Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Tue, 4 Apr 2023 20:07:46 +0900 Subject: [PATCH 23/71] Set default-directory in phpstan-analyze-project and phpstan-generate-baseline --- phpstan.el | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/phpstan.el b/phpstan.el index f6ce712..5f367e2 100644 --- a/phpstan.el +++ b/phpstan.el @@ -344,14 +344,18 @@ it returns the value of `SOURCE' as it is." (defun phpstan-analyze-project () "Analyze a PHP project using PHPStan." (interactive) - (compile (mapconcat #'shell-quote-argument (phpstan-get-command-args :include-executable t) " "))) + (let ((default-directory (or (php-project-get-root-dir) default-directory))) + (compile (mapconcat #'shell-quote-argument (phpstan-get-command-args :include-executable t) " ")))) ;;;###autoload (defun phpstan-generate-baseline () "Generate PHPStan baseline file." (interactive) - (compile (mapconcat #'shell-quote-argument - (phpstan-get-command-args :include-executable t :options '("--generate-baseline")) " "))) + (let ((default-directory (or (locate-dominating-file default-directory phpstan-baseline-file) + (php-project-get-root-dir) + default-directory))) + (compile (mapconcat #'shell-quote-argument + (phpstan-get-command-args :include-executable t :options '("--generate-baseline")) " ")))) ;;;###autoload (defun phpstan-find-baseline-file () From 1a8a18e91105891739c949a606c05ae0a8de0349 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Tue, 4 Apr 2023 20:11:08 +0900 Subject: [PATCH 24/71] Fix Cask file --- Cask | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cask b/Cask index 582b115..da984e3 100644 --- a/Cask +++ b/Cask @@ -1,6 +1,6 @@ (package "phpstan" "0.6.0" "Interface to PHPStan (PHP static analyzer)") -(source "melpa" "https://melpa.org/packages/") -(source "gnu" "https://elpa.gnu.org/packages/") +(source melpa) +(source gnu) (package-file "phpstan.el") (package-file "flycheck-phpstan.el") From ee3f8fde8fc32c2ae3e28c53be3e1c93b04a3ea7 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Tue, 4 Apr 2023 20:11:36 +0900 Subject: [PATCH 25/71] Bump version 0.7.0 --- Cask | 2 +- phpstan.el | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cask b/Cask index da984e3..a9d68f8 100644 --- a/Cask +++ b/Cask @@ -1,4 +1,4 @@ -(package "phpstan" "0.6.0" "Interface to PHPStan (PHP static analyzer)") +(package "phpstan" "0.7.0" "Interface to PHPStan (PHP static analyzer)") (source melpa) (source gnu) diff --git a/phpstan.el b/phpstan.el index 5f367e2..a7616d4 100644 --- a/phpstan.el +++ b/phpstan.el @@ -1,10 +1,10 @@ ;;; phpstan.el --- Interface to PHPStan -*- lexical-binding: t; -*- -;; Copyright (C) 2021 Friends of Emacs-PHP development +;; Copyright (C) 2023 Friends of Emacs-PHP development ;; Author: USAMI Kenta ;; Created: 15 Mar 2018 -;; Version: 0.6.0 +;; Version: 0.7.0 ;; Keywords: tools, php ;; Homepage: https://github.com/emacs-php/phpstan.el ;; Package-Requires: ((emacs "24.3") (compat "29") (php-mode "1.22.3") (php-runtime "0.2")) From 8a0889d19234c4c445cb6ae74857c2824bb3c880 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Tue, 4 Apr 2023 22:50:38 +0900 Subject: [PATCH 26/71] Make phpstan-use-xdebug-option as nil --- phpstan.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpstan.el b/phpstan.el index a7616d4..fb4c8b0 100644 --- a/phpstan.el +++ b/phpstan.el @@ -101,7 +101,7 @@ :safe (lambda (v) (or (null v) (stringp v))) :group 'phpstan) -(defcustom phpstan-use-xdebug-option 'auto +(defcustom phpstan-use-xdebug-option nil "Set --xdebug option." :type '(choice (const :tag "Set --xdebug option dynamically" 'auto) (const :tag "Add --xdebug option" t) From 6dc8f1df29f22f0b0ef839c66822d48e2c7b1848 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Tue, 4 Apr 2023 22:51:37 +0900 Subject: [PATCH 27/71] Add phpstan-generate-baseline-options for default adds --allow-empty-baseline --- phpstan.el | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/phpstan.el b/phpstan.el index fb4c8b0..2d8646e 100644 --- a/phpstan.el +++ b/phpstan.el @@ -108,6 +108,12 @@ (const :tag "No --xdebug option" nil)) :group 'phpstan) +(defcustom phpstan-generate-baseline-options '("--generate-baseline" "--allow-empty-baseline") + "Command line options for generating PHPStan baseline." + :type '(repeat string) + :safe #'listp + :group 'phpstan) + (defcustom phpstan-baseline-file "phpstan-baseline.neon" "File name of PHPStan baseline file." :type 'string @@ -355,7 +361,7 @@ it returns the value of `SOURCE' as it is." (php-project-get-root-dir) default-directory))) (compile (mapconcat #'shell-quote-argument - (phpstan-get-command-args :include-executable t :options '("--generate-baseline")) " ")))) + (phpstan-get-command-args :include-executable t :options phpstan-generate-baseline-options) " ")))) ;;;###autoload (defun phpstan-find-baseline-file () From afb83acf3f52506d7ba21a412a5c08e90efc4410 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Mon, 17 Apr 2023 20:35:57 +0900 Subject: [PATCH 28/71] Update doc comments --- phpstan.el | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/phpstan.el b/phpstan.el index 2d8646e..027049c 100644 --- a/phpstan.el +++ b/phpstan.el @@ -78,14 +78,16 @@ :group 'phpstan) (defcustom phpstan-enable-on-no-config-file t - "If T, activate configuration from composer even when `phpstan.neon' is not found." + "If T, activate config from composer even when `phpstan.neon' is not found." :type 'boolean :group 'phpstan) (defcustom phpstan-memory-limit nil "Set --memory-limit option." - :type '(choice (string :tag "Specifies the memory limit in the same format php.ini accepts.") + :type '(choice (string :tag "A memory limit number in php.ini format.") (const :tag "Not set --memory-limit option" nil)) + :link '(url-link :tag "PHP Manual" + "https://www.php.net/manual/ini.core.php#ini.memory-limit") :safe (lambda (v) (or (null v) (stringp v))) :group 'phpstan) @@ -94,7 +96,7 @@ :type '(choice (string :tag "URL or image name of Docker Hub.") (const :tag "Official Docker container" "ghcr.io/phpstan/phpstan") - (const :tag "No specify Docker image")) + (const :tag "No specify Docker image" nil)) :link '(url-link :tag "PHPStan Documentation" "https://phpstan.org/user-guide/docker") :link '(url-link :tag "GitHub Container Registry" "https://github.com/orgs/phpstan/packages/container/package/phpstan") @@ -103,9 +105,10 @@ (defcustom phpstan-use-xdebug-option nil "Set --xdebug option." - :type '(choice (const :tag "Set --xdebug option dynamically" 'auto) + :type '(choice (const :tag "Set --xdebug option dynamically" auto) (const :tag "Add --xdebug option" t) (const :tag "No --xdebug option" nil)) + :safe #'symbolp :group 'phpstan) (defcustom phpstan-generate-baseline-options '("--generate-baseline" "--allow-empty-baseline") @@ -180,7 +183,8 @@ STRING Relative path to `phpstan' configuration file from project root directory. NIL - If `phpstan-enable-on-no-config-file', search \"vendor/autoload.php\" in (phpstan-get-working-dir).") + If `phpstan-enable-on-no-config-file', search \"vendor/autoload.php\" + in (phpstan-get-working-dir).") (put 'phpstan-autoload-file 'safe-local-variable #'(lambda (v) (if (consp v) (and (eq 'root (car v)) (stringp (cdr v))) From 85d41cbc96ab4c2430c610f64156de6049807265 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Mon, 17 Apr 2023 20:38:38 +0900 Subject: [PATCH 29/71] Add config option --- phpstan.el | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/phpstan.el b/phpstan.el index 027049c..af065eb 100644 --- a/phpstan.el +++ b/phpstan.el @@ -421,10 +421,10 @@ it returns the value of `SOURCE' as it is." ((executable-find "phpstan") (list (executable-find "phpstan"))) (t (error "PHPStan executable not found"))))))) -(cl-defun phpstan-get-command-args (&key include-executable use-pro args format options) +(cl-defun phpstan-get-command-args (&key include-executable use-pro args format options config) "Return command line argument for PHPStan." (let ((executable-and-args (phpstan-get-executable-and-args)) - (path (phpstan-normalize-path (phpstan-get-config-file))) + (config (or config (phpstan-normalize-path (phpstan-get-config-file)))) (autoload (phpstan-get-autoload-file)) (memory-limit (phpstan-get-memory-limit)) (level (phpstan-get-level))) @@ -434,7 +434,7 @@ it returns the value of `SOURCE' as it is." (format "--error-format=%s" (or format "raw")) "--no-progress" "--no-interaction") (and use-pro (list "--pro" "--no-ansi")) - (and path (list "-c" path)) + (and config (list "-c" config)) (and autoload (list "-a" autoload)) (and memory-limit (list "--memory-limit" memory-limit)) (and level (list "-l" level)) From 2dc25cb2f3d83484ea0eb063c9ffca8148828a2b Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Mon, 17 Apr 2023 20:42:20 +0900 Subject: [PATCH 30/71] Bump version 0.7.2 --- Cask | 2 +- flycheck-phpstan.el | 6 +++--- flymake-phpstan.el | 6 +++--- phpstan.el | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cask b/Cask index a9d68f8..3768fee 100644 --- a/Cask +++ b/Cask @@ -1,4 +1,4 @@ -(package "phpstan" "0.7.0" "Interface to PHPStan (PHP static analyzer)") +(package "phpstan" "0.7.2" "Interface to PHPStan (PHP static analyzer)") (source melpa) (source gnu) diff --git a/flycheck-phpstan.el b/flycheck-phpstan.el index 09e3ce3..9014baf 100644 --- a/flycheck-phpstan.el +++ b/flycheck-phpstan.el @@ -1,13 +1,13 @@ ;;; flycheck-phpstan.el --- Flycheck integration for PHPStan -*- lexical-binding: t; -*- -;; Copyright (C) 2021 Friends of Emacs-PHP development +;; Copyright (C) 2023 Friends of Emacs-PHP development ;; Author: USAMI Kenta ;; Created: 15 Mar 2018 -;; Version: 0.6.0 +;; Version: 0.7.2 ;; Keywords: tools, php ;; Homepage: https://github.com/emacs-php/phpstan.el -;; Package-Requires: ((emacs "24.3") (flycheck "26") (phpstan "0.5.0")) +;; Package-Requires: ((emacs "24.3") (flycheck "26") (phpstan "0.7.2")) ;; License: GPL-3.0-or-later ;; This program is free software; you can redistribute it and/or modify diff --git a/flymake-phpstan.el b/flymake-phpstan.el index 63a3979..f3f6a15 100644 --- a/flymake-phpstan.el +++ b/flymake-phpstan.el @@ -1,13 +1,13 @@ ;;; flymake-phpstan.el --- Flymake backend for PHP using PHPStan -*- lexical-binding: t; -*- -;; Copyright (C) 2021 Friends of Emacs-PHP development +;; Copyright (C) 2023 Friends of Emacs-PHP development ;; Author: USAMI Kenta ;; Created: 31 Mar 2020 -;; Version: 0.6.0 +;; Version: 0.7.2 ;; Keywords: tools, php ;; Homepage: https://github.com/emacs-php/phpstan.el -;; Package-Requires: ((emacs "26.1") (phpstan "0.5.0")) +;; Package-Requires: ((emacs "26.1") (phpstan "0.7.2")) ;; License: GPL-3.0-or-later ;; This program is free software; you can redistribute it and/or modify diff --git a/phpstan.el b/phpstan.el index af065eb..bea7c27 100644 --- a/phpstan.el +++ b/phpstan.el @@ -4,7 +4,7 @@ ;; Author: USAMI Kenta ;; Created: 15 Mar 2018 -;; Version: 0.7.0 +;; Version: 0.7.2 ;; Keywords: tools, php ;; Homepage: https://github.com/emacs-php/phpstan.el ;; Package-Requires: ((emacs "24.3") (compat "29") (php-mode "1.22.3") (php-runtime "0.2")) From d73741f6e417f821725646641001dc20a0b14bde Mon Sep 17 00:00:00 2001 From: JenChieh Date: Tue, 12 Sep 2023 22:43:53 -0700 Subject: [PATCH 31/71] test: Build with Eask --- .github/workflows/test.yml | 45 ++++++++++++++++++++++++-------------- .gitignore | 2 ++ Eask | 19 ++++++++++++++++ Makefile | 34 +++++++--------------------- 4 files changed, 58 insertions(+), 42 deletions(-) create mode 100644 Eask diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7d3148d..431ee06 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,38 +4,51 @@ on: push: paths-ignore: - '**/*.md' + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: build: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} + continue-on-error: ${{ matrix.experimental }} strategy: + fail-fast: false matrix: - emacs_version: - - "26.3" - - "27.1" - - snapshot + os: [ubuntu-latest, macos-latest, windows-latest] + emacs-version: + - 26.3 + - 27.2 + - 28.2 + - 29.1 + experimental: [false] include: - - emacs_version: snapshot - allow_failure: true + - os: ubuntu-latest + emacs-version: snapshot + experimental: true + - os: macos-latest + emacs-version: snapshot + experimental: true + - os: windows-latest + emacs-version: snapshot + experimental: true steps: - uses: actions/setup-python@v2 with: python-version: '3.x' architecture: 'x64' - - uses: purcell/setup-emacs@master + - uses: jcs090218/setup-emacs@master with: - version: ${{ matrix.emacs_version }} + version: ${{ matrix.emacs-version }} - - uses: conao3/setup-cask@master + - uses: emacs-eask/setup-eask@master with: version: 'snapshot' - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Run make - uses: nick-invision/retry@v2 - with: - timeout_seconds: 90 - max_attempts: 3 - command: 'cask && make' + run: 'make all' diff --git a/.gitignore b/.gitignore index e9d3537..ec6fd1d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ *.elc /*-autoloads.el /.cask +/.eask +/dist /composer.lock /vendor diff --git a/Eask b/Eask new file mode 100644 index 0000000..85f33e6 --- /dev/null +++ b/Eask @@ -0,0 +1,19 @@ +(package "phpstan" + "0.7.2" + "Interface to PHPStan (PHP static analyzer)") + +(website-url "https://github.com/emacs-php/phpstan.el") +(keywords "tools" "php") + +(package-file "phpstan.el") +(files "*.el") + +(script "test" "echo \"Error: no test specified\" && exit 1") + +(source 'gnu) +(source 'melpa) + +(depends-on "emacs" "24.3") +(depends-on "compat") +(depends-on "php-mode") +(depends-on "php-runtime") diff --git a/Makefile b/Makefile index 40be38e..d902c98 100644 --- a/Makefile +++ b/Makefile @@ -1,34 +1,16 @@ EMACS ?= emacs CASK ?= cask -ELS = phpstan.el flycheck-phpstan.el flymake-phpstan.el -AUTOLOADS = phpstan-autoloads.el -ELCS = $(ELS:.el=.elc) +EASK ?= eask -.el.elc: .cask - $(EMACS) -Q -batch -L . --eval \ - "(let ((default-directory (expand-file-name \".cask\" default-directory))) \ - (require 'package) \ - (normal-top-level-add-subdirs-to-load-path))" \ - -f package-initialize -f batch-byte-compile $< +compile: + $(EASK) compile -.cask: Cask - $(CASK) +all: clean autoloads compile -all: clean autoloads $(ELCS) - -autoloads: $(AUTOLOADS) - -$(AUTOLOADS): $(ELCS) - $(EMACS) -Q -batch -L . --eval \ - "(progn \ - (require 'package) \ - (normal-top-level-add-subdirs-to-load-path) \ - (package-generate-autoloads \"phpstan\" default-directory))" +autoloads: + $(EASK) generate autoloads clean: - -rm -f $(ELCS) $(AUTOLOADS) - -clobber: clean - -rm -f .cask + $(EASK) clean all -.PHONY: all autoloads clean clobber +.PHONY: all autoloads clean From 4860741f5711ec57780e3e86bf1c702498ddb5f2 Mon Sep 17 00:00:00 2001 From: JenChieh Date: Tue, 12 Sep 2023 22:44:51 -0700 Subject: [PATCH 32/71] Enable test for lower than 27.x --- Eask | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Eask b/Eask index 85f33e6..1fa4927 100644 --- a/Eask +++ b/Eask @@ -17,3 +17,5 @@ (depends-on "compat") (depends-on "php-mode") (depends-on "php-runtime") + +(setq network-security-level 'low) ; see https://github.com/jcs090218/setup-emacs-windows/issues/156#issuecomment-932956432 From d35259c5871f4b9d67fdecec535e2bf4e4f68789 Mon Sep 17 00:00:00 2001 From: JenChieh Date: Tue, 12 Sep 2023 22:49:41 -0700 Subject: [PATCH 33/71] fix install --- Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d902c98..2d60e8a 100644 --- a/Makefile +++ b/Makefile @@ -2,10 +2,14 @@ EMACS ?= emacs CASK ?= cask EASK ?= eask +install: + $(EASK) package + $(EASK) install + compile: $(EASK) compile -all: clean autoloads compile +all: clean autoloads install compile autoloads: $(EASK) generate autoloads From 085e1a1705c966384f2005dd235822e89f5bfd7f Mon Sep 17 00:00:00 2001 From: JenChieh Date: Tue, 12 Sep 2023 22:51:46 -0700 Subject: [PATCH 34/71] test flycheck --- Eask | 1 + Makefile | 1 + 2 files changed, 2 insertions(+) diff --git a/Eask b/Eask index 1fa4927..e9f7321 100644 --- a/Eask +++ b/Eask @@ -17,5 +17,6 @@ (depends-on "compat") (depends-on "php-mode") (depends-on "php-runtime") +(depends-on "flycheck") (setq network-security-level 'low) ; see https://github.com/jcs090218/setup-emacs-windows/issues/156#issuecomment-932956432 diff --git a/Makefile b/Makefile index 2d60e8a..a5e34cc 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,7 @@ EASK ?= eask install: $(EASK) package $(EASK) install + $(EASK) install-deps compile: $(EASK) compile From 1f4f78a7b2894e98d361454bbb697b6476e6d9df Mon Sep 17 00:00:00 2001 From: Herbert Jones Date: Fri, 13 Oct 2023 11:55:02 -0500 Subject: [PATCH 35/71] Update flymake for command arg changes --- flymake-phpstan.el | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/flymake-phpstan.el b/flymake-phpstan.el index f3f6a15..d1dc8ee 100644 --- a/flymake-phpstan.el +++ b/flymake-phpstan.el @@ -90,15 +90,19 @@ (defun flymake-phpstan (report-fn &rest _ignored-args) "Flymake backend for PHPStan report using REPORT-FN." - (let ((command-args (phpstan-get-command-args t))) + (let ((command-args (phpstan-get-command-args :include-executable t))) (unless (car command-args) (user-error "Cannot find a phpstan executable command")) (when (process-live-p flymake-phpstan--proc) (kill-process flymake-phpstan--proc)) - (let ((source (current-buffer))) + (let ((source (current-buffer)) + (target-path (if (or (buffer-modified-p) (not buffer-file-name)) + (phpstan-normalize-path + (flycheck-save-buffer-to-temp #'flycheck-temp-file-inplace)) + buffer-file-name))) (save-restriction (widen) - (setq flymake-phpstan--proc (flymake-phpstan-make-process (php-project-get-root-dir) command-args report-fn source)) + (setq flymake-phpstan--proc (flymake-phpstan-make-process (php-project-get-root-dir) (append command-args (list "--" target-path)) report-fn source)) (process-send-region flymake-phpstan--proc (point-min) (point-max)) (process-send-eof flymake-phpstan--proc))))) From ef092a226df16f8b15faeff6756f6029a503f588 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Tue, 14 Nov 2023 20:18:44 +0900 Subject: [PATCH 36/71] Update CHANGELOG --- CHANGELOG.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6ec178..4657c48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,17 +1,21 @@ # Changelog -All notable changes of the phpactor.el are documented in this file using the [Keep a Changelog](https://keepachangelog.com/) principles. +All notable changes of the `phpstan.el` are documented in this file using the [Keep a Changelog](https://keepachangelog.com/) principles. -## Unreleased +## [0.7.0] ### Added * Add `phpstan-analyze-this-file` command * Add `phpstan.dist.neon` to `phpstan-get-config-file` as PHPStan config files. * Add `phpstan-pro` command to launch [PHPStan Pro]. +* Add `phpstan-find-baseline-file` command. +* Add `phpstan-generate-baseline-file` command. [PHPStan Pro]: https://phpstan.org/blog/introducing-phpstan-pro ### Changed * Make flycheck analyze the original file directly instead of temporary files when there are no changes to the file. +* [Internal] Use JSON format for flycheck-phpstan. + * Support **💡 tips** From 1c2b885f92f436775590a5f37cce50906ed2c898 Mon Sep 17 00:00:00 2001 From: Norio Suzuki Date: Mon, 11 Dec 2023 08:27:47 +0900 Subject: [PATCH 37/71] Change configs of phpstan for supporting new `bootstrapFiles` keyword --- tests/phpstan-docker.neon | 3 ++- tests/phpstan.neon | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/phpstan-docker.neon b/tests/phpstan-docker.neon index 356d55c..ff593e8 100644 --- a/tests/phpstan-docker.neon +++ b/tests/phpstan-docker.neon @@ -1,2 +1,3 @@ parameters: - bootstrap: %currentWorkingDirectory%/../app/tests/bootstrap.php + bootstrapFiles: + - %currentWorkingDirectory%/../app/tests/bootstrap.php diff --git a/tests/phpstan.neon b/tests/phpstan.neon index 2b4b28c..53c205f 100644 --- a/tests/phpstan.neon +++ b/tests/phpstan.neon @@ -1,2 +1,3 @@ parameters: - bootstrap: %rootDir%/../../../tests/bootstrap.php + bootstrapFiles: + - %rootDir%/../../../tests/bootstrap.php From 45f158ccbd81159c51acdfd50deedf75c3b619af Mon Sep 17 00:00:00 2001 From: Norio Suzuki Date: Wed, 13 Dec 2023 08:09:17 +0900 Subject: [PATCH 38/71] Fix a target path for docker execution --- phpstan.el | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/phpstan.el b/phpstan.el index bea7c27..7da2c33 100644 --- a/phpstan.el +++ b/phpstan.el @@ -338,15 +338,17 @@ it returns the value of `SOURCE' as it is." (defun phpstan-analyze-this-file () "Analyze current buffer-file using PHPStan." (interactive) - (let ((file (expand-file-name (or buffer-file-name - (read-file-name "Choose a PHP script: "))))) + (let ((file (phpstan-normalize-path + (expand-file-name (or buffer-file-name + (read-file-name "Choose a PHP script: ")))))) (compile (mapconcat #'shell-quote-argument (phpstan-get-command-args :include-executable t :args (list file)) " ")))) ;;;###autoload (defun phpstan-analyze-file (file) "Analyze a PHP script FILE using PHPStan." - (interactive (list (expand-file-name (read-file-name "Choose a PHP script: ")))) + (interactive (list (phpstan-normalize-path + (expand-file-name (read-file-name "Choose a PHP script: "))))) (compile (mapconcat #'shell-quote-argument (phpstan-get-command-args :include-executable t :args (list file)) " "))) From 753b67669a8dff98f175270b7da3f0bab0ca3fea Mon Sep 17 00:00:00 2001 From: Jen-Chieh Shen Date: Mon, 22 Jan 2024 03:16:28 -0800 Subject: [PATCH 39/71] chore: Test 29.2 --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 431ee06..0f548ff 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,7 +22,7 @@ jobs: - 26.3 - 27.2 - 28.2 - - 29.1 + - 29.2 experimental: [false] include: - os: ubuntu-latest From 084c5cf159df6ac7743e33c00f7ac02fd6bd104b Mon Sep 17 00:00:00 2001 From: Jen-Chieh Shen Date: Wed, 27 Mar 2024 00:14:30 -0700 Subject: [PATCH 40/71] ci: Bump Emacs 29.x to 3 --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0f548ff..47e7acd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,7 +22,7 @@ jobs: - 26.3 - 27.2 - 28.2 - - 29.2 + - 29.3 experimental: [false] include: - os: ubuntu-latest From eb828492d05577df8ddf1af042a6b3fa7bd4b9ed Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Tue, 14 Nov 2023 22:32:28 +0900 Subject: [PATCH 41/71] Experimental support TRAMP --- CHANGELOG.md | 6 ++++++ phpstan.el | 47 ++++++++++++++++++++++++++++++++--------------- 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4657c48..922f0e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes of the `phpstan.el` are documented in this file using the [Keep a Changelog](https://keepachangelog.com/) principles. +## Unreleased + +### Added + +* Add `phpstan-enable-remote-experimental` custom variable for activate PHPStan on TRAMP. + ## [0.7.0] ### Added diff --git a/phpstan.el b/phpstan.el index 7da2c33..0e42ef7 100644 --- a/phpstan.el +++ b/phpstan.el @@ -129,6 +129,16 @@ :safe #'stringp :group 'phpstan) +(defcustom phpstan-enable-remote-experimental nil + "Enable PHPStan analysis remotely by TRAMP. + +When non-nil, PHPStan will be executed on a remote server for code analysis. +This feature is experimental and should be used with caution as it may +have unexpected behaviors or performance implications." + :type 'boolean + :safe #'booleanp + :group 'phpstan) + (defvar-local phpstan--use-xdebug-option nil) ;;;###autoload @@ -257,11 +267,12 @@ NIL (defun phpstan-enabled () "Return non-NIL if PHPStan configured or Composer detected." - (and (not (file-remote-p default-directory)) ;; Not support remote filesystem - (or (phpstan-get-config-file) - (phpstan-get-autoload-file) - (and phpstan-enable-on-no-config-file - (php-project-get-root-dir))))) + (unless (and (not phpstan-enable-remote-experimental) + (file-remote-p default-directory)) ;; Not support remote filesystem by default + (or (phpstan-get-config-file) + (phpstan-get-autoload-file) + (and phpstan-enable-on-no-config-file + (php-project-get-root-dir))))) (defun phpstan-get-config-file () "Return path to phpstan configure file or NIL." @@ -334,21 +345,26 @@ it returns the value of `SOURCE' as it is." (let ((json-object-type 'plist) (json-array-type 'list)) (json-read-object))))) +(defun phpstan--expand-file-name (name) + "Expand file name by NAME." + (let ((file (expand-file-name name))) + (if (file-remote-p name) + (tramp-file-name-localname (tramp-dissect-file-name name)) + (expand-file-name file)))) + ;;;###autoload (defun phpstan-analyze-this-file () "Analyze current buffer-file using PHPStan." (interactive) - (let ((file (phpstan-normalize-path - (expand-file-name (or buffer-file-name - (read-file-name "Choose a PHP script: ")))))) + (let ((file (phpstan--expand-file-name (or buffer-file-name + (read-file-name "Choose a PHP script: "))))) (compile (mapconcat #'shell-quote-argument (phpstan-get-command-args :include-executable t :args (list file)) " ")))) ;;;###autoload (defun phpstan-analyze-file (file) "Analyze a PHP script FILE using PHPStan." - (interactive (list (phpstan-normalize-path - (expand-file-name (read-file-name "Choose a PHP script: "))))) + (interactive (list (phpstan--expand-file-name (read-file-name "Choose a PHP script: ")))) (compile (mapconcat #'shell-quote-argument (phpstan-get-command-args :include-executable t :args (list file)) " "))) @@ -413,13 +429,14 @@ it returns the value of `SOURCE' as it is." (listp (cdr phpstan-executable))) (cdr phpstan-executable)) ((null phpstan-executable) - (let ((vendor-phpstan (expand-file-name "vendor/bin/phpstan" - (php-project-get-root-dir)))) + (let* ((vendor-phpstan (expand-file-name "vendor/bin/phpstan" + (php-project-get-root-dir))) + (expanded-vendor-phpstan (phpstan--expand-file-name vendor-phpstan))) (cond ((file-exists-p vendor-phpstan) (if (file-executable-p vendor-phpstan) - (list vendor-phpstan) - (list php-executable vendor-phpstan))) + (list expanded-vendor-phpstan) + (list php-executable expanded-vendor-phpstan))) ((executable-find "phpstan") (list (executable-find "phpstan"))) (t (error "PHPStan executable not found"))))))) @@ -436,7 +453,7 @@ it returns the value of `SOURCE' as it is." (format "--error-format=%s" (or format "raw")) "--no-progress" "--no-interaction") (and use-pro (list "--pro" "--no-ansi")) - (and config (list "-c" config)) + (and config (list "-c" (phpstan--expand-file-name config))) (and autoload (list "-a" autoload)) (and memory-limit (list "--memory-limit" memory-limit)) (and level (list "-l" level)) From 44924b669a8c18aa243a9ae53823f66540795a8b Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Tue, 28 May 2024 05:57:35 +0900 Subject: [PATCH 42/71] Add support for php-ts-mode --- CHANGELOG.md | 1 + flycheck-phpstan.el | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 922f0e9..723c7e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ All notable changes of the `phpstan.el` are documented in this file using the [K ### Added * Add `phpstan-enable-remote-experimental` custom variable for activate PHPStan on TRAMP. +* Add support for `php-ts-mode`. ## [0.7.0] diff --git a/flycheck-phpstan.el b/flycheck-phpstan.el index 9014baf..707112a 100644 --- a/flycheck-phpstan.el +++ b/flycheck-phpstan.el @@ -103,7 +103,7 @@ :working-directory (lambda (_) (phpstan-get-working-dir)) :enabled (lambda () (flycheck-phpstan--enabled-and-set-variable)) :error-parser flycheck-phpstan-parse-output - :modes (php-mode phps-mode)) + :modes (php-mode php-ts-mode phps-mode)) (add-to-list 'flycheck-checkers 'phpstan t) (flycheck-add-next-checker 'php 'phpstan) From daa30e390198f37710be7d5d3793623471607790 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Tue, 28 May 2024 06:02:09 +0900 Subject: [PATCH 43/71] Add verbose option to phpstan-get-command-args --- phpstan.el | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/phpstan.el b/phpstan.el index 0e42ef7..c384faa 100644 --- a/phpstan.el +++ b/phpstan.el @@ -359,14 +359,14 @@ it returns the value of `SOURCE' as it is." (let ((file (phpstan--expand-file-name (or buffer-file-name (read-file-name "Choose a PHP script: "))))) (compile (mapconcat #'shell-quote-argument - (phpstan-get-command-args :include-executable t :args (list file)) " ")))) + (phpstan-get-command-args :include-executable t :args (list file) :verbose 1) " ")))) ;;;###autoload (defun phpstan-analyze-file (file) "Analyze a PHP script FILE using PHPStan." (interactive (list (phpstan--expand-file-name (read-file-name "Choose a PHP script: ")))) (compile (mapconcat #'shell-quote-argument - (phpstan-get-command-args :include-executable t :args (list file)) " "))) + (phpstan-get-command-args :include-executable t :args (list file) :verbose 1) " "))) ;;;###autoload (defun phpstan-analyze-project () @@ -440,7 +440,7 @@ it returns the value of `SOURCE' as it is." ((executable-find "phpstan") (list (executable-find "phpstan"))) (t (error "PHPStan executable not found"))))))) -(cl-defun phpstan-get-command-args (&key include-executable use-pro args format options config) +(cl-defun phpstan-get-command-args (&key include-executable use-pro args format options config verbose) "Return command line argument for PHPStan." (let ((executable-and-args (phpstan-get-executable-and-args)) (config (or config (phpstan-normalize-path (phpstan-get-config-file)))) @@ -457,6 +457,12 @@ it returns the value of `SOURCE' as it is." (and autoload (list "-a" autoload)) (and memory-limit (list "--memory-limit" memory-limit)) (and level (list "-l" level)) + (cond + ((null verbose) nil) + ((memq verbose '(1 t)) (list "-v")) + ((eq verbose 2) (list "-vv")) + ((eq verbose 3) (list "-vvv")) + (error ":verbose option should be 1, 2, 3 or `t'")) (cond (phpstan--use-xdebug-option (list phpstan--use-xdebug-option)) ((eq phpstan-use-xdebug-option 'auto) From 3c489cfd73f126d3e7327afdd35209dca918768a Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Tue, 28 May 2024 06:28:42 +0900 Subject: [PATCH 44/71] Add support error identifier to flycheck-phpstan.el --- flycheck-phpstan.el | 33 ++++++++++++++++++++++++++++----- phpstan.el | 6 ++++++ 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/flycheck-phpstan.el b/flycheck-phpstan.el index 707112a..82f62f4 100644 --- a/flycheck-phpstan.el +++ b/flycheck-phpstan.el @@ -45,6 +45,19 @@ (defvar flycheck-phpstan-executable) (defvar flycheck-phpstan--temp-buffer-name "*Flycheck PHPStan*") + +(defcustom flycheck-phpstan-ignore-metadata-list nil + "Set of metadata items to ignore in PHPStan messages for Flycheck." + :type '(set (const identifier) + (const tip)) + :group 'phpstan) + +(defcustom flycheck-phpstan-metadata-separator "\n" + "Separator of PHPStan message and metadata." + :type 'string + :safe #'stringp + :group 'phpstan) + (defun flycheck-phpstan--enabled-and-set-variable () "Return path to phpstan configure file, and set buffer execute in side effect." (let ((enabled (phpstan-enabled))) @@ -77,11 +90,21 @@ (let ((data (phpstan--parse-json json-buffer))) (cl-loop for (file . entry) in (flycheck-phpstan--plist-to-alist (plist-get data :files)) append (cl-loop for messages in (plist-get entry :messages) - for text = (let ((msg (plist-get messages :message)) - (tip (plist-get messages :tip))) - (if tip - (concat msg "\n" phpstan-tip-message-prefix tip) - msg)) + for text = (let* ((msg (plist-get messages :message)) + (ignorable (plist-get messages :ignorable)) + (identifier (unless (memq 'identifier flycheck-phpstan-ignore-metadata-list) + (plist-get messages :identifier))) + (tip (unless (memq 'tip flycheck-phpstan-ignore-metadata-list) + (plist-get messages :tip))) + (lines (list (when (and identifier ignorable) + (concat phpstan-identifier-prefix identifier)) + (when tip + (concat phpstan-tip-message-prefix tip)))) + (lines (cl-remove-if #'null lines))) + (if (null lines) + msg + (concat msg flycheck-phpstan-metadata-separator + (mapconcat #'identity lines "\n")))) collect (flycheck-error-new-at (plist-get messages :line) nil 'error text :filename file))))) diff --git a/phpstan.el b/phpstan.el index c384faa..a66a7c6 100644 --- a/phpstan.el +++ b/phpstan.el @@ -129,6 +129,12 @@ :safe #'stringp :group 'phpstan) +(defcustom phpstan-identifier-prefix "🪪 " + "Prefix of PHPStan error identifier." + :type 'string + :safe #'stringp + :group 'phpstan) + (defcustom phpstan-enable-remote-experimental nil "Enable PHPStan analysis remotely by TRAMP. From 83bae2c66a254f64a461a079bb962177dc2e9972 Mon Sep 17 00:00:00 2001 From: Jen-Chieh Shen Date: Mon, 22 Jul 2024 16:44:09 -0700 Subject: [PATCH 45/71] ci: Bump Emacs 29.x to 4 --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 47e7acd..4a34880 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,7 +22,7 @@ jobs: - 26.3 - 27.2 - 28.2 - - 29.3 + - 29.4 experimental: [false] include: - os: ubuntu-latest From 9323e06fa60152f581e7be789a872c39f1a94aff Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Tue, 29 Oct 2024 00:06:16 +0900 Subject: [PATCH 46/71] Add phpstan-insert-dumptype command --- README.org | 11 +++++++++++ phpstan.el | 28 ++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/README.org b/README.org index 818f4a9..7f50783 100644 --- a/README.org +++ b/README.org @@ -88,6 +88,17 @@ Typically, you would set the following ~.dir-locals.el~. #+END_SRC If there is a ~phpstan.neon~ file in the root directory of the project, you do not need to set both ~phpstan-working-dir~ and ~phpstan-config-file~. +** Commands +This package provides convenient commands for using PHPStan from Emacs. +*** Command ~phpstan-insert-dumptype~ +Add ~\PHPStan\dumpType(...);~ to your PHP code and analyze it to make PHPStan display the type of the expression. +#+BEGIN_SRC +(define-key php-mode-map (kbd "C-c ^") #'phpstan-insert-dumptype) +#+END_SRC + +By default, if you press ~C-u~ before invoking the command, ~\PHPStan\dumpPhpDocType()~ will be inserted. + +This feature was added in *PHPStan 1.12.7* and will dump types compatible with the ~@param~ and ~@return~ PHPDoc tags. ** API Most variables defined in this package are buffer local. If you want to set it for multiple projects, use [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Default-Value.html][setq-default]]. diff --git a/phpstan.el b/phpstan.el index a66a7c6..464d533 100644 --- a/phpstan.el +++ b/phpstan.el @@ -145,6 +145,15 @@ have unexpected behaviors or performance implications." :safe #'booleanp :group 'phpstan) +(defconst phpstan-template-dump-type "\\PHPStan\\dumpType();") +(defconst phpstan-template-dump-phpdoc-type "\\PHPStan\\dumpPhpDocType();") + +(defcustom phpstan-intert-dump-type-templates (cons phpstan-template-dump-type + phpstan-template-dump-phpdoc-type) + "Default template of PHPStan dumpType insertion." + :type '(cons string string) + :group 'phpstan) + (defvar-local phpstan--use-xdebug-option nil) ;;;###autoload @@ -480,5 +489,24 @@ it returns the value of `SOURCE' as it is." options (and args (cons "--" args))))) +;;;###autoload +(defun phpstan-insert-dumptype (&optional expression prefix-num) + "Insert PHPStan\\dumpType() expression-statement by EXPRESSION and PREFIX-NUM." + (interactive + (list + (if (region-active-p) + (buffer-substring-no-properties (region-beginning) (region-end)) + (or (thing-at-point 'symbol t) "")) + current-prefix-arg)) + (let ((template (if current-prefix-arg + (cdr phpstan-intert-dump-type-templates) + (car phpstan-intert-dump-type-templates)))) + (move-end-of-line 1) + (newline-and-indent) + (insert template) + (search-backward "(" (line-beginning-position) t) + (forward-char) + (insert expression))) + (provide 'phpstan) ;;; phpstan.el ends here From ea44313f65a030cc462746066df247647db9a3ef Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Wed, 30 Oct 2024 06:03:55 +0900 Subject: [PATCH 47/71] Fix --- phpstan.el | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/phpstan.el b/phpstan.el index 464d533..c0c44c2 100644 --- a/phpstan.el +++ b/phpstan.el @@ -477,7 +477,7 @@ it returns the value of `SOURCE' as it is." ((memq verbose '(1 t)) (list "-v")) ((eq verbose 2) (list "-vv")) ((eq verbose 3) (list "-vvv")) - (error ":verbose option should be 1, 2, 3 or `t'")) + ((error ":verbose option should be 1, 2, 3 or `t'"))) (cond (phpstan--use-xdebug-option (list phpstan--use-xdebug-option)) ((eq phpstan-use-xdebug-option 'auto) @@ -498,10 +498,10 @@ it returns the value of `SOURCE' as it is." (buffer-substring-no-properties (region-beginning) (region-end)) (or (thing-at-point 'symbol t) "")) current-prefix-arg)) - (let ((template (if current-prefix-arg + (let ((template (if prefix-num (cdr phpstan-intert-dump-type-templates) (car phpstan-intert-dump-type-templates)))) - (move-end-of-line 1) + (end-of-line) (newline-and-indent) (insert template) (search-backward "(" (line-beginning-position) t) From 0ca229899f7bd29b57a8d18c5cb50e9ad5519ef7 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Tue, 29 Oct 2024 00:50:10 +0900 Subject: [PATCH 48/71] Refactor flycheck-phpstan-parse-json --- flycheck-phpstan.el | 64 ++++++++++++++++++++------------------------- phpstan.el | 8 ++++++ 2 files changed, 37 insertions(+), 35 deletions(-) diff --git a/flycheck-phpstan.el b/flycheck-phpstan.el index 82f62f4..0d20ef8 100644 --- a/flycheck-phpstan.el +++ b/flycheck-phpstan.el @@ -45,7 +45,6 @@ (defvar flycheck-phpstan-executable) (defvar flycheck-phpstan--temp-buffer-name "*Flycheck PHPStan*") - (defcustom flycheck-phpstan-ignore-metadata-list nil "Set of metadata items to ignore in PHPStan messages for Flycheck." :type '(set (const identifier) @@ -76,45 +75,40 @@ (defun flycheck-phpstan-parse-output (output &optional _checker _buffer) "Parse PHPStan errors from OUTPUT." - (with-current-buffer (flycheck-phpstan--temp-buffer) - (erase-buffer) - (insert output)) - (flycheck-phpstan-parse-json (flycheck-phpstan--temp-buffer))) + (let* ((json-buffer (with-current-buffer (flycheck-phpstan--temp-buffer) + (erase-buffer) + (insert output) + (current-buffer))) + (data (phpstan--parse-json json-buffer)) + (errors (phpstan--plist-to-alist (plist-get data :files)))) + (flycheck-phpstan--build-errors errors))) (defun flycheck-phpstan--temp-buffer () "Return a temporary buffer for decode JSON." (get-buffer-create flycheck-phpstan--temp-buffer-name)) -(defun flycheck-phpstan-parse-json (json-buffer) - "Parse PHPStan errors from JSON-BUFFER." - (let ((data (phpstan--parse-json json-buffer))) - (cl-loop for (file . entry) in (flycheck-phpstan--plist-to-alist (plist-get data :files)) - append (cl-loop for messages in (plist-get entry :messages) - for text = (let* ((msg (plist-get messages :message)) - (ignorable (plist-get messages :ignorable)) - (identifier (unless (memq 'identifier flycheck-phpstan-ignore-metadata-list) - (plist-get messages :identifier))) - (tip (unless (memq 'tip flycheck-phpstan-ignore-metadata-list) - (plist-get messages :tip))) - (lines (list (when (and identifier ignorable) - (concat phpstan-identifier-prefix identifier)) - (when tip - (concat phpstan-tip-message-prefix tip)))) - (lines (cl-remove-if #'null lines))) - (if (null lines) - msg - (concat msg flycheck-phpstan-metadata-separator - (mapconcat #'identity lines "\n")))) - collect (flycheck-error-new-at (plist-get messages :line) - nil 'error text - :filename file))))) - -(defun flycheck-phpstan--plist-to-alist (plist) - "Convert PLIST to association list." - (let (alist) - (while plist - (push (cons (substring-no-properties (symbol-name (pop plist)) 1) (pop plist)) alist)) - (nreverse alist))) +(defun flycheck-phpstan--build-errors (errors) + "Build Flycheck errors from PHPStan ERRORS." + (cl-loop for (file . entry) in errors + append (cl-loop for messages in (plist-get entry :messages) + for text = (let* ((msg (plist-get messages :message)) + (ignorable (plist-get messages :ignorable)) + (identifier (unless (memq 'identifier flycheck-phpstan-ignore-metadata-list) + (plist-get messages :identifier))) + (tip (unless (memq 'tip flycheck-phpstan-ignore-metadata-list) + (plist-get messages :tip))) + (lines (list (when (and identifier ignorable) + (concat phpstan-identifier-prefix identifier)) + (when tip + (concat phpstan-tip-message-prefix tip)))) + (lines (cl-remove-if #'null lines))) + (if (null lines) + msg + (concat msg flycheck-phpstan-metadata-separator + (mapconcat #'identity lines "\n")))) + collect (flycheck-error-new-at (plist-get messages :line) + nil 'error text + :filename file)))) (flycheck-define-checker phpstan "PHP static analyzer based on PHPStan." diff --git a/phpstan.el b/phpstan.el index c0c44c2..04bb780 100644 --- a/phpstan.el +++ b/phpstan.el @@ -271,6 +271,14 @@ NIL (and (stringp (car v)) (listp (cdr v)))) (or (eq 'docker v) (null v) (stringp v)))))) +;; Utilities: +(defun phpstan--plist-to-alist (plist) + "Convert PLIST to association list." + (let (alist) + (while plist + (push (cons (substring-no-properties (symbol-name (pop plist)) 1) (pop plist)) alist)) + (nreverse alist))) + ;; Functions: (defun phpstan-get-working-dir () "Return path to working directory of PHPStan." From 5549c108d0c985e07523a68ac3d490ac5e411e83 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Wed, 30 Oct 2024 06:03:31 +0900 Subject: [PATCH 49/71] Add phpstan-insert-ignore command --- README.org | 7 +++- flycheck-phpstan.el | 2 + phpstan.el | 97 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 104 insertions(+), 2 deletions(-) diff --git a/README.org b/README.org index 7f50783..9a6efb1 100644 --- a/README.org +++ b/README.org @@ -5,7 +5,7 @@ #+END_HTML Emacs interface to [[https://github.com/phpstan/phpstan][PHPStan]], includes checker for [[http://www.flycheck.org/en/latest/][Flycheck]]. ** Support version -- Emacs 24+ +- Emacs 25+ - PHPStan latest/dev-master (NOT support 0.9 seriese) - PHP 7.1+ or Docker runtime ** How to install @@ -99,7 +99,12 @@ Add ~\PHPStan\dumpType(...);~ to your PHP code and analyze it to make PHPStan di By default, if you press ~C-u~ before invoking the command, ~\PHPStan\dumpPhpDocType()~ will be inserted. This feature was added in *PHPStan 1.12.7* and will dump types compatible with the ~@param~ and ~@return~ PHPDoc tags. +*** Command ~phpstan-insert-ignore~ +Insert a ~@phpstan-ignore~ tag to suppress any PHPStan errors on the current line. +By default it inserts the tag on the previous line, but if there is already a tag at the end of the current line or on the previous line, the identifiers will be appended there. + +If there is no existing tag and ~C-u~ is pressed before the command, it will be inserted at the end of the line. ** API Most variables defined in this package are buffer local. If you want to set it for multiple projects, use [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Default-Value.html][setq-default]]. diff --git a/flycheck-phpstan.el b/flycheck-phpstan.el index 0d20ef8..49431b8 100644 --- a/flycheck-phpstan.el +++ b/flycheck-phpstan.el @@ -81,6 +81,8 @@ (current-buffer))) (data (phpstan--parse-json json-buffer)) (errors (phpstan--plist-to-alist (plist-get data :files)))) + (unless phpstan-disable-buffer-errors + (phpstan-update-ignorebale-errors-from-json-buffer errors)) (flycheck-phpstan--build-errors errors))) (defun flycheck-phpstan--temp-buffer () diff --git a/phpstan.el b/phpstan.el index 04bb780..c7d6f8f 100644 --- a/phpstan.el +++ b/phpstan.el @@ -7,7 +7,7 @@ ;; Version: 0.7.2 ;; Keywords: tools, php ;; Homepage: https://github.com/emacs-php/phpstan.el -;; Package-Requires: ((emacs "24.3") (compat "29") (php-mode "1.22.3") (php-runtime "0.2")) +;; Package-Requires: ((emacs "25.1") (compat "29") (php-mode "1.22.3") (php-runtime "0.2")) ;; License: GPL-3.0-or-later ;; This program is free software; you can redistribute it and/or modify @@ -56,6 +56,7 @@ (require 'cl-lib) (require 'php-project) (require 'php-runtime) +(require 'seq) (eval-when-compile (require 'compat nil t) @@ -154,8 +155,19 @@ have unexpected behaviors or performance implications." :type '(cons string string) :group 'phpstan) +(defcustom phpstan-disable-buffer-errors nil + "If T, don't keep errors per buffer to save memory." + :type 'boolean + :group 'phpstan) + +(defcustom phpstan-not-ignorable-identifiers '("ignore.parseError") + "A list of identifiers that are prohibited from being added to the @phpstan-ignore tag." + :type '(repeat string)) + (defvar-local phpstan--use-xdebug-option nil) +(defvar-local phpstan--ignorable-errors '()) + ;;;###autoload (progn (defvar phpstan-working-dir nil @@ -278,6 +290,10 @@ NIL (while plist (push (cons (substring-no-properties (symbol-name (pop plist)) 1) (pop plist)) alist)) (nreverse alist))) + +(defsubst phpstan--current-line () + "Return the current buffer line at point. The first line is 1." + (line-number-at-pos nil t)) ;; Functions: (defun phpstan-get-working-dir () @@ -497,6 +513,85 @@ it returns the value of `SOURCE' as it is." options (and args (cons "--" args))))) +(defun phpstan-update-ignorebale-errors-from-json-buffer (errors) + "Update `phpstan--ignorable-errors' variable by ERRORS." + (let ((identifiers + (cl-loop for (_ . entry) in errors + append (cl-loop for message in (plist-get entry :messages) + if (plist-get message :ignorable) + collect (cons (plist-get message :line) + (plist-get message :identifier)))))) + (setq phpstan--ignorable-errors + (mapcar (lambda (v) (cons (car v) (mapcar #'cdr (cdr v)))) (seq-group-by #'car identifiers))))) + +(defconst phpstan--re-ignore-tag + (eval-when-compile + (rx (* (syntax whitespace)) "//" (* (syntax whitespace)) + (group "@phpstan-ignore") + (* (syntax whitespace)) + (* (not "(")) + (group (? (+ (syntax whitespace) "(")))))) + +(cl-defun phpstan--check-existing-ignore-tag (&key in-previous) + "Check existing @phpstan-ignore PHPDoc tag. +If IN-PREVIOUS is NIL, check the previous line for the tag." + (let ((new-position (if in-previous 'previous-line 'this-line)) + (line-end (line-end-position)) + new-point append) + (save-excursion + (save-match-data + (if (re-search-forward phpstan--re-ignore-tag line-end t) + (progn + (setq new-point (match-beginning 2)) + (goto-char new-point) + (when (eq (char-syntax (char-before)) ?\ ) + (left-char) + (setq new-point (point))) + (setq append (not (eq (match-end 1) (match-beginning 2)))) + (cl-values new-position new-point append)) + (if in-previous + (cl-values nil nil nil) + (previous-logical-line) + (beginning-of-line) + (phpstan--check-existing-ignore-tag :in-previous t))))))) + +;;;###autoload +(defun phpstan-insert-ignore (position) + "Insert an @phpstan-ignore comment at the specified POSITION. + +POSITION determines where to insert the comment and can be either `this-line' or +`previous-line'. + +- If POSITION is `this-line', the comment is inserted at the end of + the current line. +- If POSITION is `previous-line', the comment is inserted on a new line above + the current line." + (interactive + (list (if current-prefix-arg 'this-line 'previous-line))) + (save-restriction + (widen) + (let ((pos (point)) + (identifiers (cl-set-difference (alist-get (phpstan--current-line) phpstan--ignorable-errors) phpstan-not-ignorable-identifiers :test #'equal)) + (padding (if (eq position 'this-line) " " "")) + new-position new-point delete-region) + (cl-multiple-value-setq (new-position new-point append) (phpstan--check-existing-ignore-tag :in-previous nil)) + (when new-position + (setq position new-position)) + (unless (and append (null identifiers)) + (if (not new-point) + (cond + ((eq position 'this-line) (end-of-line)) + ((eq position 'previous-line) (progn + (previous-logical-line) + (end-of-line) + (newline-and-indent))) + ((error "Unexpected position: %s" position))) + (setq padding "") + (goto-char new-point)) + (insert (concat padding + (if new-position (if append ", " " ") "// @phpstan-ignore ") + (mapconcat #'identity identifiers ", "))))))) + ;;;###autoload (defun phpstan-insert-dumptype (&optional expression prefix-num) "Insert PHPStan\\dumpType() expression-statement by EXPRESSION and PREFIX-NUM." From 5dbbabd427e97138e9578dc01b5df2a63f367e8f Mon Sep 17 00:00:00 2001 From: Jen-Chieh Shen Date: Wed, 30 Oct 2024 08:59:00 -0700 Subject: [PATCH 50/71] ci: Exclude macos tests below 28.x --- .github/workflows/test.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4a34880..8c1704f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -34,6 +34,12 @@ jobs: - os: windows-latest emacs-version: snapshot experimental: true + exclude: + - os: macos-latest + emacs-version: "26.3" + - os: macos-latest + emacs-version: "27.2" + steps: - uses: actions/setup-python@v2 with: From a9990ee0529aa27e22d40233e2cd15327c7879e2 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Thu, 7 Nov 2024 13:21:32 +0900 Subject: [PATCH 51/71] CI: Drop Emacs 26 with GitHub Actions --- .github/workflows/test.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8c1704f..fcb2a39 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,7 +19,6 @@ jobs: matrix: os: [ubuntu-latest, macos-latest, windows-latest] emacs-version: - - 26.3 - 27.2 - 28.2 - 29.4 @@ -35,8 +34,6 @@ jobs: emacs-version: snapshot experimental: true exclude: - - os: macos-latest - emacs-version: "26.3" - os: macos-latest emacs-version: "27.2" From f4256e9f0b206a77b48da2df470c9ab0c48b4472 Mon Sep 17 00:00:00 2001 From: Jen-Chieh Shen Date: Mon, 24 Feb 2025 15:01:30 -0800 Subject: [PATCH 52/71] ci: Test Emacs 30.1 --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fcb2a39..830d229 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,6 +22,7 @@ jobs: - 27.2 - 28.2 - 29.4 + - 30.1 experimental: [false] include: - os: ubuntu-latest From f4232ce248beeef0b12a9665796709e8e063d7b6 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Mon, 31 Mar 2025 22:35:46 +0900 Subject: [PATCH 53/71] Remove unused Cask file --- Cask | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 Cask diff --git a/Cask b/Cask deleted file mode 100644 index 3768fee..0000000 --- a/Cask +++ /dev/null @@ -1,9 +0,0 @@ -(package "phpstan" "0.7.2" "Interface to PHPStan (PHP static analyzer)") -(source melpa) -(source gnu) - -(package-file "phpstan.el") -(package-file "flycheck-phpstan.el") -(package-file "flymake-phpstan.el") -(development - (depends-on "php-mode")) From c9bb8b2a7364165e1f68e9b57f4822435d66521f Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Mon, 31 Mar 2025 22:36:07 +0900 Subject: [PATCH 54/71] Bump version 0.8.1 --- CHANGELOG.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 723c7e6..e78734a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,25 @@ All notable changes of the `phpstan.el` are documented in this file using the [Keep a Changelog](https://keepachangelog.com/) principles. -## Unreleased + + +## [0.8.1] ### Added * Add `phpstan-enable-remote-experimental` custom variable for activate PHPStan on TRAMP. * Add support for `php-ts-mode`. +* Add `phpstan-insert-dumptype` command +* Add `phpstan-insert-ignore` command + +### Changed + +* Refactored `phpstan-check-buffer` command for improved performance. +* Improved logic for detecting phpstan executable. + +### Removed + +* Drop support for Emacs 24.3. ## [0.7.0] From b3243f34c2585d51174490a555c7de071300aad6 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Tue, 1 Apr 2025 04:16:26 +0900 Subject: [PATCH 55/71] Fix compile errors --- phpstan.el | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/phpstan.el b/phpstan.el index c7d6f8f..e76708c 100644 --- a/phpstan.el +++ b/phpstan.el @@ -61,7 +61,9 @@ (eval-when-compile (require 'compat nil t) (require 'php) - (require 'json)) + (require 'json) + (declare-function 'tramp-dissect-file-name "tramp" '(name &optional nodefault)) + (declare-function 'tramp-file-name-localname "tamp" '(cl-x))) ;; Variables: (defgroup phpstan nil @@ -161,7 +163,7 @@ have unexpected behaviors or performance implications." :group 'phpstan) (defcustom phpstan-not-ignorable-identifiers '("ignore.parseError") - "A list of identifiers that are prohibited from being added to the @phpstan-ignore tag." + "Lists identifiers prohibited from being added to @phpstan-ignore tags." :type '(repeat string)) (defvar-local phpstan--use-xdebug-option nil) @@ -570,10 +572,9 @@ POSITION determines where to insert the comment and can be either `this-line' or (list (if current-prefix-arg 'this-line 'previous-line))) (save-restriction (widen) - (let ((pos (point)) - (identifiers (cl-set-difference (alist-get (phpstan--current-line) phpstan--ignorable-errors) phpstan-not-ignorable-identifiers :test #'equal)) + (let ((identifiers (cl-set-difference (alist-get (phpstan--current-line) phpstan--ignorable-errors) phpstan-not-ignorable-identifiers :test #'equal)) (padding (if (eq position 'this-line) " " "")) - new-position new-point delete-region) + new-position new-point append) (cl-multiple-value-setq (new-position new-point append) (phpstan--check-existing-ignore-tag :in-previous nil)) (when new-position (setq position new-position)) From e1aa8b269c0e3281c323bc1fad509edabb668441 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Tue, 1 Apr 2025 04:20:32 +0900 Subject: [PATCH 56/71] Bump version 0.8.2 --- CHANGELOG.md | 6 ++++++ Eask | 2 +- flycheck-phpstan.el | 6 +++--- flymake-phpstan.el | 6 +++--- phpstan.el | 6 +++--- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e78734a..072c5d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes of the `phpstan.el` are documented in this file using the [K +## [0.8.2] + +### Fixed + +* Fix compilation errors on Emacs 30 + ## [0.8.1] ### Added diff --git a/Eask b/Eask index e9f7321..bc9f916 100644 --- a/Eask +++ b/Eask @@ -1,5 +1,5 @@ (package "phpstan" - "0.7.2" + "0.8.2" "Interface to PHPStan (PHP static analyzer)") (website-url "https://github.com/emacs-php/phpstan.el") diff --git a/flycheck-phpstan.el b/flycheck-phpstan.el index 49431b8..4a6242b 100644 --- a/flycheck-phpstan.el +++ b/flycheck-phpstan.el @@ -1,13 +1,13 @@ ;;; flycheck-phpstan.el --- Flycheck integration for PHPStan -*- lexical-binding: t; -*- -;; Copyright (C) 2023 Friends of Emacs-PHP development +;; Copyright (C) 2025 Friends of Emacs-PHP development ;; Author: USAMI Kenta ;; Created: 15 Mar 2018 -;; Version: 0.7.2 +;; Version: 0.8.2 ;; Keywords: tools, php ;; Homepage: https://github.com/emacs-php/phpstan.el -;; Package-Requires: ((emacs "24.3") (flycheck "26") (phpstan "0.7.2")) +;; Package-Requires: ((emacs "24.3") (flycheck "26") (phpstan "0.8.2")) ;; License: GPL-3.0-or-later ;; This program is free software; you can redistribute it and/or modify diff --git a/flymake-phpstan.el b/flymake-phpstan.el index d1dc8ee..3f1c5d2 100644 --- a/flymake-phpstan.el +++ b/flymake-phpstan.el @@ -1,13 +1,13 @@ ;;; flymake-phpstan.el --- Flymake backend for PHP using PHPStan -*- lexical-binding: t; -*- -;; Copyright (C) 2023 Friends of Emacs-PHP development +;; Copyright (C) 2025 Friends of Emacs-PHP development ;; Author: USAMI Kenta ;; Created: 31 Mar 2020 -;; Version: 0.7.2 +;; Version: 0.8.2 ;; Keywords: tools, php ;; Homepage: https://github.com/emacs-php/phpstan.el -;; Package-Requires: ((emacs "26.1") (phpstan "0.7.2")) +;; Package-Requires: ((emacs "26.1") (phpstan "0.8.2")) ;; License: GPL-3.0-or-later ;; This program is free software; you can redistribute it and/or modify diff --git a/phpstan.el b/phpstan.el index e76708c..bb95533 100644 --- a/phpstan.el +++ b/phpstan.el @@ -1,13 +1,13 @@ ;;; phpstan.el --- Interface to PHPStan -*- lexical-binding: t; -*- -;; Copyright (C) 2023 Friends of Emacs-PHP development +;; Copyright (C) 2025 Friends of Emacs-PHP development ;; Author: USAMI Kenta ;; Created: 15 Mar 2018 -;; Version: 0.7.2 +;; Version: 0.8.2 ;; Keywords: tools, php ;; Homepage: https://github.com/emacs-php/phpstan.el -;; Package-Requires: ((emacs "25.1") (compat "29") (php-mode "1.22.3") (php-runtime "0.2")) +;; Package-Requires: ((emacs "25.1") (compat "30") (php-mode "1.22.3") (php-runtime "0.2")) ;; License: GPL-3.0-or-later ;; This program is free software; you can redistribute it and/or modify From e90ed7c4521c825633c3c5aef4e047afd03c010d Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Tue, 8 Apr 2025 01:12:42 +0900 Subject: [PATCH 57/71] Requires Emacs 25 or higher --- flycheck-phpstan.el | 4 ++-- phpstan.el | 33 +++++++++++++++------------------ 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/flycheck-phpstan.el b/flycheck-phpstan.el index 4a6242b..b56243a 100644 --- a/flycheck-phpstan.el +++ b/flycheck-phpstan.el @@ -7,7 +7,7 @@ ;; Version: 0.8.2 ;; Keywords: tools, php ;; Homepage: https://github.com/emacs-php/phpstan.el -;; Package-Requires: ((emacs "24.3") (flycheck "26") (phpstan "0.8.2")) +;; Package-Requires: ((emacs "25.1") (flycheck "26") (phpstan "0.8.2")) ;; License: GPL-3.0-or-later ;; This program is free software; you can redistribute it and/or modify @@ -107,7 +107,7 @@ (if (null lines) msg (concat msg flycheck-phpstan-metadata-separator - (mapconcat #'identity lines "\n")))) + (string-join lines "\n")))) collect (flycheck-error-new-at (plist-get messages :line) nil 'error text :filename file)))) diff --git a/phpstan.el b/phpstan.el index bb95533..765aff6 100644 --- a/phpstan.el +++ b/phpstan.el @@ -158,7 +158,7 @@ have unexpected behaviors or performance implications." :group 'phpstan) (defcustom phpstan-disable-buffer-errors nil - "If T, don't keep errors per buffer to save memory." + "If non-NIL, don't keep errors per buffer to save memory." :type 'boolean :group 'phpstan) @@ -172,7 +172,7 @@ have unexpected behaviors or performance implications." ;;;###autoload (progn - (defvar phpstan-working-dir nil + (defvar-local phpstan-working-dir nil "Path to working directory of PHPStan. *NOTICE*: This is different from the project root. @@ -185,7 +185,6 @@ STRING NIL Use (php-project-get-root-dir) as working directory.") - (make-variable-buffer-local 'phpstan-working-dir) (put 'phpstan-working-dir 'safe-local-variable #'(lambda (v) (if (consp v) (and (eq 'root (car v)) (stringp (cdr v))) @@ -193,7 +192,7 @@ NIL ;;;###autoload (progn - (defvar phpstan-config-file nil + (defvar-local phpstan-config-file nil "Path to project specific configuration file of PHPStan. STRING @@ -204,7 +203,6 @@ STRING NIL Search phpstan.neon(.dist) in (phpstan-get-working-dir).") - (make-variable-buffer-local 'phpstan-config-file) (put 'phpstan-config-file 'safe-local-variable #'(lambda (v) (if (consp v) (and (eq 'root (car v)) (stringp (cdr v))) @@ -243,25 +241,24 @@ max NIL Use rule level specified in `phpstan' configuration file.") (put 'phpstan-level 'safe-local-variable - #'(lambda (v) (or (null v) - (integerp v) - (eq 'max v) - (and (stringp v) - (string= "max" v) - (string-match-p "\\`[0-9]\\'" v)))))) + (lambda (v) (or (null v) + (integerp v) + (eq 'max v) + (and (stringp v) + (or (string= "max" v) + (string-match-p "\\`[0-9]\\'" v))))))) ;;;###autoload (progn - (defvar phpstan-replace-path-prefix) - (make-variable-buffer-local 'phpstan-replace-path-prefix) + (defvar-local phpstan-replace-path-prefix nil) (put 'phpstan-replace-path-prefix 'safe-local-variable - #'(lambda (v) (or (null v) (stringp v))))) + (lambda (v) (or (null v) (stringp v))))) (defconst phpstan-docker-executable "docker") ;;;###autoload (progn - (defvar phpstan-executable nil + (defvar-local phpstan-executable nil "PHPStan excutable file. STRING @@ -278,7 +275,6 @@ STRING NIL Auto detect `phpstan' executable file.") - (make-variable-buffer-local 'phpstan-executable) (put 'phpstan-executable 'safe-local-variable #'(lambda (v) (if (consp v) (or (and (eq 'root (car v)) (stringp (cdr v))) @@ -349,7 +345,8 @@ it returns the value of `SOURCE' as it is." (cond ((eq 'docker phpstan-executable) "/app") ((and (consp phpstan-executable) - (string= "docker" (car phpstan-executable))) "/app"))))) + (string= "docker" (car phpstan-executable))) + "/app"))))) (if prefix (expand-file-name (replace-regexp-in-string (concat "\\`" (regexp-quote root-directory)) @@ -591,7 +588,7 @@ POSITION determines where to insert the comment and can be either `this-line' or (goto-char new-point)) (insert (concat padding (if new-position (if append ", " " ") "// @phpstan-ignore ") - (mapconcat #'identity identifiers ", "))))))) + (string-join identifiers ", "))))))) ;;;###autoload (defun phpstan-insert-dumptype (&optional expression prefix-num) From ca1bc43f53eb2fa3a647737cd047e85e21910821 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Tue, 8 Apr 2025 02:19:45 +0900 Subject: [PATCH 58/71] Add phpstan-copy-dumped-type command --- CHANGELOG.md | 6 +++++- README.org | 8 ++++++++ flycheck-phpstan.el | 1 + phpstan.el | 25 +++++++++++++++++++++++++ 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 072c5d5..4b4b524 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,11 @@ All notable changes of the `phpstan.el` are documented in this file using the [Keep a Changelog](https://keepachangelog.com/) principles. - +## Unreleased + +### Added + +* Add `phpstan-copy-dumped-type` command to copy the nearest dumped type from `PHPStan\dumpType()` or `PHPStan\dumpPhpDocType()` messages. ## [0.8.2] diff --git a/README.org b/README.org index 9a6efb1..f75efff 100644 --- a/README.org +++ b/README.org @@ -105,6 +105,14 @@ Insert a ~@phpstan-ignore~ tag to suppress any PHPStan errors on the current lin By default it inserts the tag on the previous line, but if there is already a tag at the end of the current line or on the previous line, the identifiers will be appended there. If there is no existing tag and ~C-u~ is pressed before the command, it will be inserted at the end of the line. +*** Command ~phpstan-copy-dumped-type~ +Copy the nearest dumped type message from PHPStan's output. + +This command looks for messages like ~Dumped type: int|string|null~ reported by ~PHPStan\dumpType()~ or ~PHPStan\dumpPhpDocType()~, and copies the type string to the kill ring. + +If there are multiple dumped types in the buffer, it selects the one closest to the current line. + +If no dumped type messages are found, the command signals an error. ** API Most variables defined in this package are buffer local. If you want to set it for multiple projects, use [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Default-Value.html][setq-default]]. diff --git a/flycheck-phpstan.el b/flycheck-phpstan.el index b56243a..d004744 100644 --- a/flycheck-phpstan.el +++ b/flycheck-phpstan.el @@ -83,6 +83,7 @@ (errors (phpstan--plist-to-alist (plist-get data :files)))) (unless phpstan-disable-buffer-errors (phpstan-update-ignorebale-errors-from-json-buffer errors)) + (phpstan-update-dumped-types errors) (flycheck-phpstan--build-errors errors))) (defun flycheck-phpstan--temp-buffer () diff --git a/phpstan.el b/phpstan.el index 765aff6..d080adb 100644 --- a/phpstan.el +++ b/phpstan.el @@ -169,6 +169,7 @@ have unexpected behaviors or performance implications." (defvar-local phpstan--use-xdebug-option nil) (defvar-local phpstan--ignorable-errors '()) +(defvar-local phpstan--dumped-types '()) ;;;###autoload (progn @@ -523,6 +524,17 @@ it returns the value of `SOURCE' as it is." (setq phpstan--ignorable-errors (mapcar (lambda (v) (cons (car v) (mapcar #'cdr (cdr v)))) (seq-group-by #'car identifiers))))) +(defun phpstan-update-dumped-types (errors) + "Update `phpstan--dumped-types' variable by ERRORS." + (save-match-data + (setq phpstan--dumped-types + (cl-loop for (_ . entry) in errors + append (cl-loop for message in (plist-get entry :messages) + for msg = (plist-get message :message) + if (string-match (eval-when-compile (rx bos "Dumped type: ")) msg) + collect (cons (plist-get message :line) + (substring-no-properties msg (match-end 0)))))))) + (defconst phpstan--re-ignore-tag (eval-when-compile (rx (* (syntax whitespace)) "//" (* (syntax whitespace)) @@ -590,6 +602,19 @@ POSITION determines where to insert the comment and can be either `this-line' or (if new-position (if append ", " " ") "// @phpstan-ignore ") (string-join identifiers ", "))))))) +;;;###autoload +(defun phpstan-copy-dumped-type () + "Copy a dumped PHPStan type." + (interactive) + (if phpstan--dumped-types + (let ((type (if (eq 1 (length phpstan--dumped-types)) + (cdar phpstan--dumped-types) + (let ((linum (line-number-at-pos))) + (cdar (seq-sort-by (lambda (elm) (abs (- linum (car elm)))) #'< phpstan--dumped-types)))))) + (kill-new type) + (message "Copied %s" type)) + (user-error "No dumped PHPStan types"))) + ;;;###autoload (defun phpstan-insert-dumptype (&optional expression prefix-num) "Insert PHPStan\\dumpType() expression-statement by EXPRESSION and PREFIX-NUM." From f289114d9c7897665381dad2f01673fd04c78afd Mon Sep 17 00:00:00 2001 From: Thomas Fini Hansen Date: Mon, 7 Apr 2025 20:39:59 +0200 Subject: [PATCH 59/71] Handle "No files" message (#43) Co-authored-by: USAMI Kenta --- flycheck-phpstan.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/flycheck-phpstan.el b/flycheck-phpstan.el index d004744..a63771e 100644 --- a/flycheck-phpstan.el +++ b/flycheck-phpstan.el @@ -79,7 +79,9 @@ (erase-buffer) (insert output) (current-buffer))) - (data (phpstan--parse-json json-buffer)) + (data (if (string-prefix-p "{" output) + (phpstan--parse-json json-buffer) + (list (flycheck-error-new-at 1 1 'warning (string-trim output))))) (errors (phpstan--plist-to-alist (plist-get data :files)))) (unless phpstan-disable-buffer-errors (phpstan-update-ignorebale-errors-from-json-buffer errors)) From 3b0a83a68c1ed1955344b0787fc28337b2a54623 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Tue, 8 Apr 2025 20:52:07 +0900 Subject: [PATCH 60/71] Prevent Flycheck from showing errors due to deleted temp files during editing Suppress unnecessary Flycheck errors when PHPStan reports "[ERROR] No files found to analyse." This happens because temporary files are deleted while editing, causing PHPStan to fail to find files. An around-advice on `flycheck-finish-checker-process` has been added to ignore such cases, preventing misleading errors from being shown in modified buffers. --- flycheck-phpstan.el | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/flycheck-phpstan.el b/flycheck-phpstan.el index a63771e..b3c60f5 100644 --- a/flycheck-phpstan.el +++ b/flycheck-phpstan.el @@ -44,6 +44,8 @@ ;; Usually it is defined dynamically by flycheck (defvar flycheck-phpstan-executable) (defvar flycheck-phpstan--temp-buffer-name "*Flycheck PHPStan*") +(defvar flycheck-phpstan--output-filter-added nil) +(defconst flycheck-phpstan--nofiles-message (eval-when-compile (regexp-quote "[ERROR] No files found to analyse."))) (defcustom flycheck-phpstan-ignore-metadata-list nil "Set of metadata items to ignore in PHPStan messages for Flycheck." @@ -57,6 +59,24 @@ :safe #'stringp :group 'phpstan) +(defun flycheck-phpstan--suppress-no-files-error (next checker exit-status files output callback cwd) + "Suppress Flycheck errors if PHPStan reports no files in a modified buffer. + +This function is intended to be used as an :around advice for +`flycheck-finish-checker-process'. + +It prevents Flycheck from displaying an error when: +- CHECKER is `phpstan', +- the current buffer is modified, +- and OUTPUT contains the message `flycheck-phpstan--nofiles-message'. + +NEXT, EXIT-STATUS, FILES, OUTPUT, CALLBACK, and CWD are the original arguments +passed to `flycheck-finish-checker-process'." + (unless (and (eq checker 'phpstan) + (buffer-modified-p) + (string-match-p flycheck-phpstan--nofiles-message output)) + (funcall next checker exit-status files output callback cwd))) + (defun flycheck-phpstan--enabled-and-set-variable () "Return path to phpstan configure file, and set buffer execute in side effect." (let ((enabled (phpstan-enabled))) @@ -71,6 +91,10 @@ (and (stringp (car-safe phpstan-executable)) (listp (cdr-safe phpstan-executable))) (null phpstan-executable))) + (unless flycheck-phpstan--output-filter-added + (advice-add 'flycheck-finish-checker-process + :around #'flycheck-phpstan--suppress-no-files-error) + (setq flycheck-phpstan--output-filter-added t)) (setq-local flycheck-phpstan-executable (car (phpstan-get-executable-and-args))))))) (defun flycheck-phpstan-parse-output (output &optional _checker _buffer) From a91ef35cee18141d48f30148018555152cd1e6d1 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Tue, 8 Apr 2025 21:05:22 +0900 Subject: [PATCH 61/71] Fix position --- flycheck-phpstan.el | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flycheck-phpstan.el b/flycheck-phpstan.el index b3c60f5..c8ba4ab 100644 --- a/flycheck-phpstan.el +++ b/flycheck-phpstan.el @@ -81,6 +81,10 @@ passed to `flycheck-finish-checker-process'." "Return path to phpstan configure file, and set buffer execute in side effect." (let ((enabled (phpstan-enabled))) (prog1 enabled + (unless flycheck-phpstan--output-filter-added + (advice-add 'flycheck-finish-checker-process + :around #'flycheck-phpstan--suppress-no-files-error) + (setq flycheck-phpstan--output-filter-added t)) (when (and enabled phpstan-flycheck-auto-set-executable (null (bound-and-true-p flycheck-phpstan-executable)) @@ -91,10 +95,6 @@ passed to `flycheck-finish-checker-process'." (and (stringp (car-safe phpstan-executable)) (listp (cdr-safe phpstan-executable))) (null phpstan-executable))) - (unless flycheck-phpstan--output-filter-added - (advice-add 'flycheck-finish-checker-process - :around #'flycheck-phpstan--suppress-no-files-error) - (setq flycheck-phpstan--output-filter-added t)) (setq-local flycheck-phpstan-executable (car (phpstan-get-executable-and-args))))))) (defun flycheck-phpstan-parse-output (output &optional _checker _buffer) From 715fef5e83519fbacf26ec8a51e838afd82c5ad7 Mon Sep 17 00:00:00 2001 From: Jen-Chieh Shen Date: Tue, 22 Apr 2025 17:20:22 -0700 Subject: [PATCH 62/71] fix: Warning missing lexical-binding cookie --- Eask | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Eask b/Eask index bc9f916..6e4d937 100644 --- a/Eask +++ b/Eask @@ -1,3 +1,5 @@ +;; -*- mode: eask; lexical-binding: t -*- + (package "phpstan" "0.8.2" "Interface to PHPStan (PHP static analyzer)") From 3b59a5b275f3dad911212b54006d89b5d6b47ce6 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Wed, 21 May 2025 23:44:47 +0900 Subject: [PATCH 63/71] Support PHPStan editor-mode --- README.org | 7 ++++++- flycheck-phpstan.el | 25 +++++++++++++++++----- flymake-phpstan.el | 34 +++++++++++++++++++++++------- phpstan.el | 51 ++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 103 insertions(+), 14 deletions(-) diff --git a/README.org b/README.org index f75efff..0c09935 100644 --- a/README.org +++ b/README.org @@ -5,9 +5,14 @@ #+END_HTML Emacs interface to [[https://github.com/phpstan/phpstan][PHPStan]], includes checker for [[http://www.flycheck.org/en/latest/][Flycheck]]. ** Support version -- Emacs 25+ +- Emacs 26+ - PHPStan latest/dev-master (NOT support 0.9 seriese) - PHP 7.1+ or Docker runtime + +> [!TIP] +> This package provides support for the [editor mode](https://phpstan.org/user-guide/editor-mode) that will be added in PHPStan 2.1.17 and 1.12.27. +> **We strongly recommend that you always update to the latest PHPStan.** + ** How to install *** Install from MELPA 1. If you have not set up MELPA, see [[https://melpa.org/#/getting-started][Getting Started - MELPA]]. diff --git a/flycheck-phpstan.el b/flycheck-phpstan.el index c8ba4ab..c96837e 100644 --- a/flycheck-phpstan.el +++ b/flycheck-phpstan.el @@ -77,6 +77,11 @@ passed to `flycheck-finish-checker-process'." (string-match-p flycheck-phpstan--nofiles-message output)) (funcall next checker exit-status files output callback cwd))) +(defcustom flycheck-phpstan-fallback-to-original-analysis-if-editor-mode-unavailable t + "If non-NIL, analyze the original file when PHPStan editor mode is unavailable." + :type 'boolean + :safe #'booleanp) + (defun flycheck-phpstan--enabled-and-set-variable () "Return path to phpstan configure file, and set buffer execute in side effect." (let ((enabled (phpstan-enabled))) @@ -139,13 +144,23 @@ passed to `flycheck-finish-checker-process'." nil 'error text :filename file)))) +(defun flycheck-phpstan-analyze-original (original) + "Return non-NIL if ORIGINAL is NIL, fallback is enabled, and buffer is modified." + (and (null original) + flycheck-phpstan-fallback-to-original-analysis-if-editor-mode-unavailable + (buffer-modified-p))) + (flycheck-define-checker phpstan "PHP static analyzer based on PHPStan." - :command ("php" (eval (phpstan-get-command-args :format "json")) - (eval (if (or (buffer-modified-p) (not buffer-file-name)) - (phpstan-normalize-path - (flycheck-save-buffer-to-temp #'flycheck-temp-file-inplace)) - buffer-file-name))) + :command ("php" + (eval + (phpstan-get-command-args + :format "json" + :editor (list + :analyze-original #'flycheck-phpstan-analyze-original + :original-file buffer-file-name + :temp-file (lambda () (flycheck-save-buffer-to-temp #'flycheck-temp-file-system)) + :inplace (lambda () (flycheck-save-buffer-to-temp #'flycheck-temp-file-inplace)))))) :working-directory (lambda (_) (phpstan-get-working-dir)) :enabled (lambda () (flycheck-phpstan--enabled-and-set-variable)) :error-parser flycheck-phpstan-parse-output diff --git a/flymake-phpstan.el b/flymake-phpstan.el index 3f1c5d2..efa0cf1 100644 --- a/flymake-phpstan.el +++ b/flymake-phpstan.el @@ -52,6 +52,11 @@ :type 'boolean :group 'flymake-phpstan) +(defcustom flycheck-phpstan-fallback-to-original-analysis-if-editor-mode-unavailable t + "If non-NIL, analyze the original file when PHPStan editor mode is unavailable." + :type 'boolean + :safe #'booleanp) + (defvar-local flymake-phpstan--proc nil) (defun flymake-phpstan-make-process (root command-args report-fn source) @@ -88,6 +93,17 @@ (kill-buffer (process-buffer proc)))) (code (user-error "PHPStan error (exit status: %s)" code))))))) +(defun flymake-phpstan-analyze-original (original) + "Return non-NIL if ORIGINAL is NIL, fallback is enabled, and buffer is modified." + (and (null original) + flymake-phpstan-fallback-to-original-analysis-if-editor-mode-unavailable + (buffer-modified-p))) + +(defun flymake-phpstan--create-temp-file () + "Create temp file and return the path." + (phpstan-normalize-path + (flymake-proc-init-create-temp-buffer-copy 'flymake-proc-create-temp-inplace))) + (defun flymake-phpstan (report-fn &rest _ignored-args) "Flymake backend for PHPStan report using REPORT-FN." (let ((command-args (phpstan-get-command-args :include-executable t))) @@ -95,14 +111,18 @@ (user-error "Cannot find a phpstan executable command")) (when (process-live-p flymake-phpstan--proc) (kill-process flymake-phpstan--proc)) - (let ((source (current-buffer)) - (target-path (if (or (buffer-modified-p) (not buffer-file-name)) - (phpstan-normalize-path - (flycheck-save-buffer-to-temp #'flycheck-temp-file-inplace)) - buffer-file-name))) + (let* ((source (current-buffer)) + (args (phpstan-get-command-args + :include-executable t + :format "raw" + :editor (list + :analyze-original #'flymake-phpstan-analyze-original + :original-file buffer-file-name + :temp-file #'flymake-phpstan--create-temp-file + :inplace #'flymake-phpstan--create-temp-file)))) (save-restriction (widen) - (setq flymake-phpstan--proc (flymake-phpstan-make-process (php-project-get-root-dir) (append command-args (list "--" target-path)) report-fn source)) + (setq flymake-phpstan--proc (flymake-phpstan-make-process (php-project-get-root-dir) args report-fn source)) (process-send-region flymake-phpstan--proc (point-min) (point-max)) (process-send-eof flymake-phpstan--proc))))) @@ -115,7 +135,7 @@ (flymake-mode 1) (when flymake-phpstan-disable-c-mode-hooks (remove-hook 'flymake-diagnostic-functions #'flymake-cc t)) - (add-hook 'flymake-diagnostic-functions #'flymake-phpstan nil t)))) + (add-hook 'flymake-diagnostic-functions #'flymake-phpstan nil 'local)))) (provide 'flymake-phpstan) ;;; flymake-phpstan.el ends here diff --git a/phpstan.el b/phpstan.el index d080adb..f514121 100644 --- a/phpstan.el +++ b/phpstan.el @@ -166,11 +166,20 @@ have unexpected behaviors or performance implications." "Lists identifiers prohibited from being added to @phpstan-ignore tags." :type '(repeat string)) +(defcustom phpstan-activate-editor-mode nil + "Controls how PHPStan's editor mode is activated." + :local t + :type '(choice (const :tag "Automatic (based on version)" nil) + (const :tag "Editor mode will be actively enabled, regardless of the PHPStan version." 'enabled) + (const :tag "Editor mode will be explicitly disabled." 'disabled))) + (defvar-local phpstan--use-xdebug-option nil) (defvar-local phpstan--ignorable-errors '()) (defvar-local phpstan--dumped-types '()) +(defvar phpstan-executable-versions-alist '()) + ;;;###autoload (progn (defvar-local phpstan-working-dir nil @@ -479,7 +488,7 @@ it returns the value of `SOURCE' as it is." ((executable-find "phpstan") (list (executable-find "phpstan"))) (t (error "PHPStan executable not found"))))))) -(cl-defun phpstan-get-command-args (&key include-executable use-pro args format options config verbose) +(cl-defun phpstan-get-command-args (&key include-executable use-pro args format options config verbose editor) "Return command line argument for PHPStan." (let ((executable-and-args (phpstan-get-executable-and-args)) (config (or config (phpstan-normalize-path (phpstan-get-config-file)))) @@ -510,6 +519,15 @@ it returns the value of `SOURCE' as it is." "--xdebug")) (list phpstan--use-xdebug-option)) (phpstan-use-xdebug-option (list "--xdebug"))) + (when editor + (let ((original-file (plist-get editor :original-file))) + (if (phpstan-editor-mode-available-p (car (phpstan-get-executable-and-args))) + (list "--tmp-file" (funcall (plist-get editor :temp-file)) + "--instead-of" original-file + "--" original-file) + (if (funcall (plist-get editor :analyze-original) original-file) + (list "--" original-file) + (list "--" (funcall (plist-get editor :inplace))))))) options (and args (cons "--" args))))) @@ -535,6 +553,37 @@ it returns the value of `SOURCE' as it is." collect (cons (plist-get message :line) (substring-no-properties msg (match-end 0)))))))) +(defun phpstan-version (executable) + "Return the PHPStan version of EXECUTABLE." + (if-let* ((cached-entry (assoc executable phpstan-executable-versions-alist))) + (cdr cached-entry) + (let* ((version (thread-first + (mapconcat #'shell-quote-argument (list executable "--version") " ") + (shell-command-to-string) + (string-trim-right) + (split-string " ") + (last) + (car-safe)))) + (prog1 version + (push (cons executable version) phpstan-executable-versions-alist))))) + +(defun phpstan-editor-mode-available-p (executable) + "Check if the specified PHPStan EXECUTABLE supports editor mode. + +If a cached result for EXECUTABLE exists, it is returned directly. +Otherwise, this function attempts to determine support by retrieving +the PHPStan version using 'phpstan --version' command." + (pcase phpstan-activate-editor-mode + ('enabled t) + ('disabled nil) + ('nil + (let* ((version (phpstan-version executable))) + (if (string-match-p (eval-when-compile (regexp-quote "-dev@")) version) + t + (pcase (elt version 0) + (?1 (version<= "1.12.27" version)) + (?2 (version<= "2.1.17" version)))))))) + (defconst phpstan--re-ignore-tag (eval-when-compile (rx (* (syntax whitespace)) "//" (* (syntax whitespace)) From 2f278be2e397c547be0f48bdc04ca841c1b2fedc Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Thu, 22 May 2025 00:02:03 +0900 Subject: [PATCH 64/71] Fix README --- README.org | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.org b/README.org index 0c09935..d13f5eb 100644 --- a/README.org +++ b/README.org @@ -9,9 +9,11 @@ Emacs interface to [[https://github.com/phpstan/phpstan][PHPStan]], includes che - PHPStan latest/dev-master (NOT support 0.9 seriese) - PHP 7.1+ or Docker runtime -> [!TIP] -> This package provides support for the [editor mode](https://phpstan.org/user-guide/editor-mode) that will be added in PHPStan 2.1.17 and 1.12.27. -> **We strongly recommend that you always update to the latest PHPStan.** +#+BEGIN_QUOTE +[!TIP] +This package provides support for the [[https://phpstan.org/user-guide/editor-mode][Editor Mode]] that will be added in PHPStan 2.1.17 and 1.12.27. +**We strongly recommend that you always update to the latest PHPStan.** +#+END_QUOTE ** How to install *** Install from MELPA From b20fb8173930365bcbedf78901ce526b8bb4dc5d Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Thu, 22 May 2025 00:03:56 +0900 Subject: [PATCH 65/71] Fix README --- README.org | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.org b/README.org index d13f5eb..a03d16a 100644 --- a/README.org +++ b/README.org @@ -11,8 +11,8 @@ Emacs interface to [[https://github.com/phpstan/phpstan][PHPStan]], includes che #+BEGIN_QUOTE [!TIP] -This package provides support for the [[https://phpstan.org/user-guide/editor-mode][Editor Mode]] that will be added in PHPStan 2.1.17 and 1.12.27. -**We strongly recommend that you always update to the latest PHPStan.** +This package provides support for the [[https://phpstan.org/user-guide/editor-mode][Editor Mode]] that will be added in PHPStan 2.1.17 and 1.12.27.\\ +*We strongly recommend that you always update to the latest PHPStan.* #+END_QUOTE ** How to install From 6d0581ca39374759a3a2a8b941b8e84f3104f8bf Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Thu, 22 May 2025 10:10:18 +0900 Subject: [PATCH 66/71] Editor mode GA --- README.org | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.org b/README.org index a03d16a..3b7e48f 100644 --- a/README.org +++ b/README.org @@ -11,7 +11,7 @@ Emacs interface to [[https://github.com/phpstan/phpstan][PHPStan]], includes che #+BEGIN_QUOTE [!TIP] -This package provides support for the [[https://phpstan.org/user-guide/editor-mode][Editor Mode]] that will be added in PHPStan 2.1.17 and 1.12.27.\\ +This package provides support for the [[https://phpstan.org/user-guide/editor-mode][Editor Mode]] introduced in PHPStan [[https://github.com/phpstan/phpstan/releases/tag/2.1.17][2.1.17]] and [[https://github.com/phpstan/phpstan/releases/tag/1.12.27][1.12.27]].\\ *We strongly recommend that you always update to the latest PHPStan.* #+END_QUOTE From 491b0a7147cd12b282d017c23ef587a49962cf97 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Thu, 22 May 2025 11:44:40 +0900 Subject: [PATCH 67/71] Do not use Editor Mode if the buffer is not being edited --- flycheck-phpstan.el | 11 ++--------- flymake-phpstan.el | 11 ++--------- phpstan.el | 15 ++++++++------- 3 files changed, 12 insertions(+), 25 deletions(-) diff --git a/flycheck-phpstan.el b/flycheck-phpstan.el index c96837e..db650ae 100644 --- a/flycheck-phpstan.el +++ b/flycheck-phpstan.el @@ -77,11 +77,6 @@ passed to `flycheck-finish-checker-process'." (string-match-p flycheck-phpstan--nofiles-message output)) (funcall next checker exit-status files output callback cwd))) -(defcustom flycheck-phpstan-fallback-to-original-analysis-if-editor-mode-unavailable t - "If non-NIL, analyze the original file when PHPStan editor mode is unavailable." - :type 'boolean - :safe #'booleanp) - (defun flycheck-phpstan--enabled-and-set-variable () "Return path to phpstan configure file, and set buffer execute in side effect." (let ((enabled (phpstan-enabled))) @@ -145,10 +140,8 @@ passed to `flycheck-finish-checker-process'." :filename file)))) (defun flycheck-phpstan-analyze-original (original) - "Return non-NIL if ORIGINAL is NIL, fallback is enabled, and buffer is modified." - (and (null original) - flycheck-phpstan-fallback-to-original-analysis-if-editor-mode-unavailable - (buffer-modified-p))) + "Return non-NIL if ORIGINAL is non-NIL and buffer is not modified." + (and original (not (buffer-modified-p)))) (flycheck-define-checker phpstan "PHP static analyzer based on PHPStan." diff --git a/flymake-phpstan.el b/flymake-phpstan.el index efa0cf1..3e24f48 100644 --- a/flymake-phpstan.el +++ b/flymake-phpstan.el @@ -52,11 +52,6 @@ :type 'boolean :group 'flymake-phpstan) -(defcustom flycheck-phpstan-fallback-to-original-analysis-if-editor-mode-unavailable t - "If non-NIL, analyze the original file when PHPStan editor mode is unavailable." - :type 'boolean - :safe #'booleanp) - (defvar-local flymake-phpstan--proc nil) (defun flymake-phpstan-make-process (root command-args report-fn source) @@ -94,10 +89,8 @@ (code (user-error "PHPStan error (exit status: %s)" code))))))) (defun flymake-phpstan-analyze-original (original) - "Return non-NIL if ORIGINAL is NIL, fallback is enabled, and buffer is modified." - (and (null original) - flymake-phpstan-fallback-to-original-analysis-if-editor-mode-unavailable - (buffer-modified-p))) + "Return non-NIL if ORIGINAL is non-NIL and buffer is not modified." + (and original (not (buffer-modified-p)))) (defun flymake-phpstan--create-temp-file () "Create temp file and return the path." diff --git a/phpstan.el b/phpstan.el index f514121..0c730cf 100644 --- a/phpstan.el +++ b/phpstan.el @@ -521,13 +521,14 @@ it returns the value of `SOURCE' as it is." (phpstan-use-xdebug-option (list "--xdebug"))) (when editor (let ((original-file (plist-get editor :original-file))) - (if (phpstan-editor-mode-available-p (car (phpstan-get-executable-and-args))) - (list "--tmp-file" (funcall (plist-get editor :temp-file)) - "--instead-of" original-file - "--" original-file) - (if (funcall (plist-get editor :analyze-original) original-file) - (list "--" original-file) - (list "--" (funcall (plist-get editor :inplace))))))) + (cond + ((funcall (plist-get editor :analyze-original) original-file) + (list "--" original-file)) + ((phpstan-editor-mode-available-p (car (phpstan-get-executable-and-args))) + (list "--tmp-file" (funcall (plist-get editor :temp-file)) + "--instead-of" original-file + "--" original-file)) + ((list "--" (funcall (plist-get editor :inplace))))))) options (and args (cons "--" args))))) From a35f991356bbf49fe364dc0c47c229652bf10825 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Thu, 22 May 2025 12:29:25 +0900 Subject: [PATCH 68/71] Explicitly set the custom variable to :local t --- phpstan.el | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/phpstan.el b/phpstan.el index 0c730cf..d373920 100644 --- a/phpstan.el +++ b/phpstan.el @@ -77,13 +77,11 @@ (defcustom phpstan-flycheck-auto-set-executable t "Set flycheck phpstan-executable automatically." - :type 'boolean - :group 'phpstan) + :type 'boolean) (defcustom phpstan-enable-on-no-config-file t "If T, activate config from composer even when `phpstan.neon' is not found." - :type 'boolean - :group 'phpstan) + :type 'boolean) (defcustom phpstan-memory-limit nil "Set --memory-limit option." @@ -92,7 +90,7 @@ :link '(url-link :tag "PHP Manual" "https://www.php.net/manual/ini.core.php#ini.memory-limit") :safe (lambda (v) (or (null v) (stringp v))) - :group 'phpstan) + :local t) (defcustom phpstan-docker-image "ghcr.io/phpstan/phpstan" "Docker image URL or Docker Hub image name or NIL." @@ -104,7 +102,7 @@ :link '(url-link :tag "GitHub Container Registry" "https://github.com/orgs/phpstan/packages/container/package/phpstan") :safe (lambda (v) (or (null v) (stringp v))) - :group 'phpstan) + :local t) (defcustom phpstan-use-xdebug-option nil "Set --xdebug option." @@ -112,31 +110,31 @@ (const :tag "Add --xdebug option" t) (const :tag "No --xdebug option" nil)) :safe #'symbolp - :group 'phpstan) + :local t) (defcustom phpstan-generate-baseline-options '("--generate-baseline" "--allow-empty-baseline") "Command line options for generating PHPStan baseline." :type '(repeat string) :safe #'listp - :group 'phpstan) + :local t) (defcustom phpstan-baseline-file "phpstan-baseline.neon" "File name of PHPStan baseline file." :type 'string :safe #'stringp - :group 'phpstan) + :local t) (defcustom phpstan-tip-message-prefix "💡 " "Prefix of PHPStan tip message." :type 'string :safe #'stringp - :group 'phpstan) + :local t) (defcustom phpstan-identifier-prefix "🪪 " "Prefix of PHPStan error identifier." :type 'string :safe #'stringp - :group 'phpstan) + :local t) (defcustom phpstan-enable-remote-experimental nil "Enable PHPStan analysis remotely by TRAMP. @@ -146,7 +144,7 @@ This feature is experimental and should be used with caution as it may have unexpected behaviors or performance implications." :type 'boolean :safe #'booleanp - :group 'phpstan) + :local t) (defconst phpstan-template-dump-type "\\PHPStan\\dumpType();") (defconst phpstan-template-dump-phpdoc-type "\\PHPStan\\dumpPhpDocType();") @@ -154,13 +152,11 @@ have unexpected behaviors or performance implications." (defcustom phpstan-intert-dump-type-templates (cons phpstan-template-dump-type phpstan-template-dump-phpdoc-type) "Default template of PHPStan dumpType insertion." - :type '(cons string string) - :group 'phpstan) + :type '(cons string string)) (defcustom phpstan-disable-buffer-errors nil "If non-NIL, don't keep errors per buffer to save memory." - :type 'boolean - :group 'phpstan) + :type 'boolean) (defcustom phpstan-not-ignorable-identifiers '("ignore.parseError") "Lists identifiers prohibited from being added to @phpstan-ignore tags." @@ -168,10 +164,11 @@ have unexpected behaviors or performance implications." (defcustom phpstan-activate-editor-mode nil "Controls how PHPStan's editor mode is activated." - :local t :type '(choice (const :tag "Automatic (based on version)" nil) - (const :tag "Editor mode will be actively enabled, regardless of the PHPStan version." 'enabled) - (const :tag "Editor mode will be explicitly disabled." 'disabled))) + (const :tag "Editor mode will be actively enabled, regardless of the PHPStan version." enabled) + (const :tag "Editor mode will be explicitly disabled." disabled)) + :safe (lambda (v) (memq v '(nil enabled disabled))) + :local t) (defvar-local phpstan--use-xdebug-option nil) @@ -573,7 +570,7 @@ it returns the value of `SOURCE' as it is." If a cached result for EXECUTABLE exists, it is returned directly. Otherwise, this function attempts to determine support by retrieving -the PHPStan version using 'phpstan --version' command." +the PHPStan version using `phpstan --version' command." (pcase phpstan-activate-editor-mode ('enabled t) ('disabled nil) From 3f8783c61db642e7c52a3d0ea49b751138fc46f3 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Thu, 22 May 2025 12:32:44 +0900 Subject: [PATCH 69/71] Add require flymake-proc --- flymake-phpstan.el | 1 + 1 file changed, 1 insertion(+) diff --git a/flymake-phpstan.el b/flymake-phpstan.el index 3e24f48..8c54f12 100644 --- a/flymake-phpstan.el +++ b/flymake-phpstan.el @@ -38,6 +38,7 @@ (require 'cl-lib) (require 'php-project) (require 'flymake) +(require 'flymake-proc) (require 'phpstan) (eval-when-compile (require 'pcase)) From 8da92fbe92dd88ba0e7add4f62da61af9a760721 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Thu, 22 May 2025 12:43:14 +0900 Subject: [PATCH 70/71] Bump version 0.9.0 --- CHANGELOG.md | 19 +++++++++++++++++-- Eask | 2 +- README.org | 7 +++++++ flycheck-phpstan.el | 2 +- flymake-phpstan.el | 2 +- phpstan.el | 2 +- 6 files changed, 28 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b4b524..53ffd34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,26 @@ All notable changes of the `phpstan.el` are documented in this file using the [Keep a Changelog](https://keepachangelog.com/) principles. -## Unreleased + + +## [0.9.0] ### Added -* Add `phpstan-copy-dumped-type` command to copy the nearest dumped type from `PHPStan\dumpType()` or `PHPStan\dumpPhpDocType()` messages. +* Add `phpstan-copy-dumped-type` command to copy the nearest dumped type from `PHPStan\dumpType()` or `PHPStan\dumpPhpDocType()` messages +* Add support for PHPStan [Editor Mode](https://phpstan.org/user-guide/editor-mode) + +### Changed + +* Improved error handling when no JSON response is returned + +### Fixed + +* Fixed erroneous dependency from `flymake-phpstan` to Flycheck functions + +### Removed + +* Drop support for Emacs 25.3 ## [0.8.2] diff --git a/Eask b/Eask index 6e4d937..dfec247 100644 --- a/Eask +++ b/Eask @@ -1,7 +1,7 @@ ;; -*- mode: eask; lexical-binding: t -*- (package "phpstan" - "0.8.2" + "0.9.0" "Interface to PHPStan (PHP static analyzer)") (website-url "https://github.com/emacs-php/phpstan.el") diff --git a/README.org b/README.org index 3b7e48f..bbaf1e8 100644 --- a/README.org +++ b/README.org @@ -162,6 +162,13 @@ Use phpstan memory limit option when non-NIL. - ex) ~"1G"~ - ~nil~ :: Use memory limit in php.ini +*** Custom variable ~phpstan-activate-editor-mode~ +Determines whether PHPStan Editor Mode is available. + +- ~nil~ (default) :: Dynamically checks the PHPStan version by getting the path of the installed PHPStan executable. +- ~'enabled~ :: Always use Editor Mode (this will cause an error in older versions of PHPStan) +- ~'disabled~ :: Never use Editor Mode (no support for editors provided) + *** Custom variable ~phpstan-docker-image~ Docker image URL or Docker Hub image name or NIL. Default as ~"ghcr.io/phpstan/phpstan"~. See [[https://phpstan.org/user-guide/docker][Docker - PHPStan Documentation]] and [[https://github.com/orgs/phpstan/packages/container/package/phpstan][GitHub Container Registory - Package phpstan]]. diff --git a/flycheck-phpstan.el b/flycheck-phpstan.el index db650ae..5fd42b9 100644 --- a/flycheck-phpstan.el +++ b/flycheck-phpstan.el @@ -4,7 +4,7 @@ ;; Author: USAMI Kenta ;; Created: 15 Mar 2018 -;; Version: 0.8.2 +;; Version: 0.9.0 ;; Keywords: tools, php ;; Homepage: https://github.com/emacs-php/phpstan.el ;; Package-Requires: ((emacs "25.1") (flycheck "26") (phpstan "0.8.2")) diff --git a/flymake-phpstan.el b/flymake-phpstan.el index 8c54f12..9e89c5f 100644 --- a/flymake-phpstan.el +++ b/flymake-phpstan.el @@ -4,7 +4,7 @@ ;; Author: USAMI Kenta ;; Created: 31 Mar 2020 -;; Version: 0.8.2 +;; Version: 0.9.0 ;; Keywords: tools, php ;; Homepage: https://github.com/emacs-php/phpstan.el ;; Package-Requires: ((emacs "26.1") (phpstan "0.8.2")) diff --git a/phpstan.el b/phpstan.el index d373920..b0135d8 100644 --- a/phpstan.el +++ b/phpstan.el @@ -4,7 +4,7 @@ ;; Author: USAMI Kenta ;; Created: 15 Mar 2018 -;; Version: 0.8.2 +;; Version: 0.9.0 ;; Keywords: tools, php ;; Homepage: https://github.com/emacs-php/phpstan.el ;; Package-Requires: ((emacs "25.1") (compat "30") (php-mode "1.22.3") (php-runtime "0.2")) From 8a6720a58589cb5c9a1da2b96475440f472932c5 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Thu, 22 May 2025 22:14:16 +0900 Subject: [PATCH 71/71] Fix phpstan-get-command-args --- phpstan.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpstan.el b/phpstan.el index b0135d8..103403d 100644 --- a/phpstan.el +++ b/phpstan.el @@ -516,6 +516,7 @@ it returns the value of `SOURCE' as it is." "--xdebug")) (list phpstan--use-xdebug-option)) (phpstan-use-xdebug-option (list "--xdebug"))) + options (when editor (let ((original-file (plist-get editor :original-file))) (cond @@ -526,8 +527,7 @@ it returns the value of `SOURCE' as it is." "--instead-of" original-file "--" original-file)) ((list "--" (funcall (plist-get editor :inplace))))))) - options - (and args (cons "--" args))))) + (if editor args (cons "--" args))))) (defun phpstan-update-ignorebale-errors-from-json-buffer (errors) "Update `phpstan--ignorable-errors' variable by ERRORS."