aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTheodor Thornhill2023-01-20 21:05:41 +0100
committerTheodor Thornhill2023-01-20 21:53:26 +0100
commitc6a7664f06710751b1122eff4492557ef5b2bfba (patch)
tree19e05e60f8a5332d0c19551d35e93eeb7a4e5996
parent1fdd720b6b8e1858e9ab92b2f63cc473402e54d1 (diff)
downloademacs-c6a7664f06710751b1122eff4492557ef5b2bfba.tar.gz
emacs-c6a7664f06710751b1122eff4492557ef5b2bfba.zip
Add html-ts-mode (bug#60972)
* lisp/textmodes/html-ts-mode.el: New major mode for HTML support powered by Tree-sitter. * etc/NEWS: Mention it in NEWS.
-rw-r--r--etc/NEWS7
-rw-r--r--lisp/textmodes/html-ts-mode.el137
2 files changed, 144 insertions, 0 deletions
diff --git a/etc/NEWS b/etc/NEWS
index f111d401df8..ceae78a6601 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -181,6 +181,13 @@ activate this behavior.
181 181
182* New Modes and Packages in Emacs 30.1 182* New Modes and Packages in Emacs 30.1
183 183
184** New major modes based on the tree-sitter library.
185
186+++
187*** New major mode 'html-ts-mode'.
188An optional major mode based on the tree-sitter library for editing
189files written in HTML.
190
184--- 191---
185** The highly accessible Modus themes collection has six items. 192** The highly accessible Modus themes collection has six items.
186The 'modus-operandi' and 'modus-vivendi' are the main themes that have 193The 'modus-operandi' and 'modus-vivendi' are the main themes that have
diff --git a/lisp/textmodes/html-ts-mode.el b/lisp/textmodes/html-ts-mode.el
new file mode 100644
index 00000000000..3f88a087163
--- /dev/null
+++ b/lisp/textmodes/html-ts-mode.el
@@ -0,0 +1,137 @@
1;;; html-ts-mode.el --- tree-sitter support for HTML -*- lexical-binding: t; -*-
2
3;; Copyright (C) 2023 Free Software Foundation, Inc.
4
5;; Author : Theodor Thornhill <theo@thornhill.no>
6;; Maintainer : Theodor Thornhill <theo@thornhill.no>
7;; Created : January 2023
8;; Keywords : html languages tree-sitter
9
10;; This file is part of GNU Emacs.
11
12;; GNU Emacs is free software: you can redistribute it and/or modify
13;; it under the terms of the GNU General Public License as published by
14;; the Free Software Foundation, either version 3 of the License, or
15;; (at your option) any later version.
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
23;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
24
25;;; Commentary:
26;;
27
28;;; Code:
29
30(require 'treesit)
31(require 'sgml-mode)
32
33(declare-function treesit-parser-create "treesit.c")
34(declare-function treesit-node-type "treesit.c")
35
36(defcustom html-ts-mode-indent-offset 2
37 "Number of spaces for each indentation step in `html-ts-mode'."
38 :version "29.1"
39 :type 'integer
40 :safe 'integerp
41 :group 'html)
42
43(defvar html-ts-mode--indent-rules
44 `((html
45 ((parent-is "fragment") parent-bol 0)
46 ((node-is "/>") parent-bol 0)
47 ((node-is ">") parent-bol 0)
48 ((node-is "end_tag") parent-bol 0)
49 ((parent-is "comment") prev-adaptive-prefix 0)
50 ((parent-is "element") parent-bol html-ts-mode-indent-offset)
51 ((parent-is "script_element") parent-bol html-ts-mode-indent-offset)
52 ((parent-is "style_element") parent-bol html-ts-mode-indent-offset)
53 ((parent-is "start_tag") parent-bol html-ts-mode-indent-offset)
54 ((parent-is "self_closing_tag") parent-bol html-ts-mode-indent-offset)))
55 "Tree-sitter indent rules.")
56
57(defvar html-ts-mode--font-lock-settings
58 (treesit-font-lock-rules
59 :language 'html
60 :override t
61 :feature 'comment
62 `((comment) @font-lock-comment-face)
63 :language 'html
64 :override t
65 :feature 'keyword
66 `("doctype" @font-lock-keyword-face)
67 :language 'html
68 :override t
69 :feature 'definition
70 `((tag_name) @font-lock-function-name-face)
71 :language 'html
72 :override t
73 :feature 'string
74 `((quoted_attribute_value) @font-lock-string-face)
75 :language 'html
76 :override t
77 :feature 'property
78 `((attribute_name) @font-lock-variable-name-face))
79 "Tree-sitter font-lock settings for `html-ts-mode'.")
80
81(defun html-ts-mode--defun-name (node)
82 "Return the defun name of NODE.
83Return nil if there is no name or if NODE is not a defun node."
84 (when (equal (treesit-node-type node) "tag_name")
85 (treesit-node-text node t)))
86
87;;;###autoload
88(define-derived-mode html-ts-mode html-mode "HTML"
89 "Major mode for editing Html, powered by tree-sitter."
90 :group 'html
91
92 (unless (treesit-ready-p 'html)
93 (error "Tree-sitter for HTML isn't available"))
94
95 (treesit-parser-create 'html)
96
97 ;; Comments.
98 (setq-local treesit-text-type-regexp
99 (regexp-opt '("comment" "text")))
100
101 ;; Indent.
102 (setq-local treesit-simple-indent-rules html-ts-mode--indent-rules)
103
104 ;; Navigation.
105 (setq-local treesit-defun-type-regexp "element")
106
107 (setq-local treesit-defun-name-function #'html-ts-mode--defun-name)
108
109 (setq-local treesit-sentence-type-regexp
110 (regexp-opt '("start_tag"
111 "self_closing_tag"
112 "end_tag")))
113
114 (setq-local treesit-sexp-type-regexp
115 (regexp-opt '("tag"
116 "text"
117 "attribute"
118 "value")))
119
120 ;; Font-lock.
121 (setq-local treesit-font-lock-settings html-ts-mode--font-lock-settings)
122 (setq-local treesit-font-lock-feature-list
123 '((comment keyword definition)
124 (property string)
125 () ()))
126
127 ;; Imenu.
128 (setq-local treesit-simple-imenu-settings
129 '(("Element" "\\`tag_name\\'" nil nil)))
130 (treesit-major-mode-setup))
131
132(if (treesit-ready-p 'html)
133 (add-to-list 'auto-mode-alist '("\\.html\\'" . html-ts-mode)))
134
135(provide 'html-ts-mode)
136
137;;; html-ts-mode.el ends here