emacs-elpa-diffs
[Top][All Lists]
Advanced

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

[nongnu] elpa/typescript-mode acd8d79952 10/10: Merge pull request #170


From: ELPA Syncer
Subject: [nongnu] elpa/typescript-mode acd8d79952 10/10: Merge pull request #170 from Fuco1/feature/fontify-arrow-fn-args
Date: Sat, 30 Jul 2022 06:59:04 -0400 (EDT)

branch: elpa/typescript-mode
commit acd8d7995204c1faf14383b8236e57f4da380ecf
Merge: e5704af123 84bab53b7a
Author: Jostein Kjønigsen <jostein@kjonigsen.net>
Commit: GitHub <noreply@github.com>

    Merge pull request #170 from Fuco1/feature/fontify-arrow-fn-args
    
    feat(fontlock): fontify arrow fn arguments
---
 typescript-mode-general-tests.el  | 191 ++++++++++++++++++++++++++++++++++----
 typescript-mode-test-utilities.el |  22 ++---
 typescript-mode.el                | 118 ++++++++++++++++++++++-
 3 files changed, 298 insertions(+), 33 deletions(-)

diff --git a/typescript-mode-general-tests.el b/typescript-mode-general-tests.el
index 34add73657..686db6bfdf 100644
--- a/typescript-mode-general-tests.el
+++ b/typescript-mode-general-tests.el
@@ -371,7 +371,7 @@ declare function declareFunctionDefn(x3: xty3, y3: yty3): 
ret3;"
       ("exportedDefaultDefn" . font-lock-function-name-face)
       ("declareFunctionDefn" . font-lock-function-name-face)
       (("x0" "x1" "x2" "x3") . font-lock-variable-name-face)
