* bug#73779: 30.0.91; [PATCH] php-ts-mode: Better indentation and font locking, support for the latest grammar version.
@ 2024-10-12 20:12 Vincenzo Pupillo
2024-10-13 4:59 ` Eli Zaretskii
0 siblings, 1 reply; 6+ messages in thread
From: Vincenzo Pupillo @ 2024-10-12 20:12 UTC (permalink / raw)
To: 73779
[-- Attachment #1: Type: text/plain, Size: 412 bytes --]
Ciao,
this patch corrects the indentation of the control structure without closing
brackets (or without the end keyword... in the case of the alternative
syntax). It supports font locking of the “asymmetric property visibility ”
introduced with grammar v0.23.3 and so-called magic methods. And others small
fix. And others small bug I discovered while writing the tests..
Thank you.
Vincenzo
[-- Attachment #2: 0001-Fix-php-ts-mode-better-indentation-and-font-locking.patch --]
[-- Type: text/x-patch, Size: 14768 bytes --]
From 5164e387c395d64b49a851b179ed92847a1cfd93 Mon Sep 17 00:00:00 2001
From: Vincenzo Pupillo <v.pupillo@gmail.com>
Date: Thu, 10 Oct 2024 16:06:37 +0200
Subject: [PATCH] Fix php-ts-mode better indentation and font locking.
Incomplete compound_statement or colon_block (statement-group without a
closing brace or closing keyword) that are not inside a function or
method are not recognized as such by tree-sitter-php.
A new function 'php-ts-mode--open-statement-group-heuristic' handles
this case. Font locking of magic methods and better support for
alternative control structure syntax.
Support for latest grammar version.
* lisp/progmodes/php-ts-mode.el
(php-ts-mode--language-source-alist): Updated grammar version.
(php-ts-mode--possibly-braceless-keyword-re): Regular expression for
braceles keyword.
(php-ts-mode--open-statement-group-heuristic): New function.
(php-ts-mode--parent-html-bol): Use the new function and doc fix.
(php-ts-mode--parent-html-heuristic): Use the new function and doc fix.
(php-ts-mode--indent-styles): Use the new function and add 'colon_block'
support.
(php-ts-mode--class-magic-methods): New predefined magic methods list.
(php-ts-mode--test-namespace-name-as-prefix-p): Doc fix.
(php-ts-mode--test-namespace-aliasing-clause-p): Fix the test and doc.
(php-ts-mode--test-namespace-use-group-clause-p): Doc fix.
(php-ts-mode--test-visibility-modifier-operation-clause-p): New function
for the new asymmetric property visibility feature of PHP 8.4.
(php-ts-mode--font-lock-settings): Font lock for class magic methods and
alternative syntax. Better font lock for 'instanceof'. Use
'font-lock-function-call-face' for scoped and member call expression.
---
lisp/progmodes/php-ts-mode.el | 164 +++++++++++++++++++++++-----------
1 file changed, 110 insertions(+), 54 deletions(-)
diff --git a/lisp/progmodes/php-ts-mode.el b/lisp/progmodes/php-ts-mode.el
index d2559e5a45f..f1c33750f47 100644
--- a/lisp/progmodes/php-ts-mode.el
+++ b/lisp/progmodes/php-ts-mode.el
@@ -84,7 +84,7 @@
;;; Install treesitter language parsers
(defvar php-ts-mode--language-source-alist
- '((php . ("https://github.com/tree-sitter/tree-sitter-php" "v0.23.0" "php/src"))
+ '((php . ("https://github.com/tree-sitter/tree-sitter-php" "v0.23.4" "php/src"))
(phpdoc . ("https://github.com/claytonrcarter/tree-sitter-phpdoc"))
(html . ("https://github.com/tree-sitter/tree-sitter-html" "v0.23.0"))
(javascript . ("https://github.com/tree-sitter/tree-sitter-javascript" "v0.23.0"))
@@ -428,6 +428,27 @@ php-ts-mode--syntax-table
\f
;;; Indent
+(defconst php-ts-mode--possibly-braceless-keyword-re
+ (concat "\\_<" (regexp-opt '("if" "for" "foreach" "while" "do") t) "\\_>")
+ "Regexp matching keywords optionally followed by an opening brace.")
+
+(defun php-ts-mode--open-statement-group-heuristic (node parent bol &rest _)
+ "Heuristic matcher for statement-group without closing bracket.
+
+Return `php-ts-mode-indent-offset' plus 1 when BOL is after
+`php-ts-mode--possibly-braceless-keyword-re', otherwise return 0. It's
+usefull for matching incomplete compound_statement or colon_block.
+PARENT is NODE's parent, BOL is the beginning of non-whitespace
+characters of the current line."
+ (and (null node)
+ (save-excursion
+ (forward-line -1)
+ (if (re-search-forward
+ php-ts-mode--possibly-braceless-keyword-re
+ bol t)
+ (+ 1 php-ts-mode-indent-offset)
+ 0))))
+
;; taken from c-ts-mode
(defun php-ts-mode--else-heuristic (node parent bol &rest _)
"Heuristic matcher for when \"else\" is followed by a closing bracket.
@@ -478,40 +499,47 @@ php-ts-mode--parent-eol
(defun php-ts-mode--parent-html-bol (node parent _bol &rest _)
"Find the first non-space characters of the HTML tags before NODE.
+When NODE is nil call `php-ts-mode--open-statement-group-heuristic'.
PARENT is NODE's parent, BOL is the beginning of non-whitespace
characters of the current line."
- (save-excursion
- (let ((html-node (treesit-search-forward node "text" t)))
- (if html-node
- (let ((end-html (treesit-node-end html-node)))
- (goto-char end-html)
- (backward-word)
- (back-to-indentation)
- (point))
- (treesit-node-start parent)))))
+ (if (null node)
+ ;; If NODE is nil it could be an open statement-group.
+ (php-ts-mode--open-statement-group-heuristic node parent _bol)
+ (save-excursion
+ (let ((html-node (treesit-search-forward node "text" t)))
+ (if html-node
+ (let ((end-html (treesit-node-end html-node)))
+ (goto-char end-html)
+ (backward-word)
+ (back-to-indentation)
+ (point))
+ (treesit-node-start parent))))))
(defun php-ts-mode--parent-html-heuristic (node parent _bol &rest _)
"Return position based on html indentation.
Returns 0 if the NODE is after the </html>, otherwise returns the
-indentation point of the last word before the NODE, plus the
-indentation offset. If there is no HTML tag, it returns the beginning
-of the parent.
+indentation point of the last word before the NODE, plus the indentation
+offset. If there is no HTML tag, it returns the beginning of the
+parent. When NODE is nil call `php-ts-mode--open-statement-group-heuristic'.
It can be used when you want to indent PHP code relative to the HTML.
PARENT is NODE's parent, BOL is the beginning of non-whitespace
characters of the current line."
- (let ((html-node (treesit-search-forward node "text" t)))
- (if html-node
- (let ((end-html (treesit-node-end html-node)))
- (save-excursion
- (goto-char end-html)
- (backward-word)
- (back-to-indentation)
- (if (search-forward "</html>" end-html t 1)
- 0
- (+ (point) php-ts-mode-indent-offset))))
- ;; Maybe it's better to use bol?
- (treesit-node-start parent))))
+ (if (null node)
+ ;; If NODE is nil it could be an open statement-group.
+ (php-ts-mode--open-statement-group-heuristic node parent _bol)
+ (let ((html-node (treesit-search-forward node "text" t)))
+ (if html-node
+ (let ((end-html (treesit-node-end html-node)))
+ (save-excursion
+ (goto-char end-html)
+ (backward-word)
+ (back-to-indentation)
+ (if (search-forward "</html>" end-html t 1)
+ 0
+ (+ (point) php-ts-mode-indent-offset))))
+ ;; Maybe it's better to use bol?
+ (treesit-node-start parent)))))
(defun php-ts-mode--array-element-heuristic (_node parent _bol &rest _)
"Return of the position of the first element of the array.
@@ -648,16 +676,22 @@ php-ts-mode--indent-styles
((parent-is "initializer_list") parent-bol php-ts-mode-indent-offset)
;; Statement in {} blocks.
- ((or (and (parent-is "compound_statement")
+ ((or (and (or (parent-is "compound_statement")
+ (parent-is "colon_block"))
;; If the previous sibling(s) are not on their
;; own line, indent as if this node is the first
;; sibling
php-ts-mode--first-sibling)
- (match null "compound_statement"))
+ (or (match null "compound_statement")
+ (match null "colon_block")))
standalone-parent php-ts-mode-indent-offset)
- ((parent-is "compound_statement") parent-bol php-ts-mode-indent-offset)
+ ((or (parent-is "compound_statement")
+ (parent-is "colon_block"))
+ parent-bol php-ts-mode-indent-offset)
;; Opening bracket.
- ((node-is "compound_statement") standalone-parent php-ts-mode-indent-offset)
+ ((or (node-is "compound_statement")
+ (node-is "colon_block"))
+ standalone-parent php-ts-mode-indent-offset)
((parent-is "match_block") parent-bol php-ts-mode-indent-offset)
((parent-is "switch_block") parent-bol 0)
@@ -667,6 +701,7 @@ php-ts-mode--indent-styles
;; rule for PHP alternative syntax
((or (node-is "else_if_clause")
(node-is "endif")
+ (node-is "endfor")
(node-is "endforeach")
(node-is "endwhile"))
parent-bol 0)
@@ -679,9 +714,13 @@ php-ts-mode--indent-styles
(parent-is "switch_statement")
(parent-is "case_statement")
(parent-is "empty_statement"))
- parent-bol php-ts-mode-indent-offset))))
+ parent-bol php-ts-mode-indent-offset)
+
+ ;; Workaround: handle "for" open statement group. Currently
+ ;; the grammar handles it differently than other control structures.
+ (no-node php-ts-mode--open-statement-group-heuristic 0))))
`((psr2
- ((parent-is "program") parent-bol 0)
+ ((parent-is "program") php-ts-mode--open-statement-group-heuristic 0)
((parent-is "text_interpolation") column-0 0)
((parent-is "function_call_expression") parent-bol php-ts-mode-indent-offset)
,@common)
@@ -774,21 +813,32 @@ php-ts-mode--predefined-constant
"__FUNCTION__" "__LINE__" "__METHOD__" "__NAMESPACE__" "__TRAIT__")
"PHP predefined constant.")
-(defun php-ts-mode--test-namespace-name-as-prefix-p ()
- "Return t if namespace_name_as_prefix keyword is a named node, nil otherwise."
+(defconst php-ts-mode--class-magic-methods
+ '("__construct" "__destruct" "__call" "__callStatic" "__get" "__set"
+ "__isset" "__unset" "__sleep" "__wakeup" "__serialize" "__unserialize"
+ "__toString" "__invoke" "__set_state" "__clone" "__debugInfo")
+ "PHP predefined magic methods.")
+
+(defun php-ts-mode--test-namespace-name-as-prefix-p ()
+ "Return t if namespace_name_as_prefix is a named node, nil otherwise."
(ignore-errors
(progn (treesit-query-compile 'php "(namespace_name_as_prefix)" t) t)))
-(defun php-ts-mode--test-namespace-aliasing-clause-p ()
- "Return t if namespace_name_as_prefix keyword is named node, nil otherwise."
+(defun php-ts-mode--test-namespace-aliasing-clause-p ()
+ "Return t if namespace_aliasing_clause is a named node, nil otherwise."
(ignore-errors
- (progn (treesit-query-compile 'php "(namespace_name_as_prefix)" t) t)))
+ (progn (treesit-query-compile 'php "(namespace_aliasing_clause)" t) t)))
(defun php-ts-mode--test-namespace-use-group-clause-p ()
- "Return t if namespace_use_group_clause keyword is named node, nil otherwise."
+ "Return t if namespace_use_group_clause is a named node, nil otherwise."
(ignore-errors
(progn (treesit-query-compile 'php "(namespace_use_group_clause)" t) t)))
+(defun php-ts-mode--test-visibility-modifier-operation-clause-p ()
+ "Return t if (visibility_modifier (operation)) is defined, nil otherwise."
+ (ignore-errors
+ (progn (treesit-query-compile 'php "(visibility_modifier (operation))" t) t)))
+
(defun php-ts-mode--font-lock-settings ()
"Tree-sitter font-lock settings."
(treesit-font-lock-rules
@@ -796,7 +846,10 @@ php-ts-mode--font-lock-settings
:language 'php
:feature 'keyword
:override t
- `([,@php-ts-mode--keywords] @font-lock-keyword-face)
+ `([,@php-ts-mode--keywords] @font-lock-keyword-face
+ ,@(when (php-ts-mode--test-visibility-modifier-operation-clause-p)
+ '((visibility_modifier (operation) @font-lock-builtin-face)))
+ (var_modifier) @font-lock-builtin-face)
:language 'php
:feature 'comment
@@ -826,7 +879,6 @@ php-ts-mode--font-lock-settings
(named_label_statement (name) @font-lock-constant-face))
:language 'php
- ;;:override t
:feature 'delimiter
`((["," ":" ";" "\\"]) @font-lock-delimiter-face)
@@ -850,7 +902,6 @@ php-ts-mode--font-lock-settings
:language 'php
:feature 'string
- ;;:override t
`(("\"") @font-lock-string-face
(encapsed_string) @font-lock-string-face
(string_content) @font-lock-string-face
@@ -892,32 +943,37 @@ php-ts-mode--font-lock-settings
name: (_) @font-lock-type-face)
(trait_declaration
name: (_) @font-lock-type-face)
- (property_declaration
- (visibility_modifier) @font-lock-keyword-face)
- (property_declaration
- (var_modifier) @font-lock-keyword-face)
(enum_declaration
name: (_) @font-lock-type-face)
(function_definition
name: (_) @font-lock-function-name-face)
(method_declaration
name: (_) @font-lock-function-name-face)
+ (method_declaration
+ name: (name) @font-lock-builtin-face
+ (:match ,(rx-to-string
+ `(: bos (or ,@php-ts-mode--class-magic-methods) eos))
+ @font-lock-builtin-face))
("=>") @font-lock-keyword-face
(object_creation_expression
(name) @font-lock-type-face)
,@(when (php-ts-mode--test-namespace-name-as-prefix-p)
- '((namespace_name_as_prefix "\\" @font-lock-delimiter-face)
- (namespace_name_as_prefix
- (namespace_name (name)) @font-lock-type-face)))
+ '((namespace_name_as_prefix "\\" @font-lock-delimiter-face)
+ (namespace_name_as_prefix
+ (namespace_name (name)) @font-lock-type-face)))
,@(if (php-ts-mode--test-namespace-aliasing-clause-p)
- '((namespace_aliasing_clause (name) @font-lock-type-face))
- '((namespace_use_clause alias: (name) @font-lock-type-face)))
+ '((namespace_aliasing_clause (name) @font-lock-type-face))
+ '((namespace_use_clause alias: (name) @font-lock-type-face)))
,@(when (not (php-ts-mode--test-namespace-use-group-clause-p))
- '((namespace_use_group
- (namespace_use_clause (name) @font-lock-type-face))))
+ '((namespace_use_group
+ (namespace_use_clause (name) @font-lock-type-face))))
(namespace_name "\\" @font-lock-delimiter-face)
(namespace_name (name) @font-lock-type-face)
- (use_declaration (name) @font-lock-property-use-face))
+ (use_declaration (name) @font-lock-property-use-face)
+ (use_instead_of_clause (name) @font-lock-type-face)
+ (binary_expression
+ operator: "instanceof"
+ right: (name) @font-lock-type-face))
:language 'php
:feature 'function-scope
@@ -932,9 +988,9 @@ php-ts-mode--font-lock-settings
'((function_call_expression
function: (name) @font-lock-function-call-face)
(scoped_call_expression
- name: (_) @font-lock-function-name-face)
+ name: (_) @font-lock-function-call-face)
(member_call_expression
- name: (_) @font-lock-function-name-face)
+ name: (_) @font-lock-function-call-face)
(nullsafe_member_call_expression
name: (_) @font-lock-constant-face))
--
2.47.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* bug#73779: 30.0.91; [PATCH] php-ts-mode: Better indentation and font locking, support for the latest grammar version.
2024-10-12 20:12 bug#73779: 30.0.91; [PATCH] php-ts-mode: Better indentation and font locking, support for the latest grammar version Vincenzo Pupillo
@ 2024-10-13 4:59 ` Eli Zaretskii
2024-10-13 9:19 ` Vincenzo Pupillo
0 siblings, 1 reply; 6+ messages in thread
From: Eli Zaretskii @ 2024-10-13 4:59 UTC (permalink / raw)
To: Vincenzo Pupillo; +Cc: 73779
> From: Vincenzo Pupillo <v.pupillo@gmail.com>
> Date: Sat, 12 Oct 2024 22:12:30 +0200
>
> this patch corrects the indentation of the control structure without closing
> brackets (or without the end keyword... in the case of the alternative
> syntax). It supports font locking of the “asymmetric property visibility ”
> introduced with grammar v0.23.3 and so-called magic methods. And others small
> fix. And others small bug I discovered while writing the tests..
Thank you.
I have two questions about this:
. will the code which uses the "asymmetric property visibility" also
work without problems with versions of the grammar library before
0.23.3?
. do you consider the code changes to be tested well enough and thus
safe to be installed on the emacs-30 release branch?
I'd prefer to install on emacs-30, because this mode is new in Emacs
30, unless you are not sure the code is safe enough.
^ permalink raw reply [flat|nested] 6+ messages in thread
* bug#73779: 30.0.91; [PATCH] php-ts-mode: Better indentation and font locking, support for the latest grammar version.
2024-10-13 4:59 ` Eli Zaretskii
@ 2024-10-13 9:19 ` Vincenzo Pupillo
2024-10-18 6:51 ` Eli Zaretskii
0 siblings, 1 reply; 6+ messages in thread
From: Vincenzo Pupillo @ 2024-10-13 9:19 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: 73779
Ciao Eli,
> I have two questions about this:
>
> . will the code which uses the "asymmetric property visibility" also
> work without problems with versions of the grammar library before
> 0.23.3?
Yes, I tested it with older versions of the grammars.
'php-ts-mode--test-visibility-modifier-operation-clause-p' is used to check if
this new feature is defined or not, and behaves accordingly.
> . do you consider the code changes to be tested well enough and thus
> safe to be installed on the emacs-30 release branch?
>
Yes, I've been using this patch at work for about a week and haven't had any
problems.
> I'd prefer to install on emacs-30, because this mode is new in Emacs
> 30, unless you are not sure the code is safe enough.
Thank you.
Vincenzo
^ permalink raw reply [flat|nested] 6+ messages in thread
* bug#73779: 30.0.91; [PATCH] php-ts-mode: Better indentation and font locking, support for the latest grammar version.
2024-10-13 9:19 ` Vincenzo Pupillo
@ 2024-10-18 6:51 ` Eli Zaretskii
2024-10-19 12:13 ` Vincenzo Pupillo
0 siblings, 1 reply; 6+ messages in thread
From: Eli Zaretskii @ 2024-10-18 6:51 UTC (permalink / raw)
To: Vincenzo Pupillo; +Cc: 73779
> From: Vincenzo Pupillo <v.pupillo@gmail.com>
> Cc: 73779@debbugs.gnu.org
> Date: Sun, 13 Oct 2024 11:19:31 +0200
>
> > I have two questions about this:
> >
> > . will the code which uses the "asymmetric property visibility" also
> > work without problems with versions of the grammar library before
> > 0.23.3?
>
> Yes, I tested it with older versions of the grammars.
> 'php-ts-mode--test-visibility-modifier-operation-clause-p' is used to check if
> this new feature is defined or not, and behaves accordingly.
>
> > . do you consider the code changes to be tested well enough and thus
> > safe to be installed on the emacs-30 release branch?
> >
> Yes, I've been using this patch at work for about a week and haven't had any
> problems.
I was about to install this, but byte-compiling the modified file
yields the following warnings:
ELC progmodes/php-ts-mode.elc
In php-ts-mode--open-statement-group-heuristic:
progmodes/php-ts-mode.el:435:58: Warning: Unused lexical argument `parent'
progmodes/php-ts-mode.el:499:50: Warning: argument `_bol' not left unused
progmodes/php-ts-mode.el:518:56: Warning: argument `_bol' not left unused
Could you please fix these and resubmit the patch?
^ permalink raw reply [flat|nested] 6+ messages in thread
* bug#73779: 30.0.91; [PATCH] php-ts-mode: Better indentation and font locking, support for the latest grammar version.
2024-10-18 6:51 ` Eli Zaretskii
@ 2024-10-19 12:13 ` Vincenzo Pupillo
2024-10-19 13:13 ` Eli Zaretskii
0 siblings, 1 reply; 6+ messages in thread
From: Vincenzo Pupillo @ 2024-10-19 12:13 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: 73779
[-- Attachment #1: Type: text/plain, Size: 534 bytes --]
> I was about to install this, but byte-compiling the modified file
> yields the following warnings:
>
> ELC progmodes/php-ts-mode.elc
>
> In php-ts-mode--open-statement-group-heuristic:
> progmodes/php-ts-mode.el:435:58: Warning: Unused lexical argument `parent'
> progmodes/php-ts-mode.el:499:50: Warning: argument `_bol' not left unused
> progmodes/php-ts-mode.el:518:56: Warning: argument `_bol' not left unused
>
> Could you please fix these and resubmit the patch?
Sorry Eli, it's okay now.
Thank you.
Vincenzo
[-- Attachment #2: 0001-Fix-php-ts-mode-better-indentation-and-font-locking.patch --]
[-- Type: text/x-patch, Size: 14959 bytes --]
From fdf80d7e8db62ad17c70fc52eebd531c7d504206 Mon Sep 17 00:00:00 2001
From: Vincenzo Pupillo <v.pupillo@gmail.com>
Date: Thu, 10 Oct 2024 16:06:37 +0200
Subject: [PATCH] Fix php-ts-mode better indentation and font locking.
Incomplete compound_statement or colon_block (statement-group without a
closing brace or closing keyword) that are not inside a function or
method are not recognized as such by tree-sitter-php.
A new function 'php-ts-mode--open-statement-group-heuristic' handles
this case. Font locking of magic methods and better support for
alternative control structure syntax.
Support for latest grammar version.
* lisp/progmodes/php-ts-mode.el
(php-ts-mode--language-source-alist): Updated grammar version.
(php-ts-mode--possibly-braceless-keyword-re): Regular expression for
braceles keyword.
(php-ts-mode--open-statement-group-heuristic): New function.
(php-ts-mode--parent-html-bol): Use the new function and doc fix.
(php-ts-mode--parent-html-heuristic): Use the new function and doc fix.
(php-ts-mode--indent-styles): Use the new function and add 'colon_block'
support.
(php-ts-mode--class-magic-methods): New predefined magic methods list.
(php-ts-mode--test-namespace-name-as-prefix-p): Doc fix.
(php-ts-mode--test-namespace-aliasing-clause-p): Fix the test and doc.
(php-ts-mode--test-namespace-use-group-clause-p): Doc fix.
(php-ts-mode--test-visibility-modifier-operation-clause-p): New function
for the new asymmetric property visibility feature of PHP 8.4.
(php-ts-mode--font-lock-settings): Font lock for class magic methods and
alternative syntax. Better font lock for 'instanceof'. Use
'font-lock-function-call-face' for scoped and member call expression.
---
lisp/progmodes/php-ts-mode.el | 170 ++++++++++++++++++++++------------
1 file changed, 113 insertions(+), 57 deletions(-)
diff --git a/lisp/progmodes/php-ts-mode.el b/lisp/progmodes/php-ts-mode.el
index d2559e5a45f..1c5fdb6f617 100644
--- a/lisp/progmodes/php-ts-mode.el
+++ b/lisp/progmodes/php-ts-mode.el
@@ -84,7 +84,7 @@
;;; Install treesitter language parsers
(defvar php-ts-mode--language-source-alist
- '((php . ("https://github.com/tree-sitter/tree-sitter-php" "v0.23.0" "php/src"))
+ '((php . ("https://github.com/tree-sitter/tree-sitter-php" "v0.23.4" "php/src"))
(phpdoc . ("https://github.com/claytonrcarter/tree-sitter-phpdoc"))
(html . ("https://github.com/tree-sitter/tree-sitter-html" "v0.23.0"))
(javascript . ("https://github.com/tree-sitter/tree-sitter-javascript" "v0.23.0"))
@@ -428,6 +428,27 @@ php-ts-mode--syntax-table
\f
;;; Indent
+(defconst php-ts-mode--possibly-braceless-keyword-re
+ (regexp-opt '("if" "for" "foreach" "while" "do") 'symbols)
+ "Regexp matching keywords optionally followed by an opening brace.")
+
+(defun php-ts-mode--open-statement-group-heuristic (node _parent bol &rest _)
+ "Heuristic matcher for statement-group without closing bracket.
+
+Return `php-ts-mode-indent-offset' plus 1 when BOL is after
+`php-ts-mode--possibly-braceless-keyword-re', otherwise return 0. It's
+usefull for matching incomplete compound_statement or colon_block.
+PARENT is NODE's parent, BOL is the beginning of non-whitespace
+characters of the current line."
+ (and (null node)
+ (save-excursion
+ (forward-line -1)
+ (if (re-search-forward
+ php-ts-mode--possibly-braceless-keyword-re
+ bol t)
+ (+ 1 php-ts-mode-indent-offset)
+ 0))))
+
;; taken from c-ts-mode
(defun php-ts-mode--else-heuristic (node parent bol &rest _)
"Heuristic matcher for when \"else\" is followed by a closing bracket.
@@ -475,43 +496,50 @@ php-ts-mode--parent-eol
(goto-char (treesit-node-start parent))
(line-end-position)))
-(defun php-ts-mode--parent-html-bol (node parent _bol &rest _)
+(defun php-ts-mode--parent-html-bol (node parent bol &rest _)
"Find the first non-space characters of the HTML tags before NODE.
+When NODE is nil call `php-ts-mode--open-statement-group-heuristic'.
PARENT is NODE's parent, BOL is the beginning of non-whitespace
characters of the current line."
- (save-excursion
- (let ((html-node (treesit-search-forward node "text" t)))
- (if html-node
- (let ((end-html (treesit-node-end html-node)))
- (goto-char end-html)
- (backward-word)
- (back-to-indentation)
- (point))
- (treesit-node-start parent)))))
-
-(defun php-ts-mode--parent-html-heuristic (node parent _bol &rest _)
+ (if (null node)
+ ;; If NODE is nil it could be an open statement-group.
+ (php-ts-mode--open-statement-group-heuristic node parent bol)
+ (save-excursion
+ (let ((html-node (treesit-search-forward node "text" t)))
+ (if html-node
+ (let ((end-html (treesit-node-end html-node)))
+ (goto-char end-html)
+ (backward-word)
+ (back-to-indentation)
+ (point))
+ (treesit-node-start parent))))))
+
+(defun php-ts-mode--parent-html-heuristic (node parent bol &rest _)
"Return position based on html indentation.
Returns 0 if the NODE is after the </html>, otherwise returns the
-indentation point of the last word before the NODE, plus the
-indentation offset. If there is no HTML tag, it returns the beginning
-of the parent.
+indentation point of the last word before the NODE, plus the indentation
+offset. If there is no HTML tag, it returns the beginning of the
+parent. When NODE is nil call `php-ts-mode--open-statement-group-heuristic'.
It can be used when you want to indent PHP code relative to the HTML.
PARENT is NODE's parent, BOL is the beginning of non-whitespace
characters of the current line."
- (let ((html-node (treesit-search-forward node "text" t)))
- (if html-node
- (let ((end-html (treesit-node-end html-node)))
- (save-excursion
- (goto-char end-html)
- (backward-word)
- (back-to-indentation)
- (if (search-forward "</html>" end-html t 1)
- 0
- (+ (point) php-ts-mode-indent-offset))))
- ;; Maybe it's better to use bol?
- (treesit-node-start parent))))
+ (if (null node)
+ ;; If NODE is nil it could be an open statement-group.
+ (php-ts-mode--open-statement-group-heuristic node parent bol)
+ (let ((html-node (treesit-search-forward node "text" t)))
+ (if html-node
+ (let ((end-html (treesit-node-end html-node)))
+ (save-excursion
+ (goto-char end-html)
+ (backward-word)
+ (back-to-indentation)
+ (if (search-forward "</html>" end-html t 1)
+ 0
+ (+ (point) php-ts-mode-indent-offset))))
+ ;; Maybe it's better to use bol?
+ (treesit-node-start parent)))))
(defun php-ts-mode--array-element-heuristic (_node parent _bol &rest _)
"Return of the position of the first element of the array.
@@ -648,16 +676,22 @@ php-ts-mode--indent-styles
((parent-is "initializer_list") parent-bol php-ts-mode-indent-offset)
;; Statement in {} blocks.
- ((or (and (parent-is "compound_statement")
+ ((or (and (or (parent-is "compound_statement")
+ (parent-is "colon_block"))
;; If the previous sibling(s) are not on their
;; own line, indent as if this node is the first
;; sibling
php-ts-mode--first-sibling)
- (match null "compound_statement"))
+ (or (match null "compound_statement")
+ (match null "colon_block")))
standalone-parent php-ts-mode-indent-offset)
- ((parent-is "compound_statement") parent-bol php-ts-mode-indent-offset)
+ ((or (parent-is "compound_statement")
+ (parent-is "colon_block"))
+ parent-bol php-ts-mode-indent-offset)
;; Opening bracket.
- ((node-is "compound_statement") standalone-parent php-ts-mode-indent-offset)
+ ((or (node-is "compound_statement")
+ (node-is "colon_block"))
+ standalone-parent php-ts-mode-indent-offset)
((parent-is "match_block") parent-bol php-ts-mode-indent-offset)
((parent-is "switch_block") parent-bol 0)
@@ -667,6 +701,7 @@ php-ts-mode--indent-styles
;; rule for PHP alternative syntax
((or (node-is "else_if_clause")
(node-is "endif")
+ (node-is "endfor")
(node-is "endforeach")
(node-is "endwhile"))
parent-bol 0)
@@ -679,9 +714,13 @@ php-ts-mode--indent-styles
(parent-is "switch_statement")
(parent-is "case_statement")
(parent-is "empty_statement"))
- parent-bol php-ts-mode-indent-offset))))
+ parent-bol php-ts-mode-indent-offset)
+
+ ;; Workaround: handle "for" open statement group. Currently
+ ;; the grammar handles it differently than other control structures.
+ (no-node php-ts-mode--open-statement-group-heuristic 0))))
`((psr2
- ((parent-is "program") parent-bol 0)
+ ((parent-is "program") php-ts-mode--open-statement-group-heuristic 0)
((parent-is "text_interpolation") column-0 0)
((parent-is "function_call_expression") parent-bol php-ts-mode-indent-offset)
,@common)
@@ -774,21 +813,32 @@ php-ts-mode--predefined-constant
"__FUNCTION__" "__LINE__" "__METHOD__" "__NAMESPACE__" "__TRAIT__")
"PHP predefined constant.")
-(defun php-ts-mode--test-namespace-name-as-prefix-p ()
- "Return t if namespace_name_as_prefix keyword is a named node, nil otherwise."
+(defconst php-ts-mode--class-magic-methods
+ '("__construct" "__destruct" "__call" "__callStatic" "__get" "__set"
+ "__isset" "__unset" "__sleep" "__wakeup" "__serialize" "__unserialize"
+ "__toString" "__invoke" "__set_state" "__clone" "__debugInfo")
+ "PHP predefined magic methods.")
+
+(defun php-ts-mode--test-namespace-name-as-prefix-p ()
+ "Return t if namespace_name_as_prefix is a named node, nil otherwise."
(ignore-errors
(progn (treesit-query-compile 'php "(namespace_name_as_prefix)" t) t)))
-(defun php-ts-mode--test-namespace-aliasing-clause-p ()
- "Return t if namespace_name_as_prefix keyword is named node, nil otherwise."
+(defun php-ts-mode--test-namespace-aliasing-clause-p ()
+ "Return t if namespace_aliasing_clause is a named node, nil otherwise."
(ignore-errors
- (progn (treesit-query-compile 'php "(namespace_name_as_prefix)" t) t)))
+ (progn (treesit-query-compile 'php "(namespace_aliasing_clause)" t) t)))
(defun php-ts-mode--test-namespace-use-group-clause-p ()
- "Return t if namespace_use_group_clause keyword is named node, nil otherwise."
+ "Return t if namespace_use_group_clause is a named node, nil otherwise."
(ignore-errors
(progn (treesit-query-compile 'php "(namespace_use_group_clause)" t) t)))
+(defun php-ts-mode--test-visibility-modifier-operation-clause-p ()
+ "Return t if (visibility_modifier (operation)) is defined, nil otherwise."
+ (ignore-errors
+ (progn (treesit-query-compile 'php "(visibility_modifier (operation))" t) t)))
+
(defun php-ts-mode--font-lock-settings ()
"Tree-sitter font-lock settings."
(treesit-font-lock-rules
@@ -796,7 +846,10 @@ php-ts-mode--font-lock-settings
:language 'php
:feature 'keyword
:override t
- `([,@php-ts-mode--keywords] @font-lock-keyword-face)
+ `([,@php-ts-mode--keywords] @font-lock-keyword-face
+ ,@(when (php-ts-mode--test-visibility-modifier-operation-clause-p)
+ '((visibility_modifier (operation) @font-lock-builtin-face)))
+ (var_modifier) @font-lock-builtin-face)
:language 'php
:feature 'comment
@@ -826,7 +879,6 @@ php-ts-mode--font-lock-settings
(named_label_statement (name) @font-lock-constant-face))
:language 'php
- ;;:override t
:feature 'delimiter
`((["," ":" ";" "\\"]) @font-lock-delimiter-face)
@@ -850,7 +902,6 @@ php-ts-mode--font-lock-settings
:language 'php
:feature 'string
- ;;:override t
`(("\"") @font-lock-string-face
(encapsed_string) @font-lock-string-face
(string_content) @font-lock-string-face
@@ -892,32 +943,37 @@ php-ts-mode--font-lock-settings
name: (_) @font-lock-type-face)
(trait_declaration
name: (_) @font-lock-type-face)
- (property_declaration
- (visibility_modifier) @font-lock-keyword-face)
- (property_declaration
- (var_modifier) @font-lock-keyword-face)
(enum_declaration
name: (_) @font-lock-type-face)
(function_definition
name: (_) @font-lock-function-name-face)
(method_declaration
name: (_) @font-lock-function-name-face)
+ (method_declaration
+ name: (name) @font-lock-builtin-face
+ (:match ,(rx-to-string
+ `(: bos (or ,@php-ts-mode--class-magic-methods) eos))
+ @font-lock-builtin-face))
("=>") @font-lock-keyword-face
(object_creation_expression
(name) @font-lock-type-face)
,@(when (php-ts-mode--test-namespace-name-as-prefix-p)
- '((namespace_name_as_prefix "\\" @font-lock-delimiter-face)
- (namespace_name_as_prefix
- (namespace_name (name)) @font-lock-type-face)))
+ '((namespace_name_as_prefix "\\" @font-lock-delimiter-face)
+ (namespace_name_as_prefix
+ (namespace_name (name)) @font-lock-type-face)))
,@(if (php-ts-mode--test-namespace-aliasing-clause-p)
- '((namespace_aliasing_clause (name) @font-lock-type-face))
- '((namespace_use_clause alias: (name) @font-lock-type-face)))
+ '((namespace_aliasing_clause (name) @font-lock-type-face))
+ '((namespace_use_clause alias: (name) @font-lock-type-face)))
,@(when (not (php-ts-mode--test-namespace-use-group-clause-p))
- '((namespace_use_group
- (namespace_use_clause (name) @font-lock-type-face))))
+ '((namespace_use_group
+ (namespace_use_clause (name) @font-lock-type-face))))
(namespace_name "\\" @font-lock-delimiter-face)
(namespace_name (name) @font-lock-type-face)
- (use_declaration (name) @font-lock-property-use-face))
+ (use_declaration (name) @font-lock-property-use-face)
+ (use_instead_of_clause (name) @font-lock-type-face)
+ (binary_expression
+ operator: "instanceof"
+ right: (name) @font-lock-type-face))
:language 'php
:feature 'function-scope
@@ -932,9 +988,9 @@ php-ts-mode--font-lock-settings
'((function_call_expression
function: (name) @font-lock-function-call-face)
(scoped_call_expression
- name: (_) @font-lock-function-name-face)
+ name: (_) @font-lock-function-call-face)
(member_call_expression
- name: (_) @font-lock-function-name-face)
+ name: (_) @font-lock-function-call-face)
(nullsafe_member_call_expression
name: (_) @font-lock-constant-face))
--
2.47.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* bug#73779: 30.0.91; [PATCH] php-ts-mode: Better indentation and font locking, support for the latest grammar version.
2024-10-19 12:13 ` Vincenzo Pupillo
@ 2024-10-19 13:13 ` Eli Zaretskii
0 siblings, 0 replies; 6+ messages in thread
From: Eli Zaretskii @ 2024-10-19 13:13 UTC (permalink / raw)
To: Vincenzo Pupillo; +Cc: 73779-done
> From: Vincenzo Pupillo <v.pupillo@gmail.com>
> Cc: 73779@debbugs.gnu.org
> Date: Sat, 19 Oct 2024 14:13:33 +0200
>
> > I was about to install this, but byte-compiling the modified file
> > yields the following warnings:
> >
> > ELC progmodes/php-ts-mode.elc
> >
> > In php-ts-mode--open-statement-group-heuristic:
> > progmodes/php-ts-mode.el:435:58: Warning: Unused lexical argument `parent'
> > progmodes/php-ts-mode.el:499:50: Warning: argument `_bol' not left unused
> > progmodes/php-ts-mode.el:518:56: Warning: argument `_bol' not left unused
> >
> > Could you please fix these and resubmit the patch?
>
> Sorry Eli, it's okay now.
Thanks, installed on the emacs-30 branch, and closing the bug.
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2024-10-19 13:13 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-12 20:12 bug#73779: 30.0.91; [PATCH] php-ts-mode: Better indentation and font locking, support for the latest grammar version Vincenzo Pupillo
2024-10-13 4:59 ` Eli Zaretskii
2024-10-13 9:19 ` Vincenzo Pupillo
2024-10-18 6:51 ` Eli Zaretskii
2024-10-19 12:13 ` Vincenzo Pupillo
2024-10-19 13:13 ` Eli Zaretskii
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.