From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Theodor Thornhill Newsgroups: gmane.emacs.devel Subject: Re: Call for volunteers: add tree-sitter support to major modes Date: Mon, 10 Oct 2022 09:08:57 +0200 Message-ID: <87o7uk5f5i.fsf@thornhill.no> References: <83czb1jrm3.fsf@gnu.org> <84436B1D-3359-487F-B997-A7F56FDEA636@thornhill.no> <83bkqljih5.fsf@gnu.org> <87fsfx6ufb.fsf@thornhill.no> <8335bxjdpf.fsf@gnu.org> <1D07A0F1-A269-410A-9D3C-8A53113FFE2F@thornhill.no> <83sfjxhuvc.fsf@gnu.org> <87bkqk7qb0.fsf@thornhill.no> <8735bw7kwm.fsf@thornhill.no> <158F25C9-A539-4515-8D49-50A7E6252960@gmail.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="6730"; mail-complaints-to="usenet@ciao.gmane.io" Cc: Eli Zaretskii , emacs-devel@gnu.org To: Yuan Fu Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Mon Oct 10 09:10:52 2022 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1ohmw6-0001VO-Rj for ged-emacs-devel@m.gmane-mx.org; Mon, 10 Oct 2022 09:10:51 +0200 Original-Received: from localhost ([::1]:45350 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ohmw5-0006Yh-MH for ged-emacs-devel@m.gmane-mx.org; Mon, 10 Oct 2022 03:10:49 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:34376) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ohmuR-0005an-AH for emacs-devel@gnu.org; Mon, 10 Oct 2022 03:09:08 -0400 Original-Received: from out0.migadu.com ([2001:41d0:2:267::]:65153) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ohmuM-0006DP-Fy; Mon, 10 Oct 2022 03:09:06 -0400 X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=thornhill.no; s=key1; t=1665385738; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=c3DtqBJUAwwv5oZa/B0+cChmnopS1BrKcOMoJV6dUew=; b=Bp3XqV5ra00KS42ITjeacQuD7VlJMQVEjvxW8ZvuTUHLRnBX/F9SNgHEN0vq4In4OeahED Mv8eK41qSAt0agKfbMGeXqkv1UdMhQMoh3zqGlUC+05E9Sh0J6W7z6797A+FVVlNVPZxgD Wsbs/vfvT5cEn2X+wocz39YAiBtZLp9P97cL2xz5+pqC42jj5tXzOMin0eLDaHxyOAJwrj XdPkTp8BV4KmH1rWtFL5JOthVdBvdX3cRQndgLuIaGf2LIZDe/Y/z/mV1RiK2B807e5Ng6 tfUJsG3D8AySSbQ1zy2mO0qWyrgfe/yh0mqJiOxShHMLOFOFnouvU3UbkEPbUw== In-Reply-To: <158F25C9-A539-4515-8D49-50A7E6252960@gmail.com> X-Migadu-Flow: FLOW_OUT Received-SPF: pass client-ip=2001:41d0:2:267::; envelope-from=theo@thornhill.no; helo=out0.migadu.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.io gmane.emacs.devel:297323 Archived-At: --=-=-= Content-Type: text/plain Hi! > Looks good! Here are some comments. > > + > + ;; FIXME: We need to be able to set the priority for font-locking > + ;; somehow. We cannot just override all of the template string, > + ;; as that would mess up interpolated expressions > + ;; > + ;; (template_string) @font-lock-string-face > + (template_substitution ["${" "}"] @font-lock-constant-face) > + ))) > > What exactly do you mean by priority here? Why doesn't :override t > work? > In template strings in JavaScript we have issues with precedence in that we default to string font locking for everything that does _not_ have specific rules. An image speaks a thousand words, so I'll add screenshots. What I need is some sort of way to ensure that inside of template strings font-locking should _not_ happen > + > +(defvar js-treesit--defun-query > + "[(class_declaration) > + (method_definition) > + (function_declaration) > + (variable_declarator)] @defun") > > This should be compiled. > > + > +(defun js--treesit-enable () > + (unless (and (treesit-can-enable-p) > + (treesit-language-available-p 'javascript)) > + (error "Tree sitter isn't available")) > > I don't think we should error here, I'd displaying a message instead. > > + > + ;; Comments > + (setq-local comment-start "// ") > + (setq-local comment-start-skip "\\(?://+\\|/\\*+\\)\\s *") > + (setq-local comment-end "") > > I think it's best to not repeat code, could you move this outside the > (if tree-sitter) form and have it run regardless? > > +(defun js--json-treesit-enable () > + (unless (and (treesit-can-enable-p) > + (treesit-language-available-p 'json)) > + (error "Tree sitter isn't available")) > > Same as above, IMO message is better. > I added some variartion of this. I think also message is better, because user-error makes the logic a little harder. What do you think? Thanks, see attached patch: --=-=-= Content-Type: image/png Content-Disposition: attachment; filename=font-lock-on-string.png Content-Transfer-Encoding: base64 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 Bnm/otP65KPM4H4DACwtLZctW0YcPtm5c+eYMWOI4zHkqeStQB6V6fZIAEAcpSPOuBUWFlpbW/fp 04fKbI9OVPRHN0krNMqeEADkcvmePXs0Lejg4NCzZ09i1yGRSDZv3nz37l1izVOnTnXq1CkoKOjP P/80WBvkyPdX+Dmow3St/46gNNtzdnZ2d3dfu3atEalG8PDwePjwoeYLNwDcv38/MjJS8zI3N1c7 NScnx8rKisFgaC9scORReXp6pqSkaPdpqVR69epVnUzs7e3Hjx+/ffv2eo1AkvI6OjomJSVpr6w5 3UmzRHFxcQwGY8mSJWfPnr1x4wb8bw9ChUwm43K5XC5XLpcTS1QqVWZmJsW3kyCPik7MBpG0Ap3y enh4EJfsaDx+/Fjzf4sWLX799VedMKqqqlxdXdPS0owvDO02IqkNg+PXaOSjjMp2z58/rzlTplQq 9+3bRyWVvBUojn1TKCgo0L64KjU1dfLkyRwOx6T3M9If3eStQMJEe0IAEIvF2i2Ympo6fPhwIufr 16/rrCyRSKytrYn/6dQG+f7KdJ+DQqGw9tMzjh07pvk+Q+Lt+xx8d1Ca7XXr1u3u3bv6PjjJU/Vx c3PTDHKZTDZ9+nRNEnENivbKxcXFAoGAyWQS+widq0cVCgWDwWCxWCZtYPKoLC0ts7KyyHNgMBgz Z868detWfT8JSMrL4/FkMlm9ctMgLxFxJU1VVVVJSUlubm69ck5NTS0oKPjyyy+vXLmSkZGRkZHR UN8vyaOiE7NBJK1Ap7wikSgjI0N7iXaDCoXCmTNnEmc3NLhcrkAgMLIY/0OzjUhqw+D4NRr5KKOy XfJBqi+VvBWojH0T0TlkUlxczGAwLCwsGuT5HfrQH91GV5eJ9oRQqyYlEgmbzebz+ZWVlQKBYOTI kUFBQUKhkMViAQCbzdaMWTq1Qb6/Mt3nYHl5ee0H95SVlVGJ+e37HHx3GJ7tMRiMrl276rshnDyV RHZ29tdff038r/MZwOFwdNqV6L4cDqcRW5Q8Kirfpz/99FMWi/XJJ580YFRKpZLNZhv3XtPVs1Kp XL58eXh4uL+/f+fOnZ2cnJ4/f753717yxyy9ueiUl7zncDic3bt3P3z4UGc5cc1QY8VMznT9ymBd Gdwu+SDVl0reCqY+lkYdEQaHwzHpVuj3HFNUF509YW1EhFwut7KycvLkya6urrt37y4sLCQ+qjT3 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 --=-=-= Content-Type: image/png Content-Disposition: attachment; filename=no-font-lock.png Content-Transfer-Encoding: base64 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 soeHR0JCQm5urkgkys3NjY6ONjd/uy+o3UbkuvL39z9//nxxcXFlZeXDhw/lb25SGxVZYGBgUlIS j8errKy8efNm27Zt5VP79+9//fr14uJioVCYkZGxefNmY2NjOjVJLpHamMnrJcdMxjAqQoslb0GG 9UxAaBsUwjYiYLKXqW3tqsrr5+cnlUr37dtXXl5+7ty5li1bpqamVlZWJiQk6OvrA8COHTsuXLjw 559/8ng8oVD44sWLZcuW6enROoNELpHGMdNBaDlq1yuVSjt27LhkyZKcnJzy8vLLly+3aNFClsqk PU+cODE1NZXP5wuFwtTU1G3btvF4PIXI09PTs7Ky+vfvT7OkAAAmFpD/qtYUUSXcPKE4WykXLJoq zcDMxJJX9q7FykZ1YQMXromo1T87O3if3SflGBgBjREFYayidkTRzMZNNt3XS3HvZjLOMTY29vHx uX//vtKqkKmurk5LS+vYsSN5trq4XG7TpsrrWSUjQ9ODW7KXfX/Kp2VX26YuPi27rl98/efFN/T1 2QBgbGR2ZHvB7Ml73Z397W09+gVNOhlbGdRxOLVs2MCFZ/bW/Gd8VAvXABtrJ+8WXaJXP/x+0i4q 1drS4Y9dognD17o5tbGxdvJwabtwesKW5clUqqWFnVUT+22Rd4eFRFg1saf+1S/0P09C6EAl001M 4HoSrPoRvLzAyQmGDIY7f0O/vrRSG4idnZ29vf3du3cjIiLs/0eWOnbsWKlU+ssvv/j6+rq6ug4f PpzH48n3/vr6+tQiFRUVCl2Dg4ODSCRau3ZtmzZtnJyc2rZtm5CQkJycTDMwHeU8bdq03NzcL7/8 0snJycvLa968eeXl5c2bN6cZFQA8efJk7NixdaerHdjV1NRERUUFBAQ4OTl16dLl4cOHu3a9bbGm pqbZ2dmnTp3q2rWri4tL165dr1+/fuPGDTabDeq2EbmuzMzMCgoK9u7d6+/v7+HhMWnSpMrKyuHD h8tiJkRFZm9vz+fzt23b1rp161atWk2fPr2wsFD2vdK+fXuBQDBnzhxvb28XF5devXrdvn17//79 dGqSXCJyzOT1kmNWS+Oo1LZYQs7M61kVctugELYRAZO9jNzaCeWlBnaxsbEeHh63b9/Oy8ubPHly mzZtSktLP//8cwDYsWNHWVnZlClTvL29XV1dhw4dWlhYuHjxYoUArl69WvcaO3KJNI5ZLXLLUdsz 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 2K46dOggH0bPnj0zMjIUriopKSmpeycgnRLpImY6LUcXvTfZoUOHQkNDv/nmGwMDA0NDw9DQUKXv I7GwsHBycqpf1kNmQvPag2DX1sBiQXHt09YOHpCneDszWUlpXjMbN/kp9rZ0+2fyWIWi2YiCyTiH 8vfff/fq1Ys8T9u2bU1MTP755x/62VI8PDzq3jauytsy3Eg+xmZzFs442qpFZ1trZ1+v7ivnnv+6 /1y2vgEA/PfO7yZG5rO+3e3m1Mbe1r1f0KQhX8w+k/QLnRV4urWfPzW+d9dxdk1d7Zq6+nv3nPvd /jd5T/MK3w2D7qUl9goc09E/xLapS3DnEUe2FypsdU0kXgETU/hxBXh6gqMjDBkM48fBseO0UhtU YmLimDFjQkJCXFxcRowYUVhYqDBGUaVZs2bUk5BYLJa1tTX1mTpw1b59+/j4+HHjxrm6urq6uvbs 2XP//v1Pnz6lORjVUc6JiYkrV67s2rWrk5OTn59fdHS0qalp37596T85WZWrV6/a2touX77c3d3d zc0tJCTk559/prnssWPHOBzO0aNHO3fu7Ozs3L179/Pnz8+dO1f+om/CNiLU1e+//25ubr579+42 bdq4u7tPmjRp9uzZv/xCaz8iO3jwoI+Pz9atW318fFxdXXv37r1u3TpZamxsbJcuXaKjo/39/d3c 3EaMGJGYmKgwQCEglIiMvF5yzLqLSm2LJeSsu3rWXdtgvpepau0M25WLi0t8fHzHjh3d3NyGDh26 evXquuX9+++/w8LCPvvss27dum3evJl+iXQRM52+The9N9k///wzbdq0n376SSgUVlZWRkdHU09I VphNkwcUe7WHyBMQ0AfMrUGfDT6dYXYMPE2B4toP9rK2B1497ngFgPtPrjYxtx0zeLm9rXszG7eO /iHfjqTbP5PHKhTCiMLSohn1HDsWi2Vuak19pg4fMhnnUOLj44cPH07+1TRq1KiTJ09qcOGsvb19 vZ5X8JajvdeS//vt8Lb8P3aL47fkzBi3s+6bJ45HlZyME/yy5hH9Z9IAQK/AMTFr0v7YJToZJ9i7 IWPud/sVxm36+uypo7cc2V7wx27x3g0Zg/rW5xW5qh5QDP97t8RfN+DO33Dy91pPuVOb2nDYbDb1 egmxWJyRkSF7YfDYsWMVbq23t7eXSqWy32FVVVXSOqjHgQLAmDFj0tLSRCKRQCDIyMjYv38/zR5H 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 --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=0001-Add-tree-sitter-functionality-to-js-mode.patch >From 42628d295ffa2a83a113a0d77a70d360c119060d Mon Sep 17 00:00:00 2001 From: Theodor Thornhill Date: Sun, 9 Oct 2022 21:22:55 +0200 Subject: [PATCH] Add tree-sitter functionality to js-mode * lisp/progmodes/js.el (treesit): Add tree-sitter dependency (js-use-treesitter): Defcustom to enable tree-sitter as the engine for font-lock, indentation and more. (js--treesit-backward-up-list): Helper to enable indenting of empty bodies. (js--treesit-indent-rules): Rules to be used when indenting JavaScript code. (js--treesit-keywords): Keywords as seen with tree-sitter. (js--treesit-settings): Font-Lock settings for JavaScript. (js-treesit-current-defun): Helper for which-function-mode. (js--treesit-move-to-node): Helper for movement to specific nodes in the tree-sitter tree. (js--treesit-beginning-of-defun, js--treesit-end-of-defun): Movement functions for js-mode. (js--treesit-enable): Helper function to enable tree-sitter. Skips over most initalization done by the CC-Mode variant. (js-json-use-treesitter): Defcustom to enable tree-sitter as the engine for font-lock and indentation for JSON files. (js--json-treesit-settings): Font-Lock settings for JSON. (js--json-treesit-indent-rules): Rules to be used when indenting JSON code (js--json-treesit-enable): Helper function to enable tree-sitter. Skips over most initialization done by the CC-Mode variant, in addition to ignoring some JavaScript specific settings. (js-mode, js-json-mode, js-jsx-mode): Add support for tree-sitter functionalities. --- lisp/progmodes/js.el | 460 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 376 insertions(+), 84 deletions(-) diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el index b920ef6c2c..d1f655cdc4 100644 --- a/lisp/progmodes/js.el +++ b/lisp/progmodes/js.el @@ -53,6 +53,7 @@ (require 'imenu) (require 'json) (require 'prog-mode) +(require 'treesit) (eval-when-compile (require 'cl-lib) @@ -3400,100 +3401,389 @@ js-jsx--detect-after-change (c-lang-defconst c-paragraph-start js-mode "\\(@[[:alpha:]]+\\>\\|$\\)") +;;; Tree sitter integration +(defcustom js-use-treesitter nil + "If non-nil, `js-mode' tries to use tree-sitter. +Currently `js-mode' uses tree-sitter for font-locking, +indentation, which-function and movement functions." + :version "29.1" + :type 'boolean + :safe 'booleanp) + +(defun js--treesit-backward-up-list () + (lambda (_node _parent _bol &rest _) + (save-excursion + (backward-up-list 1 nil t) + (goto-char + (treesit-node-start + (treesit-node-at (point)))) + (back-to-indentation) + (point)))) + +(defvar js--treesit-indent-rules + `((javascript + (no-node (js--treesit-backward-up-list) ,js-indent-level) + ((node-is "}") parent-bol 0) + ((node-is ")") parent-bol 0) + ((node-is "]") parent-bol 0) + ((node-is ">") parent-bol 0) + ((node-is ".") parent-bol ,js-indent-level) + ((parent-is "named_imports") parent-bol ,js-indent-level) + ((parent-is "statement_block") parent-bol ,js-indent-level) + ((parent-is "variable_declarator") parent-bol ,js-indent-level) + ((parent-is "arguments") parent-bol ,js-indent-level) + ((parent-is "array") parent-bol ,js-indent-level) + ((parent-is "formal_parameters") parent-bol ,js-indent-level) + ((parent-is "template_substitution") parent-bol ,js-indent-level) + ((parent-is "object_pattern") parent-bol ,js-indent-level) + ((parent-is "object") parent-bol ,js-indent-level) + ((parent-is "arrow_function") parent-bol ,js-indent-level) + ((parent-is "parenthesized_expression") parent-bol ,js-indent-level) + + ;; JSX + ((parent-is "jsx_opening_element") parent ,js-indent-level) + ((node-is "jsx_closing_element") parent 0) + ((node-is "jsx_text") parent ,js-indent-level) + ((parent-is "jsx_element") parent ,js-indent-level) + ((node-is "/") parent 0) + ((parent-is "jsx_self_closing_element") parent ,js-indent-level)))) + +(defvar js--treesit-keywords + '("as" "async" "await" "break" "case" "catch" "class" "const" "continue" + "debugger" "default" "delete" "do" "else" "export" "extends" "finally" + "for" "from" "function" "get" "if" "import" "in" "instanceof" "let" "new" + "of" "return" "set" "static" "switch" "switch" "target" "throw" "try" + "typeof" "var" "void" "while" "with" "yield")) + +(defvar js--treesit-settings + (treesit-font-lock-rules + :language 'javascript + :override t + `( + ((identifier) @font-lock-constant-face + (:match "^[A-Z_][A-Z_\\d]*$" @font-lock-constant-face)) + + (new_expression + constructor: (identifier) @font-lock-type-face) + + (function + name: (identifier) @font-lock-function-name-face) + + (class_declaration + name: (identifier) @font-lock-type-face) + + (function_declaration + name: (identifier) @font-lock-function-name-face) + + (method_definition + name: (property_identifier) @font-lock-function-name-face) + + (variable_declarator + name: (identifier) @font-lock-function-name-face + value: [(function) (arrow_function)]) + + (variable_declarator + name: (array_pattern (identifier) (identifier) @font-lock-function-name-face) + value: (array (number) (function))) + + (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 + function: [(identifier) @font-lock-function-name-face + (member_expression + property: (property_identifier) @font-lock-function-name-face)]) + + (variable_declarator + name: (identifier) @font-lock-variable-name-face) + + (assignment_expression + left: [(identifier) @font-lock-variable-name-face + (member_expression property: (property_identifier) @font-lock-variable-name-face)]) + + (for_in_statement + left: (identifier) @font-lock-variable-name-face) + + (arrow_function + parameter: (identifier) @font-lock-variable-name-face) + + (pair key: (property_identifier) @font-lock-variable-name-face) + + (pair value: (identifier) @font-lock-variable-name-face) + + (pair + key: (property_identifier) @font-lock-function-name-face + value: [(function) (arrow_function)]) + + ((shorthand_property_identifier) @font-lock-variable-name-face) + + (pair_pattern key: (property_identifier) @font-lock-variable-name-face) + + ((shorthand_property_identifier_pattern) @font-lock-variable-name-face) + + (array_pattern (identifier) @font-lock-variable-name-face) + + (jsx_opening_element + [(nested_identifier (identifier)) (identifier)] + @font-lock-function-name-face) + + (jsx_closing_element + [(nested_identifier (identifier)) (identifier)] + @font-lock-function-name-face) + + (jsx_self_closing_element + [(nested_identifier (identifier)) (identifier)] + @font-lock-function-name-face) + + (jsx_attribute + (property_identifier) + @font-lock-constant-face) + + [(this) (super)] @font-lock-keyword-face + + [(true) (false) (null)] @font-lock-constant-face + (regex pattern: (regex_pattern)) @font-lock-string-face + (number) @font-lock-constant-face + + (string) @font-lock-string-face + (comment) @font-lock-comment-face + [,@js--treesit-keywords] @font-lock-keyword-face + + ;; FIXME: We need to be able to set the priority for font-locking + ;; somehow. We cannot just override all of the template string, + ;; as that would mess up interpolated expressions + ;; + ;; (template_string) @font-lock-string-face + (template_substitution ["${" "}"] @font-lock-constant-face) + ))) + + +(defun js-treesit-current-defun () + "Return name of surrounding function. +This function can be used as a value in `which-func-functions'" + (let ((node (treesit-node-at (point))) + (name-list ())) + (cl-loop while node + if (pcase (treesit-node-type node) + ("function_declaration" t) + ("method_definition" t) + ("class_declaration" t) + ("variable_declarator" t) + (_ nil)) + do (push (treesit-node-text + (treesit-node-child-by-field-name node "name") + t) + name-list) + do (setq node (treesit-node-parent node)) + finally return (string-join name-list ".")))) + +(defun js--treesit-move-to-node (fn) + (when-let ((found-node + (treesit-parent-until + (treesit-node-at (point)) + (lambda (parent) + (treesit-query-capture + parent + js-treesit--defun-query))))) + (goto-char (funcall fn found-node)))) + +(defun js--treesit-beginning-of-defun (&optional _arg) + (js--treesit-move-to-node #'treesit-node-start)) + +(defun js--treesit--end-of-defun (&optional _arg) + (js--tressit-move-to-node #'treesit-node-end)) + +(defvar js-treesit--defun-query + (treesit-query-compile + 'javascript + "[(class_declaration) + (method_definition) + (function_declaration) + (variable_declarator)] @defun")) + +(defun js--treesit-can-enable-p () + (if (and js-use-treesitter + (treesit-can-enable-p) + (treesit-language-available-p 'javascript)) + t + (message "Cannot enable Tree Sitter for JavaScript.") + nil)) + +(defun js--treesit-enable () + (setq-local treesit-simple-indent-rules js--treesit-indent-rules) + (setq-local indent-line-function #'treesit-indent) + + (setq-local beginning-of-defun-function #'js--treesit-beginning-of-defun) + (setq-local end-of-defun-function #'js--treesit-end-of-defun) + + (setq-local font-lock-defaults '(nil t)) + (setq-local treesit-font-lock-settings js--treesit-settings) + + (add-hook 'which-func-functions #'js-treesit-current-defun nil t) + + (treesit-font-lock-enable)) + ;;; Main Function ;;;###autoload (define-derived-mode js-mode prog-mode "JavaScript" "Major mode for editing JavaScript." :group 'js - ;; Ensure all CC Mode "lang variables" are set to valid values. - (c-init-language-vars js-mode) - (setq-local indent-line-function #'js-indent-line) - (setq-local beginning-of-defun-function #'js-beginning-of-defun) - (setq-local end-of-defun-function #'js-end-of-defun) - (setq-local open-paren-in-column-0-is-defun-start nil) - (setq-local font-lock-defaults - (list js--font-lock-keywords nil nil nil nil - '(font-lock-syntactic-face-function - . js-font-lock-syntactic-face-function))) - (setq-local syntax-propertize-function #'js-syntax-propertize) - (add-hook 'syntax-propertize-extend-region-functions - #'syntax-propertize-multiline 'append 'local) - (add-hook 'syntax-propertize-extend-region-functions - #'js--syntax-propertize-extend-region 'append 'local) - (setq-local prettify-symbols-alist js--prettify-symbols-alist) - - (setq-local parse-sexp-ignore-comments t) - (setq-local which-func-imenu-joiner-function #'js--which-func-joiner) - ;; Comments (setq-local comment-start "// ") (setq-local comment-start-skip "\\(?://+\\|/\\*+\\)\\s *") (setq-local comment-end "") - (setq-local fill-paragraph-function #'js-fill-paragraph) - (setq-local normal-auto-fill-function #'js-do-auto-fill) - - ;; Parse cache - (add-hook 'before-change-functions #'js--flush-caches t t) - - ;; Frameworks - (js--update-quick-match-re) - - ;; Syntax extensions - (unless (js-jsx--detect-and-enable) - (add-hook 'after-change-functions #'js-jsx--detect-after-change nil t)) - (js-use-syntactic-mode-name) - - ;; Imenu - (setq imenu-case-fold-search nil) - (setq imenu-create-index-function #'js--imenu-create-index) - - ;; for filling, pretend we're cc-mode - (c-foreign-init-lit-pos-cache) - (add-hook 'before-change-functions #'c-foreign-truncate-lit-pos-cache nil t) - (setq-local comment-line-break-function #'c-indent-new-comment-line) - (setq-local comment-multi-line t) - (setq-local electric-indent-chars - (append "{}():;," electric-indent-chars)) ;FIXME: js2-mode adds "[]*". - (setq-local electric-layout-rules - '((?\; . after) (?\{ . after) (?\} . before))) - - (let ((c-buffer-is-cc-mode t)) - ;; FIXME: These are normally set by `c-basic-common-init'. Should - ;; we call it instead? (Bug#6071) - (make-local-variable 'paragraph-start) - (make-local-variable 'paragraph-separate) - (make-local-variable 'paragraph-ignore-fill-prefix) - (make-local-variable 'adaptive-fill-mode) - (make-local-variable 'adaptive-fill-regexp) - ;; While the full CC Mode style system is not yet in use, set the - ;; pertinent style variables manually. - (c-initialize-builtin-style) - (let ((style (cc-choose-style-for-mode 'js-mode c-default-style))) - (c-set-style style)) - (setq c-block-comment-prefix "* " - c-comment-prefix-regexp "//+\\|\\**") - (c-setup-paragraph-variables)) - - ;; Important to fontify the whole buffer syntactically! If we don't, - ;; then we might have regular expression literals that aren't marked - ;; as strings, which will screw up parse-partial-sexp, scan-lists, - ;; etc. and produce maddening "unbalanced parenthesis" errors. - ;; When we attempt to find the error and scroll to the portion of - ;; the buffer containing the problem, JIT-lock will apply the - ;; correct syntax to the regular expression literal and the problem - ;; will mysteriously disappear. - ;; FIXME: We should instead do this fontification lazily by adding - ;; calls to syntax-propertize wherever it's really needed. - ;;(syntax-propertize (point-max)) - ) + + (if (js--treesit-can-enable-p) + (js--treesit-enable) + ;; Ensure all CC Mode "lang variables" are set to valid values. + (c-init-language-vars js-mode) + (setq-local indent-line-function #'js-indent-line) + (setq-local beginning-of-defun-function #'js-beginning-of-defun) + (setq-local end-of-defun-function #'js-end-of-defun) + (setq-local open-paren-in-column-0-is-defun-start nil) + (setq-local font-lock-defaults + (list js--font-lock-keywords nil nil nil nil + '(font-lock-syntactic-face-function + . js-font-lock-syntactic-face-function))) + (setq-local syntax-propertize-function #'js-syntax-propertize) + (add-hook 'syntax-propertize-extend-region-functions + #'syntax-propertize-multiline 'append 'local) + (add-hook 'syntax-propertize-extend-region-functions + #'js--syntax-propertize-extend-region 'append 'local) + (setq-local prettify-symbols-alist js--prettify-symbols-alist) + + (setq-local parse-sexp-ignore-comments t) + (setq-local which-func-imenu-joiner-function #'js--which-func-joiner) + + (setq-local fill-paragraph-function #'js-fill-paragraph) + (setq-local normal-auto-fill-function #'js-do-auto-fill) + + ;; Parse cache + (add-hook 'before-change-functions #'js--flush-caches t t) + + ;; Frameworks + (js--update-quick-match-re) + + ;; Syntax extensions + (unless (js-jsx--detect-and-enable) + (add-hook 'after-change-functions #'js-jsx--detect-after-change nil t)) + (js-use-syntactic-mode-name) + + ;; Imenu + (setq imenu-case-fold-search nil) + (setq imenu-create-index-function #'js--imenu-create-index) + + ;; for filling, pretend we're cc-mode + (c-foreign-init-lit-pos-cache) + (add-hook 'before-change-functions #'c-foreign-truncate-lit-pos-cache nil t) + (setq-local comment-line-break-function #'c-indent-new-comment-line) + (setq-local comment-multi-line t) + (setq-local electric-indent-chars + (append "{}():;," electric-indent-chars)) ;FIXME: js2-mode adds "[]*". + (setq-local electric-layout-rules + '((?\; . after) (?\{ . after) (?\} . before))) + + (let ((c-buffer-is-cc-mode t)) + ;; FIXME: These are normally set by `c-basic-common-init'. Should + ;; we call it instead? (Bug#6071) + (make-local-variable 'paragraph-start) + (make-local-variable 'paragraph-separate) + (make-local-variable 'paragraph-ignore-fill-prefix) + (make-local-variable 'adaptive-fill-mode) + (make-local-variable 'adaptive-fill-regexp) + ;; While the full CC Mode style system is not yet in use, set the + ;; pertinent style variables manually. + (c-initialize-builtin-style) + (let ((style (cc-choose-style-for-mode 'js-mode c-default-style))) + (c-set-style style)) + (setq c-block-comment-prefix "* " + c-comment-prefix-regexp "//+\\|\\**") + (c-setup-paragraph-variables)) + + ;; Important to fontify the whole buffer syntactically! If we don't, + ;; then we might have regular expression literals that aren't marked + ;; as strings, which will screw up parse-partial-sexp, scan-lists, + ;; etc. and produce maddening "unbalanced parenthesis" errors. + ;; When we attempt to find the error and scroll to the portion of + ;; the buffer containing the problem, JIT-lock will apply the + ;; correct syntax to the regular expression literal and the problem + ;; will mysteriously disappear. + ;; FIXME: We should instead do this fontification lazily by adding + ;; calls to syntax-propertize wherever it's really needed. + ;;(syntax-propertize (point-max)) + )) + +(defcustom js-json-use-treesitter nil + "If non-nil, `js-json-mode' tries to use tree-sitter. +Currently `js-json-mode' uses tree-sitter for font-locking and +indentation." + :version "29.1" + :type 'boolean + :safe 'booleanp) + +(defvar js--json-treesit-settings + (treesit-font-lock-rules + :language 'json + :override t + `( + (pair + key: (_) @font-lock-string-face) + + (string) @font-lock-string-face + + (number) @font-lock-constant-face + + [(null) (true) (false)] @font-lock-constant-face + + (escape_sequence) @font-lock-constant-face + + (comment) @font-lock-comment-face + ))) + + +(defvar js--json-treesit-indent-rules + `((json + (no-node (js--treesit-backward-up-list) ,js-indent-level) + ((node-is "}") parent-bol 0) + ((node-is ")") parent-bol 0) + ((node-is "]") parent-bol 0) + ((parent-is "object") parent-bol ,js-indent-level) + ))) + + +(defun js--json-treesit-can-enable-p () + (if (and js-json-use-treesitter + (treesit-can-enable-p) + (treesit-language-available-p 'json)) + t + (error "Cannot enable Tree Sitter for JSON.") + nil)) + + +(defun js--json-treesit-enable () + (setq-local treesit-simple-indent-rules js--json-treesit-indent-rules) + (setq-local indent-line-function #'treesit-indent) + + (setq-local beginning-of-defun-function #'ignore) + (setq-local end-of-defun-function #'ignore) + + (setq-local font-lock-defaults '(nil t)) + (setq-local treesit-font-lock-settings js--json-treesit-settings) + + (treesit-font-lock-enable)) + ;;;###autoload (define-derived-mode js-json-mode js-mode "JSON" - (setq-local js-enabled-frameworks nil) - ;; Speed up `syntax-ppss': JSON files can be big but can't hold - ;; regexp matchers nor #! thingies (and `js-enabled-frameworks' is nil). - (setq-local syntax-propertize-function #'ignore)) + (if (js--json-treesit-can-enable-p) + (js--json-treesit-enable) + (setq-local js-enabled-frameworks nil) + ;; Speed up `syntax-ppss': JSON files can be big but can't hold + ;; regexp matchers nor #! thingies (and `js-enabled-frameworks' is nil). + (setq-local syntax-propertize-function #'ignore))) ;; Since we made JSX support available and automatically-enabled in ;; the base `js-mode' (for ease of use), now `js-jsx-mode' simply @@ -3520,9 +3810,11 @@ js-jsx-mode `js-jsx-enable' in `js-mode-hook'. You may be better served by one of the aforementioned options instead of using this mode." :group 'js - (js-jsx-enable) - (setq-local comment-region-function #'js-jsx--comment-region) - (js-use-syntactic-mode-name)) + (if (js--treesit-can-enable-p) + (js--treesit-enable) + (js-jsx-enable) + (setq-local comment-region-function #'js-jsx--comment-region) + (js-use-syntactic-mode-name))) (defun js-jsx--comment-region (beg end &optional arg) (if (or (js-jsx--context) -- 2.34.1 --=-=-=--