1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-16 19:00:55 -08:00

Add new TypeScript mode tsx-ts-mode

There are in fact two languages supporting TypeScript for tree-sitter.
Because TSX causes some ambiguities with types there are two grammars,
one called typescript and one called tsx.  To account for this and to
be as correct as possible we enable using both.

* lisp/progmodes/typescript-ts-mode.el
(typescript-ts-mode--indent-rules): Change to a function to accomodate
the two languages.
(typescript-ts-mode--font-lock-settings): Change to a function to
accomodate the two languages.
(typescript-ts-base-mode): Parent mode for typescript-ts-mode
and tsx-ts-mode.
(typescript-ts-mode): Derive from typescript-ts-base-mode and
extend with language specific settings
(tsx-ts-mode): New major mode that derives from
typescript-ts-base-mode and extend it with language specific
settings

Add autoload cookies for the respective file type extensions: .ts and
.tsx.

* etc/NEWS: Mention the new mode.
This commit is contained in:
Theodor Thornhill 2022-11-29 21:39:38 +01:00 committed by Yuan Fu
parent ad0563855f
commit 1aa1f8432b
No known key found for this signature in database
GPG key ID: 56E19BC57664A442
2 changed files with 108 additions and 56 deletions

View file

@ -2989,7 +2989,14 @@ when visiting JSON files.
** New major mode 'typescript-ts-mode'. ** New major mode 'typescript-ts-mode'.
A major mode based on the tree-sitter library for editing programs A major mode based on the tree-sitter library for editing programs
in the TypeScript language. It includes support for font-locking, in the TypeScript language. It includes support for font-locking,
indentation, and navigation. indentation, and navigation. This mode will be auto-enabled for
files with the '.ts' extension.
** New major mode 'tsx-ts-mode'.
A major mode based on the tree-sitter library for editing programs
in the TypeScript language, with support for TSX. It includes
support for font-locking, indentation, and navigation. This mode
will be auto-enabled for files with the '.tsx' extension.
** New major mode 'c-ts-mode'. ** New major mode 'c-ts-mode'.
A major mode based on the tree-sitter library for editing programs A major mode based on the tree-sitter library for editing programs

View file

