emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master d9d90666f5: Merge from origin/emacs-29


From: Stefan Kangas
Subject: master d9d90666f5: Merge from origin/emacs-29
Date: Thu, 29 Dec 2022 00:45:33 -0500 (EST)

branch: master
commit d9d90666f545dc25be63c1b16c030ce1aa96510e
Merge: dce6791e99 909091d757
Author: Stefan Kangas <stefankangas@gmail.com>
Commit: Stefan Kangas <stefankangas@gmail.com>

    Merge from origin/emacs-29
    
    909091d7578 ; Minor cleanup for tree-sitter font-lock rules in js-ts-...
    e78e69b3318 Clean up font-lock rules in js-ts-mode
    0a61e4e2b71 ; * doc/lispref/parsing.texi (Using Parser): Minor improv...
    398ed75c276 ; * lisp/progmodes/c-ts-mode.el (c-ts-mode--fill-paragrap...
    19b8733aa27 Fix syntax for < and > in c++-ts-mode (bug#60351)
    f509246ba12 Call tree-sitter parser notifier on the first parse
    ec6feeaa191 Fix tree-sitter parser notifier recursion
---
 doc/lispref/parsing.texi    |   4 +-
 lisp/progmodes/c-ts-mode.el |  48 ++++++++++++++----
 lisp/progmodes/js.el        | 116 ++++++++++++++++++++++----------------------
 src/treesit.c               |  43 +++++++++++-----
 4 files changed, 131 insertions(+), 80 deletions(-)

diff --git a/doc/lispref/parsing.texi b/doc/lispref/parsing.texi
index b7199f071b..86b3bd54e7 100644
--- a/doc/lispref/parsing.texi
+++ b/doc/lispref/parsing.texi
@@ -505,7 +505,9 @@ notification.
 
 Every time a parser reparses a buffer, it compares the old and new
 parse-tree, computes the ranges in which nodes have changed, and
-passes the ranges to notifier functions.
+passes the ranges to notifier functions.  Note that the initial parse
+is also considered a ``change'', so notifier functions are called on
+the initial parse, with range being the whole buffer.
 
 @defun treesit-parser-add-notifier parser function
 This function adds @var{function} to @var{parser}'s list of
diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el
index 73e488a805..12e021bc67 100644
--- a/lisp/progmodes/c-ts-mode.el
+++ b/lisp/progmodes/c-ts-mode.el
@@ -63,6 +63,8 @@ follows the form of `treesit-simple-indent-rules'."
                  (function :tag "A function for user customized style" ignore))
   :group 'c)
 
+;;; Syntax table
+
 (defvar c-ts-mode--syntax-table
   (let ((table (make-syntax-table)))
     ;; Taken from the cc-langs version
@@ -85,13 +87,27 @@ follows the form of `treesit-simple-indent-rules'."
     table)
   "Syntax table for `c-ts-mode'.")
 
-(defvar c++-ts-mode--syntax-table
-  (let ((table (make-syntax-table c-ts-mode--syntax-table)))
-    ;; Template delimiters.
-    (modify-syntax-entry ?<  "("     table)
-    (modify-syntax-entry ?>  ")"     table)
-    table)
-  "Syntax table for `c++-ts-mode'.")
+(defun c-ts-mode--syntax-propertize (beg end)
+  "Apply syntax text property to template delimiters between BEG and END.
+
+< and > are usually punctuation, e.g., in ->.  But when used for
+templates, they should be considered pairs.
+
+This function checks for < and > in the changed RANGES and apply
+appropriate text property to alter the syntax of template
+delimiters < and >'s."
+  (goto-char beg)
+  (while (re-search-forward (rx (or "<" ">")) end t)
+    (pcase (treesit-node-type
+            (treesit-node-parent
+             (treesit-node-at (match-beginning 0))))
+      ("template_argument_list"
+       (put-text-property (match-beginning 0)
+                          (match-end 0)
+                          'syntax-table
+                          (pcase (char-before)
+                            (?< '(4 . ?>))
+                            (?> '(5 . ?<))))))))
 
 ;;; Indent
 
@@ -574,6 +590,10 @@ ARG is passed to `fill-paragraph'."
             (goto-char (match-beginning 1))
             (setq start-marker (point-marker))
             (replace-match " " nil nil nil 1))
+          ;; Include whitespaces before /*.
+          (goto-char start)
+          (beginning-of-line)
+          (setq start (point))
           ;; Mask spaces before "*/" if it is attached at the end
           ;; of a sentence rather than on its own line.
           (goto-char end)
@@ -645,11 +665,18 @@ Set up:
               (concat (rx (* (syntax whitespace))
                           (group (or (seq "/" (+ "/")) (* "*"))))
                       adaptive-fill-regexp))
-  ;; Same as `adaptive-fill-regexp'.
+  ;; Note the missing * comparing to `adaptive-fill-regexp'.  The
+  ;; reason for its absence is a bit convoluted to explain.  Suffice
+  ;; to say that without it, filling a single line paragraph that
+  ;; starts with /* doesn't insert * at the beginning of each
+  ;; following line, and filling a multi-line paragraph whose first
+  ;; two lines start with * does insert * at the beginning of each
+  ;; following line.  If you know how does adaptive filling works, you
+  ;; know what I mean.
   (setq-local adaptive-fill-first-line-regexp
               (rx bos
                   (seq (* (syntax whitespace))
-                       (group (or (seq "/" (+ "/")) (* "*")))
+                       (group (seq "/" (+ "/")))
                        (* (syntax whitespace)))
                   eos))
   ;; Same as `adaptive-fill-regexp'.
@@ -751,7 +778,6 @@ Set up:
 (define-derived-mode c++-ts-mode c-ts-base-mode "C++"
   "Major mode for editing C++, powered by tree-sitter."
   :group 'c++
-  :syntax-table c++-ts-mode--syntax-table
 
   (unless (treesit-ready-p 'cpp)
     (error "Tree-sitter for C++ isn't available"))
@@ -761,6 +787,8 @@ Set up:
                             "raw_string_literal")))
 
   (treesit-parser-create 'cpp)
+  (setq-local syntax-propertize-function
+              #'c-ts-mode--syntax-propertize)
 
   (setq-local treesit-simple-indent-rules
               (c-ts-mode--set-indent-style 'cpp))
diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index 653038a09e..79b7e74ec4 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -3479,36 +3479,35 @@ This function is intended for use in 
`after-change-functions'."
   (treesit-font-lock-rules
 
    :language 'javascript
-   :override t
    :feature 'comment
-   `((comment) @font-lock-comment-face)
+   '((comment) @font-lock-comment-face)
 
    :language 'javascript
-   :override t
    :feature 'constant
-   `(((identifier) @font-lock-constant-face
+   '(((identifier) @font-lock-constant-face
       (:match "^[A-Z_][A-Z_\\d]*$" @font-lock-constant-face))
 
      [(true) (false) (null)] @font-lock-constant-face)
 
    :language 'javascript
-   :override t
    :feature 'keyword
    `([,@js--treesit-keywords] @font-lock-keyword-face
      [(this) (super)] @font-lock-keyword-face)
 
    :language 'javascript
-   :override t
    :feature 'string
-   `((regex pattern: (regex_pattern)) @font-lock-string-face
-     (string) @font-lock-string-face
-     (template_string) @js--fontify-template-string
-     (template_substitution ["${" "}"] @font-lock-builtin-face))
+   '((regex pattern: (regex_pattern)) @font-lock-string-face
+     (string) @font-lock-string-face)
 
    :language 'javascript
+   :feature 'string-interpolation
    :override t
-   :feature 'declaration
-   `((function
+   '((template_string) @js--fontify-template-string
+     (template_substitution ["${" "}"] @font-lock-delimiter-face))
+
+   :language 'javascript
+   :feature 'definition
+   '((function
       name: (identifier) @font-lock-function-name-face)
 
      (class_declaration
@@ -3535,24 +3534,10 @@ This function is intended for use in 
`after-change-functions'."
       value: (array (number) (function))))
 
    :language 'javascript
-   :override t
-   :feature 'identifier
-   `((new_expression
-      constructor: (identifier) @font-lock-type-face)
-
-     (for_in_statement
-      left: (identifier) @font-lock-variable-name-face)
-
-     (arrow_function
-      parameter: (identifier) @font-lock-variable-name-face))
-
-   :language 'javascript
-   :override t
    :feature 'property
-   ;; This needs to be before function-name feature, because methods
-   ;; can be both property and function-name, and we want them in
-   ;; function-name face.
-   `((property_identifier) @font-lock-property-face
+   '(((property_identifier) @font-lock-property-face
+      (:pred js--treesit-property-not-function-p
+             @font-lock-property-face))
 
      (pair value: (identifier) @font-lock-variable-name-face)
 
@@ -3561,36 +3546,27 @@ This function is intended for use in 
`after-change-functions'."
      ((shorthand_property_identifier_pattern) @font-lock-property-face))
 
    :language 'javascript
-   :override t
-   :feature 'expression
-   `((assignment_expression
-      left: [(identifier) @font-lock-function-name-face
-             (member_expression property: (property_identifier)
-                                @font-lock-function-name-face)]
-      right: [(function) (arrow_function)])
-
-     (call_expression
+   :feature 'assignment
+   '((assignment_expression
+      left: (_) @js--treesit-fontify-assignment-lhs))
+
+   :language 'javascript
+   :feature 'function
+   '((call_expression
       function: [(identifier) @font-lock-function-name-face
                  (member_expression
                   property:
                   (property_identifier) @font-lock-function-name-face)])
-
-     (assignment_expression
-      left: [(identifier) @font-lock-variable-name-face
-             (member_expression
-              property: (property_identifier) @font-lock-variable-name-face)]))
-
-   :language 'javascript
-   :override t
-   :feature 'pattern
-   `((pair_pattern key: (property_identifier) @font-lock-variable-name-face)
-     (array_pattern (identifier) @font-lock-variable-name-face))
+     (method_definition
+      name: (property_identifier) @font-lock-function-name-face)
+     (function_declaration
+      name: (identifier) @font-lock-function-name-face)
+     (function
+      name: (identifier) @font-lock-function-name-face))
 
    :language 'javascript
-   :override t
    :feature 'jsx
-   `(
-     (jsx_opening_element
+   '((jsx_opening_element
       [(nested_identifier (identifier)) (identifier)]
       @font-lock-function-name-face)
 
@@ -3608,7 +3584,7 @@ This function is intended for use in 
`after-change-functions'."
 
    :language 'javascript
    :feature 'number
-   `((number) @font-lock-number-face
+   '((number) @font-lock-number-face
      ((identifier) @font-lock-number-face
       (:match "^\\(:?NaN\\|Infinity\\)$" @font-lock-number-face)))
 
@@ -3657,6 +3633,31 @@ OVERRIDE is the override flag described in
       (setq font-beg (treesit-node-end child)
             child (treesit-node-next-sibling child)))))
 
+(defun js--treesit-property-not-function-p (node)
+  "Check that NODE, a property_identifier, is not used as a function."
+  (not (equal (treesit-node-type
+               (treesit-node-parent ; Maybe call_expression.
+                (treesit-node-parent ; Maybe member_expression.
+                 node)))
+              "call_expression")))
+
+(defvar js--treesit-lhs-identifier-query
+  (treesit-query-compile 'javascript '((identifier) @id
+                                       (property_identifier) @id))
+  "Query that captures identifier and query_identifier.")
+
+(defun js--treesit-fontify-assignment-lhs (node override start end &rest _)
+  "Fontify the lhs NODE of an assignment_expression.
+For OVERRIDE, START, END, see `treesit-font-lock-rules'."
+  (dolist (node (treesit-query-capture
+                 node js--treesit-lhs-identifier-query nil nil t))
+    (treesit-fontify-with-override
+     (treesit-node-start node) (treesit-node-end node)
+     (pcase (treesit-node-type node)
+       ("identifier" 'font-lock-variable-name-face)
+       ("property_identifier" 'font-lock-property-face))
+     override start end)))
+
 (defun js--treesit-defun-name (node)
   "Return the defun name of NODE.
 Return nil if there is no name or if NODE is not a defun node."
@@ -3815,11 +3816,12 @@ Currently there are `js-mode' and `js-ts-mode'."
     ;; Fontification.
     (setq-local treesit-font-lock-settings js--treesit-font-lock-settings)
     (setq-local treesit-font-lock-feature-list
-                '(( comment declaration)
+                '(( comment definition)
                   ( keyword string)
-                  ( constant escape-sequence expression
-                    identifier jsx number pattern property)
-                  ( bracket delimiter operator)))
+                  ( assignment constant escape-sequence jsx number
+                    pattern)
+                  ( bracket delimiter function operator property
+                    string-interpolation)))
     ;; Imenu
     (setq-local treesit-simple-imenu-settings
                 `(("Function" "\\`function_declaration\\'" nil nil)
diff --git a/src/treesit.c b/src/treesit.c
index 813d4222f9..6570ada1d9 100644
--- a/src/treesit.c
+++ b/src/treesit.c
@@ -933,11 +933,24 @@ static void
 treesit_call_after_change_functions (TSTree *old_tree, TSTree *new_tree,
                                     Lisp_Object parser)
 {
-  uint32_t len;
-  TSRange *ranges = ts_tree_get_changed_ranges (old_tree, new_tree, &len);
+  /* If the old_tree is NULL, meaning this is the first parse, the
+     changed range is the whole buffer.  */
+  Lisp_Object lisp_ranges;
   struct buffer *buf = XBUFFER (XTS_PARSER (parser)->buffer);
-  Lisp_Object lisp_ranges = treesit_make_ranges (ranges, len, buf);
-  xfree (ranges);
+  if (old_tree)
+    {
+      uint32_t len;
+      TSRange *ranges = ts_tree_get_changed_ranges (old_tree, new_tree, &len);
+      lisp_ranges = treesit_make_ranges (ranges, len, buf);
+      xfree (ranges);
+    }
+  else
+    {
+      struct buffer *oldbuf = current_buffer;
+      set_buffer_internal (buf);
+      lisp_ranges = Fcons (Fcons (Fpoint_min (), Fpoint_max ()), Qnil);
+      set_buffer_internal (oldbuf);
+    }
 
   specpdl_ref count = SPECPDL_INDEX ();
 
@@ -955,6 +968,11 @@ treesit_call_after_change_functions (TSTree *old_tree, 
TSTree *new_tree,
 static void
 treesit_ensure_parsed (Lisp_Object parser)
 {
+  /* Make sure this comes before everything else, see comment
+     (ref:notifier-inside-ensure-parsed) for more detail.  */
+  if (!XTS_PARSER (parser)->need_reparse)
+    return;
+
   struct buffer *buffer = XBUFFER (XTS_PARSER (parser)->buffer);
 
   /* Before we parse, catch up with the narrowing situation.  */
@@ -963,8 +981,6 @@ treesit_ensure_parsed (Lisp_Object parser)
      because it might set the flag to true.  */
   treesit_sync_visible_region (parser);
 
-  if (!XTS_PARSER (parser)->need_reparse)
-    return;
   TSParser *treesit_parser = XTS_PARSER (parser)->parser;
   TSTree *tree = XTS_PARSER (parser)->tree;
   TSInput input = XTS_PARSER (parser)->input;
@@ -984,14 +1000,17 @@ treesit_ensure_parsed (Lisp_Object parser)
       xsignal1 (Qtreesit_parse_error, buf);
     }
 
-  if (tree != NULL)
-    {
-      treesit_call_after_change_functions (tree, new_tree, parser);
-      ts_tree_delete (tree);
-    }
-
   XTS_PARSER (parser)->tree = new_tree;
   XTS_PARSER (parser)->need_reparse = false;
+
+  /* After-change functions should run at the very end, most crucially
+     after need_reparse is set to false, this way if the function
+     calls some tree-sitter function which invokes
+     treesit_ensure_parsed again, it returns early and do not
+     recursively call the after change functions again.
+     (ref:notifier-inside-ensure-parsed)  */
+  treesit_call_after_change_functions (tree, new_tree, parser);
+  ts_tree_delete (tree);
 }
 
 /* This is the read function provided to tree-sitter to read from a



reply via email to

[Prev in Thread] Current Thread [Next in Thread]