Created
May 19, 2024 19:36
-
-
Save lesteral/007afd6f0cf2505efcacaaf640edb698 to your computer and use it in GitHub Desktop.
Angular templating setup with typescript-ts-mode
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; This gist is intended to be guidance for a developer of Angular “Components”, | |
; which may include embedded HTML in inline “template” strings | |
; (see https://angular.io/guide/component-overview#defining-a-components-template for an example), | |
; to achieve proper formatting of both the Typescript and HTML code, | |
; in Emacs, when using `typescript-ts-mode' (a “tree-sitter” mode). | |
; The approach is based on the methodology described at | |
; https://www.gnu.org/software/emacs/manual/html_node/elisp/Multiple-Languages.html - 37.6 Parsing Text in Multiple Languages | |
; I’ve used this approach successfully with this software combination: | |
; (1) Emacs 29.3, compiled with tree-sitter support | |
; (I’m using https://packages.debian.org/bookworm-backports/emacs-pgtk , which also includes `typescript-ts-mode'.) | |
; (2) https://github.com/tree-sitter/tree-sitter-typescript/releases/tag/v0.20.3 - both typescript (and tsx) parsers must be separately installed | |
; (I haven’t tried 'v0.20.4', released Jan. 31, 2024 - the latest as of May 19, 2024.) | |
; (3) https://github.com/tree-sitter/tree-sitter-html/releases/tag/v0.20.1 - also separately installed | |
; (4) https://github.com/mickeynp/html-ts-mode/blob/master/html-ts-mode.el - Mickey Petersen’s “html ts mode for Combobulate” | |
; Mickey Petersen’s articles: | |
; * https://www.masteringemacs.org/article/how-to-get-started-tree-sitter - “How to Get Started with Tree-Sitter” | |
; * https://www.masteringemacs.org/article/lets-write-a-treesitter-major-mode - “Let’s Write a Tree-Sitter Major Mode” | |
; are very helpful in teaching how to set up and use tree-sitter (with Emacs 29). | |
; | |
; I also found Mickey’s “Combobulate” package ( https://github.com/mickeynp/combobulate ) | |
; to be quite useful in constructing the tree-sitter query used below. | |
; Thanks especially to Dmitry Gutov for the suggestions & guidance in https://github.com/dgutov/mmm-mode/issues/142 . | |
; (“mmm-mode” is itself targeted at multi-language support. | |
; I found “mmm-mode” to be very effective for this purpose, with `typescript-mode' https://github.com/emacs-typescript/typescript.el .) | |
(require 'typescript-ts-mode) | |
(require 'html-ts-mode) | |
(add-hook 'typescript-ts-mode-hook | |
(lambda () | |
(when (and (treesit-available-p) (treesit-ready-p 'typescript) (treesit-ready-p 'html)) | |
(setq treesit-range-settings | |
(treesit-range-rules | |
(lambda (beg end) | |
(treesit-parser-set-included-ranges (treesit-parser-create 'html) | |
(seq-map | |
; using "1+" & "1-" to skip leading/trailing backquotes which delimit Angular “template” strings | |
(lambda (elt) (let ((node (cdr elt))) (cons (1+ (treesit-node-start node)) (1- (treesit-node-end node))))) | |
(seq-filter (lambda (elt) (eq (car elt) 'templ)) | |
(treesit-query-capture 'typescript '(((pair key: (property_identifier) @propid value: (template_string) @templ) (:equal "template" @propid))) beg end) )))))) | |
; as per https://www.masteringemacs.org/article/lets-write-a-treesitter-major-mode#:~:text=you%20can%20safely%20append%20to%20treesit%2Dfont%2Dlock%2Dsettings%20at%20any%20point | |
(setq treesit-font-lock-settings (append (apply #'treesit-font-lock-rules html-ts-font-lock-rules) treesit-font-lock-settings)) | |
; The following is also needed in order for indenting to work properly in Typescript + HTML code, | |
; esp. on account of this behavior of `treesit-language-at': | |
; “... It returns the return value of `treesit-language-at-point-function' if it’s non-nil, | |
; otherwise it returns the language of the first parser in `treesit-parser-list', or nil if there is no parser.” | |
; In the context of this gist, `treesit-parser-list' returns: (#<treesit-parser for html> #<treesit-parser for typescript>), | |
; for which case the “first” parser is 'html, not 'typescript, which leads to various issues, if not configured as shown below. | |
(setq-local treesit-language-at-point-function | |
(lambda (pos) | |
(if (string= "template_string" (treesit-node-type (treesit-node-parent (treesit-node-at pos 'typescript)))) | |
'html | |
'typescript) | |
)) | |
; It’s also useful to add HTML indenting rules to `treesit-simple-indent-rules', so that indenting also works in the embedded HTML template strings. | |
; I found that Mickey Petersen’s rules work well for this purpose: | |
; https://github.com/mickeynp/html-ts-mode/blob/master/html-ts-mode.el#:~:text=%28setq%2Dlocal-,treesit%2Dsimple%2Dindent%2Drules | |
; e.g.: (setq treesit-simple-indent-rules (append <HTML-TS-MODE--INDENT-RULES> treesit-simple-indent-rules)) | |
))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment