branch: elpa/php-mode
commit 8293aea4328329bfea03ad3b581810efde2f64e0
Author: USAMI Kenta <[email protected]>
Commit: USAMI Kenta <[email protected]>

    Fix closure body indentation on Emacs 31+
    
    CC Mode >= 31 (the change for bug#19867) no longer treats a brace block
    whose contents are inconclusive -- e.g. a closure body whose first line
    is only a comment -- as a statement block.  `c-looking-at-statement-block'
    now falls back to context analysis, and for an anonymous PHP `function
    () {...}' the token before the parameter list is the `function' keyword
    rather than a function-name identifier, so the body is misclassified as a
    brace list.  This mis-indents both the body and its closing brace (the
    `lang/function/closure.php' indentation test fails on Emacs 31/32 but
    passes on 30.2).
    
    Advise `c-looking-at-statement-block' to report a closure-opening brace
    as a statement block.  A closure body always is one, so this is also
    correct on Emacs versions unaffected by the change.
---
 lisp/php-mode.el | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/lisp/php-mode.el b/lisp/php-mode.el
index bae38fc0fb..c844f93db4 100644
--- a/lisp/php-mode.el
+++ b/lisp/php-mode.el
@@ -681,6 +681,57 @@ a backward search limit."
         (cons (point) t))))
    (t nil)))
 
+(defun php-mode--anonymous-function-brace-p (pos)
+  "Return non-nil when the opening brace at POS starts a closure body.
+
+POS must be the position of a `{'.  A closure is an anonymous
+`function (...) [use (...)] [: type] {' expression; named function
+declarations and other constructs (e.g. `match', `if') return nil."
+  (save-excursion
+    (goto-char pos)
+    (c-backward-syntactic-ws)
+    ;; Step back over an optional return type declaration `): Type {' so
+    ;; that point lands just after the parameter (or `use') list's `)'.
+    (unless (eq (char-before) ?\))
+      (let ((colon (save-excursion
+                     (skip-chars-backward "^):;{}(" (point-min))
+                     (and (eq (char-before) ?:) (1- (point))))))
+        (when colon
+          (goto-char colon)
+          (c-backward-syntactic-ws))))
+    ;; Walk backwards over the `)...(' list(s): the parameter list, plus an
+    ;; optional `use (...)' clause, until we reach `function' or give up.
+    (let ((result nil) (continue t))
+      (while (and continue (eq (char-before) ?\)))
+        (condition-case nil
+            (backward-list)
+          (error (setq continue nil)))
+        (when continue
+          (c-backward-syntactic-ws)
+          (if (zerop (c-backward-token-2))
+              (cond
+               ((looking-at-p "\\_<function\\_>") (setq result t continue nil))
+               ((looking-at-p "\\_<use\\_>") (c-backward-syntactic-ws))
+               (t (setq continue nil)))
+            (setq continue nil))))
+      result)))
+
+(defun php-c-looking-at-statement-block (orig-fun &rest args)
+  "Treat a closure body as a statement block around 
`c-looking-at-statement-block'.
+
+Emacs' CC Mode >= 31 (the change for bug#19867) fails to recognize an
+anonymous function body whose first line is a comment as a statement
+block, and reports it as a brace list, mis-indenting both the body and
+its closing brace.  When point is at the opening brace of such a closure,
+return non-nil; otherwise fall back to ORIG-FUN with ARGS.
+
+A closure body is always a statement block, so this is also correct on
+Emacs versions unaffected by the bug."
+  (or (and (derived-mode-p 'php-mode)
+           (eq (char-after) ?\{)
+           (php-mode--anonymous-function-brace-p (point)))
+      (apply orig-fun args)))
+
 (c-add-style
  "php"
  `((c-basic-offset . 4)
@@ -1256,6 +1307,9 @@ After setting the stylevars run hook 
`php-mode-STYLENAME-hook'."
 
   (advice-add 'c-looking-at-or-maybe-in-bracelist
               :around 'php-c-looking-at-or-maybe-in-bracelist)
+  (when (fboundp 'c-looking-at-statement-block)
+    (advice-add 'c-looking-at-statement-block
+                :around 'php-c-looking-at-statement-block))
   (advice-add 'fixup-whitespace :after #'php-mode--fixup-whitespace-after)
 
   (advice-add 'acm-backend-tabnine-candidate-expand

Reply via email to