[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: TypeScript support for tree-sitter (was Re: Call for volunteers: add
From: |
Yuan Fu |
Subject: |
Re: TypeScript support for tree-sitter (was Re: Call for volunteers: add tree-sitter support to major modes) |
Date: |
Mon, 10 Oct 2022 10:07:07 -0700 |
> On Oct 10, 2022, at 9:43 AM, Theodor Thornhill <theo@thornhill.no> wrote:
>
> Eli Zaretskii <eliz@gnu.org> writes:
>
>>> From: Theodor Thornhill <theo@thornhill.no>
>>> Cc: Yuan Fu <casouri@gmail.com>
>>> Date: Mon, 10 Oct 2022 17:28:11 +0200
>>>
>>> Here's support for TypeScript with tree-sitter.
>>
>> Thanks, please announce in NEWS.
>
>
> See attached patch. I believe this should adhere to Yuan Fu's standards
> aswell.
>
> Thanks,
>
> Theodor
>
> <0001-Add-TypeScript-support-with-tree-sitter.patch>
Thanks! Some very minor comments:
From 92138c19ca09b08f7b8aff964542b2c440c7bb8e Mon Sep 17 00:00:00 2001
From: Theodor Thornhill <theo@thornhill.no>
Date: Mon, 10 Oct 2022 17:23:59 +0200
Subject: [PATCH] Add TypeScript support with tree-sitter
* lisp/progmodes/typescript-mode.el (typescript-mode): New major mode
for TypeScript with support for tree-sitter
---
etc/NEWS | 6 +
lisp/progmodes/typescript-mode.el | 320 ++++++++++++++++++++++++++++++
2 files changed, 326 insertions(+)
create mode 100644 lisp/progmodes/typescript-mode.el
diff --git a/etc/NEWS b/etc/NEWS
index 88b1431d6a..e1f816d4db 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -2774,3 +2774,9 @@ Emacs buffers, like indentation and the like. The new
ert function
This is a lightweight variant of 'js-mode' that is used by default
when visiting JSON files.
+
+** New mode 'typescript-mode'.
+Support is added for TypeScript, based on the new integration with
+Tree-Sitter. There's support for font-locking, indentation and
+navigation.
+
I think we should menntion that this mode requires tree-sitter to function.
* Incompatible Lisp Changes in Emacs 29.1
diff --git a/lisp/progmodes/typescript-mode.el
b/lisp/progmodes/typescript-mode.el
new file mode 100644
index 0000000000..363f7d150d
--- /dev/null
+++ b/lisp/progmodes/typescript-mode.el
@@ -0,0 +1,8 @@
+;;; typescript-mode.el --- tree sitter support for Typescript -*-
lexical-binding: t; -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+
+;; Author : Theodor Thornhill <theo@thornhill.no>
+;; Maintainer : Theodor Thornhill <theo@thornhill.no>
+;; Created : April 2022
+;; Keywords : typescript languages tree-sitter
I think we're suppose to add "This file is part of GNU Emacs" in the
header.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+(require 'treesit)
+
+
+(defcustom typescript-mode-indent-offset 2
+ "Number of spaces for each indentation step in `typescript-mode'."
+ :type 'integer
+ :safe 'integerp
+ :group 'typescript)
+
+(defvar typescript-mode--syntax-table
+ (let ((table (make-syntax-table)))
+ ;; Taken from the cc-langs version
+ (modify-syntax-entry ?_ "_" table)
+ (modify-syntax-entry ?$ "_" table)
+ (modify-syntax-entry ?\\ "\\" table)
+ (modify-syntax-entry ?+ "." table)
+ (modify-syntax-entry ?- "." table)
+ (modify-syntax-entry ?= "." table)
+ (modify-syntax-entry ?% "." table)
+ (modify-syntax-entry ?< "." table)
+ (modify-syntax-entry ?> "." table)
+ (modify-syntax-entry ?& "." table)
+ (modify-syntax-entry ?| "." table)
+ (modify-syntax-entry ?` "\"" table)
+ (modify-syntax-entry ?\240 "." table)
+ table)
+ "Syntax table for `typescript-mode'.")
+
Regarding below: again, sorry for the nitpick, but could you wrap lines
to 70 columns?
+(defvar typescript-mode--indent-rules
+ `((tsx
+ ((node-is "}") parent-bol 0)
+ ((node-is ")") parent-bol 0)
+ ((node-is "]") parent-bol 0)
+ ((node-is ">") parent-bol 0)
+ ((node-is ".") parent-bol ,typescript-mode-indent-offset)
+ ((parent-is "ternary_expression") parent-bol
,typescript-mode-indent-offset)
+ ((parent-is "named_imports") parent-bol ,typescript-mode-indent-offset)
+ ((parent-is "statement_block") parent-bol ,typescript-mode-indent-offset)
+ ((parent-is "type_arguments") parent-bol ,typescript-mode-indent-offset)
+ ((parent-is "variable_declarator") parent-bol
,typescript-mode-indent-offset)
+ ((parent-is "arguments") parent-bol ,typescript-mode-indent-offset)
+ ((parent-is "array") parent-bol ,typescript-mode-indent-offset)
+ ((parent-is "formal_parameters") parent-bol
,typescript-mode-indent-offset)
+ ((parent-is "template_substitution") parent-bol
,typescript-mode-indent-offset)
+ ((parent-is "object_pattern") parent-bol ,typescript-mode-indent-offset)
+ ((parent-is "object") parent-bol ,typescript-mode-indent-offset)
+ ((parent-is "object_type") parent-bol ,typescript-mode-indent-offset)
+ ((parent-is "enum_body") parent-bol ,typescript-mode-indent-offset)
+ ((parent-is "arrow_function") parent-bol ,typescript-mode-indent-offset)
+ ((parent-is "parenthesized_expression") parent-bol
,typescript-mode-indent-offset)
+
+ ;; JSX
+ ((parent-is "jsx_opening_element") parent ,typescript-mode-indent-offset)
+ ((node-is "jsx_closing_element") parent 0)
+ ((parent-is "jsx_element") parent ,typescript-mode-indent-offset)
+ ((node-is "/") parent 0)
+ ((parent-is "jsx_self_closing_element") parent
,typescript-mode-indent-offset)
+ (no-node parent-bol 0))))
+
+(defvar typescript-mode--settings
+ (treesit-font-lock-rules
+ :language 'tsx
+ :override t
+ '(
+ (template_string) @font-lock-string-face
+
+ ((identifier) @font-lock-constant-face
+ (:match "^[A-Z_][A-Z_\\d]*$" @font-lock-constant-face))
+
+ (nested_type_identifier module: (identifier) @font-lock-type-face)
+ (type_identifier) @font-lock-type-face
+ (predefined_type) @font-lock-type-face
+
+ (new_expression
+ constructor: (identifier) @font-lock-type-face)
+
+ (function
+ name: (identifier) @font-lock-function-name-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)
+
+ (enum_declaration (identifier) @font-lock-type-face)
+
+ (enum_body (property_identifier) @font-lock-type-face)
+
+ (enum_assignment name: (property_identifier) @font-lock-type-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)
+
+ (arrow_function
+ parameters: [(_ (identifier) @font-lock-variable-name-face)
+ (_ (_ (identifier) @font-lock-variable-name-face))
+ (_ (_ (_ (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)])
+
+ (property_signature
+ name: (property_identifier) @font-lock-variable-name-face)
+
+ ((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
+ (template_string) @font-lock-string-face
+
+ (template_substitution
+ ["${" "}"] @font-lock-constant-face)
+
+ ["!"
+ "abstract"
+ "as"
+ "async"
+ "await"
+ "break"
+ "case"
+ "catch"
+ "class"
+ "const"
+ "continue"
+ "debugger"
+ "declare"
+ "default"
+ "delete"
+ "do"
+ "else"
+ "enum"
+ "export"
+ "extends"
+ "finally"
+ "for"
+ "from"
+ "function"
+ "get"
+ "if"
+ "implements"
+ "import"
+ "in"
+ "instanceof"
+ "interface"
+ "keyof"
+ "let"
+ "namespace"
+ "new"
+ "of"
+ "private"
+ "protected"
+ "public"
+ "readonly"
+ "return"
+ "set"
+ "static"
+ "switch"
+ "target"
+ "throw"
+ "try"
+ "type"
+ "typeof"
+ "var"
+ "void"
+ "while"
+ "with"
+ "yield"
+ ] @font-lock-keyword-face
+
+ (comment) @font-lock-comment-face
+ )))
+
+(defun typescript-mode--move-to-node (fn)
+ (when-let ((found-node
+ (treesit-parent-until
+ (treesit-node-at (point))
+ (lambda (parent)
+ (treesit-query-capture
+ parent
+ typescript-mode--defun-query)))))
+ (goto-char (funcall fn found-node))))
+
+(defun typescript-mode--beginning-of-defun (&optional _arg)
+ (typescript-mode--move-to-node #'treesit-node-start))
+
+(defun typescript-mode--end-of-defun (&optional _arg)
+ (typescript-mode--move-to-node #'treesit-node-end))
+
+(defvar typescript-mode--defun-query
+ (treesit-query-compile
+ 'tsx
+ "[(import_statement)
+ (function_declaration)
+ (type_alias_declaration)
+ (interface_declaration)
+ (lexical_declaration)] @defun"))
+
+;;;###autoload
+(add-to-list 'auto-mode-alist '("\\.ts\\'" . typescript-mode))
+
+;;;###autoload
+(add-to-list 'auto-mode-alist '("\\.tsx\\'" . typescript-mode))
+
+(define-derived-mode typescript-mode prog-mode "TypeScript"
+ "Major mode for editing typescript."
+ :group 'typescript
+ :syntax-table typescript-mode--syntax-table
+
+ (unless (or (treesit-can-enable-p)
+ (treesit-language-available-p 'tsx))
+ (error "Tree sitter for TypeScript isn't available."))
+
+ ;; Comments
+ (setq-local comment-start "// ")
+ (setq-local comment-start-skip "\\(?://+\\|/\\*+\\)\\s *")
+ (setq-local comment-end "")
+
+ (setq-local treesit-simple-indent-rules typescript-mode--indent-rules)
+ (setq-local indent-line-function #'treesit-indent)
+
+ (setq-local beginning-of-defun-function
#'typescript-mode--beginning-of-defun)
+ (setq-local end-of-defun-function #'typescript-mode--end-of-defun)
+
+ (unless font-lock-defaults
+ (setq font-lock-defaults '(nil t)))
+
+ (setq-local treesit-font-lock-settings typescript-mode--settings)
+
+ (treesit-font-lock-enable))
+
+(provide 'typescript-mode)
+
+;;; typescript-mode.el ends here
--
2.34.1
- Re: Call for volunteers: add tree-sitter support to major modes, (continued)
TypeScript support for tree-sitter (was Re: Call for volunteers: add tree-sitter support to major modes), Theodor Thornhill, 2022/10/10
- Re: TypeScript support for tree-sitter (was Re: Call for volunteers: add tree-sitter support to major modes), Eli Zaretskii, 2022/10/10
- Re: TypeScript support for tree-sitter (was Re: Call for volunteers: add tree-sitter support to major modes), Theodor Thornhill, 2022/10/10
- Re: TypeScript support for tree-sitter (was Re: Call for volunteers: add tree-sitter support to major modes),
Yuan Fu <=
- Re: TypeScript support for tree-sitter (was Re: Call for volunteers: add tree-sitter support to major modes), Theodor Thornhill, 2022/10/10
- Re: TypeScript support for tree-sitter (was Re: Call for volunteers: add tree-sitter support to major modes), Theodor Thornhill, 2022/10/10
- Re: TypeScript support for tree-sitter (was Re: Call for volunteers: add tree-sitter support to major modes), Theodor Thornhill, 2022/10/10
- Re: TypeScript support for tree-sitter (was Re: Call for volunteers: add tree-sitter support to major modes), Theodor Thornhill, 2022/10/11
- Re: TypeScript support for tree-sitter (was Re: Call for volunteers: add tree-sitter support to major modes), Theodor Thornhill, 2022/10/11
- Re: TypeScript support for tree-sitter (was Re: Call for volunteers: add tree-sitter support to major modes), Yuan Fu, 2022/10/12
- Re: TypeScript support for tree-sitter (was Re: Call for volunteers: add tree-sitter support to major modes), Theodor Thornhill, 2022/10/12
Re: TypeScript support for tree-sitter (was Re: Call for volunteers: add tree-sitter support to major modes), Po Lu, 2022/10/11
Re: TypeScript support for tree-sitter (was Re: Call for volunteers: add tree-sitter support to major modes), Theodor Thornhill, 2022/10/11
Re: TypeScript support for tree-sitter (was Re: Call for volunteers: add tree-sitter support to major modes), Stefan Monnier, 2022/10/11