|
7 | 7 | ;; Version: 0.7.2
|
8 | 8 | ;; Keywords: tools, php
|
9 | 9 | ;; Homepage: https://github.com/emacs-php/phpstan.el
|
10 |
| -;; Package-Requires: ((emacs "24.3") (compat "29") (php-mode "1.22.3") (php-runtime "0.2")) |
| 10 | +;; Package-Requires: ((emacs "25.1") (compat "29") (php-mode "1.22.3") (php-runtime "0.2")) |
11 | 11 | ;; License: GPL-3.0-or-later
|
12 | 12 |
|
13 | 13 | ;; This program is free software; you can redistribute it and/or modify
|
|
56 | 56 | (require 'cl-lib)
|
57 | 57 | (require 'php-project)
|
58 | 58 | (require 'php-runtime)
|
| 59 | +(require 'seq) |
59 | 60 |
|
60 | 61 | (eval-when-compile
|
61 | 62 | (require 'compat nil t)
|
@@ -154,8 +155,19 @@ have unexpected behaviors or performance implications."
|
154 | 155 | :type '(cons string string)
|
155 | 156 | :group 'phpstan)
|
156 | 157 |
|
| 158 | +(defcustom phpstan-disable-buffer-errors nil |
| 159 | + "If T, don't keep errors per buffer to save memory." |
| 160 | + :type 'boolean |
| 161 | + :group 'phpstan) |
| 162 | + |
| 163 | +(defcustom phpstan-not-ignorable-identifiers '("ignore.parseError") |
| 164 | + "A list of identifiers that are prohibited from being added to the @phpstan-ignore tag." |
| 165 | + :type '(repeat string)) |
| 166 | + |
157 | 167 | (defvar-local phpstan--use-xdebug-option nil)
|
158 | 168 |
|
| 169 | +(defvar-local phpstan--ignorable-errors '()) |
| 170 | + |
159 | 171 | ;;;###autoload
|
160 | 172 | (progn
|
161 | 173 | (defvar phpstan-working-dir nil
|
|
271 | 283 | (and (stringp (car v)) (listp (cdr v))))
|
272 | 284 | (or (eq 'docker v) (null v) (stringp v))))))
|
273 | 285 |
|
| 286 | +;; Utilities: |
| 287 | +(defun phpstan--plist-to-alist (plist) |
| 288 | + "Convert PLIST to association list." |
| 289 | + (let (alist) |
| 290 | + (while plist |
| 291 | + (push (cons (substring-no-properties (symbol-name (pop plist)) 1) (pop plist)) alist)) |
| 292 | + (nreverse alist))) |
| 293 | + |
| 294 | +(defsubst phpstan--current-line () |
| 295 | + "Return the current buffer line at point. The first line is 1." |
| 296 | + (line-number-at-pos nil t)) |
| 297 | + |
274 | 298 | ;; Functions:
|
275 | 299 | (defun phpstan-get-working-dir ()
|
276 | 300 | "Return path to working directory of PHPStan."
|
@@ -489,6 +513,85 @@ it returns the value of `SOURCE' as it is."
|
489 | 513 | options
|
490 | 514 | (and args (cons "--" args)))))
|
491 | 515 |
|
| 516 | +(defun phpstan-update-ignorebale-errors-from-json-buffer (errors) |
| 517 | + "Update `phpstan--ignorable-errors' variable by ERRORS." |
| 518 | + (let ((identifiers |
| 519 | + (cl-loop for (_ . entry) in errors |
| 520 | + append (cl-loop for message in (plist-get entry :messages) |
| 521 | + if (plist-get message :ignorable) |
| 522 | + collect (cons (plist-get message :line) |
| 523 | + (plist-get message :identifier)))))) |
| 524 | + (setq phpstan--ignorable-errors |
| 525 | + (mapcar (lambda (v) (cons (car v) (mapcar #'cdr (cdr v)))) (seq-group-by #'car identifiers))))) |
| 526 | + |
| 527 | +(defconst phpstan--re-ignore-tag |
| 528 | + (eval-when-compile |
| 529 | + (rx (* (syntax whitespace)) "//" (* (syntax whitespace)) |
| 530 | + (group "@phpstan-ignore") |
| 531 | + (* (syntax whitespace)) |
| 532 | + (* (not "(")) |
| 533 | + (group (? (+ (syntax whitespace) "(")))))) |
| 534 | + |
| 535 | +(cl-defun phpstan--check-existing-ignore-tag (&key in-previous) |
| 536 | + "Check existing @phpstan-ignore PHPDoc tag. |
| 537 | +If IN-PREVIOUS is NIL, check the previous line for the tag." |
| 538 | + (let ((new-position (if in-previous 'previous-line 'this-line)) |
| 539 | + (line-end (line-end-position)) |
| 540 | + new-point append) |
| 541 | + (save-excursion |
| 542 | + (save-match-data |
| 543 | + (if (re-search-forward phpstan--re-ignore-tag line-end t) |
| 544 | + (progn |
| 545 | + (setq new-point (match-beginning 2)) |
| 546 | + (goto-char new-point) |
| 547 | + (when (eq (char-syntax (char-before)) ?\ ) |
| 548 | + (left-char) |
| 549 | + (setq new-point (point))) |
| 550 | + (setq append (not (eq (match-end 1) (match-beginning 2)))) |
| 551 | + (cl-values new-position new-point append)) |
| 552 | + (if in-previous |
| 553 | + (cl-values nil nil nil) |
| 554 | + (previous-logical-line) |
| 555 | + (beginning-of-line) |
| 556 | + (phpstan--check-existing-ignore-tag :in-previous t))))))) |
| 557 | + |
| 558 | +;;;###autoload |
| 559 | +(defun phpstan-insert-ignore (position) |
| 560 | + "Insert an @phpstan-ignore comment at the specified POSITION. |
| 561 | +
|
| 562 | +POSITION determines where to insert the comment and can be either `this-line' or |
| 563 | +`previous-line'. |
| 564 | +
|
| 565 | +- If POSITION is `this-line', the comment is inserted at the end of |
| 566 | + the current line. |
| 567 | +- If POSITION is `previous-line', the comment is inserted on a new line above |
| 568 | + the current line." |
| 569 | + (interactive |
| 570 | + (list (if current-prefix-arg 'this-line 'previous-line))) |
| 571 | + (save-restriction |
| 572 | + (widen) |
| 573 | + (let ((pos (point)) |
| 574 | + (identifiers (cl-set-difference (alist-get (phpstan--current-line) phpstan--ignorable-errors) phpstan-not-ignorable-identifiers :test #'equal)) |
| 575 | + (padding (if (eq position 'this-line) " " "")) |
| 576 | + new-position new-point delete-region) |
| 577 | + (cl-multiple-value-setq (new-position new-point append) (phpstan--check-existing-ignore-tag :in-previous nil)) |
| 578 | + (when new-position |
| 579 | + (setq position new-position)) |
| 580 | + (unless (and append (null identifiers)) |
| 581 | + (if (not new-point) |
| 582 | + (cond |
| 583 | + ((eq position 'this-line) (end-of-line)) |
| 584 | + ((eq position 'previous-line) (progn |
| 585 | + (previous-logical-line) |
| 586 | + (end-of-line) |
| 587 | + (newline-and-indent))) |
| 588 | + ((error "Unexpected position: %s" position))) |
| 589 | + (setq padding "") |
| 590 | + (goto-char new-point)) |
| 591 | + (insert (concat padding |
| 592 | + (if new-position (if append ", " " ") "// @phpstan-ignore ") |
| 593 | + (mapconcat #'identity identifiers ", "))))))) |
| 594 | + |
492 | 595 | ;;;###autoload
|
493 | 596 | (defun phpstan-insert-dumptype (&optional expression prefix-num)
|
494 | 597 | "Insert PHPStan\\dumpType() expression-statement by EXPRESSION and PREFIX-NUM."
|
|
0 commit comments