@@ -166,11 +166,20 @@ have unexpected behaviors or performance implications."
166166 " Lists identifiers prohibited from being added to @phpstan-ignore tags."
167167 :type '(repeat string))
168168
169+ (defcustom phpstan-activate-editor-mode nil
170+ " Controls how PHPStan's editor mode is activated."
171+ :local t
172+ :type '(choice (const :tag " Automatic (based on version)" nil )
173+ (const :tag " Editor mode will be actively enabled, regardless of the PHPStan version." 'enabled )
174+ (const :tag " Editor mode will be explicitly disabled." 'disabled )))
175+
169176(defvar-local phpstan--use-xdebug-option nil )
170177
171178(defvar-local phpstan--ignorable-errors '())
172179(defvar-local phpstan--dumped-types '())
173180
181+ (defvar phpstan-executable-versions-alist '())
182+
174183;;;### autoload
175184(progn
176185 (defvar-local phpstan-working-dir nil
@@ -479,7 +488,7 @@ it returns the value of `SOURCE' as it is."
479488 ((executable-find " phpstan" ) (list (executable-find " phpstan" )))
480489 (t (error " PHPStan executable not found " )))))))
481490
482- (cl-defun phpstan-get-command-args (&key include-executable use-pro args format options config verbose )
491+ (cl-defun phpstan-get-command-args (&key include-executable use-pro args format options config verbose editor )
483492 " Return command line argument for PHPStan."
484493 (let ((executable-and-args (phpstan-get-executable-and-args))
485494 (config (or config (phpstan-normalize-path (phpstan-get-config-file))))
@@ -510,6 +519,15 @@ it returns the value of `SOURCE' as it is."
510519 " --xdebug" ))
511520 (list phpstan--use-xdebug-option))
512521 (phpstan-use-xdebug-option (list " --xdebug" )))
522+ (when editor
523+ (let ((original-file (plist-get editor :original-file )))
524+ (if (phpstan-editor-mode-available-p (car (phpstan-get-executable-and-args)))
525+ (list " --tmp-file" (funcall (plist-get editor :temp-file ))
526+ " --instead-of" original-file
527+ " --" original-file)
528+ (if (funcall (plist-get editor :analyze-original ) original-file)
529+ (list " --" original-file)
530+ (list " --" (funcall (plist-get editor :inplace )))))))
513531 options
514532 (and args (cons " --" args)))))
515533
@@ -535,6 +553,37 @@ it returns the value of `SOURCE' as it is."
535553 collect (cons (plist-get message :line )
536554 (substring-no-properties msg (match-end 0 ))))))))
537555
556+ (defun phpstan-version (executable )
557+ " Return the PHPStan version of EXECUTABLE."
558+ (if-let* ((cached-entry (assoc executable phpstan-executable-versions-alist)))
559+ (cdr cached-entry)
560+ (let* ((version (thread-first
561+ (mapconcat #'shell-quote-argument (list executable " --version" ) " " )
562+ (shell-command-to-string )
563+ (string-trim-right )
564+ (split-string " " )
565+ (last )
566+ (car-safe ))))
567+ (prog1 version
568+ (push (cons executable version) phpstan-executable-versions-alist)))))
569+
570+ (defun phpstan-editor-mode-available-p (executable )
571+ " Check if the specified PHPStan EXECUTABLE supports editor mode.
572+
573+ If a cached result for EXECUTABLE exists, it is returned directly.
574+ Otherwise, this function attempts to determine support by retrieving
575+ the PHPStan version using 'phpstan --version' command."
576+ (pcase phpstan-activate-editor-mode
577+ ('enabled t )
578+ ('disabled nil )
579+ ('nil
580+ (let* ((version (phpstan-version executable)))
581+ (if (string-match-p (eval-when-compile (regexp-quote " -dev@" )) version)
582+ t
583+ (pcase (elt version 0 )
584+ (?1 (version<= " 1.12.27" version))
585+ (?2 (version<= " 2.1.17" version))))))))
586+
538587(defconst phpstan--re-ignore-tag
539588 (eval-when-compile
540589 (rx (* (syntax whitespace)) " //" (* (syntax whitespace))
0 commit comments