Skip to content

Commit

Permalink
Add phpstan-insert-ignore command
Browse files Browse the repository at this point in the history
  • Loading branch information
zonuexe committed Oct 30, 2024
1 parent 0ca2298 commit 5d86ece
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 2 deletions.
7 changes: 6 additions & 1 deletion README.org
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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]].

Expand Down
2 changes: 2 additions & 0 deletions flycheck-phpstan.el
Original file line number Diff line number Diff line change
Expand Up @@ -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 ()
Expand Down
98 changes: 97 additions & 1 deletion phpstan.el
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -56,6 +56,7 @@
(require 'cl-lib)
(require 'php-project)
(require 'php-runtime)
(require 'seq)

(eval-when-compile
(require 'compat nil t)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 ()
Expand Down Expand Up @@ -497,6 +513,86 @@ 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."
Expand Down

0 comments on commit 5d86ece

Please sign in to comment.