From c3cc4c999e5427d7a0ec9fba5531c998707570c1 Mon Sep 17 00:00:00 2001 From: USAMI Kenta Date: Fri, 17 Jul 2026 03:01:07 +0900 Subject: [PATCH] Add php-pipe-op face for the PHP 8.5 pipe operator The pipe operator came out half-fontified. No rule matched `|>', so the comparison-operator matcher -- whose `[<>]=?' alternative claims a bare `>' -- took the second character and left the first one plain: '|' -> nil '>' -> php-comparison-op Give it a face of its own. php-pipe-op inherits php-operator like the rest of the operator faces, and its rule sits ahead of the comparison operators so it wins the `>'. The rule is deliberately narrow (`|>' only), so nothing else moves: `||', `>=', `>', `===', `<=>', `=>' and a bare `|' all keep the faces they had. A test pins that down alongside the pipe itself. See https://www.php.net/releases/8.5/en.php --- lisp/php-face.el | 5 +++++ lisp/php-mode.el | 5 +++++ tests/php-mode-test.el | 30 ++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/lisp/php-face.el b/lisp/php-face.el index 15395fb2..85aa38dd 100644 --- a/lisp/php-face.el +++ b/lisp/php-face.el @@ -126,6 +126,11 @@ "PHP Mode face used to object operators (->)." :tag "PHP Object Op") +(defface php-pipe-op '((t (:inherit php-operator))) + "PHP Mode face used to the pipe operator (|>). +The operator was added in PHP 8.5." + :tag "PHP Pipe Op") + (defface php-paamayim-nekudotayim '((t ())) "PHP Mode face used to highlight scope resolution operators (::). The operator is also knows as \"Paamayim Nekudotayim\"." diff --git a/lisp/php-mode.el b/lisp/php-mode.el index 4b050d24..4fd23b29 100644 --- a/lisp/php-mode.el +++ b/lisp/php-mode.el @@ -1518,6 +1518,11 @@ for \\[find-tag] (which see)." ;; Assignment operators (=, +=, ...) ("\\([^=]+?\\([\-+./%]?=\\)[^=) --- PHP 8.5. Must precede the comparison + ;; operators, whose `[<>]=?' alternative would otherwise claim the + ;; `>' and leave the `|' unfontified. + ("\\(|>\\)" 1 'php-pipe-op) + ;; Comparison operators (==, ===, >=, ...) ("\\([!=]=\\{1,2\\}[>]?\\|[<>]=?\\)" 1 'php-comparison-op) diff --git a/tests/php-mode-test.el b/tests/php-mode-test.el index 09a33754..1d5ef11f 100644 --- a/tests/php-mode-test.el +++ b/tests/php-mode-test.el @@ -803,6 +803,36 @@ path; sending those to an HTML mode would take most PHP files away from "Test highlighting language constructs added in PHP 8.4." (with-php-mode-test ("8.4/property-hooks.php" :faces t))) +(defun php-mode-test--faces-of (code token) + "Return the list of faces on TOKEN's characters after fontifying CODE." + (with-temp-buffer + (insert code) + (php-mode) + (font-lock-ensure) + (goto-char (point-min)) + (should (search-forward token nil t)) + (let ((start (- (point) (length token)))) + (mapcar (lambda (i) (get-text-property (+ start i) 'face)) + (number-sequence 0 (1- (length token))))))) + +(ert-deftest php-mode-test-php85-pipe-op () + "The PHP 8.5 pipe operator is fontified as `php-pipe-op'. + +Both characters must get the face. The comparison-operator matcher +claims a bare `>', so without a rule of its own `|>' came out +half-fontified: the `|' plain and the `>' as `php-comparison-op'." + (should (equal '(php-pipe-op php-pipe-op) + (php-mode-test--faces-of " trim(...);\n" "|>"))) + ;; Operators that the new rule must not steal from. + (dolist (probe '(("= $c;\n" ">=" (php-comparison-op php-comparison-op)) + (" $c;\n" ">" (php-comparison-op)) + (" $c;\n" "<=>" (php-comparison-op php-comparison-op php-comparison-op)) + ("