-      (("y0" "y1" "y2" "y3") . font-lock-variable-name-face)
+      (("\\by0" "\\by1" "\\by2" "\\by3") . font-lock-variable-name-face)
       (("ret0" "ret1" "ret2" "ret3") . nil))))
 
 (ert-deftest font-lock/level-four ()
@@ -393,7 +393,7 @@ snake_cased_function(1, 2, 3)"
       ("methodCall" . font-lock-function-name-face)
       ("snake_cased_function" . font-lock-function-name-face)
       (("string" "boolean" "number" "any") . typescript-primitive-face)
-      (("endpoint" "data") . nil)
+      (("endpoint" "data") . font-lock-variable-name-face)
       (("<" ">" ",") . nil))))
 
 (ert-deftest font-lock/method-call-with-keyword-name ()
@@ -621,19 +621,24 @@ should be fontified as variable, keyword and type."
     (should (eq (get-face-at "Namespaced") 'font-lock-type-face))
     (should (eq (get-face-at "ClassName") 'font-lock-type-face))))
 
-(ert-deftest font-lock/variables-in-declaration-multiline-with-types ()
+(ert-deftest font-lock/funargs--function--multiline-with-types ()
   "Variables should be highlighted in multiline declarations with types."
   (test-with-fontified-buffer
       "function test(
-var1: Type1,
-var2: Type2,
+var1: Promise<U1, V1>,
+var2: (xxx: Foo) => Bar,
+var3: Type3,
 ): RetType {\n}"
     (should (eq (get-face-at "var1") 'font-lock-variable-name-face))
     (should (eq (get-face-at "var2") 'font-lock-variable-name-face))
-    (should (eq (get-face-at "Type1") 'font-lock-type-face))
-    (should (eq (get-face-at "Type2") 'font-lock-type-face))))
+    (should (eq (get-face-at "var3") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "xxx") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "Promise") 'font-lock-type-face))
+    (should (eq (get-face-at "U1") 'font-lock-type-face))
+    (should (eq (get-face-at "Foo") 'font-lock-type-face))
+    (should (eq (get-face-at "Type3") 'font-lock-type-face))))
 
-(ert-deftest font-lock/variables-in-declaration-multiline-without-types ()
+(ert-deftest font-lock/funargs--function--multiline-without-types ()
   "Variables should be highlighted in multiline declarations without types."
   (test-with-fontified-buffer
       "function test(
@@ -643,8 +648,8 @@ var2,
     (should (eq (get-face-at "var1") 'font-lock-variable-name-face))
     (should (eq (get-face-at "var2") 'font-lock-variable-name-face))))
 
-(ert-deftest font-lock/variables-in-declaration-multiline-no-hanging-paren ()
-  "Variables should be highlighted in multiline declarations with no hanging 
paren."
+(ert-deftest font-lock/funargs--function--multiline-hanging-paren ()
+  "Variables should be highlighted in multiline declarations with hanging 
paren."
   (test-with-fontified-buffer
    "function test(
 var1,
@@ -652,8 +657,8 @@ var2): RetType {\n}"
    (should (eq (get-face-at "var1") 'font-lock-variable-name-face))
    (should (eq (get-face-at "var2") 'font-lock-variable-name-face))))
 
-(ert-deftest 
font-lock/variables-in-declaration-multiline-ending-comma-no-hanging-paren ()
-  "Variables should be highlighted in multiline declarations with no hanging 
paren and trailing comma."
+(ert-deftest font-lock/funargs--function--multiline-ending-comma-hanging-paren 
()
+  "Variables should be highlighted in multiline declarations with hanging 
paren and trailing comma."
   (test-with-fontified-buffer
    "function test(
 var1,
@@ -661,15 +666,15 @@ var2,): RetType {\n}"
    (should (eq (get-face-at "var1") 'font-lock-variable-name-face))
    (should (eq (get-face-at "var2") 'font-lock-variable-name-face))))
 
-(ert-deftest 
font-lock/variables-in-declaration-singleline-ending-comma-hanging-paren ()
-  "Variables should be highlighted in singleline declarations with hanging 
paren and trailing comma."
+(ert-deftest 
font-lock/funargs--function--singleline-ending-comma-no-hanging-paren ()
+  "Variables should be highlighted in singleline declarations with no hanging 
paren and trailing comma."
   (test-with-fontified-buffer
       "function test(var1,var2,
 ): RetType {\n}"
    (should (eq (get-face-at "var1") 'font-lock-variable-name-face))
    (should (eq (get-face-at "var2") 'font-lock-variable-name-face))))
 
-(ert-deftest font-lock/variables-in-declaration-singleline-with-types ()
+(ert-deftest font-lock/funargs--function--singleline-with-types ()
   "Variables should be highlighted in singleline declarations with types."
   (test-with-fontified-buffer
       "function test(var1: Foo, var2: Bar,): RetType {\n}"
@@ -678,13 +683,165 @@ var2,): RetType {\n}"
    (should (eq (get-face-at "Foo") 'font-lock-type-face))
    (should (eq (get-face-at "Bar") 'font-lock-type-face))))
 
-(ert-deftest 
font-lock/variables-in-declaration-singleline-ending-comma-no-hanging-paren ()
-  "Variables should be highlighted in singleline declarations with no hanging 
paren and trailing comma."
+(ert-deftest 
font-lock/funargs--function--singleline-ending-comma-hanging-paren ()
+  "Variables should be highlighted in singleline declarations with hanging 
paren and trailing comma."
   (test-with-fontified-buffer
    "function test(var1,var2,): RetType {\n}"
    (should (eq (get-face-at "var1") 'font-lock-variable-name-face))
    (should (eq (get-face-at "var2") 'font-lock-variable-name-face))))
 
+(ert-deftest font-lock/funargs--function--keywords-as-variables ()
+  "Keywords when used as variables should have variable face"
+  (test-with-fontified-buffer
+      "function test(type, unknown): void {}"
+    (should (eq (get-face-at "type") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "unknown") 'font-lock-variable-name-face))))
+
+(ert-deftest font-lock/funargs--arrow--keywords-as-variables ()
+  "Keywords when used as variables should have variable face"
+  (test-with-fontified-buffer
+      "const test = (type, unknown): void => {}"
+    (should (eq (get-face-at "type") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "unknown") 'font-lock-variable-name-face))))
+
+(ert-deftest font-lock/funargs--arrow--single-line--no-type ()
+  (test-with-fontified-buffer
+      "const test = (aaa, bbb, ccc): void => {}"
+    (should (eq (get-face-at "aaa") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "bbb") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "ccc") 'font-lock-variable-name-face))))
+
+(ert-deftest font-lock/funargs--arrow--single-line--no-type--no-return-type ()
+  (test-with-fontified-buffer
+      "const test = (aaa, bbb, ccc) => {}"
+    (should (eq (get-face-at "aaa") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "bbb") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "ccc") 'font-lock-variable-name-face))))
+
+(ert-deftest font-lock/funargs--arrow--single-line--no-type--trailing-comma ()
+  (test-with-fontified-buffer
+      "const test = (aaa, bbb, ccc,): void => {}"
+    (should (eq (get-face-at "aaa") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "bbb") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "ccc") 'font-lock-variable-name-face))))
+
+(ert-deftest font-lock/funargs--arrow--single-line--no-type--optional ()
+  (test-with-fontified-buffer
+      "const test = (aaa, bbb?): void => {}"
+    (should (eq (get-face-at "aaa") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "bbb?") 'font-lock-variable-name-face))))
+
+(ert-deftest font-lock/funargs--arrow--multiline--no-type ()
+  (test-with-fontified-buffer
+      "const test = (aaa, bbb,
+ccc, ddd): void => {}"
+    (should (eq (get-face-at "aaa") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "bbb") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "ccc") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "ddd") 'font-lock-variable-name-face))))
+
+(ert-deftest font-lock/funargs--arrow--multiline--no-type--newline-after-last 
()
+  (test-with-fontified-buffer
+      "const test = (aaa, bbb,
+ccc, ddd
+): void => {}"
+    (should (eq (get-face-at "aaa") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "bbb") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "ccc") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "ddd") 'font-lock-variable-name-face))))
+
+(ert-deftest 
font-lock/funargs--arrow--multiline--no-type--newline-before-first ()
+  (test-with-fontified-buffer
+      "const test = (
+aaa, bbb,
+ccc, ddd
+): void => {}"
+    (should (eq (get-face-at "aaa") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "bbb") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "ccc") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "ddd") 'font-lock-variable-name-face))))
+
+(ert-deftest font-lock/funargs--arrow--multiline--no-type--with-comment ()
+  (test-with-fontified-buffer
+      "const test = (
+aaa, bbb, // comment
+ccc, ddd  // comment
+): void => {}"
+    (should (eq (get-face-at "aaa") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "bbb") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "ccc") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "ddd") 'font-lock-variable-name-face))))
+
+(ert-deftest 
font-lock/funargs--arrow--single--mixed-type--newline-before-first ()
+  (test-with-fontified-buffer
+      "const test = (aaa, bbb: Promise, ccc: number, ddd): void => {}"
+    (should (eq (get-face-at "aaa") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "bbb") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "ccc") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "ddd") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "Promise") 'font-lock-type-face))
+    (should (eq (get-face-at "number") 'typescript-primitive-face))))
+
+(ert-deftest font-lock/funargs--arrow--single--with-type--complex-type ()
+  (test-with-fontified-buffer
+      "const test = (aaa: Promise<U, V, (xxx: A) => Foo>, bbb): void => {}"
+    (should (eq (get-face-at "aaa") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "bbb") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "xxx") 'font-lock-variable-name-face))))
+
+(ert-deftest 
font-lock/funargs--arrow--multiline--with-type--newline-before-first-after-last 
()
+  (test-with-fontified-buffer
+      "const test = (
+aaa: Foo,
+bbb: Bar
+): void => {}"
+    (should (eq (get-face-at "aaa") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "bbb") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "Foo") 'font-lock-type-face))
+    (should (eq (get-face-at "Bar") 'font-lock-type-face))))
+
+(ert-deftest 
font-lock/funargs--arrow--multiline--with-type--newline-before-first-after-last--hanging-comma
 ()
+  (test-with-fontified-buffer
+      "const test = (
+aaa: Foo,
+bbb: Bar,
+): void => {}"
+    (should (eq (get-face-at "aaa") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "bbb") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "Foo") 'font-lock-type-face))
+    (should (eq (get-face-at "Bar") 'font-lock-type-face))))
+
+(ert-deftest font-lock/funargs--method--multiline--with-type ()
+  (test-with-fontified-buffer
+      "class Foo { foo(
+aaa: Foo,
+bbb: Bar,
+): void {}"
+    (should (eq (get-face-at "aaa") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "bbb") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "Foo") 'font-lock-type-face))
+    (should (eq (get-face-at "Bar") 'font-lock-type-face))))
+
+(ert-deftest font-lock/funargs--method--single-line--with-type ()
+  (test-with-fontified-buffer
+      "class Foo { foo(aaa: Foo,bbb: Bar,): void {}"
+    (should (eq (get-face-at "aaa") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "bbb") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "Foo") 'font-lock-type-face))
+    (should (eq (get-face-at "Bar") 'font-lock-type-face))))
+
+(ert-deftest font-lock/funargs--method--single-line--no-type ()
+  (test-with-fontified-buffer
+      "class Foo { foo(aaa, bbb): void {}"
+    (should (eq (get-face-at "aaa") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "bbb") 'font-lock-variable-name-face))))
+
+(ert-deftest font-lock/funargs--method--single-line--no-return-type ()
+  (test-with-fontified-buffer
+      "class Foo { foo(aaa, bbb) {}"
+    (should (eq (get-face-at "aaa") 'font-lock-variable-name-face))
+    (should (eq (get-face-at "bbb") 'font-lock-variable-name-face))))
+
 (defun flyspell-predicate-test (search-for)
   "This function runs a test on
 `typescript--flyspell-mode-predicate'.  `SEARCH-FOR' is a string
diff --git a/typescript-mode-test-utilities.el 
b/typescript-mode-test-utilities.el
index faa6c1166a..8a1d21e1ae 100644
--- a/typescript-mode-test-utilities.el
+++ b/typescript-mode-test-utilities.el
@@ -26,8 +26,8 @@
   (declare (debug t)
            (indent 1))
   `(test-with-temp-buffer
-    ,content
-     (font-lock-fontify-buffer)
+       ,content
+     (font-lock-ensure (point-min) (point-max))
      ,@body))
 
 (defun get-face-at (loc)
@@ -48,15 +48,15 @@ It should be a list of (LOCATION . FACE) pairs, where
 LOCATION can be either a single location, or list of locations,
 that are all expected to have the same face."
   (test-with-fontified-buffer
-   contents
-   ;; Make sure our propertize function has been applied to the whole
-   ;; buffer.
-   (syntax-propertize (point-max))
-   (dolist (spec expected)
-     (if (listp (car spec))
-         (dolist (source (car spec))
-           (should (eq (get-face-at source) (cdr spec))))
-       (should (eq (get-face-at (car spec)) (cdr spec)))))))
+      contents
+    ;; Make sure our propertize function has been applied to the whole
+    ;; buffer.
+    (syntax-propertize (point-max))
+    (dolist (spec expected)
+      (if (listp (car spec))
+          (dolist (source (car spec))
+            (should (eq (get-face-at source) (cdr spec))))
+        (should (eq (get-face-at (car spec)) (cdr spec)))))))
 
 (provide 'typescript-mode-test-utilities)
 
diff --git a/typescript-mode.el b/typescript-mode.el
index e3ad84c499..032abbc7a5 100644
--- a/typescript-mode.el
+++ b/typescript-mode.el
@@ -1015,7 +1015,7 @@ lines."
                         (progn
                           (forward-comment most-positive-fixnum)
                           (memq (char-after) '(?\, ?\; ?\] ?\) ?\}))))
-              do (forward-sexp)))
+                 do (forward-sexp)))
    while (and (eq (char-after) ?\n)
               (save-excursion
                 (forward-char)
@@ -1686,6 +1686,82 @@ point of view of font-lock.  It applies highlighting 
directly with
   ;; Matcher always "fails"
   nil)
 
+(defun typescript--function-argument-matcher (limit)
+  "Font-lock matcher for variables in argument lists.
+
+Because the syntax of the argument list is shared between
+functions, arrow functions and methods, this same matcher is used
+for all of them.  The context for the search is set up as
+anchored matcher.
+
+This is a cc-mode-style matcher that *always* fails, from the
+point of view of font-lock.  It applies highlighting directly
+with `font-lock-apply-highlight'."
+  (condition-case nil
+      (save-restriction
+        (widen)
+        (narrow-to-region (point-min) limit)
+        (while (re-search-forward
+                (rx (group
+                     (regexp "[a-zA-Z_$]\\(?:\\s_\\|\\sw\\)*")
+                     ;; name can be optionally followed by ? to mark
+                     ;; the argument optional
+                     (? "?"))
+                    (* whitespace)
+                    (group (or "," ":" ")"
+                               ;; last variable in the list with a
+                               ;; paren on next line and no hanging
+                               ;; comma.  extra logic is added to deal
+                               ;; with possible comments after the
+                               ;; variable.
+                               eol
+                               (and (* whitespace) (or "//" "/*") (* any) 
eol))))
+                nil t)
+          (font-lock-apply-highlight '(1 font-lock-variable-name-face t))
+
+          ;; If ender is a ":" it means that the currently matched
+          ;; variable also has a type signature.
+          (let ((ender (match-string 2)))
+            ;; We need to skip the type specification.  The regexp
+            ;; basically either searches for the next thing which we
+            ;; believe is a parameter or the end of the argument list.
+            (when (equal ender ":")
+              (let ((perform-match t))
+                (while (and perform-match
+                            (re-search-forward
+                             (rx (or
+                                  ;; variable without type at the end
+                                  ;; of line
+                                  (and "," eol)
+                                  ;; next thing is a functional
+                                  ;; argument, such as f:(x) => void
+                                  (and "(")
+                                  ;; closing of a function type argument.
+                                  ;; here, the type of `f'.
+                                  ;; (f: (x: number) => foo): void => { }
+                                  (and ")" (? (* whitespace) "=>" (* 
whitespace)))
+                                  (and ","
+                                       (* whitespace)
+                                       (regexp 
"[a-zA-Z_$]\\(?:\\s_\\|\\sw\\)*")
+                                       ;; optional ? to mark the
+                                       ;; argument optional
+                                       (? "?")
+                                       (group (or ":" ")")))))
+                             nil t))
+                  ;; In case the skipped type was the end of a
+                  ;; function type argument, the next token is the
+                  ;; return type of the inner function, so we need to
+                  ;; match but not fontify the next "name" (which
+                  ;; really is the type).
+                  (if (string-match-p "=>" (match-string 0))
+                      (setq perform-match t)
+                    (goto-char (match-beginning 0))
+                    (setq perform-match nil))))))))
+    ;; conditions to handle
+    (scan-error nil)
+    (end-of-buffer nil))
+  nil)
+
 (defun typescript--in-documentation-comment-p ()
   "Reports whether point is inside a documentation comment."
   (let ((parse (syntax-ppss)))
@@ -1863,16 +1939,48 @@ and searches for the next token to be highlighted."
       (concat "\\_<instanceof\\_>\\s-+\\(" typescript--dotted-name-re "\\)")
       (list 1 'font-lock-type-face))
 
-    ;; formal parameters
+    ;; formal parameters in "function" function call
+    ;; function helloWorld(a: number, b: Promise<number>): void { }
     ,(list
       (concat
        "\\_<function\\_>\\(\\s-+" typescript--name-re 
"\\)?\\s-*\\(<.*>\\)?\\s-*(\\s-*"
        "\\(?:$\\|" typescript--name-start-re "\\)")
-      `(,(concat "\\(" typescript--name-re "\\)\\(?:\\s-*?\\([,:)]\\|$\\)\\)")
-        (prog1 (save-excursion (re-search-forward ")" nil t))
+      `(typescript--function-argument-matcher
+        (prog1 (save-excursion (ignore-errors (up-list)) (point))
           (backward-char))
         nil
-        (1 font-lock-variable-name-face))))
+        nil))
+
+    ;; formal parameters in arrow function
+    ;; const helloWorld = (a: number, b: Promise<number>): void => { }
+    ,(list
+      (rx (group "=>") (* whitespace) (? eol) (* whitespace) "{")
+      '(1 font-lock-keyword-face)
+      `(typescript--function-argument-matcher
+        (prog1 (progn
+                 (backward-char)
+                 (typescript--backward-to-parameter-list)
+                 (point))
+          (backward-sexp))
+        (re-search-forward "{" nil t)
+        nil))
+
+    ;; formal parameters in method definitions
+    ;; class Foo { helloWorld(a: number, b: Promise<number>): void { } }
+    ,(list
+      typescript--function-call-re
+      `(typescript--function-argument-matcher
+        (let ((point-orig (point))
+              (is-method-def
+               (ignore-errors
+                 (up-list)
+                 (looking-at-p
+                  (rx (* (or whitespace ?\n)) (or ":" "{"))))))
+          (if is-method-def
+              (prog1 (point) (goto-char point-orig))
+            (point)))
+        nil
+        nil)))
   "Level three font lock for `typescript-mode'.")
 
 (defun typescript--flyspell-mode-predicate ()



reply via email to

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