From 11d1c65dd397220c8cb5f47182c0e3b1915e067c Mon Sep 17 00:00:00 2001 From: USAMI Kenta <tadsan@zonu.me> Date: Mon, 10 May 2021 04:34:21 +0900 Subject: [PATCH 1/4] Improve php-imenu-generic-expression The old list had duplicate items and lacked an index of modern syntax elements. Modern PHP code focuses on building one class per file. (PSR-4) --- CHANGELOG.md | 11 ++++ lisp/php.el | 113 +++++++++++++++++++++++++++-------------- tests/php-mode-test.el | 9 ++-- 3 files changed, 90 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f2a6446..27450d1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,17 @@ All notable changes of the PHP Mode 1.19.1 release series are documented in this * Support new PHP 8.0 and 8.1 syntax hilighting and indentation * [8.0] `#[Attributes]` + * Add `php-imenu-generic-expression-default` for default value or `php-imenu-generic-expression` + +### Changed + + * Re-organized `php-imenu-generic-expression` + * Added `Import`, `Constants` and `Properties` + * Removed `Anonymous Functions` + * Renamed `Named Functions` to `Functions` + * Renamed `All Methods` to `Methods` + * Removed `Public Methods`, `Protected Methods` and `Provate Methods` + * Unified `Classes`, `Traits`, `Interfaces` into `Classes` ## [1.24.0] - 2021-03-07 diff --git a/lisp/php.el b/lisp/php.el index 3cc23cfe..fcb82868 100644 --- a/lisp/php.el +++ b/lisp/php.el @@ -227,7 +227,7 @@ it is the character that will terminate the string, or t if the string should be "Regular expression for a PHP function.") (eval-when-compile - (defun php-create-regexp-for-method (&optional visibility) + (cl-defun php-create-regexp-for-method (&optional visibility &key include-args) "Make a regular expression for methods with the given VISIBILITY. VISIBILITY must be a string that names the visibility for a PHP @@ -242,22 +242,25 @@ which will be the name of the method." (setq visibility (list visibility))) (rx-to-string `(: line-start (* (syntax whitespace)) - ,@(if visibility - `((* (or "abstract" "final" "static") - (+ (syntax whitespace))) - (or ,@visibility) - (+ (syntax whitespace)) - (* (or "abstract" "final" "static") - (+ (syntax whitespace)))) - '((* (* (or "abstract" "final" "static" - "private" "protected" "public") - (+ (syntax whitespace)))))) - "function" - (+ (syntax whitespace)) - (? "&" (* (syntax whitespace))) - (group (+ (or (syntax word) (syntax symbol)))) - (* (syntax whitespace)) - "("))) + (group + ,@(if visibility + `((* (or "abstract" "final" "static") + (+ (syntax whitespace))) + (or ,@visibility) + (+ (syntax whitespace)) + (* (or "abstract" "final" "static") + (+ (syntax whitespace)))) + '((* (* (or "abstract" "final" "static" + "private" "protected" "public") + (+ (syntax whitespace)))))) + "function" + (+ (syntax whitespace)) + (? "&" (* (syntax whitespace))) + (group (+ (or (syntax word) (syntax symbol)))) + (* (syntax whitespace)) + "(" + ,@(when include-args + '((* any) line-end)))))) (defun php-create-regexp-for-classlike (type) "Accepts a `TYPE' of a 'classlike' object as a string, such as @@ -275,30 +278,66 @@ can be used to match against definitions for that classlike." ;; this is not necessarily correct for all values of `type'. "\\s-+\\(\\(?:\\sw\\|\\\\\\|\\s_\\)+\\)"))) -(defconst php-imenu-generic-expression +(defconst php-imenu-generic-expression-default (eval-when-compile - `(("Namespaces" - ,(php-create-regexp-for-classlike "namespace") 1) + `(("Methods" + ,(php-create-regexp-for-method nil :include-args t) 1) + ("Properties" + ,(rx line-start + (* (syntax whitespace)) + (group + (+ (or "public" "protected" "private" "static" "var") + (+ (syntax whitespace))) + (* (? (? (or "|" "?")) + (or "\\" (syntax word) (syntax symbol)) + (+ (syntax whitespace)))) + "$" (+ (or (syntax word) (syntax symbol))) + word-boundary)) + 1) + ("Constants" + ,(rx line-start + (* (syntax whitespace)) + (group + (* (or "public" "protected" "private") + (+ (syntax whitespace))) + "const" + (+ (syntax whitespace)) + (+ (or (syntax word) (syntax symbol))) + (* (syntax whitespace)) + (? "=" (* (syntax whitespace)) + (repeat 0 40 any)))) + 1) + ("Functions" + ,(rx line-start + (* (syntax whitespace)) + (group + "function" + (+ (syntax whitespace)) + (+ (or (syntax word) (syntax symbol))) + (* (syntax whitespace)) + "(" + (repeat 0 100 any))) + 1) + ("Import" + ,(rx line-start + ;; (* (syntax whitespace)) + (group + "use" + (+ (syntax whitespace)) + (repeat 0 100 any))) + 1) ("Classes" - ,(php-create-regexp-for-classlike "class") 1) - ("Interfaces" - ,(php-create-regexp-for-classlike "interface") 1) - ("Traits" - ,(php-create-regexp-for-classlike "trait") 1) - ("All Methods" - ,(php-create-regexp-for-method) 1) - ("Private Methods" - ,(php-create-regexp-for-method '("private")) 1) - ("Protected Methods" - ,(php-create-regexp-for-method '("protected")) 1) - ("Public Methods" - ,(php-create-regexp-for-method '("public")) 1) - ("Anonymous Functions" - "\\<\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*=\\s-*f\\(unctio\\)?n\\s-*(" 1) - ("Named Functions" - "^\\s-*function\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" 1))) + ,(php-create-regexp-for-classlike "\\(?:class\\|interface\\|trait\\|enum\\)") 0) + ("Namespace" + ,(php-create-regexp-for-classlike "namespace") 1))) "Imenu generic expression for PHP Mode. See `imenu-generic-expression'.") +(defcustom php-imenu-generic-expression php-imenu-generic-expression-default + "Default Imenu generic expression for PHP Mode. See `imenu-generic-expression'." + :type '(alist :key-type string + :value-type list) + :group 'php) + (defconst php--re-namespace-pattern (eval-when-compile (php-create-regexp-for-classlike "namespace"))) diff --git a/tests/php-mode-test.el b/tests/php-mode-test.el index c53da223..ebce565f 100644 --- a/tests/php-mode-test.el +++ b/tests/php-mode-test.el @@ -319,12 +319,9 @@ style from Drupal." "All static method should appear on imenu whether 'static' keyword is placed before or after visibility" (with-php-mode-test ("issue-83.php") (let* ((index-alist (imenu--make-index-alist)) - (public-methods (mapcar 'car (cdr (assoc "Public Methods" index-alist)))) - (all-methods (mapcar 'car (cdr (assoc "All Methods" index-alist))))) - (should (member "staticBeforeVisibility" public-methods)) - (should (member "staticBeforeVisibility" all-methods)) - (should (member "staticAfterVisibility" public-methods)) - (should (member "staticAfterVisibility" all-methods))))) + (all-methods (mapcar 'car (cdr (assoc "Methods" index-alist))))) + (should (member "static public function staticBeforeVisibility()" all-methods)) + (should (member "public static function staticAfterVisibility()" all-methods))))) (ert-deftest php-mode-test-issue-99 () "Proper indentation for 'foreach' statements without braces." From d4b7076ad5ccf026a7342cbfe0c6bcb14d663e39 Mon Sep 17 00:00:00 2001 From: USAMI Kenta <tadsan@zonu.me> Date: Mon, 10 May 2021 05:11:13 +0900 Subject: [PATCH 2/4] Add php-imenu-generic-expression-simple and php-imenu-generic-expression-legacy --- CHANGELOG.md | 2 ++ lisp/php.el | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27450d1f..d7779fe4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ All notable changes of the PHP Mode 1.19.1 release series are documented in this * Support new PHP 8.0 and 8.1 syntax hilighting and indentation * [8.0] `#[Attributes]` * Add `php-imenu-generic-expression-default` for default value or `php-imenu-generic-expression` + * Add `php-imenu-generic-expression-legacy` for compatibility + * Add `php-imenu-generic-expression-simple` for simple display ### Changed diff --git a/lisp/php.el b/lisp/php.el index fcb82868..46ac047f 100644 --- a/lisp/php.el +++ b/lisp/php.el @@ -332,6 +332,70 @@ can be used to match against definitions for that classlike." ,(php-create-regexp-for-classlike "namespace") 1))) "Imenu generic expression for PHP Mode. See `imenu-generic-expression'.") +(defconst php-imenu-generic-expression-simple + (eval-when-compile + `(("Methods" + ,(php-create-regexp-for-method nil) 2) + ("Properties" + ,(rx line-start + (* (syntax whitespace)) + (+ (or "public" "protected" "private" "static" "var") + (+ (syntax whitespace))) + (* (? (? (or "|" "?")) + (or "\\" (syntax word) (syntax symbol)) + (+ (syntax whitespace)))) + (group + "$" (+ (or (syntax word) (syntax symbol)))) + word-boundary) + 1) + ("Constants" + ,(rx line-start + (* (syntax whitespace)) + (group + (* (or "public" "protected" "private") + (+ (syntax whitespace))) + "const" + (+ (syntax whitespace)) + (+ (or (syntax word) (syntax symbol))))) + 1) + ("Functions" + ,(rx line-start + (* (syntax whitespace)) + "function" + (+ (syntax whitespace)) + (group + (+ (or (syntax word) (syntax symbol))))) + 1) + ("Classes" + ,(php-create-regexp-for-classlike "\\(?:class\\|interface\\|trait\\|enum\\)") 1) + ("Namespace" + ,(php-create-regexp-for-classlike "namespace") 1))) + "Imenu generic expression for PHP Mode. See `imenu-generic-expression'.") + +(defconst php-imenu-generic-expression-legacy + (eval-when-compile + `(("Namespaces" + ,(php-create-regexp-for-classlike "namespace") 1) + ("Classes" + ,(php-create-regexp-for-classlike "class") 1) + ("Interfaces" + ,(php-create-regexp-for-classlike "interface") 1) + ("Traits" + ,(php-create-regexp-for-classlike "trait") 1) + ("All Methods" + ,(php-create-regexp-for-method) 1) + ("Private Methods" + ,(php-create-regexp-for-method '("private")) 2) + ("Protected Methods" + ,(php-create-regexp-for-method '("protected")) 2) + ("Public Methods" + ,(php-create-regexp-for-method '("public")) 2) + ("Anonymous Functions" + "\\<\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*=\\s-*f\\(unctio\\)?n\\s-*(" 1) + ("Named Functions" + "^\\s-*function\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" 1))) + "Imenu generic expression for PHP Mode. See `imenu-generic-expression'.") + (defcustom php-imenu-generic-expression php-imenu-generic-expression-default "Default Imenu generic expression for PHP Mode. See `imenu-generic-expression'." :type '(alist :key-type string From c1843b1463bd7ad93f2402be5a8420c054055a7b Mon Sep 17 00:00:00 2001 From: USAMI Kenta <tadsan@zonu.me> Date: Mon, 10 May 2021 05:24:16 +0900 Subject: [PATCH 3/4] Separate the dependency of make test on .cask --- .github/workflows/test.yml | 2 +- Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 25d4be7d..4eb8d06e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,7 +37,7 @@ jobs: - uses: actions/checkout@v2 - name: Run tests if: matrix.allow_failure != true - run: 'make test' + run: 'make .cask test' - name: Run tests (allow failure) if: matrix.allow_failure == true run: 'make test || true' diff --git a/Makefile b/Makefile index c495e2d6..e27eeca3 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,7 @@ dev: # # for an example of using a script like this with the 'git bisect run' # command. -test: .cask clean all +test: clean all touch tests/project/1/.git $(EMACS) -Q -batch -L lisp/ --eval \ "(let ((default-directory (expand-file-name \".cask\" default-directory))) \ From 0817e36fb4153f8f3cc7311b5b1c4d452758b688 Mon Sep 17 00:00:00 2001 From: USAMI Kenta <tadsan@zonu.me> Date: Mon, 10 May 2021 21:46:48 +0900 Subject: [PATCH 4/4] Make php-imenu-generic-expression accept symbol of variable name --- lisp/php-mode.el | 4 +++- lisp/php.el | 8 +++++--- tests/php-mode-test.el | 6 ++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/lisp/php-mode.el b/lisp/php-mode.el index e35b688f..4a53a960 100644 --- a/lisp/php-mode.el +++ b/lisp/php-mode.el @@ -1195,7 +1195,9 @@ After setting the stylevars run hooks according to STYLENAME (add-hook 'syntax-propertize-extend-region-functions #'php-syntax-propertize-extend-region t t) - (setq imenu-generic-expression php-imenu-generic-expression) + (setq imenu-generic-expression (if (symbolp php-imenu-generic-expression) + (symbol-value php-imenu-generic-expression) + php-imenu-generic-expression)) ;; PHP vars are case-sensitive (setq case-fold-search t) diff --git a/lisp/php.el b/lisp/php.el index 46ac047f..0ae6d342 100644 --- a/lisp/php.el +++ b/lisp/php.el @@ -396,10 +396,12 @@ can be used to match against definitions for that classlike." "^\\s-*function\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" 1))) "Imenu generic expression for PHP Mode. See `imenu-generic-expression'.") -(defcustom php-imenu-generic-expression php-imenu-generic-expression-default +(defcustom php-imenu-generic-expression 'php-imenu-generic-expression-default "Default Imenu generic expression for PHP Mode. See `imenu-generic-expression'." - :type '(alist :key-type string - :value-type list) + :type '(choice (alist :key-type string :value-type list) + (const 'php-imenu-generic-expression-legacy) + (const 'php-imenu-generic-expression-simple) + variable) :group 'php) (defconst php--re-namespace-pattern diff --git a/tests/php-mode-test.el b/tests/php-mode-test.el index ebce565f..9ee41647 100644 --- a/tests/php-mode-test.el +++ b/tests/php-mode-test.el @@ -320,8 +320,10 @@ style from Drupal." (with-php-mode-test ("issue-83.php") (let* ((index-alist (imenu--make-index-alist)) (all-methods (mapcar 'car (cdr (assoc "Methods" index-alist))))) - (should (member "static public function staticBeforeVisibility()" all-methods)) - (should (member "public static function staticAfterVisibility()" all-methods))))) + (should (equal all-methods + (list + "static public function staticBeforeVisibility()" + "public static function staticAfterVisibility()")))))) (ert-deftest php-mode-test-issue-99 () "Proper indentation for 'foreach' statements without braces."