@ -22,6 +22,10 @@
;; You should have received a copy of the GNU General Public License ;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;
;;; Code: ;;; Code:
(require 'treesit) (require 'treesit)
@ -56,8 +60,10 @@
table) table)
"Syntax table for `typescript-ts-mode'.") "Syntax table for `typescript-ts-mode'.")
(defvar typescript-ts-mode--indent-rules (defun typescript-ts-mode--indent-rules (language)
`((tsx "Rules used for indentation.
Argument LANGUAGE is either `typescript' or `tsx'."
`((,language
((parent-is "program") parent-bol 0) ((parent-is "program") parent-bol 0)
((node-is "}") parent-bol 0) ((node-is "}") parent-bol 0)
((node-is ")") parent-bol 0) ((node-is ")") parent-bol 0)
@ -82,14 +88,13 @@
((parent-is "arrow_function") parent-bol typescript-ts-mode-indent-offset) ((parent-is "arrow_function") parent-bol typescript-ts-mode-indent-offset)
((parent-is "parenthesized_expression") parent-bol typescript-ts-mode-indent-offset) ((parent-is "parenthesized_expression") parent-bol typescript-ts-mode-indent-offset)
;; TSX ,@(when (eq language 'tsx)
((parent-is "jsx_opening_element") parent typescript-ts-mode-indent-offset) `(((parent-is "jsx_opening_element") parent typescript-ts-mode-indent-offset)
((node-is "jsx_closing_element") parent 0) ((node-is "jsx_closing_element") parent 0)
((parent-is "jsx_element") parent typescript-ts-mode-indent-offset) ((parent-is "jsx_element") parent typescript-ts-mode-indent-offset)
((node-is "/") parent 0) ((node-is "/") parent 0)
((parent-is "jsx_self_closing_element") parent typescript-ts-mode-indent-offset) ((parent-is "jsx_self_closing_element") parent typescript-ts-mode-indent-offset)))
(no-node parent-bol 0))) (no-node parent-bol 0))))
"Tree-sitter indent rules.")
(defvar typescript-ts-mode--keywords (defvar typescript-ts-mode--keywords
'("!" "abstract" "as" "async" "await" "break" '("!" "abstract" "as" "async" "await" "break"
@ -110,14 +115,16 @@
"&&" "||" "!" "?.") "&&" "||" "!" "?.")
"TypeScript operators for tree-sitter font-locking.") "TypeScript operators for tree-sitter font-locking.")
(defvar typescript-ts-mode--font-lock-settings (defun typescript-ts-mode--font-lock-settings (language)
"Tree-sitter font-lock settings.
Argument LANGUAGE is either `typescript' or `tsx'."
(treesit-font-lock-rules (treesit-font-lock-rules
:language 'tsx :language language
:override t :override t
:feature 'comment :feature 'comment
`((comment) @font-lock-comment-face) `((comment) @font-lock-comment-face)
:language 'tsx :language language
:override t :override t
:feature 'constant :feature 'constant
`(((identifier) @font-lock-constant-face `(((identifier) @font-lock-constant-face
@ -125,13 +132,13 @@
[(true) (false) (null)] @font-lock-constant-face) [(true) (false) (null)] @font-lock-constant-face)
:language 'tsx :language language
:override t :override t
:feature 'keyword :feature 'keyword
`([,@typescript-ts-mode--keywords] @font-lock-keyword-face `([,@typescript-ts-mode--keywords] @font-lock-keyword-face
[(this) (super)] @font-lock-keyword-face) [(this) (super)] @font-lock-keyword-face)
:language 'tsx :language language
:override t :override t
:feature 'string :feature 'string
`((regex pattern: (regex_pattern)) @font-lock-string-face `((regex pattern: (regex_pattern)) @font-lock-string-face
@ -139,7 +146,7 @@
(template_string) @js--fontify-template-string (template_string) @js--fontify-template-string
(template_substitution ["${" "}"] @font-lock-builtin-face)) (template_substitution ["${" "}"] @font-lock-builtin-face))
:language 'tsx :language language
:override t :override t
:feature 'declaration :feature 'declaration
`((function `((function
@ -177,7 +184,7 @@
(identifier) @font-lock-function-name-face) (identifier) @font-lock-function-name-face)
value: (array (number) (function)))) value: (array (number) (function))))
:language 'tsx :language language
:override t :override t
:feature 'identifier :feature 'identifier
`((nested_type_identifier `((nested_type_identifier
@ -208,7 +215,7 @@
(_ (_ (identifier) @font-lock-variable-name-face)) (_ (_ (identifier) @font-lock-variable-name-face))
(_ (_ (_ (identifier) @font-lock-variable-name-face)))])) (_ (_ (_ (identifier) @font-lock-variable-name-face)))]))
:language 'tsx :language language
:override t :override t
:feature 'expression :feature 'expression
'((assignment_expression '((assignment_expression
@ -223,7 +230,7 @@
(member_expression (member_expression
property: (property_identifier) @font-lock-function-name-face)])) property: (property_identifier) @font-lock-function-name-face)]))
:language 'tsx :language language
:override t :override t
:feature 'pattern :feature 'pattern
`((pair_pattern `((pair_pattern
@ -231,7 +238,7 @@
(array_pattern (identifier) @font-lock-variable-name-face)) (array_pattern (identifier) @font-lock-variable-name-face))
:language 'tsx :language language
:override t :override t
:feature 'jsx :feature 'jsx
`((jsx_opening_element `((jsx_opening_element
@ -248,31 +255,31 @@
(jsx_attribute (property_identifier) @font-lock-constant-face)) (jsx_attribute (property_identifier) @font-lock-constant-face))
:language 'tsx :language language
:feature 'number :feature 'number
`((number) @font-lock-number-face `((number) @font-lock-number-face
((identifier) @font-lock-number-face ((identifier) @font-lock-number-face
(:match "^\\(:?NaN\\|Infinity\\)$" @font-lock-number-face))) (:match "^\\(:?NaN\\|Infinity\\)$" @font-lock-number-face)))
:language 'tsx :language language
:feature 'operator :feature 'operator
`([,@typescript-ts-mode--operators] @font-lock-operator-face `([,@typescript-ts-mode--operators] @font-lock-operator-face
(ternary_expression ["?" ":"] @font-lock-operator-face)) (ternary_expression ["?" ":"] @font-lock-operator-face))
:language 'tsx :language language
:feature 'bracket :feature 'bracket
'((["(" ")" "[" "]" "{" "}"]) @font-lock-bracket-face) '((["(" ")" "[" "]" "{" "}"]) @font-lock-bracket-face)
:language 'tsx :language language
:feature 'delimiter :feature 'delimiter
'((["," "." ";" ":"]) @font-lock-delimiter-face) '((["," "." ";" ":"]) @font-lock-delimiter-face)
:language 'tsx :language language
:feature 'escape-sequence :feature 'escape-sequence
:override t :override t
'((escape_sequence) @font-lock-escape-face) '((escape_sequence) @font-lock-escape-face)
:language 'tsx :language language
:override t :override t
:feature 'property :feature 'property
`((pair value: (identifier) @font-lock-variable-name-face) `((pair value: (identifier) @font-lock-variable-name-face)
@ -280,17 +287,71 @@
((shorthand_property_identifier) @font-lock-property-face) ((shorthand_property_identifier) @font-lock-property-face)
((shorthand_property_identifier_pattern) ((shorthand_property_identifier_pattern)
@font-lock-property-face))) @font-lock-property-face))))
"Tree-sitter font-lock settings.")
;;;###autoload ;;;###autoload
(add-to-list 'auto-mode-alist '("\\.ts\\'" . typescript-ts-mode)) (add-to-list 'auto-mode-alist '("\\.ts\\'" . typescript-ts-mode))
;;;###autoload ;;;###autoload
(add-to-list 'auto-mode-alist '("\\.tsx\\'" . typescript-ts-mode)) (add-to-list 'auto-mode-alist '("\\.tsx\\'" . tsx-ts-mode))
;;;###autoload ;;;###autoload
(define-derived-mode typescript-ts-mode prog-mode "TypeScript" (define-derived-mode typescript-ts-base-mode prog-mode "TypeScript"
"Major mode for editing TypeScript."
:group 'typescript
:syntax-table typescript-ts-mode--syntax-table
;; Comments.
(setq-local comment-start "// ")
(setq-local comment-end "")
(setq-local comment-start-skip "\\(?://+\\|/\\*+\\)\\s *")
(setq-local comment-end-skip
(rx (* (syntax whitespace))
(group (or (syntax comment-end)
(seq (+ "*") "/")))))
;; Electric
(setq-local electric-indent-chars
(append "{}():;," electric-indent-chars))
;; Navigation.
(setq-local treesit-defun-type-regexp
(regexp-opt '("class_declaration"
"method_definition"
"function_declaration"
"lexical_declaration")))
;; Imenu.
(setq-local imenu-create-index-function #'js--treesit-imenu)
;; Which-func (use imenu).
(setq-local which-func-functions nil))
;;;###autoload
(define-derived-mode typescript-ts-mode typescript-ts-base-mode "TypeScript"
"Major mode for editing TypeScript."
:group 'typescript
:syntax-table typescript-ts-mode--syntax-table
(when (treesit-ready-p 'typescript)
(treesit-parser-create 'typescript)
;; Indent.
(setq-local treesit-simple-indent-rules
(typescript-ts-mode--indent-rules 'typescript))
;; Font-lock.
(setq-local treesit-font-lock-settings
(typescript-ts-mode--font-lock-settings 'typescript))
(setq-local treesit-font-lock-feature-list
'((comment declaration)
(keyword string)
(constant expression identifier number pattern property)
(bracket delimiter)))
(treesit-major-mode-setup)))
;;;###autoload
(define-derived-mode tsx-ts-mode typescript-ts-base-mode "TypeScript[TSX]"
"Major mode for editing TypeScript." "Major mode for editing TypeScript."
:group 'typescript :group 'typescript
:syntax-table typescript-ts-mode--syntax-table :syntax-table typescript-ts-mode--syntax-table
@ -301,43 +362,27 @@
;; Comments. ;; Comments.
(setq-local comment-start "// ") (setq-local comment-start "// ")
(setq-local comment-end "") (setq-local comment-end "")
(setq-local comment-start-skip (rx (group "/" (or (+ "/") (+ "*"))) (setq-local comment-start-skip "\\(?://+\\|/\\*+\\)\\s *")
(* (syntax whitespace))))
(setq-local comment-end-skip (setq-local comment-end-skip
(rx (* (syntax whitespace)) (rx (* (syntax whitespace))
(group (or (syntax comment-end) (group (or (syntax comment-end)
(seq (+ "*") "/"))))) (seq (+ "*") "/")))))
;; Electric
(setq-local electric-indent-chars
(append "{}():;," electric-indent-chars))
;; Indent. ;; Indent.
(setq-local treesit-simple-indent-rules typescript-ts-mode--indent-rules) (setq-local treesit-simple-indent-rules
(typescript-ts-mode--indent-rules 'tsx))
;; Navigation.
(setq-local treesit-defun-type-regexp
(rx (or "class_declaration"
"method_definition"
"function_declaration"
"lexical_declaration")))
;; Font-lock. ;; Font-lock.
(setq-local treesit-font-lock-settings typescript-ts-mode--font-lock-settings) (setq-local treesit-font-lock-settings
(typescript-ts-mode--font-lock-settings 'tsx))
(setq-local treesit-font-lock-feature-list (setq-local treesit-font-lock-feature-list
'(( comment declaration) '((comment declaration)
( keyword string) (keyword string)
( constant expression identifier jsx number pattern property) (constant expression identifier jsx number pattern property)
( bracket delimiter))) (bracket delimiter)))
;; Imenu.
(setq-local imenu-create-index-function #'js--treesit-imenu)
;; Which-func (use imenu).
(setq-local which-func-functions nil)
(treesit-major-mode-setup))) (treesit-major-mode-setup)))
(provide 'typescript-ts-mode) (provide 'typescript-ts-mode)
;;; typescript-ts-mode.el ends here ;;; typescript-ts-mode.el ends here