From b99d893a46222e455670d90a337a2d0cd42d8432 Mon Sep 17 00:00:00 2001 From: Matus Goljer Date: Mon, 8 Aug 2022 14:30:26 +0200 Subject: [PATCH] fix(fontlock): fix special forms/ternary mistaken for method declarations Sometimes a special form such as if (...) {..} or a ternary a ? b(...) : c might look like a method declaration and then the insides of the parentheses get fontified as variables. Here we add a heuristic to discard these cases. It's not 100% but works in most real-life situations. --- typescript-mode-general-tests.el | 16 ++++++++++++++++ typescript-mode.el | 30 ++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/typescript-mode-general-tests.el b/typescript-mode-general-tests.el index ff8220b..8522eed 100644 --- a/typescript-mode-general-tests.el +++ b/typescript-mode-general-tests.el @@ -846,6 +846,22 @@ bbb: Bar, (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--no-fontification-in-ternary () + "Do not apply fontification on a function call inside a ternary +operator, which might look like method with return type +declaration." + (test-with-fontified-buffer + "true ? funcall(helloWorld) : false" + (should (eq (get-face-at "helloWorld") nil)))) + +(ert-deftest font-lock/funargs--method--no-fontification-in-special-form () + "Do not apply fontification inside a special form paren-form, +such as inside of if/while/switch etc. These look like method +declarations without a return type annotation but are not." + (test-with-fontified-buffer + "if (hello && world) { }" + (should (eq (get-face-at "world") nil)))) + (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.el b/typescript-mode.el index 47d5c4b..47f8fa9 100644 --- a/typescript-mode.el +++ b/typescript-mode.el @@ -1974,8 +1974,34 @@ and searches for the next token to be highlighted." (is-method-def (ignore-errors (up-list) - (looking-at-p - (rx (* (or whitespace ?\n)) (or ":" "{")))))) + (and + (or + ;; After the "argument list" is a bracket, this is + ;; either a special form (if, while...) or a method + ;; declaration. + (looking-at-p (rx (* (or whitespace ?\n)) "{")) + ;; After the "argument list" is a colon, this is + ;; either a method declaration with a return type + ;; annotation or ternary form. We need to discard + ;; the ternary form case. + (and + (looking-at-p (rx (* (or whitespace ?\n)) ":")) + (save-excursion + (backward-sexp 2) + (skip-syntax-backward " >") + (not (eq (char-before) ??))))) + ;; HACK: here we check the fontification of + ;; the "function name". Because the keywords + ;; are fontified before this check runs, a + ;; keyword would already have been fontified + ;; and therefore we can conclude it is not a + ;; function/method definition. + (save-excursion + (backward-sexp) + (backward-word) + (not (memq + 'font-lock-keyword-face + (face-at-point nil t)))))))) (if is-method-def (prog1 (point) (goto-char point-orig)) (point)))