Package: emacs;
Reported by: Vincenzo Pupillo <v.pupillo <at> gmail.com>
Date: Fri, 29 Nov 2024 21:58:01 UTC
Severity: wishlist
Fixed in version 31.0.50
Done: Juri Linkov <juri <at> linkov.net>
Bug is archived. No further changes may be made.
To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 74610 in the body.
You can then email your comments to 74610 AT debbugs.gnu.org in the normal way.
Toggle the display of automated, internal messages from the tracker.
View this report as an mbox folder, status mbox, maintainer mbox
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Fri, 29 Nov 2024 21:58:01 GMT) Full text and rfc822 format available.Vincenzo Pupillo <v.pupillo <at> gmail.com>
:bug-gnu-emacs <at> gnu.org
.
(Fri, 29 Nov 2024 21:58:02 GMT) Full text and rfc822 format available.Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
From: Vincenzo Pupillo <v.pupillo <at> gmail.com> To: Bug Emacs <bug-gnu-emacs <at> gnu.org> Subject: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Fri, 29 Nov 2024 22:57:05 +0100
[Message part 1 (text/plain, inline)]
Ciao, following the discussion https://lists.gnu.org/archive/html/emacs-devel/2024-11/msg00079.html I would like to ask if it would be possible to add to emacs this new mode for editing html files alternative to mhtml-mode. Thank you. Vincenzo.
[0001-Add-mhtml-ts-mode.patch (text/x-patch, attachment)]
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Sun, 01 Dec 2024 06:03:01 GMT) Full text and rfc822 format available.Message #8 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Yuan Fu <casouri <at> gmail.com> To: Vincenzo Pupillo <v.pupillo <at> gmail.com> Cc: 74610 <at> debbugs.gnu.org Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Sat, 30 Nov 2024 22:01:21 -0800
> On Nov 29, 2024, at 1:57 PM, Vincenzo Pupillo <v.pupillo <at> gmail.com> wrote: > > Ciao, > following the discussion > https://lists.gnu.org/archive/html/emacs-devel/2024-11/msg00079.html I would > like to ask if it would be possible to add to emacs this new mode for editing > html files alternative to mhtml-mode. > > Thank you. > > Vincenzo.<0001-Add-mhtml-ts-mode.patch> Thank you so much! This will be very helpful for others. Here’re some comments. Yuan From 8a1c792aaddf4daef2808f5a74212a2fb8b0a01e Mon Sep 17 00:00:00 2001 From: Vincenzo Pupillo <v.pupillo <at> gmail.com> Date: Fri, 29 Nov 2024 22:48:45 +0100 Subject: [PATCH] Add mhtml-ts-mode. New major-mode alternative to mhtml-mode, based on treesitter, for editing files containing html, javascript and css. * etc/NEWS: Mention the new mode. * lisp/textmodes/mhtml-ts-mode.el: New file. --- etc/NEWS | 8 + lisp/textmodes/mhtml-ts-mode.el | 462 ++++++++++++++++++++++++++++++++ 2 files changed, 470 insertions(+) create mode 100644 lisp/textmodes/mhtml-ts-mode.el diff --git a/etc/NEWS b/etc/NEWS index 4d2a2c893d0..8f9a04dcf01 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -797,6 +797,14 @@ destination window is chosen using 'display-buffer-alist'. Example: * New Modes and Packages in Emacs 31.1 +** New major modes based on the tree-sitter library + ++++ +*** New major mode 'mhtml-ts-mode'. +An optional major mode based on the tree-sitter library for editing html +files. This mode handles indentation, fontification, and commenting for +embedded JavaScript and CSS. + * Incompatible Lisp Changes in Emacs 31.1 diff --git a/lisp/textmodes/mhtml-ts-mode.el b/lisp/textmodes/mhtml-ts-mode.el new file mode 100644 index 00000000000..b6b220663e3 --- /dev/null +++ b/lisp/textmodes/mhtml-ts-mode.el @@ -0,0 +1,100 @@ +;;; mhtml-ts-mode.el --- Major mode for HTML using tree-sitter -*- lexical-binding: t; -*- + +;; Copyright (C) 2024 Free Software Foundation, Inc. + +;; Author: Vincenzo Pupillo <v.pupillo <at> gmail.com> +;; Maintainer: Vincenzo Pupillo <v.pupillo <at> gmail.com> +;; Created: Nov 2024 +;; Keywords: HTML language tree-sitter + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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. + +;; GNU Emacs 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: +;; +;; This package provides `mhtml-ts-mode' which is a major mode +;; for editing HTML files with embedded JavaScript and CSS. +;; Tree Sitter is used to parse each of these languages. +;; +;; Please note that this package requires `html-ts-mode', which +;; registers itself as the major mode for editing HTML. +;; +;; This package is compatible and has been tested with the following +;; tree-sitter grammars: +;; * https://github.com/tree-sitter/tree-sitter-html +;; * https://github.com/tree-sitter/tree-sitter-javascript +;; * https://github.com/tree-sitter/tree-sitter-jsdoc +;; * https://github.com/tree-sitter/tree-sitter-css +;; +;; Features +;; +;; * Indent +;; * IMenu +;; * Navigation +;; * Which-function +;; * Tree-sitter parser installation helper + +;;; Code: + +(require 'treesit) +(require 'html-ts-mode) +(require 'css-mode) ;; for embed css into html +(require 'js) ;; for embed javascript into html + +(eval-when-compile + (require 'rx)) + +;; Declare all native functions used by the major mode. +;; This tells the byte-compiler where the functions are defined. +(declare-function treesit-node-end "treesit.c") +(declare-function treesit-node-parent "treesit.c") +(declare-function treesit-node-start "treesit.c") +(declare-function treesit-node-type "treesit.c") +(declare-function treesit-parser-create "treesit.c") + +;; In a multi-language major mode can be useful to have an "installer" to +;; simplify the installation of the grammars supported by the major-mode. +(defvar mhtml-ts-mode--language-source-alist + '((html . ("https://github.com/tree-sitter/tree-sitter-html" "v0.23.0")) + (javascript . ("https://github.com/tree-sitter/tree-sitter-javascript" "v0.23.0")) + (jsdoc . ("https://github.com/tree-sitter/tree-sitter-jsdoc" "v0.23.0")) + (css . ("https://github.com/tree-sitter/tree-sitter-css" "v0.23.0"))) + "Treesitter language parsers required by `mhtml-ts-mode'. +You can customize this variable if you want to stick to a specific +commit and/or use different parsers.") + +(defun mhtml-ts-mode-install-parsers () + "Install all the required treesitter parsers. +`mhtml-ts-mode--language-source-alist' defines which parsers to install." + (interactive) + (let ((treesit-language-source-alist mhtml-ts-mode--language-source-alist)) + (dolist (item mhtml-ts-mode--language-source-alist) + (treesit-install-language-grammar (car item))))) + +;;; Custom variables + +(defgroup mhtml-ts-mode nil + "Major mode for editing HTML files, based on `html-ts-mode'. +Works with JS and CSS and for that use `js-ts-mode' and `css-ts-mode'." + :prefix "html-ts-mode-" + :group 'languages) + +(defcustom mhtml-ts-mode-js-css-indent-offset 2 + "JavaScript and CSS indent spaces related to the <script> and <style> HTML tags. +By default should have same value as `html-ts-mode-indent-offset'." + :tag "HTML javascript or css indent offset" + :version "31.1" + :type 'integer + :safe 'integerp) It's not uncommon to see different indent offset for CSS and Javascript, so it's a good idea to have separate control for them. + +(defvar mhtml-ts-mode--js-css-indent-offset + mhtml-ts-mode-js-css-indent-offset + "Internal copy of `mhtml-ts-mode-js-css-indent-offset'. +The value changes, by `mhtml-ts-mode--tag-relative-indent-offset' according to +the value of `mhtml-ts-mode-tag-relative-indent'.") + +(defun mhtml-ts-mode--tag-relative-indent-offset (sym val) + "Custom setter for `mhtml-ts-mode-tag-relative-indent'. + +Apart from setting the default value of SYM to VAL, also change the +value of SYM in `mhtml-ts-mode' buffers to VAL. SYM should be +`mhtml-ts-mode-tag-relative-indent', and VAL should be t, nil or +`ignore'. When sym is `mhtml-ts-mode-tag-relative-indent' set the +value of `mhtml-ts-mode--js-css-indent-offset' to 0 if VAL is t, +otherwise to `mhtml-ts-mode-js-css-indent-offset'." + (set-default sym val) + (when (eq sym 'mhtml-ts-mode-tag-relative-indent) + (setq-local + mhtml-ts-mode--js-css-indent-offset + (if (eq val t) + mhtml-ts-mode-js-css-indent-offset + 0)))) + +(defcustom mhtml-ts-mode-tag-relative-indent t + "How <script> and <style> bodies are indented relative to the tag. + +When t, indentation looks like: + + <script> + code(); + </script> + +When nil, indentation of the script body starts just below the +tag, like: + + <script> + code(); + </script> + +When `ignore', the script body starts in the first column, like: + + <script> +code(); + </script>" + :type '(choice (const nil) (const t) (const ignore)) + :safe 'symbolp + :set #'mhtml-ts-mode--tag-relative-indent-offset + :version "31.1") + +(defcustom mhtml-ts-mode-css-fontify-colors t + "Whether CSS colors should be fontified using the color as the background. +If non-nil, text representing a CSS color will be fontified +such that its background is the color itself. +Works like `css--fontify-region'." + :tag "HTML colors the CSS properties values." + :version "31.1" + :type 'boolean + :safe 'booleanp) + +;; To enable some basic treesiter functionality, you should define +;; a function that recognizes which grammar is used at-point. +;; This function should be assigned to `treesit-language-at-point-function' +(defun mhtml-ts-mode--language-at-point (point) + "Return the language at POINT assuming the point is within a HTML buffer." + (let* ((node (treesit-node-at point 'html)) + (parent (treesit-node-parent node)) + (node-query (format "(%s (%s))" + (treesit-node-type parent) + (treesit-node-type node)))) + (cond + ((string-equal "(script_element (raw_text))" node-query) 'javascript) + ((string-equal "(style_element (raw_text))" node-query) 'css) + (t 'html)))) + +;; Sometimes you need to override some property attached to a node. +;; The signature of the function should be conforming to signature +;; QUERY-SPEC required by `treesit-font-lock-rules'. "property attached to a node" is vague. I would just say ;; Custom font-lock function that's used to apply color to css color ;; values. This function is used below where we define font-lock rules. +(defun mhtml-ts-mode--colorize-css-value (node override start end &rest _) + "Colorize CSS property value like `css--fontify-region'. +For NODE, OVERRIDE, START, and END, see `treesit-font-lock-rules'." + (if (and mhtml-ts-mode-css-fontify-colors + (string-equal "plain_value" (treesit-node-type node))) + (let ((color (css--compute-color start (treesit-node-text node t)))) + (when color + (with-silent-modifications + (add-text-properties + (treesit-node-start node) (treesit-node-end node) + (list 'face (list :background color + :foreground (readable-foreground-color + color) + :box '(:line-width -1))))))) + (treesit-fontify-with-override + (treesit-node-start node) (treesit-node-end node) + 'font-lock-variable-name-face + override start end))) + +;; Embedded languages should be indented according to the language +;; that embeds them. +;; This function signature complies with `treesit-simple-indent-rules' +;; ANCHOR. +(defun mhtml-ts-mode--js-css-tag-bol (_node _parent &rest _) + "Find the first non-space characters of html tags <script> or <style>. +Return `line-beginning-position' when `treesit-node-at' is html, or +`mhtml-ts-mode-tag-relative-indent' is equal to ignore. +NODE and PARENT are ignored." + (if (or (eq (treesit-language-at (point)) 'html) + (eq mhtml-ts-mode-tag-relative-indent 'ignore)) + (line-beginning-position) + ;; Ok, we are in js or css block. + (save-excursion + (re-search-backward "<script.*>\\|<style.*>" nil t)))) + +;; Treesit supports 4 level of decoration, `treesit-font-lock-level' +;; define which level use. Major-modes categorize their fontification +;; features, these categories are defined by `treesit-font-lock-rules' of +;; each major-mode using :feature keyword. +;; In a multiple language major-mode it's a good idea to provvide, for each +;; level, the union of the :feature of the same level. "which level to use", "Major modes", and "provide" +(defvar mhtml-ts-mode--feature-list + '(;; level 1 + (;; common + comment definition + ;; JS specific + document + ;; CSS specific + query selector) + ;; level 2 + (keyword name property string type) + ;; level 3 + (;; common + attribute assignment constant escape-sequence + base-clause literal variable-name variable + ;; Javascript specific + jsx number pattern string-interpolation) + ;; level 4 + (bracket delimiter error operator function))) + +;; In order to support wich-fuction-mode we should define "which-function-mode" +;; a function that return the defun name. +;; In a multilingual treesit mode, this can be implemented simply by +;; calling language-specific functions. +(defun mhtml-ts-mode--defun-name (node) + "Return the defun name of NODE. +Return nil if there is no name or if NODE is not a defun node." + ;; (message "node type ""%s""" (treesit-node-type node)) + (let ((lang (mhtml-ts-mode--language-at-point (point)))) + (cond + ((eq lang 'html) (html-ts-mode--defun-name node)) + ((eq lang 'javascript) (js--treesit-defun-name node)) + ((eq lang 'css) (css--treesit-defun-name node))))) + +(define-derived-mode mhtml-ts-mode html-mode + '("HTML+" (:eval (let ((lang (mhtml-ts-mode--language-at-point (point)))) + (cond ((eq lang 'html) "") + ((eq lang 'javascript) "JS") + ((eq lang 'css) "CSS"))))) + "Major mode for editing HTML with embedded JavaScript and CSS. +Powered by tree-sitter." + (if (not (and + (treesit-ready-p 'html) + (treesit-ready-p 'javascript) + (treesit-ready-p 'css))) + (error "Tree-sitter parsers for HTML isn't + available. You can install the parsers with M-x + `mhtml-ts-mode-install-parsers'") + + ;; When an language is embedded, you should initialize some variable + ;; just like it's done in the original mode. + + ;; Comment. + ;; indenting settings for js-ts-mode. + (c-ts-common-comment-setup) + (setq-local comment-multi-line t) + + ;; Font-lock. + + ;; There are two kind of treesitter parser: + ;; 1. global parser + ;; 2. local parser + ;; The global parser considers each piece of text, + ;; in a multilingual buffer, as if it were a single buffer in its + ;; own language. Local parsers, on the other hand, consider each + ;; piece of text, in a multilingual buffer, as if they were + ;; separate buffers. + ;; In a multilingual buffer you should create only global ones. + ;; Local ones are created automatically. + ;; Warning: do not create a local parser! It may cause side + ;; effects that are difficult to handle. + + ;; There are two types of treesitter parsers: + ;; 1. global parsers + ;; 2. local parsers + ;; A global parser treats each piece of text, + ;; in a multilingual buffer, as if it were a single buffer in its + ;; language. Local parser, on the other hand, treat each + ;; piece of text, in a multilingual buffer, as if they were separate buffers. + ;; In a multilingual buffer you should only create global ones. + ;; The local ones are created automatically. + ;; Warning: do not create a local parser! It may cause side effects that are difficult to handle. Seems like a duplicate? And I want to highlight the fact that we're talking about embedded parsers here, so I would say: There are two ways to handle embedded code: 1. Use a single parser for all the embedded code in the buffer. In this case, the embedded code blocks are concatenated together and are seen as a single continuous document to the parser. 2. Each embedded code block gets its own parser. Each parser only sees that particular code block. If you go with 2 for a language, the local parsers are created and destroyed automatically by Emacs. So don't create a global parser for that embedded language here. + + ;; Create the parsers, only the global one. "only global ones", I think + ;; jsdoc is a local parser, don't create a parser for it. + (treesit-parser-create 'css) + (treesit-parser-create 'javascript) + + ;; jsdoc is not mandatory for js-ts-mode, so we respect this by + ;; adding jsdoc range rules only when jsdoc is available. + (if (treesit-ready-p 'jsdoc t) + (setq-local treesit-range-settings + (treesit-range-rules + :embed 'javascript + :host 'html + :offset '(1 . -1) + '((script_element + (start_tag (tag_name)) + (raw_text) @cap)) + + :embed 'jsdoc + :host 'javascript + :local t + `(((comment) @cap + (:match ,js--treesit-jsdoc-beginning-regexp @cap))) + + :embed 'css + :host 'html + :offset '(1 . -1) + '((style_element + (start_tag (tag_name)) + (raw_text) @cap)))) + (setq-local treesit-range-settings + (treesit-range-rules + :embed 'javascript + :host 'html + :offset '(1 . -1) + '((script_element + (start_tag (tag_name)) + (raw_text) @cap)) + + :embed 'css + :host 'html + :offset '(1 . -1) + '((style_element + (start_tag (tag_name)) + (raw_text) @cap))))) You can create range rules for each language and append them, that way you don't need to duplicate the code here. It's just like the font-lock settings. + + ;; Many treesit fuctions need to know the language at-point. + ;; So you should define such a function. + (setq-local treesit-language-at-point-function #'mhtml-ts-mode--language-at-point) + + ;; Indent. + + ;; Since mhtl-ts-mode inherits indentation rules from html-ts-mode, js + ;; and css, if you want to change the offset you have to act on the + ;; *-offset variables defined for those languages. + + ;; JavaScript and CSS must be indented relative to their code block. + ;; This is done by inserting a special rule before the normal + ;; indentation rules of these languages. + ;; The value of mhtml-ts-mode--js-css-indent-offset changes based on + ;; mhtml-ts-mode-tag-relative-indent and can be used to indent + ;; JavaScript and CSS code relative to the HTML that contains them, + ;; just like in mhtml-mode. + (setq-local treesit-simple-indent-rules + (append html-ts-mode--indent-rules + ;; Extended rules for js and css, to + ;; indent appropriately when injected + ;; into html + `((javascript ((parent-is "program") + mhtml-ts-mode--js-css-tag-bol + mhtml-ts-mode--js-css-indent-offset) + ,@(cdr (car js--treesit-indent-rules)))) + `((css ((parent-is "stylesheet") + mhtml-ts-mode--js-css-tag-bol + mhtml-ts-mode--js-css-indent-offset) + ,@(cdr (car css--treesit-indent-rules)))))) + ;; Navigation. + + ;; This regular expression tells treesit how to match the node type + ;; of defun nodes. + ;; Used by `treesit-beginning-of-defun' and friends for + ;; navigations. + (setq-local treesit-defun-type-regexp + (rx (or + ;; Javascript + "class_declaration" + "method_definition" + "function_declaration" + "lexical_declaration" + ;; HTML + "element" + ;; CSS + "rule_set"))) You can actually define a defun "thing" in treesit-thing-setting, and it should work the same. + ;; This is for finding defun name, it's used by IMenu as default + ;; function no specific functions are defined. + (setq-local treesit-defun-name-function #'mhtml-ts-mode--defun-name) + + ;; Define what are 'thing' for treesit. + ;; 'Thing' is a symbol representing the thing, like `defun', `sexp', or + ;; `sentence'. + (setq-local treesit-thing-settings + `((html + (sexp ,(regexp-opt '("element" + "text" + "attribute" + "value"))) + (sentence "tag") + (text ,(regexp-opt '("comment" "text")))) + (javascript + (sexp ,(js--regexp-opt-symbol js--treesit-sexp-nodes)) + (sentence ,(js--regexp-opt-symbol js--treesit-sentence-nodes)) + (text ,(js--regexp-opt-symbol '("comment" + "string_fragment")))))) + + ;; Font-lock. + + ;; In a multi-language scenario, font lock settings are usually a + ;; concatenation of language rules. As you can see, it is possible + ;; to extend/modify the default rule or use a different set of + ;; rules. See `php-ts-mode--custom-html-font-lock-settings' for more + ;; advanced usage. + (setq-local treesit-font-lock-settings + (append html-ts-mode--font-lock-settings + js--treesit-font-lock-settings + (append + ;; Rule for coloring CSS property values. + ;; Placed before `css--treesit-settings' + ;; to win against the same rule contained therein. + (treesit-font-lock-rules + :language 'css + :override t + :feature 'variable + '((plain_value) @mhtml-ts-mode--colorize-css-value)) + css--treesit-settings))) + + ;; Tells treesit the list of features to fontify. + (setq-local treesit-font-lock-feature-list mhtml-ts-mode--feature-list) + + ;; Imenu + + ;; Setup Imenu: if no function is specified, try to find an object + ;; using `treesit-defun-name-function'. + ;; TODO: we need to see if it is possible to extend Imenu to + ;; embedded languages as well. + (setq-local treesit-simple-imenu-settings + `(("Element" "\\`tag_name\\'" nil nil))) + + ;; This should be the last thing to do. + ;; Treesit tries to find out what the primary language is, but it is better + ;; to say it explicitly. Correction: multi-language modes must set the primary parser explicitly, the auto-guessing trick only works for single-language modes. You can also move this line next to where you created the other parsers, for better readability. + (setq-local treesit-primary-parser (treesit-parser-create 'html)) + (treesit-font-lock-recompute-features) You don't need to call treesit-font-lock-recompute-features, treesit-major-mode-setup will do that for you. + (treesit-major-mode-setup))) + +(when (and (treesit-ready-p 'html) (treesit-ready-p 'javascript) (treesit-ready-p 'css)) + (add-to-list + 'auto-mode-alist '("\\.[sx]?html?\\(\\.[a-zA-Z_]+\\)?\\'" . mhtml-ts-mode))) + +(provide 'mhtml-ts-mode) +;;; mhtml-ts-mode.el ends here -- 2.47.1
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Sun, 01 Dec 2024 08:01:01 GMT) Full text and rfc822 format available.Message #11 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Eli Zaretskii <eliz <at> gnu.org> To: Yuan Fu <casouri <at> gmail.com> Cc: v.pupillo <at> gmail.com, 74610 <at> debbugs.gnu.org Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Sun, 01 Dec 2024 10:00:06 +0200
> Cc: 74610 <at> debbugs.gnu.org > From: Yuan Fu <casouri <at> gmail.com> > Date: Sat, 30 Nov 2024 22:01:21 -0800 > > > > > On Nov 29, 2024, at 1:57 PM, Vincenzo Pupillo <v.pupillo <at> gmail.com> wrote: > > > > Ciao, > > following the discussion > > https://lists.gnu.org/archive/html/emacs-devel/2024-11/msg00079.html I would > > like to ask if it would be possible to add to emacs this new mode for editing > > html files alternative to mhtml-mode. > > > > Thank you. > > > > Vincenzo.<0001-Add-mhtml-ts-mode.patch> > > Thank you so much! This will be very helpful for others. Here’re some comments. Yuan, I don't see any comments, only what I think is the original patch.
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Sun, 01 Dec 2024 08:21:02 GMT) Full text and rfc822 format available.Message #14 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Yuan Fu <casouri <at> gmail.com> To: Eli Zaretskii <eliz <at> gnu.org> Cc: v.pupillo <at> gmail.com, 74610 <at> debbugs.gnu.org Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Sun, 1 Dec 2024 00:18:59 -0800
> On Dec 1, 2024, at 12:00 AM, Eli Zaretskii <eliz <at> gnu.org> wrote: > >> Cc: 74610 <at> debbugs.gnu.org >> From: Yuan Fu <casouri <at> gmail.com> >> Date: Sat, 30 Nov 2024 22:01:21 -0800 >> >> >> >>> On Nov 29, 2024, at 1:57 PM, Vincenzo Pupillo <v.pupillo <at> gmail.com> wrote: >>> >>> Ciao, >>> following the discussion >>> https://lists.gnu.org/archive/html/emacs-devel/2024-11/msg00079.html I would >>> like to ask if it would be possible to add to emacs this new mode for editing >>> html files alternative to mhtml-mode. >>> >>> Thank you. >>> >>> Vincenzo.<0001-Add-mhtml-ts-mode.patch> >> >> Thank you so much! This will be very helpful for others. Here’re some comments. > > Yuan, I don't see any comments, only what I think is the original > patch. Ah, I guess I’m supposed to quote the original patch when making comments :-( The lines that aren’t prefixed by + are my comments. Yuan
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Sun, 01 Dec 2024 08:21:02 GMT) Full text and rfc822 format available.bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Tue, 03 Dec 2024 14:31:02 GMT) Full text and rfc822 format available.Message #20 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Vincenzo Pupillo <v.pupillo <at> gmail.com> To: Yuan Fu <casouri <at> gmail.com> Cc: Eli Zaretskii <eliz <at> gnu.org>, 74610 <at> debbugs.gnu.org Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Tue, 03 Dec 2024 15:29:06 +0100
In data domenica 1 dicembre 2024 07:01:21 Ora standard dell’Europa centrale, Yuan Fu ha scritto: > It's not uncommon to see different indent offset for CSS and > Javascript, so it's a good idea to have separate control for them. Is the behavior the same as mhtml-mode, or would you like something like this? <style> z { color: red; } </style> <script> function myFunction(p1, p2) { return p1 * p2; } </script> The mhtml-ts-mode-js-css-indent-offset variable controls only the indentation relative to the <style> and <script> tags. V.
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Wed, 04 Dec 2024 01:29:01 GMT) Full text and rfc822 format available.Message #23 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Dmitry Gutov <dmitry <at> gutov.dev> To: Vincenzo Pupillo <v.pupillo <at> gmail.com>, 74610 <at> debbugs.gnu.org Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Wed, 4 Dec 2024 03:27:53 +0200
On 29/11/2024 23:57, Vincenzo Pupillo wrote: > +;; This package provides `mhtml-ts-mode' which is a major mode > +;; for editing HTML files with embedded JavaScript and CSS. > +;; Tree Sitter is used to parse each of these languages. > +;; > +;; Please note that this package requires `html-ts-mode', which > +;; registers itself as the major mode for editing HTML. Hi! Do you foresee cases for when html-ts-mode would be preferred by the user instead of this advanced mhtml-ts-mode? Or maybe the former is better in its current shape when used by e.g. php-ts-mode? In other words, I'm wondering why not update the existing mode with sub-parsers rather than add a new one. html-mode had such a reason - it's quite old, and has been used in various placed the way it is now (including multi-mode packages). But ts modes don't work too well with multi-mode packages, not currently anyway.
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Wed, 04 Dec 2024 10:50:02 GMT) Full text and rfc822 format available.Message #26 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Vincenzo Pupillo <v.pupillo <at> gmail.com> To: Dmitry Gutov <dmitry <at> gutov.dev>, 74610 <at> debbugs.gnu.org Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Wed, 04 Dec 2024 11:47:51 +0100
Hi Dmitry, In data mercoledì 4 dicembre 2024 02:27:53 Ora standard dell’Europa centrale, hai scritto: > On 29/11/2024 23:57, Vincenzo Pupillo wrote: > > +;; This package provides `mhtml-ts-mode' which is a major mode > > +;; for editing HTML files with embedded JavaScript and CSS. > > +;; Tree Sitter is used to parse each of these languages. > > +;; > > +;; Please note that this package requires `html-ts-mode', which > > +;; registers itself as the major mode for editing HTML. > > Hi! > > Do you foresee cases for when html-ts-mode would be preferred by the > user instead of this advanced mhtml-ts-mode? For everyday use mhtml-ts-mode is better, just like mhtml-mode (which has been the default for html editing for a while now). > Or maybe the former is > better in its current shape when used by e.g. php-ts-mode? Yes, personally I think that major modes that handle (for tree-sitters) only one language are easier to put together at the moment. It's Lego vs. Playmobil. We are in an experimental phase, like all other editors. See https://github.com/helix-editor/helix/pull/1170#issuecomment-997294090 In some ways, by having a different approach from other editors, we have a greater degree of flexibility IMHO. > > In other words, I'm wondering why not update the existing mode with > sub-parsers rather than add a new one. html-mode had such a reason - > it's quite old, and has been used in various placed the way it is now > (including multi-mode packages). But ts modes don't work too well with > multi-mode packages, not currently anyway. It's something I've thought about but haven't tried yet. One of the themes of the email thread (on emacs-devel) was to have a simple multi language major mode that was also a sort of “user's guide.” Vincenzo.
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Thu, 05 Dec 2024 16:53:01 GMT) Full text and rfc822 format available.Message #29 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Dmitry Gutov <dmitry <at> gutov.dev> To: Vincenzo Pupillo <v.pupillo <at> gmail.com>, 74610 <at> debbugs.gnu.org Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Thu, 5 Dec 2024 18:51:55 +0200
Hi Vincenzo, On 04/12/2024 12:47, Vincenzo Pupillo wrote: >> Do you foresee cases for when html-ts-mode would be preferred by the >> user instead of this advanced mhtml-ts-mode? > For everyday use mhtml-ts-mode is better, just like mhtml-mode (which has been > the default for html editing for a while now). > >> Or maybe the former is >> better in its current shape when used by e.g. php-ts-mode? > Yes, personally I think that major modes that handle (for tree-sitters) only > one language are easier to put together at the moment. It's Lego vs. > Playmobil. > We are in an experimental phase, like all other editors. > See https://github.com/helix-editor/helix/pull/1170#issuecomment-997294090 > In some ways, by having a different approach from other editors, we have a > greater degree of flexibility IMHO. Makes sense, thanks. >> In other words, I'm wondering why not update the existing mode with >> sub-parsers rather than add a new one. html-mode had such a reason - >> it's quite old, and has been used in various placed the way it is now >> (including multi-mode packages). But ts modes don't work too well with >> multi-mode packages, not currently anyway. > > It's something I've thought about but haven't tried yet. > One of the themes of the email thread (on emacs-devel) was to have a simple > multi language major mode that was also a sort of “user's guide.” I though the updated html-ts-mode could be that mode. Anyway, good to hear that this alternative had been given consideration.
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Fri, 06 Dec 2024 13:42:02 GMT) Full text and rfc822 format available.Message #32 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Vincenzo Pupillo <v.pupillo <at> gmail.com> To: 74610 <at> debbugs.gnu.org, Dmitry Gutov <dmitry <at> gutov.dev> Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Fri, 06 Dec 2024 14:39:56 +0100
Ciao Dmitry, In data giovedì 5 dicembre 2024 17:51:55 Ora standard dell’Europa centrale, Dmitry Gutov ha scritto: > Hi Vincenzo, > > On 04/12/2024 12:47, Vincenzo Pupillo wrote: > >> Do you foresee cases for when html-ts-mode would be preferred by the > >> user instead of this advanced mhtml-ts-mode? > > > > For everyday use mhtml-ts-mode is better, just like mhtml-mode (which has > > been the default for html editing for a while now). > > > >> Or maybe the former is > >> better in its current shape when used by e.g. php-ts-mode? > > > > Yes, personally I think that major modes that handle (for tree-sitters) > > only one language are easier to put together at the moment. It's Lego vs. > > Playmobil. > > We are in an experimental phase, like all other editors. > > See https://github.com/helix-editor/helix/pull/1170#issuecomment-997294090 > > In some ways, by having a different approach from other editors, we have a > > greater degree of flexibility IMHO. > > Makes sense, thanks. > > >> In other words, I'm wondering why not update the existing mode with > >> sub-parsers rather than add a new one. html-mode had such a reason - > >> it's quite old, and has been used in various placed the way it is now > >> (including multi-mode packages). But ts modes don't work too well with > >> multi-mode packages, not currently anyway. > > > > It's something I've thought about but haven't tried yet. > > One of the themes of the email thread (on emacs-devel) was to have a > > simple > > multi language major mode that was also a sort of “user's guide.” > > I though the updated html-ts-mode could be that mode. Anyway, good to > hear that this alternative had been given consideration. Since the development of Emacs 31 has just started and this major mode is not urgent, I will try some experiments in the next few days to see if html-ts- mode can be modified without compromising the integration with php-ts-mode. Vincenzo
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Wed, 11 Dec 2024 04:56:01 GMT) Full text and rfc822 format available.Message #35 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Yuan Fu <casouri <at> gmail.com> To: Vincenzo Pupillo <v.pupillo <at> gmail.com> Cc: Eli Zaretskii <eliz <at> gnu.org>, 74610 <at> debbugs.gnu.org Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Tue, 10 Dec 2024 20:54:09 -0800
> On Dec 3, 2024, at 6:29 AM, Vincenzo Pupillo <v.pupillo <at> gmail.com> wrote: > > In data domenica 1 dicembre 2024 07:01:21 Ora standard dell’Europa centrale, > Yuan Fu ha scritto: >> It's not uncommon to see different indent offset for CSS and >> Javascript, so it's a good idea to have separate control for them. > > Is the behavior the same as mhtml-mode, or would you like something like this? > > <style> > z { > color: red; > } > </style> > <script> > function myFunction(p1, p2) { > return p1 * p2; > } > </script> > > The mhtml-ts-mode-js-css-indent-offset variable controls only the indentation > relative to the <style> and <script> tags. Ah, I see, it’s the offset from the enclosing tag. In that case it should be fine to use a common variable. Yuan
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Sat, 14 Dec 2024 10:39:02 GMT) Full text and rfc822 format available.Message #38 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Vincenzo Pupillo <v.pupillo <at> gmail.com> To: Yuan Fu <casouri <at> gmail.com> Cc: Eli Zaretskii <eliz <at> gnu.org>, 74610 <at> debbugs.gnu.org Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Sat, 14 Dec 2024 11:37:01 +0100
[Message part 1 (text/plain, inline)]
In data mercoledì 11 dicembre 2024 05:54:09 Ora standard dell’Europa centrale, Yuan Fu ha scritto: > > On Dec 3, 2024, at 6:29 AM, Vincenzo Pupillo <v.pupillo <at> gmail.com> wrote: > > > > In data domenica 1 dicembre 2024 07:01:21 Ora standard dell’Europa > > centrale,> > > Yuan Fu ha scritto: > >> It's not uncommon to see different indent offset for CSS and > >> Javascript, so it's a good idea to have separate control for them. > > > > Is the behavior the same as mhtml-mode, or would you like something like > > this?> > > <style> > > > > z { > > > > color: red; > > > > } > > > > </style> > > <script> > > > > function myFunction(p1, p2) { > > > > return p1 * p2; > > > > } > > > > </script> > > > > The mhtml-ts-mode-js-css-indent-offset variable controls only the > > indentation relative to the <style> and <script> tags. > > Ah, I see, it’s the offset from the enclosing tag. In that case it should be > fine to use a common variable. > > Yuan Thank you Yuan. Attached is the revised patch following your previous comments. As I already wrote to Dmitry, I am doing some tests to see if html-ts-mode can be extended and if there is a way to integrate one multi-language mode into another multi-language mode. Vincenzo
[0001-Add-mhtml-ts-mode.patch (text/x-patch, attachment)]
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Mon, 16 Dec 2024 17:46:03 GMT) Full text and rfc822 format available.Message #41 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Juri Linkov <juri <at> linkov.net> To: Vincenzo Pupillo <v.pupillo <at> gmail.com> Cc: Yuan Fu <casouri <at> gmail.com>, Eli Zaretskii <eliz <at> gnu.org>, 74610 <at> debbugs.gnu.org Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Mon, 16 Dec 2024 19:37:35 +0200
Ciao Vincenzo, > In data mercoledì 11 dicembre 2024 05:54:09 Ora standard dell’Europa centrale, > > Attached is the revised patch following your previous comments. > As I already wrote to Dmitry, I am doing some tests to see if html-ts-mode can > be extended and if there is a way to integrate one multi-language mode into > another multi-language mode. I'm testing your patch with mhtml-ts-mode, and everything works nicely. At the same time I'm adding a new ts-thing named 'sexp-list' in bug#73404. While 'sexp' defines both lists and atoms, 'sexp-list' defines only lists. So I added (sexp-list ,(regexp-opt '("element")) 'symbols) to treesit-thing-settings in html-ts-mode.el. But then discovered surprisingly that it has no effect on mhtml-ts-mode. The problem is that treesit-thing-settings should be duplicated from html-ts-mode to mhtml-ts-mode. On the one hand, integrating multi-language mode to the exiting mode html-ts-mode could avoid the need to duplicate treesit-thing-settings for html. But on the other hand, integrating mhtml-ts-mode to html-ts-mode doesn't help to avoid such duplication for other embedded modes. Because I needed to duplicate treesit-thing-settings for javascript as well. So extending html-ts-mode doesn't help here, and maybe even better to add mhtml-ts-mode to keep the symmetry with existing mhtml-mode such as used in mode remapping: (add-to-list 'major-mode-remap-alist '(mhtml-mode . mhtml-ts-mode)) What could really help is to try to get settings from html-ts-mode and js-ts-mode to avoid the need to duplicate settings in mhtml-ts-mode.
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Tue, 17 Dec 2024 21:28:02 GMT) Full text and rfc822 format available.Message #44 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Vincenzo Pupillo <v.pupillo <at> gmail.com> To: Juri Linkov <juri <at> linkov.net> Cc: Yuan Fu <casouri <at> gmail.com>, Eli Zaretskii <eliz <at> gnu.org> Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Tue, 17 Dec 2024 22:25:59 +0100
Ciao Juri, In data lunedì 16 dicembre 2024 18:37:35 Ora standard dell’Europa centrale, Juri Linkov ha scritto: > Ciao Vincenzo, > > > In data mercoledì 11 dicembre 2024 05:54:09 Ora standard dell’Europa > > centrale, > > > > Attached is the revised patch following your previous comments. > > As I already wrote to Dmitry, I am doing some tests to see if html-ts-mode > > can be extended and if there is a way to integrate one multi-language > > mode into another multi-language mode. > > I'm testing your patch with mhtml-ts-mode, and everything works nicely. > Thanks > At the same time I'm adding a new ts-thing named 'sexp-list' in bug#73404. > While 'sexp' defines both lists and atoms, 'sexp-list' defines only lists. > > So I added (sexp-list ,(regexp-opt '("element")) 'symbols) > to treesit-thing-settings in html-ts-mode.el. > > But then discovered surprisingly that it has no effect on mhtml-ts-mode. > > The problem is that treesit-thing-settings should be duplicated > from html-ts-mode to mhtml-ts-mode. > > On the one hand, integrating multi-language mode to the exiting mode > html-ts-mode could avoid the need to duplicate treesit-thing-settings > for html. > > But on the other hand, integrating mhtml-ts-mode to html-ts-mode > doesn't help to avoid such duplication for other embedded modes. > Because I needed to duplicate treesit-thing-settings for javascript > as well. > > So extending html-ts-mode doesn't help here, and maybe even better > to add mhtml-ts-mode to keep the symmetry with existing mhtml-mode > such as used in mode remapping: > > (add-to-list 'major-mode-remap-alist '(mhtml-mode . > mhtml-ts-mode)) > > What could really help is to try to get settings from html-ts-mode > and js-ts-mode to avoid the need to duplicate settings in mhtml-ts-mode. I think we need something like a generalized version of the `mhtml--construct-submode' function. I'm doing some testing on that and hope to have something decent after Christmas. Vincenzo.
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Tue, 24 Dec 2024 08:39:01 GMT) Full text and rfc822 format available.Message #47 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Yuan Fu <casouri <at> gmail.com> To: Vincenzo Pupillo <v.pupillo <at> gmail.com> Cc: Eli Zaretskii <eliz <at> gnu.org>, 74610 <at> debbugs.gnu.org Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Tue, 24 Dec 2024 00:37:02 -0800
> On Dec 14, 2024, at 2:37 AM, Vincenzo Pupillo <v.pupillo <at> gmail.com> wrote: > > In data mercoledì 11 dicembre 2024 05:54:09 Ora standard dell’Europa centrale, > Yuan Fu ha scritto: >>> On Dec 3, 2024, at 6:29 AM, Vincenzo Pupillo <v.pupillo <at> gmail.com> wrote: >>> >>> In data domenica 1 dicembre 2024 07:01:21 Ora standard dell’Europa >>> centrale,> >>> Yuan Fu ha scritto: >>>> It's not uncommon to see different indent offset for CSS and >>>> Javascript, so it's a good idea to have separate control for them. >>> >>> Is the behavior the same as mhtml-mode, or would you like something like >>> this?> >>> <style> >>> >>> z { >>> >>> color: red; >>> >>> } >>> >>> </style> >>> <script> >>> >>> function myFunction(p1, p2) { >>> >>> return p1 * p2; >>> >>> } >>> >>> </script> >>> >>> The mhtml-ts-mode-js-css-indent-offset variable controls only the >>> indentation relative to the <style> and <script> tags. >> >> Ah, I see, it’s the offset from the enclosing tag. In that case it should be >> fine to use a common variable. >> >> Yuan > Thank you Yuan. > Attached is the revised patch following your previous comments. > As I already wrote to Dmitry, I am doing some tests to see if html-ts-mode can > be extended and if there is a way to integrate one multi-language mode into > another multi-language mode. > > Vincenzo > <0001-Add-mhtml-ts-mode.patch> Btw, mhtml-ts-mode--defun-name seems to contain some debugging code? And also I think you should use treesit-node-language. Yuan
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Tue, 24 Dec 2024 22:20:02 GMT) Full text and rfc822 format available.Message #50 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Yuan Fu <casouri <at> gmail.com> To: Vincenzo Pupillo <v.pupillo <at> gmail.com> Cc: Eli Zaretskii <eliz <at> gnu.org>, 74610 <at> debbugs.gnu.org Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Tue, 24 Dec 2024 14:18:39 -0800
> On Dec 24, 2024, at 12:37 AM, Yuan Fu <casouri <at> gmail.com> wrote: > > > >> On Dec 14, 2024, at 2:37 AM, Vincenzo Pupillo <v.pupillo <at> gmail.com> wrote: >> >> In data mercoledì 11 dicembre 2024 05:54:09 Ora standard dell’Europa centrale, >> Yuan Fu ha scritto: >>>> On Dec 3, 2024, at 6:29 AM, Vincenzo Pupillo <v.pupillo <at> gmail.com> wrote: >>>> >>>> In data domenica 1 dicembre 2024 07:01:21 Ora standard dell’Europa >>>> centrale,> >>>> Yuan Fu ha scritto: >>>>> It's not uncommon to see different indent offset for CSS and >>>>> Javascript, so it's a good idea to have separate control for them. >>>> >>>> Is the behavior the same as mhtml-mode, or would you like something like >>>> this?> >>>> <style> >>>> >>>> z { >>>> >>>> color: red; >>>> >>>> } >>>> >>>> </style> >>>> <script> >>>> >>>> function myFunction(p1, p2) { >>>> >>>> return p1 * p2; >>>> >>>> } >>>> >>>> </script> >>>> >>>> The mhtml-ts-mode-js-css-indent-offset variable controls only the >>>> indentation relative to the <style> and <script> tags. >>> >>> Ah, I see, it’s the offset from the enclosing tag. In that case it should be >>> fine to use a common variable. >>> >>> Yuan >> Thank you Yuan. >> Attached is the revised patch following your previous comments. >> As I already wrote to Dmitry, I am doing some tests to see if html-ts-mode can >> be extended and if there is a way to integrate one multi-language mode into >> another multi-language mode. >> >> Vincenzo >> <0001-Add-mhtml-ts-mode.patch> > > Btw, mhtml-ts-mode--defun-name seems to contain some debugging code? And also I think you should use treesit-node-language. > > Yuan I just added treesit-aggregated-simple-imenu-settings to master. This variable will allow you to setup Imenu for multiple languages. Please give it a try. I tested locally with mhtml-ts-mode and works well. Yuan
Stefan Kangas <stefankangas <at> gmail.com>
to control <at> debbugs.gnu.org
.
(Thu, 02 Jan 2025 01:57:03 GMT) Full text and rfc822 format available.bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Tue, 14 Jan 2025 21:42:02 GMT) Full text and rfc822 format available.Message #55 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Vincenzo Pupillo <v.pupillo <at> gmail.com> To: Yuan Fu <casouri <at> gmail.com>, Juri Linkov <juri <at> linkov.net> Cc: Eli Zaretskii <eliz <at> gnu.org>, 74610 <at> debbugs.gnu.org Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Tue, 14 Jan 2025 22:41:01 +0100
[Message part 1 (text/plain, inline)]
Ciao Yuan and Juri, this is an updated version of mhtml-ts-mode. I have tried to reduce as much as possible copies of parts of the major modes from which it is derived. To do this, I had to move some values that were assigned directly to treesit's own variables (in ccs-mode.el, in js.el, and in html-ts-mode.el) into new variables. I also added three new functions to treesit.el to make it easier to combine parts derived from the other major modes. So now any changes to these new variables are directly reflected in the behavior of mhtml-ts-mode. There are a few things I would like to highlight: 1. treesit-font-lock-feature-lists are not defined per parser, so simply merging the different lists will cause display differences from the original major-modes; for example “function” is defined at level 3 in css-ts-mode but at level 4 in js-ts-mode. 2. treesit-defun-type-regexp has the same problem as treesit-font-lock- feature-list, so I had to define it myself. But other than that, it works pretty well. IMHO, a global "list" where you can define "font-lock", "indent-list", "font- lock-feature", etc. by language (perhaps with getter and setter methods) might make it easier to define new multilingual major-modes. It could improve the decoupling between multilingual major-modes and the major-modes they are derived from. It could also better decouple the internal implementation of treesit.el from the treesitter-based major-modes. Let me know what you think. Thanks. Vincenzo p.s. In this version I also added support for wich-function-mode, for flymake and a pretty-print function. In data martedì 24 dicembre 2024 23:18:39 Ora standard dell’Europa centrale, Yuan Fu ha scritto: > > On Dec 24, 2024, at 12:37 AM, Yuan Fu <casouri <at> gmail.com> wrote: > >> On Dec 14, 2024, at 2:37 AM, Vincenzo Pupillo <v.pupillo <at> gmail.com> > >> wrote: > >> > >> In data mercoledì 11 dicembre 2024 05:54:09 Ora standard dell’Europa > >> centrale,>> > >> Yuan Fu ha scritto: > >>>> On Dec 3, 2024, at 6:29 AM, Vincenzo Pupillo <v.pupillo <at> gmail.com> > >>>> wrote: > >>>> > >>>> In data domenica 1 dicembre 2024 07:01:21 Ora standard dell’Europa > >>>> centrale,> > >>>> > >>>> Yuan Fu ha scritto: > >>>>> It's not uncommon to see different indent offset for CSS and > >>>>> Javascript, so it's a good idea to have separate control for them. > >>>> > >>>> Is the behavior the same as mhtml-mode, or would you like something > >>>> like > >>>> this?> > >>>> > >>>> <style> > >>>> > >>>> z { > >>>> > >>>> color: red; > >>>> > >>>> } > >>>> > >>>> </style> > >>>> <script> > >>>> > >>>> function myFunction(p1, p2) { > >>>> > >>>> return p1 * p2; > >>>> > >>>> } > >>>> > >>>> </script> > >>>> > >>>> The mhtml-ts-mode-js-css-indent-offset variable controls only the > >>>> indentation relative to the <style> and <script> tags. > >>> > >>> Ah, I see, it’s the offset from the enclosing tag. In that case it > >>> should be fine to use a common variable. > >>> > >>> Yuan > >> > >> Thank you Yuan. > >> Attached is the revised patch following your previous comments. > >> As I already wrote to Dmitry, I am doing some tests to see if > >> html-ts-mode can be extended and if there is a way to integrate one > >> multi-language mode into another multi-language mode. > >> > >> Vincenzo > >> <0001-Add-mhtml-ts-mode.patch> > > > > Btw, mhtml-ts-mode--defun-name seems to contain some debugging code? And > > also I think you should use treesit-node-language. > > > > Yuan > > I just added treesit-aggregated-simple-imenu-settings to master. This > variable will allow you to setup Imenu for multiple languages. Please give > it a try. I tested locally with mhtml-ts-mode and works well. > > Yuan
[0001-Add-mhtml-ts-mode.patch (text/x-patch, attachment)]
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Wed, 15 Jan 2025 07:52:01 GMT) Full text and rfc822 format available.Message #58 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Juri Linkov <juri <at> linkov.net> To: Vincenzo Pupillo <v.pupillo <at> gmail.com> Cc: Yuan Fu <casouri <at> gmail.com>, Eli Zaretskii <eliz <at> gnu.org>, 74610 <at> debbugs.gnu.org Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Wed, 15 Jan 2025 09:50:06 +0200
> this is an updated version of mhtml-ts-mode. Thanks. Please also attach a new version of the mhtml-ts-mode.el file. > I have tried to reduce as much as possible copies of parts of the major modes > from which it is derived. > > To do this, I had to move some values that were assigned directly to treesit's > own variables (in ccs-mode.el, in js.el, and in html-ts-mode.el) into new > variables. I had a thought that maybe for treesit-thing-settings we could have a global registry like auto-mode-alist, not a buffer-local value. Then modes could just add own info to it. e.g. (add-to-list 'treesit-thing-global-settings '(javascript (sentence ...))) This can be shared between embedded ts-modes.
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Wed, 15 Jan 2025 09:00:01 GMT) Full text and rfc822 format available.Message #61 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Vincenzo Pupillo <v.pupillo <at> gmail.com> To: Juri Linkov <juri <at> linkov.net> Cc: Yuan Fu <casouri <at> gmail.com>, Eli Zaretskii <eliz <at> gnu.org>, 74610 <at> debbugs.gnu.org Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Wed, 15 Jan 2025 09:59:00 +0100
[Message part 1 (text/plain, inline)]
Ciao Juri, In data mercoledì 15 gennaio 2025 08:50:06 Ora standard dell’Europa centrale, Juri Linkov ha scritto: > > this is an updated version of mhtml-ts-mode. > > Thanks. Please also attach a new version of the mhtml-ts-mode.el file. Okay, I have attached all the files that I have modified. > > > I have tried to reduce as much as possible copies of parts of the major > > modes from which it is derived. > > > > To do this, I had to move some values that were assigned directly to > > treesit's own variables (in ccs-mode.el, in js.el, and in > > html-ts-mode.el) into new variables. > > I had a thought that maybe for treesit-thing-settings we could have > a global registry like auto-mode-alist, not a buffer-local value. > Then modes could just add own info to it. e.g. > > (add-to-list 'treesit-thing-global-settings > '(javascript (sentence ...))) > > This can be shared between embedded ts-modes. Yes, that is exactly what I was thinking, but I obviously explained it wrong. Thanks. Vincenzo
[treesit.el (text/x-emacs-lisp, attachment)]
[js.el (text/x-emacs-lisp, attachment)]
[css-mode.el (text/x-emacs-lisp, attachment)]
[html-ts-mode.el (text/x-emacs-lisp, attachment)]
[mhtml-ts-mode.el (text/x-emacs-lisp, attachment)]
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Sat, 18 Jan 2025 01:39:01 GMT) Full text and rfc822 format available.Message #64 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Yuan Fu <casouri <at> gmail.com> To: Vincenzo Pupillo <v.pupillo <at> gmail.com> Cc: Eli Zaretskii <eliz <at> gnu.org>, 74610 <at> debbugs.gnu.org, Juri Linkov <juri <at> linkov.net> Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Fri, 17 Jan 2025 17:37:53 -0800
> On Jan 14, 2025, at 1:41 PM, Vincenzo Pupillo <v.pupillo <at> gmail.com> wrote: > > Ciao Yuan and Juri, > this is an updated version of mhtml-ts-mode. > I have tried to reduce as much as possible copies of parts of the major modes > from which it is derived. > To do this, I had to move some values that were assigned directly to treesit's > own variables (in ccs-mode.el, in js.el, and in html-ts-mode.el) into new > variables. > I also added three new functions to treesit.el to make it easier to combine > parts derived from the other major modes. So now any changes to these new > variables are directly reflected in the behavior of mhtml-ts-mode. > There are a few things I would like to highlight: > 1. treesit-font-lock-feature-lists are not defined per parser, so simply > merging the different lists will cause display differences from the original > major-modes; for example “function” is defined at level 3 in css-ts-mode but > at level 4 in js-ts-mode. Yeah, that’s not pretty, I don’t have a good solution for now. Technically a major mode can use treesit-font-lock-recompute-features after treesit-major-mode-setup to do fine adjustments, but it’s ugly. > 2. treesit-defun-type-regexp has the same problem as treesit-font-lock- > feature-list, so I had to define it myself. Maybe you can use treesit-thing-settings instead? > > But other than that, it works pretty well. > > IMHO, a global "list" where you can define "font-lock", "indent-list", "font- > lock-feature", etc. by language (perhaps with getter and setter methods) might > make it easier to define new multilingual major-modes. It could improve the > decoupling between multilingual major-modes and the major-modes they are > derived from. It could also better decouple the internal implementation of > treesit.el from the treesitter-based major-modes. > > Let me know what you think. That’s what I had in mind. That’s also why I added a new variable treesit-aggregated-simple-imenu-settings instead of piggybacking on treesit-simple-imenu-settings. A separate variable is simpler to borrow settings from. But I didn’t have time to think it though yet. (By language, or by mode and language? Should packages set it on load, or define a function that loads these settings? Etc.) Yuan
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Sun, 19 Jan 2025 17:10:02 GMT) Full text and rfc822 format available.Message #67 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Vincenzo Pupillo <v.pupillo <at> gmail.com> To: Yuan Fu <casouri <at> gmail.com> Cc: Eli Zaretskii <eliz <at> gnu.org>, 74610 <at> debbugs.gnu.org, Juri Linkov <juri <at> linkov.net> Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Sun, 19 Jan 2025 18:09:31 +0100
[Message part 1 (text/plain, inline)]
Ciao Yuan, In data sabato 18 gennaio 2025 02:37:53 Ora standard dell’Europa centrale, Yuan Fu ha scritto: > > On Jan 14, 2025, at 1:41 PM, Vincenzo Pupillo <v.pupillo <at> gmail.com> wrote: > > > > Ciao Yuan and Juri, > > this is an updated version of mhtml-ts-mode. > > I have tried to reduce as much as possible copies of parts of the major > > modes from which it is derived. > > To do this, I had to move some values that were assigned directly to > > treesit's own variables (in ccs-mode.el, in js.el, and in > > html-ts-mode.el) into new variables. > > I also added three new functions to treesit.el to make it easier to > > combine > > parts derived from the other major modes. So now any changes to these new > > variables are directly reflected in the behavior of mhtml-ts-mode. > > There are a few things I would like to highlight: > > 1. treesit-font-lock-feature-lists are not defined per parser, so simply > > merging the different lists will cause display differences from the > > original major-modes; for example “function” is defined at level 3 in > > css-ts-mode but at level 4 in js-ts-mode. > > Yeah, that’s not pretty, I don’t have a good solution for now. Technically a > major mode can use treesit-font-lock-recompute-features after > treesit-major-mode-setup to do fine adjustments, but it’s ugly. > > 2. treesit-defun-type-regexp has the same problem as treesit-font-lock- > > feature-list, so I had to define it myself. > > Maybe you can use treesit-thing-settings instead? Ok, done. > > > But other than that, it works pretty well. > > > > IMHO, a global "list" where you can define "font-lock", "indent-list", > > "font- lock-feature", etc. by language (perhaps with getter and setter > > methods) might make it easier to define new multilingual major-modes. It > > could improve the decoupling between multilingual major-modes and the > > major-modes they are derived from. It could also better decouple the > > internal implementation of treesit.el from the treesitter-based > > major-modes. > > > > Let me know what you think. > > That’s what I had in mind. That’s also why I added a new variable > treesit-aggregated-simple-imenu-settings instead of piggybacking on > treesit-simple-imenu-settings. A separate variable is simpler to borrow > settings from. Yes, in this new patch I used treesit-aggregated-simple-imenu-settings. > But I didn’t have time to think it though yet. (By language, or by mode and > language? Should packages set it on load, or define a function that loads > these settings? Etc.) > I would say by mode and language, both mhtml-ts mode and html-ts mode have the same primary parser. For the second question, I don't know. I don't have enough experience with it to know what the pros and cons are. > Yuan Vincenzo
[0001-Add-mhtml-ts-mode.patch (text/x-patch, attachment)]
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Sat, 08 Feb 2025 09:03:02 GMT) Full text and rfc822 format available.Message #70 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Eli Zaretskii <eliz <at> gnu.org> To: casouri <at> gmail.com, juri <at> linkov.net, Vincenzo Pupillo <v.pupillo <at> gmail.com> Cc: 74610 <at> debbugs.gnu.org Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Sat, 08 Feb 2025 11:01:48 +0200
Ping! Can we please make progress with this issue? is the patch ready to be installed? > From: Vincenzo Pupillo <v.pupillo <at> gmail.com> > Cc: Juri Linkov <juri <at> linkov.net>, 74610 <at> debbugs.gnu.org, > Eli Zaretskii <eliz <at> gnu.org> > Date: Sun, 19 Jan 2025 18:09:31 +0100 > > Ciao Yuan, > In data sabato 18 gennaio 2025 02:37:53 Ora standard dell’Europa centrale, > Yuan Fu ha scritto: > > > On Jan 14, 2025, at 1:41 PM, Vincenzo Pupillo <v.pupillo <at> gmail.com> wrote: > > > > > > Ciao Yuan and Juri, > > > this is an updated version of mhtml-ts-mode. > > > I have tried to reduce as much as possible copies of parts of the major > > > modes from which it is derived. > > > To do this, I had to move some values that were assigned directly to > > > treesit's own variables (in ccs-mode.el, in js.el, and in > > > html-ts-mode.el) into new variables. > > > I also added three new functions to treesit.el to make it easier to > > > combine > > > parts derived from the other major modes. So now any changes to these new > > > variables are directly reflected in the behavior of mhtml-ts-mode. > > > There are a few things I would like to highlight: > > > 1. treesit-font-lock-feature-lists are not defined per parser, so simply > > > merging the different lists will cause display differences from the > > > original major-modes; for example “function” is defined at level 3 in > > > css-ts-mode but at level 4 in js-ts-mode. > > > > Yeah, that’s not pretty, I don’t have a good solution for now. Technically a > > major mode can use treesit-font-lock-recompute-features after > > treesit-major-mode-setup to do fine adjustments, but it’s ugly. > > > 2. treesit-defun-type-regexp has the same problem as treesit-font-lock- > > > feature-list, so I had to define it myself. > > > > Maybe you can use treesit-thing-settings instead? > Ok, done. > > > > > > But other than that, it works pretty well. > > > > > > IMHO, a global "list" where you can define "font-lock", "indent-list", > > > "font- lock-feature", etc. by language (perhaps with getter and setter > > > methods) might make it easier to define new multilingual major-modes. It > > > could improve the decoupling between multilingual major-modes and the > > > major-modes they are derived from. It could also better decouple the > > > internal implementation of treesit.el from the treesitter-based > > > major-modes. > > > > > > Let me know what you think. > > > > That’s what I had in mind. That’s also why I added a new variable > > treesit-aggregated-simple-imenu-settings instead of piggybacking on > > treesit-simple-imenu-settings. A separate variable is simpler to borrow > > settings from. > Yes, in this new patch I used treesit-aggregated-simple-imenu-settings. > > > But I didn’t have time to think it though yet. (By language, or by mode and > > language? Should packages set it on load, or define a function that loads > > these settings? Etc.) > > > I would say by mode and language, both mhtml-ts mode and html-ts mode have the > same primary parser. For the second question, I don't know. I don't have > enough experience with it to know what the pros and cons are. > > > Yuan > > Vincenzo > > From 199af27f1d761d100f6a8a6163c27e35e6ab2ea0 Mon Sep 17 00:00:00 2001 > From: Vincenzo Pupillo <v.pupillo <at> gmail.com> > Date: Sun, 19 Jan 2025 17:49:30 +0100 > Subject: [PATCH] Add mhtml-ts-mode. > > New major-mode alternative to mhtml-mode, based on treesitter, for > editing files containing html, javascript and css. > > * etc/NEWS: Mention the new mode and new functions. > * lisp/textmodes/mhtml-ts-mode.el: New file. > * lisp/progmodes/js.el (js--treesit-thing-settings): New variable. > (js--treesit-font-lock-feature-list); New variable. > (js--treesit-simple-imenu-settings): New variable. > (js--treesit-defun-type-regexp): New variable. > (js--treesit-jsdoc-comment-regexp): New variable. > (js-ts-mode): Use of new variables instead of direct assignment of > values. > * lisp/textmodes/css-mode.el (css-mode--menu): New variable. > (css-mode-map): Use new variable. > (css--treesit-font-lock-feature-list): New variable. > (css--treesit-simple-imenu-settings): New variable. > (css--treesit-defun-type-regexp): New variable. > (cs-ts-mode): Use of new variables instead of direct assignment of > values. > * lisp/textmodes/html-ts-mode.el > (html-ts-mode--treesit-things-settings): New variable. > (html-ts-mode--treesit-font-lock-feature-list): New variable. > (html-ts-mode--treesit-simple-imenu-settings): New variable. > (html-ts-mode--treesit-defun-type-regexp): New variable. > (html-ts-mode): Use of new variables instead of direct assignment of > values. > * lisp/treesit.el > (treesit-merge-font-lock-feature-list): New fuction. > (treesit-replace-font-lock-feature-settings): New fuction. > (treesit-modify-indent-rules): New function. > --- > etc/NEWS | 28 ++ > lisp/progmodes/js.el | 72 ++-- > lisp/textmodes/css-mode.el | 47 ++- > lisp/textmodes/html-ts-mode.el | 45 ++- > lisp/textmodes/mhtml-ts-mode.el | 600 ++++++++++++++++++++++++++++++++ > lisp/treesit.el | 65 ++++ > 6 files changed, 798 insertions(+), 59 deletions(-) > create mode 100644 lisp/textmodes/mhtml-ts-mode.el > > diff --git a/etc/NEWS b/etc/NEWS > index 0b849dec450..6360a082e9f 100644 > --- a/etc/NEWS > +++ b/etc/NEWS > @@ -965,6 +965,12 @@ destination window is chosen using 'display-buffer-alist'. Example: > > > * New Modes and Packages in Emacs 31.1 > +** New major modes based on the tree-sitter library > + > +*** New major mode 'mhtml-ts-mode'. > +An optional major mode based on the tree-sitter library for editing html > +files. This mode handles indentation, fontification, and commenting for > +embedded JavaScript and CSS. > > > * Incompatible Lisp Changes in Emacs 31.1 > @@ -1098,6 +1104,28 @@ language symbol. For example, 'cpp' is translated to "C++". A new > variable 'treesit-language-display-name-alist' holds the translations of > language symbols where that translation is not trivial. > > ++++ > +*** New function 'treesit-merge-font-lock-feature-list'. > +This function the merge two tree-sitter font lock feature lists. > +Returns a new font lock feature list with no duplicates in the same level. > +It can be used to merge font lock feature lists in a multi-language major mode. > + > ++++ > +*** New function 'treesit-replace-font-lock-feature-settings'. > +Given two treesit-font-lock-settings replaces the feature in the second > +font-lock-settings with the same feature in the first > +font-lock-settings. In a multi-linguage major mode it is sometimes > +necessary to replace features from one of the major modes, with others > +that are better suited to the new multilingual context. > + > ++++ > +*** New function 'treesit-modify-indent-rules'. > +Given two treesit ident rules, it replaces, adds, or prepends the new > +rules to the old ones, then returns a new treesit indent rules. > +In a multi-linguage major mode it is sometimes necessary to modify rules > +from one of the major modes, with others that are better suited to the > +new multilingual context. > + > +++ > *** New command 'treesit-explore' > This command replaces 'treesit-explore-mode'. It turns on > diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el > index 101b882c718..be9d6f64aef 100644 > --- a/lisp/progmodes/js.el > +++ b/lisp/progmodes/js.el > @@ -3901,6 +3901,44 @@ js--treesit-list-nodes > (defvar js--treesit-jsdoc-beginning-regexp (rx bos "/**") > "Regular expression matching the beginning of a jsdoc block comment.") > > +(defvar js--treesit-thing-settings > + `((javascript > + (sexp ,(js--regexp-opt-symbol js--treesit-sexp-nodes)) > + (list ,(js--regexp-opt-symbol js--treesit-list-nodes)) > + (sentence ,(js--regexp-opt-symbol js--treesit-sentence-nodes)) > + (text ,(js--regexp-opt-symbol '("comment" > + "string_fragment"))))) > + "Settings for `treesit-thing-settings'.") > + > +(defvar js--treesit-font-lock-feature-list > + '(( comment document definition) > + ( keyword string) > + ( assignment constant escape-sequence jsx number > + pattern string-interpolation) > + ( bracket delimiter function operator property)) > + "Settings for `treesit-font-lock-feature-list'.") > + > +(defvar js--treesit-simple-imenu-settings > + `(("Function" "\\`function_declaration\\'" nil nil) > + ("Variable" "\\`lexical_declaration\\'" > + js--treesit-valid-imenu-entry nil) > + ("Class" ,(rx bos (or "class_declaration" > + "method_definition") > + eos) > + nil nil)) > + "Settings for `treesit-simple-imenu'.") > + > +(defvar js--treesit-defun-type-regexp > + (rx (or "class_declaration" > + "method_definition" > + "function_declaration" > + "lexical_declaration")) > + "Settings for `treesit-defun-type-regexp'.") > + > +(defvar js--treesit-jsdoc-comment-regexp > + (rx (or "comment" "line_comment" "block_comment" "description")) > + "Regexp for `c-ts-common--comment-regexp'.") > + > ;;;###autoload > (define-derived-mode js-ts-mode js-base-mode "JavaScript" > "Major mode for editing JavaScript. > @@ -3931,29 +3969,15 @@ js-ts-mode > ;; Indent. > (setq-local treesit-simple-indent-rules js--treesit-indent-rules) > ;; Navigation. > - (setq-local treesit-defun-type-regexp > - (rx (or "class_declaration" > - "method_definition" > - "function_declaration" > - "lexical_declaration"))) > + (setq-local treesit-defun-type-regexp js--treesit-defun-type-regexp) > + > (setq-local treesit-defun-name-function #'js--treesit-defun-name) > > - (setq-local treesit-thing-settings > - `((javascript > - (sexp ,(js--regexp-opt-symbol js--treesit-sexp-nodes)) > - (list ,(js--regexp-opt-symbol js--treesit-list-nodes)) > - (sentence ,(js--regexp-opt-symbol js--treesit-sentence-nodes)) > - (text ,(js--regexp-opt-symbol '("comment" > - "string_fragment")))))) > + (setq-local treesit-thing-settings js--treesit-thing-settings) > > ;; Fontification. > (setq-local treesit-font-lock-settings js--treesit-font-lock-settings) > - (setq-local treesit-font-lock-feature-list > - '(( comment document definition) > - ( keyword string) > - ( assignment constant escape-sequence jsx number > - pattern string-interpolation) > - ( bracket delimiter function operator property))) > + (setq-local treesit-font-lock-feature-list js--treesit-font-lock-feature-list) > > (when (treesit-ready-p 'jsdoc t) > (setq-local treesit-range-settings > @@ -3963,17 +3987,11 @@ js-ts-mode > :local t > `(((comment) @capture (:match ,js--treesit-jsdoc-beginning-regexp @capture))))) > > - (setq c-ts-common--comment-regexp (rx (or "comment" "line_comment" "block_comment" "description")))) > + (setq c-ts-common--comment-regexp js--treesit-jsdoc-comment-regexp)) > > ;; Imenu > - (setq-local treesit-simple-imenu-settings > - `(("Function" "\\`function_declaration\\'" nil nil) > - ("Variable" "\\`lexical_declaration\\'" > - js--treesit-valid-imenu-entry nil) > - ("Class" ,(rx bos (or "class_declaration" > - "method_definition") > - eos) > - nil nil))) > + (setq-local treesit-simple-imenu-settings js--treesit-simple-imenu-settings) > + > (treesit-major-mode-setup) > > (add-to-list 'auto-mode-alist > diff --git a/lisp/textmodes/css-mode.el b/lisp/textmodes/css-mode.el > index 53340195386..35c61e4f66d 100644 > --- a/lisp/textmodes/css-mode.el > +++ b/lisp/textmodes/css-mode.el > @@ -893,13 +893,7 @@ css-mode-syntax-table > (modify-syntax-entry ?? "." st) > st)) > > -(defvar-keymap css-mode-map > - :doc "Keymap used in `css-mode'." > - "<remap> <info-lookup-symbol>" #'css-lookup-symbol > - ;; `info-complete-symbol' is not used. > - "<remap> <complete-symbol>" #'completion-at-point > - "C-c C-f" #'css-cycle-color-format > - :menu > +(defvar css-mode--menu > '("CSS" > :help "CSS-specific features" > ["Reformat block" fill-paragraph > @@ -910,7 +904,17 @@ css-mode-map > ["Describe symbol" css-lookup-symbol > :help "Display documentation for a CSS symbol"] > ["Complete symbol" completion-at-point > - :help "Complete symbol before point"])) > + :help "Complete symbol before point"]) > + "Menu bar for `css-mode'") > + > +(defvar-keymap css-mode-map > + :doc "Keymap used in `css-mode'." > + "<remap> <info-lookup-symbol>" #'css-lookup-symbol > + ;; `info-complete-symbol' is not used. > + "<remap> <complete-symbol>" #'completion-at-point > + "C-c C-f" #'css-cycle-color-format > + :menu > + css-mode--menu) > > (eval-and-compile > (defconst css--uri-re > @@ -1771,6 +1775,21 @@ css--extract-index-name > (replace-regexp-in-string "[\n ]+" " " s))) > res))))))) > > +(defvar css--treesit-font-lock-feature-list > + '((selector comment query keyword) > + (property constant string) > + (error variable function operator bracket)) > + "Settings for `treesit-font-lock-feature-list'.") > + > +(defvar css--treesit-simple-imenu-settings > + `(( nil ,(rx bos (or "rule_set" "media_statement") eos) > + nil nil)) > + "Settings for `treesit-simple-imenu'.") > + > +(defvar css--treesit-defun-type-regexp > + "rule_set" > + "Settings for `treesit-defun-type-regexp'.") > + > (define-derived-mode css-base-mode prog-mode "CSS" > "Generic mode to edit Cascading Style Sheets (CSS). > > @@ -1825,16 +1844,12 @@ css-ts-mode > ;; Tree-sitter specific setup. > (setq treesit-primary-parser (treesit-parser-create 'css)) > (setq-local treesit-simple-indent-rules css--treesit-indent-rules) > - (setq-local treesit-defun-type-regexp "rule_set") > + (setq-local treesit-defun-type-regexp css--treesit-defun-type-regexp) > (setq-local treesit-defun-name-function #'css--treesit-defun-name) > (setq-local treesit-font-lock-settings css--treesit-settings) > - (setq-local treesit-font-lock-feature-list > - '((selector comment query keyword) > - (property constant string) > - (error variable function operator bracket))) > - (setq-local treesit-simple-imenu-settings > - `(( nil ,(rx bos (or "rule_set" "media_statement") eos) > - nil nil))) > + (setq-local treesit-font-lock-feature-list css--treesit-font-lock-feature-list) > + (setq-local treesit-simple-imenu-settings css--treesit-simple-imenu-settings) > + > (treesit-major-mode-setup) > > (add-to-list 'auto-mode-alist '("\\.css\\'" . css-ts-mode)))) > diff --git a/lisp/textmodes/html-ts-mode.el b/lisp/textmodes/html-ts-mode.el > index dad49b7ed4c..5700c2b406b 100644 > --- a/lisp/textmodes/html-ts-mode.el > +++ b/lisp/textmodes/html-ts-mode.el > @@ -87,6 +87,31 @@ html-ts-mode--font-lock-settings > `((attribute_name) @font-lock-variable-name-face)) > "Tree-sitter font-lock settings for `html-ts-mode'.") > > +(defvar html-ts-mode--treesit-things-settings > + `((html > + (sexp ,(regexp-opt '("element" > + "text" > + "attribute" > + "value"))) > + (list ,(regexp-opt '("element")) 'symbols) > + (sentence "tag") > + (text ,(regexp-opt '("comment" "text"))))) > + "Settings for `treesit-thing-settings'.") > + > +(defvar html-ts-mode--treesit-font-lock-feature-list > + '((comment keyword definition) > + (property string) > + () ()) > + "Settings for `treesit-font-lock-feature-list'.") > + > +(defvar html-ts-mode--treesit-simple-imenu-settings > + '(("Element" "\\`tag_name\\'" nil nil)) > + "Settings for `treesit-simple-imenu'.") > + > +(defvar html-ts-mode--treesit-defun-type-regexp > + "element" > + "Settings for `treesit-defun-type-regexp'.") > + > (defun html-ts-mode--defun-name (node) > "Return the defun name of NODE. > Return nil if there is no name or if NODE is not a defun node." > @@ -107,30 +132,18 @@ html-ts-mode > (setq-local treesit-simple-indent-rules html-ts-mode--indent-rules) > > ;; Navigation. > - (setq-local treesit-defun-type-regexp "element") > + (setq-local treesit-defun-type-regexp html-ts-mode--treesit-defun-type-regexp) > > (setq-local treesit-defun-name-function #'html-ts-mode--defun-name) > > - (setq-local treesit-thing-settings > - `((html > - (sexp ,(regexp-opt '("element" > - "text" > - "attribute" > - "value"))) > - (list ,(regexp-opt '("element")) 'symbols) > - (sentence "tag") > - (text ,(regexp-opt '("comment" "text")))))) > + (setq-local treesit-thing-settings html-ts-mode--treesit-things-settings) > > ;; Font-lock. > (setq-local treesit-font-lock-settings html-ts-mode--font-lock-settings) > - (setq-local treesit-font-lock-feature-list > - '((comment keyword definition) > - (property string) > - () ())) > + (setq-local treesit-font-lock-feature-list html-ts-mode--treesit-font-lock-feature-list) > > ;; Imenu. > - (setq-local treesit-simple-imenu-settings > - '(("Element" "\\`tag_name\\'" nil nil))) > + (setq-local treesit-simple-imenu-settings html-ts-mode--treesit-simple-imenu-settings) > > ;; Outline minor mode. > (setq-local treesit-outline-predicate "\\`element\\'") > diff --git a/lisp/textmodes/mhtml-ts-mode.el b/lisp/textmodes/mhtml-ts-mode.el > new file mode 100644 > index 00000000000..272d00a1ef6 > --- /dev/null > +++ b/lisp/textmodes/mhtml-ts-mode.el > @@ -0,0 +1,600 @@ > +;;; mhtml-ts-mode.el --- Major mode for HTML using tree-sitter -*- lexical-binding: t; -*- > + > +;; Copyright (C) 2024 Free Software Foundation, Inc. > + > +;; Author: Vincenzo Pupillo <v.pupillo <at> gmail.com> > +;; Maintainer: Vincenzo Pupillo <v.pupillo <at> gmail.com> > +;; Created: Nov 2024 > +;; Keywords: HTML languages hypermedia tree-sitter > + > +;; This file is part of GNU Emacs. > + > +;; GNU Emacs 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. > + > +;; GNU Emacs 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>. > + > +;;; Commentary: > +;; > +;; This package provides `mhtml-ts-mode' which is a major mode > +;; for editing HTML files with embedded JavaScript and CSS. > +;; Tree Sitter is used to parse each of these languages. > +;; > +;; Please note that this package requires `html-ts-mode', which > +;; registers itself as the major mode for editing HTML. > +;; > +;; This package is compatible and has been tested with the following > +;; tree-sitter grammars: > +;; * https://github.com/tree-sitter/tree-sitter-html > +;; * https://github.com/tree-sitter/tree-sitter-javascript > +;; * https://github.com/tree-sitter/tree-sitter-jsdoc > +;; * https://github.com/tree-sitter/tree-sitter-css > +;; > +;; Features > +;; > +;; * Indent > +;; * Flymake > +;; * IMenu > +;; * Navigation > +;; * Which-function > +;; * Tree-sitter parser installation helper > + > +;;; Code: > + > +(require 'treesit) > +(require 'html-ts-mode) > +(require 'css-mode) ;; for embed css into html > +(require 'js) ;; for embed javascript into html > + > +(eval-when-compile > + (require 'rx)) > + > +;; This tells the byte-compiler where the functions are defined. > +;; Is only needed when a file needs to be able to byte-compile > +;; in a Emacs not built with tree-sitter library. > +(treesit-declare-unavailable-functions) > + > +;; In a multi-language major mode can be useful to have an "installer" to > +;; simplify the installation of the grammars supported by the major-mode. > +(defvar mhtml-ts-mode--language-source-alist > + '((html . ("https://github.com/tree-sitter/tree-sitter-html" "v0.23.2")) > + (javascript . ("https://github.com/tree-sitter/tree-sitter-javascript" "v0.23.1")) > + (jsdoc . ("https://github.com/tree-sitter/tree-sitter-jsdoc" "v0.23.2")) > + (css . ("https://github.com/tree-sitter/tree-sitter-css" "v0.23.1"))) > + "Treesitter language parsers required by `mhtml-ts-mode'. > +You can customize this variable if you want to stick to a specific > +commit and/or use different parsers.") > + > +(defun mhtml-ts-mode-install-parsers () > + "Install all the required treesitter parsers. > +`mhtml-ts-mode--language-source-alist' defines which parsers to install." > + (interactive) > + (let ((treesit-language-source-alist mhtml-ts-mode--language-source-alist)) > + (dolist (item mhtml-ts-mode--language-source-alist) > + (treesit-install-language-grammar (car item))))) > + > +;;; Custom variables > + > +(defgroup mhtml-ts-mode nil > + "Major mode for editing HTML files, based on `html-ts-mode'. > +Works with JS and CSS and for that use `js-ts-mode' and `css-ts-mode'." > + :prefix "mhtml-ts-mode-" > + ;; :group 'languages > + :group 'html) > + > +(defcustom mhtml-ts-mode-js-css-indent-offset 2 > + "JavaScript and CSS indent spaces related to the <script> and <style> HTML tags. > +By default should have same value as `html-ts-mode-indent-offset'." > + :tag "HTML javascript or css indent offset" > + :version "31.1" > + :type 'integer > + :safe 'integerp) > + > +(defcustom mhtml-ts-mode-pretty-print-command > + ;; prefer tidy because it's used by sgml-mode > + (let ((executable nil)) > + (cond ((setq executable (executable-find "tidy")) > + (format > + "%s --gnu-emacs yes --wrap 0 --indent-spaces %s -q -i -" > + executable html-ts-mode-indent-offset)) > + ((setq executable (executable-find "xmllint")) > + (format "%s --html --quiet --format -" executable)) > + (t "Install tidy, ore some other HTML pretty print tool, and set `mhtml-ts-mode-pretty-print-command'."))) > + "The command to pretty print the current HTML buffer." > + :type 'string > + :version "31.1") > + > +(defvar mhtml-ts-mode--js-css-indent-offset > + mhtml-ts-mode-js-css-indent-offset > + "Internal copy of `mhtml-ts-mode-js-css-indent-offset'. > +The value changes, by `mhtml-ts-mode--tag-relative-indent-offset' according to > +the value of `mhtml-ts-mode-tag-relative-indent'.") > + > +(defun mhtml-ts-mode--tag-relative-indent-offset (sym val) > + "Custom setter for `mhtml-ts-mode-tag-relative-indent'. > +Apart from setting the default value of SYM to VAL, also change the > +value of SYM in `mhtml-ts-mode' buffers to VAL. SYM should be > +`mhtml-ts-mode-tag-relative-indent', and VAL should be t, nil or > +`ignore'. When sym is `mhtml-ts-mode-tag-relative-indent' set the > +value of `mhtml-ts-mode--js-css-indent-offset' to 0 if VAL is t, > +otherwise to `mhtml-ts-mode-js-css-indent-offset'." > + (set-default sym val) > + (when (eq sym 'mhtml-ts-mode-tag-relative-indent) > + (setq > + mhtml-ts-mode--js-css-indent-offset > + (if (eq val t) > + mhtml-ts-mode-js-css-indent-offset > + 0)))) > + > +(defcustom mhtml-ts-mode-tag-relative-indent t > + "How <script> and <style> bodies are indented relative to the tag. > + > +When t, indentation looks like: > + > + <script> > + code(); > + </script> > + > +When nil, indentation of the tag body starts just below the > +tag, like: > + > + <script> > + code(); > + </script> > + > +When `ignore', the tag body starts in the first column, like: > + > + <script> > +code(); > + </script>" > + :type '(choice (const nil) (const t) (const ignore)) > + :safe 'symbolp > + :set #'mhtml-ts-mode--tag-relative-indent-offset > + :version "31.1") > + > +(defcustom mhtml-ts-mode-css-fontify-colors t > + "Whether CSS colors should be fontified using the color as the background. > +If non-nil, text representing a CSS color will be fontified > +such that its background is the color itself. > +Works like `css--fontify-region'." > + :tag "HTML colors the CSS properties values." > + :version "31.1" > + :type 'boolean > + :safe 'booleanp) > + > +(defvar mhtml-ts-mode-saved-pretty-print-command nil > + "The command last used to pretty print in this buffer.") > + > +(defun mhtml-ts-mode-pretty-print (command) > + "Prettify the current buffer. > +Argument COMMAND The command to use." > + (interactive > + (list (read-string > + "Prettify command: " > + (or mhtml-ts-mode-saved-pretty-print-command > + (concat mhtml-ts-mode-pretty-print-command " "))))) > + (setq mhtml-ts-mode-saved-pretty-print-command command) > + (save-excursion > + (shell-command-on-region > + (point-min) (point-max) > + command (buffer-name) t > + "*mhtml-ts-mode-pretty-pretty-print-errors*" t))) > + > +(defun mhtml-ts-mode--switch-fill-defun (&rest arguments) > + "Switch between `fill-paragraph' and `prog-fill-reindent-defun'. > +In an HTML region it calls `fill-paragraph' as does `html-ts-mode', > +otherwise it calls `prog-fill-reindent-defun'. > +Optional ARGUMENTS to to be passed to it." > + (interactive) > + (if (eq (treesit-language-at (point)) 'html) > + (funcall-interactively #'fill-paragraph arguments) > + (funcall-interactively #'prog-fill-reindent-defun arguments))) > + > +(defvar-keymap mhtml-ts-mode-map > + :doc "Keymap for `mhtml-ts-mode' buffers." > + :parent html-mode-map > + ;; `mhtml-ts-mode' derive from `html-ts-mode' so the keymap is the > + ;; same, we need to add some mapping from others languages. > + "C-c C-f" #'css-cycle-color-format > + "M-q" #'mhtml-ts-mode--switch-fill-defun) > + > +;; Place the CSS menu in the menu bar as well. > +(easy-menu-define mhtml-ts-mode-menu mhtml-ts-mode-map > + "Menu bar for `mhtml-ts-mode'." > + css-mode--menu) > + > +;; Not used at the moment. > +(defun mthml-ts-mode--js-language-at-point (point) > + "Return the language at POINT assuming the point is within a Javascript region." > + (let* ((node (treesit-node-at point 'javascript)) > + (node-type (treesit-node-type node)) > + (node-start (treesit-node-start node)) > + (node-end (treesit-node-end node))) > + (if (not (treesit-ready-p 'jsdoc t)) > + 'javascript > + (if (equal node-type "comment") > + (save-excursion > + ;; (message "node start = %s , end = %s" node-start node-end) > + (goto-char node-start) > + (if (search-forward "/**" node-end t) > + 'jsdoc > + 'javascript)) > + 'javascript)))) > + > +;; To enable some basic treesiter functionality, you should define > +;; a function that recognizes which grammar is used at-point. > +;; This function should be assigned to `treesit-language-at-point-function' > +(defun mhtml-ts-mode--language-at-point (point) > + "Return the language at POINT assuming the point is within a HTML buffer." > + (let* ((node (treesit-node-at point 'html)) > + (parent (treesit-node-parent node)) > + (node-query (format "(%s (%s))" > + (treesit-node-type parent) > + (treesit-node-type node)))) > + (cond > + ((equal "(script_element (raw_text))" node-query) 'javascript) > + ;; ((equal "(script_element (raw_text))" node-query) 'mthml-ts-mode--js-language-at-point) > + ((equal "(style_element (raw_text))" node-query) 'css) > + (t 'html)))) > + > +;; Custom font-lock function that's used to apply color to css color > +;; The signature of the function should be conforming to signature > +;; QUERY-SPEC required by `treesit-font-lock-rules'. > +(defun mhtml-ts-mode--colorize-css-value (node override start end &rest _) > + "Colorize CSS property value like `css--fontify-region'. > +For NODE, OVERRIDE, START, and END, see `treesit-font-lock-rules'." > + (if (and mhtml-ts-mode-css-fontify-colors > + (string-equal "plain_value" (treesit-node-type node))) > + (let ((color (css--compute-color start (treesit-node-text node t)))) > + (when color > + (with-silent-modifications > + (add-text-properties > + (treesit-node-start node) (treesit-node-end node) > + (list 'face (list :background color > + :foreground (readable-foreground-color > + color) > + :box '(:line-width -1))))))) > + (treesit-fontify-with-override > + (treesit-node-start node) (treesit-node-end node) > + 'font-lock-variable-name-face > + override start end))) > + > +;; Embedded languages should be indented according to the language > +;; that embeds them. > +;; This function signature complies with `treesit-simple-indent-rules' > +;; ANCHOR. > +(defun mhtml-ts-mode--js-css-tag-bol (_node _parent &rest _) > + "Find the first non-space characters of html tags <script> or <style>. > +Return `line-beginning-position' when `treesit-node-at' is html, or > +`mhtml-ts-mode-tag-relative-indent' is equal to ignore. > +NODE and PARENT are ignored." > + (if (or (eq (treesit-language-at (point)) 'html) > + (eq mhtml-ts-mode-tag-relative-indent 'ignore)) > + (line-beginning-position) > + ;; Ok, we are in js or css block. > + (save-excursion > + (re-search-backward "<script.*>\\|<style.*>" nil t)))) > + > +;; Treesit supports 4 level of decoration, `treesit-font-lock-level' > +;; define which level to use. Major modes categorize their fontification > +;; features, these categories are defined by `treesit-font-lock-rules' of > +;; each major-mode using :feature keyword. > +;; In a multiple language Major mode it's a good idea to provide, for each > +;; level, the union of the :feature of the same level. > +;; TODO: Since the feature-list is not defined per "parser" (like, for > +;; example, the thing-settings), the same feature can appear in > +;; different levels, so the appearance of a multiple main mode can be > +;; different from the main mode used. For e.g the feature "function" is > +;; at level 4 for Javascript while it is at level 3 for CSS. > +(defvar mhtml-ts-mode--treesit-font-lock-feature-list > + (treesit-merge-font-lock-feature-list > + html-ts-mode--treesit-font-lock-feature-list > + (treesit-merge-font-lock-feature-list > + js--treesit-font-lock-feature-list > + css--treesit-font-lock-feature-list)) > + "Settings for `treesit-font-lock-feature-list'.") > + > +(defvar mhtml-ts-mode--treesit-font-lock-settings > + (append html-ts-mode--font-lock-settings > + js--treesit-font-lock-settings > + ;; Let's replace a css rule with a new one that adds color to > + ;; the css value. > + (treesit-replace-font-lock-feature-settings > + (treesit-font-lock-rules > + :language 'css > + :override t > + :feature 'variable > + '((plain_value) @font-lock-variable-name-face > + (plain_value) @mhtml-ts-mode--colorize-css-value)) > + css--treesit-settings)) > + "Settings for `treesit-font-lock-settings'.") > + > +(defvar mhtml-ts-mode--treesit-thing-settings > + ;; In addition to putting together the various definitions, we need to > + ;; add 'defun' which is used to support `imenu' and 'which-function'. > + (list > + ;; HTML thing settings > + (append > + (car html-ts-mode--treesit-things-settings) > + `((defun ,(regexp-opt (list html-ts-mode--treesit-defun-type-regexp))))) > + ;; Javascript thing settings > + (append > + (car js--treesit-thing-settings) > + `((defun ,js--treesit-defun-type-regexp))) > + ;; CSS thing settings > + `(css > + (defun ,(regexp-opt (list css--treesit-defun-type-regexp))))) > + "Settings for `treesit-thing-settings'.") > + > +(defvar mhtml-ts-mode--treesit-indent-rules > + (treesit--indent-rules-optimize > + (append html-ts-mode--indent-rules > + ;; Extended rules for js and css, to > + ;; indent appropriately when injected > + ;; into html > + (treesit-modify-indent-rules > + `((javascript ((parent-is "program") > + mhtml-ts-mode--js-css-tag-bol > + mhtml-ts-mode--js-css-indent-offset))) > + js--treesit-indent-rules > + :replace) > + (treesit-modify-indent-rules > + `((css ((parent-is "stylesheet") > + mhtml-ts-mode--js-css-tag-bol > + mhtml-ts-mode--js-css-indent-offset))) > + css--treesit-indent-rules 'prepend) > + :replace)) > + "Settings for `treesit-simple-indent-rules'.") > + > +(defvar mhtml-ts-mode--treesit-aggregated-simple-imenu-settings > + `((html ,@html-ts-mode--treesit-simple-imenu-settings) > + (javascript ,@js--treesit-simple-imenu-settings) > + (css ,@css--treesit-simple-imenu-settings)) > + "Settings for `treesit-simple-imenu'.") > + > +;; TODO: treesit-defun-type-regexp should have an aggregated version, > +;; like treesit-aggregated-simple-imenu-settings. Otherwise we can't > +;; reuse the regex defined in the major mode we use. > +(defvar mhtml-ts-mode--treesit-defun-type-regexp > + (regexp-opt '("class_declaration" > + "method_definition" > + "function_declaration" > + "lexical_declaration" > + "element" > + "rule_set")) > + "Settings for `treesit-defun-type-regexp'.") > + > +;; In order to support `prettify-symbols-mode', just `append' the prettify > +;; alist of all the languages. In our case only javascript defined this alist. > +(defvar mhtml-ts-mode--prettify-symbols-alist js--prettify-symbols-alist > + "Alist of symbol prettifications for various supported languages.") > + > +;; In order to support `which-fuction-mode' we should define > +;; a function that return the defun name. > +;; In a multilingual treesit mode, this can be implemented simply by > +;; calling language-specific functions. > +(defun mhtml-ts-mode--defun-name (node) > + "Return the defun name of NODE. > +Return nil if there is no name or if NODE is not a defun node." > + (let ((html-name (html-ts-mode--defun-name node)) > + (js-name (js--treesit-defun-name node)) > + (css-name (css--treesit-defun-name node))) > + (cond > + (html-name html-name) > + (js-name js-name) > + (css-name css-name)))) > + > +;;; Flymake integration > + > +(defvar-local mhtml-ts-mode--flymake-process nil > + "Store the Flymake process.") > + > +(defun mhtml-ts-mode-flymake-mhtml (report-fn &rest _args) > + "MHTML backend for Flymake. > +Calls REPORT-FN directly. Requires tidy." > + (when (process-live-p mhtml-ts-mode--flymake-process) > + (kill-process mhtml-ts-mode--flymake-process)) > + (let ((tidy (executable-find "tidy")) > + (source (current-buffer)) > + (diagnostics-pattern (eval-when-compile > + (rx bol > + "line " (group (+ num)) ;; :1 line > + " column " (group (+ num)) ;; :2 column > + " - " (group (+? nonl)) ;; :3 type > + ": " (group (+? nonl)) ;; :4 msg > + eol)))) > + (if (not tidy) > + (error "Unable to find tidy command") > + (save-restriction > + (widen) > + (setq mhtml-ts-mode--flymake-process > + (make-process > + :name "mhtml-ts-mode-flymake" > + :noquery t > + :connection-type 'pipe > + :buffer (generate-new-buffer "*mhtml-ts-mode-flymake*") > + :command `(,tidy "--gnu-emacs" "yes" "-e" "-q") > + :sentinel > + (lambda (proc _event) > + (when (eq 'exit (process-status proc)) > + (unwind-protect > + (if (with-current-buffer source > + (eq proc mhtml-ts-mode--flymake-process)) > + (with-current-buffer (process-buffer proc) > + (goto-char (point-min)) > + (let (diags) > + (while (search-forward-regexp diagnostics-pattern nil t) > + (let* ((pos > + (flymake-diag-region > + source > + (string-to-number (match-string 1)) > + (string-to-number (match-string 2)))) ;; line and column > + (type (cond ((equal (match-string 3) "Warning") :warning) > + ((equal (match-string 3) "Error") :error))) ;; type of message > + (msg (match-string 4))) ;; message > + (push (flymake-make-diagnostic source (car pos) (cdr pos) type msg) > + diags))) > + (funcall report-fn diags))) > + (flymake-log :warning "Canceling obsolete check %s" proc)) > + (kill-buffer (process-buffer proc))))))) > + (process-send-region mhtml-ts-mode--flymake-process (point-min) (point-max)) > + (process-send-eof mhtml-ts-mode--flymake-process))))) > + > +(define-derived-mode mhtml-ts-mode html-ts-mode > + '("HTML+" (:eval (let ((lang (mhtml-ts-mode--language-at-point (point)))) > + (cond ((eq lang 'html) "") > + ((eq lang 'javascript) "JS") > + ((eq lang 'css) "CSS"))))) > + "Major mode for editing HTML with embedded JavaScript and CSS. > +Powered by tree-sitter." > + (if (not (and > + (treesit-ready-p 'html) > + (treesit-ready-p 'javascript) > + (treesit-ready-p 'css))) > + (error "Tree-sitter parsers for HTML isn't available. You can > + install the parsers with M-x `mhtml-ts-mode-install-parsers'") > + > + ;; When an language is embedded, you should initialize some variable > + ;; just like it's done in the original mode. > + > + ;; Comment. > + ;; indenting settings for js-ts-mode. > + (c-ts-common-comment-setup) > + (setq-local comment-multi-line t) > + > + ;; Font-lock. > + > + ;; There are two ways to handle embedded code: > + ;; 1. Use a single parser for all the embedded code in the buffer. In > + ;; this case, the embedded code blocks are concatenated together and are > + ;; seen as a single continuous document to the parser. > + ;; 2. Each embedded code block gets its own parser. Each parser only sees > + ;; that particular code block. > + > + ;; If you go with 2 for a language, the local parsers are created and > + ;; destroyed automatically by Emacs. So don't create a global parser for > + ;; that embedded language here. > + > + ;; Create the parsers, only the global ones. > + ;; jsdoc is a local parser, don't create a parser for it. > + (treesit-parser-create 'css) > + (treesit-parser-create 'javascript) > + > + ;; Multi-language modes must set the primary parser. > + (setq-local treesit-primary-parser (treesit-parser-create 'html)) > + > + (setq-local treesit-range-settings > + (treesit-range-rules > + :embed 'javascript > + :host 'html > + '((script_element > + (start_tag (tag_name)) > + (raw_text) @cap)) > + > + ;; Another rule could be added that when it matches an > + ;; attribute_value that has as its parent an > + ;; attribute_name "style" it captures it and then > + ;; passes it to the css parser. > + :embed 'css > + :host 'html > + '((style_element > + (start_tag (tag_name)) > + (raw_text) @cap)))) > + > + ;; jsdoc is not mandatory for js-ts-mode, so we respect this by > + ;; adding jsdoc range rules only when jsdoc is available. > + (when (treesit-ready-p 'jsdoc t) > + (setq-local treesit-range-settings > + (append treesit-range-settings > + (treesit-range-rules > + :embed 'jsdoc > + :host 'javascript > + :local t > + `(((comment) @cap > + (:match ,js--treesit-jsdoc-beginning-regexp @cap)))))) > + (setq-local c-ts-common--comment-regexp > + js--treesit-jsdoc-comment-regexp)) > + > + > + ;; Many treesit fuctions need to know the language at-point. > + ;; So you should define such a function. > + (setq-local treesit-language-at-point-function #'mhtml-ts-mode--language-at-point) > + (setq-local prettify-symbols-alist mhtml-ts-mode--prettify-symbols-alist) > + > + ;; Indent. > + > + ;; Since `mhtml-ts-mode' inherits indentation rules from `html-ts-mode', `js-ts-mode' > + ;; and `css-ts-mode', if you want to change the offset you have to act on the > + ;; *-offset variables defined for those languages. > + > + ;; JavaScript and CSS must be indented relative to their code block. > + ;; This is done by inserting a special rule before the normal > + ;; indentation rules of these languages. > + ;; The value of `mhtml-ts-mode--js-css-indent-offset' changes based on > + ;; `mhtml-ts-mode-tag-relative-indent' and can be used to indent > + ;; JavaScript and CSS code relative to the HTML that contains them, > + ;; just like in mhtml-mode. > + (setq-local treesit-simple-indent-rules mhtml-ts-mode--treesit-indent-rules) > + > + ;; Navigation. > + > + ;; This is for which-function-mode. > + ;; Since mhtml-ts-mode is derived from html-ts-mode, which sets > + ;; the value of `treesit-defun-type-regexp', you have to reset it to nil > + ;; otherwise `imenu' and `which-function-mode' will not work. > + (setq-local treesit-defun-type-regexp nil) > + > + ;; This is for finding defun name, it's used by IMenu as default > + ;; function no specific functions are defined. > + (setq-local treesit-defun-name-function #'mhtml-ts-mode--defun-name) > + > + ;; Define what are 'thing' for treesit. > + ;; 'Thing' is a symbol representing the thing, like `defun', `sexp', or > + ;; `sentence'. > + ;; As an alternative, if you want just defun, you can define a `treesit-defun-type-regexp'. > + (setq-local treesit-thing-settings mhtml-ts-mode--treesit-thing-settings) > + > + ;; Font-lock. > + > + ;; In a multi-language scenario, font lock settings are usually a > + ;; concatenation of language rules. As you can see, it is possible > + ;; to extend/modify the default rule or use a different set of > + ;; rules. See `php-ts-mode--custom-html-font-lock-settings' for more > + ;; advanced usage. > + (setq-local treesit-font-lock-settings mhtml-ts-mode--treesit-font-lock-settings) > + > + ;; Tells treesit the list of features to fontify. > + (setq-local treesit-font-lock-feature-list mhtml-ts-mode--treesit-font-lock-feature-list) > + > + ;; Imenu > + > + ;; Setup Imenu: if no function is specified, try to find an object > + ;; using `treesit-defun-name-function'. > + (setq-local treesit-aggregated-simple-imenu-settings > + mhtml-ts-mode--treesit-aggregated-simple-imenu-settings) > + > + (treesit-major-mode-setup) > + > + ;; This is sort of a prog-mode as well as a text mode. > + (run-mode-hooks 'prog-mode-hook) > + > + ;; Flymake > + (add-hook 'flymake-diagnostic-functions #'mhtml-ts-mode-flymake-mhtml nil 'local))) > + > +;; Add nome extra parents. > +(derived-mode-add-parents 'mhtml-ts-mode '(css-mode js-mode)) > + > +(when (and (treesit-ready-p 'html) (treesit-ready-p 'javascript) (treesit-ready-p 'css)) > + (add-to-list > + 'auto-mode-alist '("\\.[sx]?html?\\(\\.[a-zA-Z_]+\\)?\\'" . mhtml-ts-mode))) > + > +(provide 'mhtml-ts-mode) > +;;; mhtml-ts-mode.el ends here > diff --git a/lisp/treesit.el b/lisp/treesit.el > index 8d86d142e3f..00b7d266e74 100644 > --- a/lisp/treesit.el > +++ b/lisp/treesit.el > @@ -1297,6 +1297,40 @@ treesit-font-lock-recompute-features > ((memq feature remove-list) nil) > (t current-value)))))) > > +(defun treesit-merge-font-lock-feature-list (features-list-1 features-list-2) > + "Merge two tree-sitter font lock feature lists. > +Returns a new font lock feature list with no duplicates in the same level. > +It can be used to merge font lock feature lists in a multi-language major mode. > +FEATURES-LIST-1 and FEATURES-LIST-2 are list of lists of feature symbols." > + (let ((result nil) > + (features-1 (car features-list-1)) > + (features-2 (car features-list-2))) > + (while (or features-1 features-2) > + (cond > + ((and features-1 (not features-2)) (push features-1 result)) > + ((and (not features-1) features-2) (push features-2 result)) > + ((and features-1 features-2) (push (cl-union features-1 features-2) result))) > + (setq features-list-1 (cdr features-list-1) > + features-list-2 (cdr features-list-2) > + features-1 (car features-list-1) > + features-2 (car features-list-2))) > + (nreverse result))) > + > +(defun treesit-replace-font-lock-feature-settings (new-settings settings) > + "Replaces :feature in SETTINGS with :feature from NEW-SETTINGS. > +Both SETTINGS and NEW-SETTINGS must be a value suitable for > +`treesit-font-lock-settings'. > +Return a value suitable for `treesit-font-lock-settings'" > + (let ((result nil)) > + (dolist (new-setting new-settings) > + (let ((new-feature (treesit-font-lock-setting-feature new-setting))) > + (dolist (setting settings) > + (let ((feature (treesit-font-lock-setting-feature setting))) > + (if (eq new-feature feature) > + (push new-setting result) > + (push setting result)))))) > + (nreverse result))) > + > (defun treesit-add-font-lock-rules (rules &optional how feature) > "Add font-lock RULES to the current buffer. > > @@ -2401,6 +2435,37 @@ treesit--indent-rules-optimize > offset))))) > (cons lang (mapcar #'optimize-rule indent-rules))))) > > +(defun treesit-modify-indent-rules (new-rules rules &optional how) > + "Modify RULES using NEW-RULES. > +As default replace rules with the same anchor. > +When HOW is :prepend NEW-RULES are prepend to RULES, when > +:append NEW-RULES are appended to RULES, when :replace (the default) > +NEW-RULES replace rule in RULES which the same anchor." > + (let ((n-lang (car (car new-rules))) > + (lang (car (car rules)))) > + (when (not (eq n-lang lang)) > + (error "The language must be the same")) > + (let* ((nr (cdr (car new-rules))) > + (r (cdr (car rules))) > + (tmp nil) > + (result > + (cond > + ((eq how :prepend) > + (append nr r)) > + ((eq how :append) > + (append r nr)) > + ((or (eq how :replace) t) > + (nreverse > + (progn > + (dolist (new-rule nr) > + (dolist (rule r) > + (if (equal (nth 0 new-rule) (nth 0 rule)) > + (push new-rule tmp) > + (push rule tmp)))) > + tmp)))))) > + (push lang result) > + `(,result)))) > + > ;;; Search > > (defun treesit-search-forward-goto > -- > 2.48.1 >
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Sun, 09 Feb 2025 14:37:02 GMT) Full text and rfc822 format available.Message #73 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Vincenzo Pupillo <v.pupillo <at> gmail.com> To: casouri <at> gmail.com, juri <at> linkov.net, Eli Zaretskii <eliz <at> gnu.org> Cc: 74610 <at> debbugs.gnu.org Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Sun, 09 Feb 2025 15:35:44 +0100
[Message part 1 (text/plain, inline)]
Ciao Eli, This attached patch is the third version. Adapted to support the latest changes introduced in treesit.el and js.el (as described in bug#75456). @Jury, @Yuan what do you think about this version? Thanks. Vincenzo In data sabato 8 febbraio 2025 10:01:48 Ora standard dell’Europa centrale, Eli Zaretskii ha scritto: > Ping! Can we please make progress with this issue? is the patch ready > to be installed? > > > From: Vincenzo Pupillo <v.pupillo <at> gmail.com> > > Cc: Juri Linkov <juri <at> linkov.net>, 74610 <at> debbugs.gnu.org, > > > > Eli Zaretskii <eliz <at> gnu.org> > > > > Date: Sun, 19 Jan 2025 18:09:31 +0100 > > > > Ciao Yuan, > > In data sabato 18 gennaio 2025 02:37:53 Ora standard dell’Europa centrale, > > > > Yuan Fu ha scritto: > > > > On Jan 14, 2025, at 1:41 PM, Vincenzo Pupillo <v.pupillo <at> gmail.com> > > > > wrote: > > > > > > > > Ciao Yuan and Juri, > > > > this is an updated version of mhtml-ts-mode. > > > > I have tried to reduce as much as possible copies of parts of the > > > > major > > > > modes from which it is derived. > > > > To do this, I had to move some values that were assigned directly to > > > > treesit's own variables (in ccs-mode.el, in js.el, and in > > > > html-ts-mode.el) into new variables. > > > > I also added three new functions to treesit.el to make it easier to > > > > combine > > > > parts derived from the other major modes. So now any changes to these > > > > new > > > > variables are directly reflected in the behavior of mhtml-ts-mode. > > > > There are a few things I would like to highlight: > > > > 1. treesit-font-lock-feature-lists are not defined per parser, so > > > > simply > > > > merging the different lists will cause display differences from the > > > > original major-modes; for example “function” is defined at level 3 in > > > > css-ts-mode but at level 4 in js-ts-mode. > > > > > > Yeah, that’s not pretty, I don’t have a good solution for now. > > > Technically a major mode can use treesit-font-lock-recompute-features > > > after > > > treesit-major-mode-setup to do fine adjustments, but it’s ugly. > > > > > > > 2. treesit-defun-type-regexp has the same problem as > > > > treesit-font-lock- > > > > feature-list, so I had to define it myself. > > > > > > Maybe you can use treesit-thing-settings instead? > > > > Ok, done. > > > > > > But other than that, it works pretty well. > > > > > > > > IMHO, a global "list" where you can define "font-lock", "indent-list", > > > > "font- lock-feature", etc. by language (perhaps with getter and setter > > > > methods) might make it easier to define new multilingual major-modes. > > > > It > > > > could improve the decoupling between multilingual major-modes and the > > > > major-modes they are derived from. It could also better decouple the > > > > internal implementation of treesit.el from the treesitter-based > > > > major-modes. > > > > > > > > Let me know what you think. > > > > > > That’s what I had in mind. That’s also why I added a new variable > > > treesit-aggregated-simple-imenu-settings instead of piggybacking on > > > treesit-simple-imenu-settings. A separate variable is simpler to borrow > > > settings from. > > > > Yes, in this new patch I used treesit-aggregated-simple-imenu-settings. > > > > > But I didn’t have time to think it though yet. (By language, or by mode > > > and > > > language? Should packages set it on load, or define a function that > > > loads > > > these settings? Etc.) > > > > I would say by mode and language, both mhtml-ts mode and html-ts mode have > > the same primary parser. For the second question, I don't know. I don't > > have enough experience with it to know what the pros and cons are. > > > > > Yuan > > > > Vincenzo > > > > From 199af27f1d761d100f6a8a6163c27e35e6ab2ea0 Mon Sep 17 00:00:00 2001 > > From: Vincenzo Pupillo <v.pupillo <at> gmail.com> > > Date: Sun, 19 Jan 2025 17:49:30 +0100 > > Subject: [PATCH] Add mhtml-ts-mode. > > > > New major-mode alternative to mhtml-mode, based on treesitter, for > > editing files containing html, javascript and css. > > > > * etc/NEWS: Mention the new mode and new functions. > > * lisp/textmodes/mhtml-ts-mode.el: New file. > > * lisp/progmodes/js.el (js--treesit-thing-settings): New variable. > > (js--treesit-font-lock-feature-list); New variable. > > (js--treesit-simple-imenu-settings): New variable. > > (js--treesit-defun-type-regexp): New variable. > > (js--treesit-jsdoc-comment-regexp): New variable. > > (js-ts-mode): Use of new variables instead of direct assignment of > > values. > > * lisp/textmodes/css-mode.el (css-mode--menu): New variable. > > (css-mode-map): Use new variable. > > (css--treesit-font-lock-feature-list): New variable. > > (css--treesit-simple-imenu-settings): New variable. > > (css--treesit-defun-type-regexp): New variable. > > (cs-ts-mode): Use of new variables instead of direct assignment of > > values. > > * lisp/textmodes/html-ts-mode.el > > (html-ts-mode--treesit-things-settings): New variable. > > (html-ts-mode--treesit-font-lock-feature-list): New variable. > > (html-ts-mode--treesit-simple-imenu-settings): New variable. > > (html-ts-mode--treesit-defun-type-regexp): New variable. > > (html-ts-mode): Use of new variables instead of direct assignment of > > values. > > * lisp/treesit.el > > (treesit-merge-font-lock-feature-list): New fuction. > > (treesit-replace-font-lock-feature-settings): New fuction. > > (treesit-modify-indent-rules): New function. > > --- > > > > etc/NEWS | 28 ++ > > lisp/progmodes/js.el | 72 ++-- > > lisp/textmodes/css-mode.el | 47 ++- > > lisp/textmodes/html-ts-mode.el | 45 ++- > > lisp/textmodes/mhtml-ts-mode.el | 600 ++++++++++++++++++++++++++++++++ > > lisp/treesit.el | 65 ++++ > > 6 files changed, 798 insertions(+), 59 deletions(-) > > create mode 100644 lisp/textmodes/mhtml-ts-mode.el > > > > diff --git a/etc/NEWS b/etc/NEWS > > index 0b849dec450..6360a082e9f 100644 > > --- a/etc/NEWS > > +++ b/etc/NEWS > > > > @@ -965,6 +965,12 @@ destination window is chosen using 'display-buffer- alist'. Example: > > > > * New Modes and Packages in Emacs 31.1 > > > > +** New major modes based on the tree-sitter library > > + > > +*** New major mode 'mhtml-ts-mode'. > > +An optional major mode based on the tree-sitter library for editing html > > +files. This mode handles indentation, fontification, and commenting for > > +embedded JavaScript and CSS. > > > > > > * Incompatible Lisp Changes in Emacs 31.1 > > > > @@ -1098,6 +1104,28 @@ language symbol. For example, 'cpp' is translated > > to "C++". A new> > > variable 'treesit-language-display-name-alist' holds the translations of > > language symbols where that translation is not trivial. > > > > ++++ > > +*** New function 'treesit-merge-font-lock-feature-list'. > > +This function the merge two tree-sitter font lock feature lists. > > +Returns a new font lock feature list with no duplicates in the same > > level. > > +It can be used to merge font lock feature lists in a multi-language major > > mode. + > > ++++ > > +*** New function 'treesit-replace-font-lock-feature-settings'. > > +Given two treesit-font-lock-settings replaces the feature in the second > > +font-lock-settings with the same feature in the first > > +font-lock-settings. In a multi-linguage major mode it is sometimes > > +necessary to replace features from one of the major modes, with others > > +that are better suited to the new multilingual context. > > + > > ++++ > > +*** New function 'treesit-modify-indent-rules'. > > +Given two treesit ident rules, it replaces, adds, or prepends the new > > +rules to the old ones, then returns a new treesit indent rules. > > +In a multi-linguage major mode it is sometimes necessary to modify rules > > +from one of the major modes, with others that are better suited to the > > +new multilingual context. > > + > > > > +++ > > *** New command 'treesit-explore' > > This command replaces 'treesit-explore-mode'. It turns on > > > > diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el > > index 101b882c718..be9d6f64aef 100644 > > --- a/lisp/progmodes/js.el > > +++ b/lisp/progmodes/js.el > > @@ -3901,6 +3901,44 @@ js--treesit-list-nodes > > > > (defvar js--treesit-jsdoc-beginning-regexp (rx bos "/**") > > > > "Regular expression matching the beginning of a jsdoc block comment.") > > > > +(defvar js--treesit-thing-settings > > + `((javascript > > + (sexp ,(js--regexp-opt-symbol js--treesit-sexp-nodes)) > > + (list ,(js--regexp-opt-symbol js--treesit-list-nodes)) > > + (sentence ,(js--regexp-opt-symbol js--treesit-sentence-nodes)) > > + (text ,(js--regexp-opt-symbol '("comment" > > + "string_fragment"))))) > > + "Settings for `treesit-thing-settings'.") > > + > > +(defvar js--treesit-font-lock-feature-list > > + '(( comment document definition) > > + ( keyword string) > > + ( assignment constant escape-sequence jsx number > > + pattern string-interpolation) > > + ( bracket delimiter function operator property)) > > + "Settings for `treesit-font-lock-feature-list'.") > > + > > +(defvar js--treesit-simple-imenu-settings > > + `(("Function" "\\`function_declaration\\'" nil nil) > > + ("Variable" "\\`lexical_declaration\\'" > > + js--treesit-valid-imenu-entry nil) > > + ("Class" ,(rx bos (or "class_declaration" > > + "method_definition") > > + eos) > > + nil nil)) > > + "Settings for `treesit-simple-imenu'.") > > + > > +(defvar js--treesit-defun-type-regexp > > + (rx (or "class_declaration" > > + "method_definition" > > + "function_declaration" > > + "lexical_declaration")) > > + "Settings for `treesit-defun-type-regexp'.") > > + > > +(defvar js--treesit-jsdoc-comment-regexp > > + (rx (or "comment" "line_comment" "block_comment" "description")) > > + "Regexp for `c-ts-common--comment-regexp'.") > > + > > > > ;;;###autoload > > (define-derived-mode js-ts-mode js-base-mode "JavaScript" > > > > "Major mode for editing JavaScript. > > > > @@ -3931,29 +3969,15 @@ js-ts-mode > > > > ;; Indent. > > (setq-local treesit-simple-indent-rules js--treesit-indent-rules) > > ;; Navigation. > > > > - (setq-local treesit-defun-type-regexp > > - (rx (or "class_declaration" > > - "method_definition" > > - "function_declaration" > > - "lexical_declaration"))) > > + (setq-local treesit-defun-type-regexp js--treesit-defun-type-regexp) > > + > > > > (setq-local treesit-defun-name-function #'js--treesit-defun-name) > > > > - (setq-local treesit-thing-settings > > - `((javascript > > - (sexp ,(js--regexp-opt-symbol js--treesit-sexp-nodes)) > > - (list ,(js--regexp-opt-symbol js--treesit-list-nodes)) > > - (sentence ,(js--regexp-opt-symbol > > js--treesit-sentence-nodes)) - (text > > ,(js--regexp-opt-symbol '("comment" > > - > > "string_fragment")))))) > > + (setq-local treesit-thing-settings js--treesit-thing-settings) > > > > ;; Fontification. > > (setq-local treesit-font-lock-settings > > js--treesit-font-lock-settings) > > > > - (setq-local treesit-font-lock-feature-list > > - '(( comment document definition) > > - ( keyword string) > > - ( assignment constant escape-sequence jsx number > > - pattern string-interpolation) > > - ( bracket delimiter function operator property))) > > + (setq-local treesit-font-lock-feature-list > > js--treesit-font-lock-feature-list)> > > (when (treesit-ready-p 'jsdoc t) > > > > (setq-local treesit-range-settings > > > > @@ -3963,17 +3987,11 @@ js-ts-mode > > > > :local t > > > > `(((comment) @capture (:match > > ,js--treesit-jsdoc-beginning-regexp @capture)))))> > > - (setq c-ts-common--comment-regexp (rx (or "comment" "line_comment" > > "block_comment" "description")))) + (setq > > c-ts-common--comment-regexp js--treesit-jsdoc-comment-regexp))> > > ;; Imenu > > > > - (setq-local treesit-simple-imenu-settings > > - `(("Function" "\\`function_declaration\\'" nil nil) > > - ("Variable" "\\`lexical_declaration\\'" > > - js--treesit-valid-imenu-entry nil) > > - ("Class" ,(rx bos (or "class_declaration" > > - "method_definition") > > - eos) > > - nil nil))) > > + (setq-local treesit-simple-imenu-settings > > js--treesit-simple-imenu-settings) + > > > > (treesit-major-mode-setup) > > > > (add-to-list 'auto-mode-alist > > > > diff --git a/lisp/textmodes/css-mode.el b/lisp/textmodes/css-mode.el > > index 53340195386..35c61e4f66d 100644 > > --- a/lisp/textmodes/css-mode.el > > +++ b/lisp/textmodes/css-mode.el > > @@ -893,13 +893,7 @@ css-mode-syntax-table > > > > (modify-syntax-entry ?? "." st) > > st)) > > > > -(defvar-keymap css-mode-map > > - :doc "Keymap used in `css-mode'." > > - "<remap> <info-lookup-symbol>" #'css-lookup-symbol > > - ;; `info-complete-symbol' is not used. > > - "<remap> <complete-symbol>" #'completion-at-point > > - "C-c C-f" #'css-cycle-color-format > > - :menu > > +(defvar css-mode--menu > > > > '("CSS" > > > > :help "CSS-specific features" > > > > ["Reformat block" fill-paragraph > > > > @@ -910,7 +904,17 @@ css-mode-map > > > > ["Describe symbol" css-lookup-symbol > > > > :help "Display documentation for a CSS symbol"] > > > > ["Complete symbol" completion-at-point > > > > - :help "Complete symbol before point"])) > > + :help "Complete symbol before point"]) > > + "Menu bar for `css-mode'") > > + > > +(defvar-keymap css-mode-map > > + :doc "Keymap used in `css-mode'." > > + "<remap> <info-lookup-symbol>" #'css-lookup-symbol > > + ;; `info-complete-symbol' is not used. > > + "<remap> <complete-symbol>" #'completion-at-point > > + "C-c C-f" #'css-cycle-color-format > > + :menu > > + css-mode--menu) > > > > (eval-and-compile > > > > (defconst css--uri-re > > > > @@ -1771,6 +1775,21 @@ css--extract-index-name > > > > (replace-regexp-in-string "[\n ]+" " " s))) > > > > res))))))) > > > > +(defvar css--treesit-font-lock-feature-list > > + '((selector comment query keyword) > > + (property constant string) > > + (error variable function operator bracket)) > > + "Settings for `treesit-font-lock-feature-list'.") > > + > > +(defvar css--treesit-simple-imenu-settings > > + `(( nil ,(rx bos (or "rule_set" "media_statement") eos) > > + nil nil)) > > + "Settings for `treesit-simple-imenu'.") > > + > > +(defvar css--treesit-defun-type-regexp > > + "rule_set" > > + "Settings for `treesit-defun-type-regexp'.") > > + > > > > (define-derived-mode css-base-mode prog-mode "CSS" > > > > "Generic mode to edit Cascading Style Sheets (CSS). > > > > @@ -1825,16 +1844,12 @@ css-ts-mode > > > > ;; Tree-sitter specific setup. > > (setq treesit-primary-parser (treesit-parser-create 'css)) > > (setq-local treesit-simple-indent-rules css--treesit-indent-rules) > > > > - (setq-local treesit-defun-type-regexp "rule_set") > > + (setq-local treesit-defun-type-regexp css--treesit-defun-type-regexp) > > > > (setq-local treesit-defun-name-function #'css--treesit-defun-name) > > (setq-local treesit-font-lock-settings css--treesit-settings) > > > > - (setq-local treesit-font-lock-feature-list > > - '((selector comment query keyword) > > - (property constant string) > > - (error variable function operator bracket))) > > - (setq-local treesit-simple-imenu-settings > > - `(( nil ,(rx bos (or "rule_set" "media_statement") eos) > > - nil nil))) > > + (setq-local treesit-font-lock-feature-list > > css--treesit-font-lock-feature-list) + (setq-local > > treesit-simple-imenu-settings css--treesit-simple-imenu-settings) + > > > > (treesit-major-mode-setup) > > > > (add-to-list 'auto-mode-alist '("\\.css\\'" . css-ts-mode)))) > > > > diff --git a/lisp/textmodes/html-ts-mode.el > > b/lisp/textmodes/html-ts-mode.el index dad49b7ed4c..5700c2b406b 100644 > > --- a/lisp/textmodes/html-ts-mode.el > > +++ b/lisp/textmodes/html-ts-mode.el > > @@ -87,6 +87,31 @@ html-ts-mode--font-lock-settings > > > > `((attribute_name) @font-lock-variable-name-face)) > > > > "Tree-sitter font-lock settings for `html-ts-mode'.") > > > > +(defvar html-ts-mode--treesit-things-settings > > + `((html > > + (sexp ,(regexp-opt '("element" > > + "text" > > + "attribute" > > + "value"))) > > + (list ,(regexp-opt '("element")) 'symbols) > > + (sentence "tag") > > + (text ,(regexp-opt '("comment" "text"))))) > > + "Settings for `treesit-thing-settings'.") > > + > > +(defvar html-ts-mode--treesit-font-lock-feature-list > > + '((comment keyword definition) > > + (property string) > > + () ()) > > + "Settings for `treesit-font-lock-feature-list'.") > > + > > +(defvar html-ts-mode--treesit-simple-imenu-settings > > + '(("Element" "\\`tag_name\\'" nil nil)) > > + "Settings for `treesit-simple-imenu'.") > > + > > +(defvar html-ts-mode--treesit-defun-type-regexp > > + "element" > > + "Settings for `treesit-defun-type-regexp'.") > > + > > > > (defun html-ts-mode--defun-name (node) > > > > "Return the defun name of NODE. > > > > Return nil if there is no name or if NODE is not a defun node." > > > > @@ -107,30 +132,18 @@ html-ts-mode > > > > (setq-local treesit-simple-indent-rules html-ts-mode--indent-rules) > > > > ;; Navigation. > > > > - (setq-local treesit-defun-type-regexp "element") > > + (setq-local treesit-defun-type-regexp > > html-ts-mode--treesit-defun-type-regexp)> > > (setq-local treesit-defun-name-function #'html-ts-mode--defun-name) > > > > - (setq-local treesit-thing-settings > > - `((html > > - (sexp ,(regexp-opt '("element" > > - "text" > > - "attribute" > > - "value"))) > > - (list ,(regexp-opt '("element")) 'symbols) > > - (sentence "tag") > > - (text ,(regexp-opt '("comment" "text")))))) > > + (setq-local treesit-thing-settings > > html-ts-mode--treesit-things-settings)> > > ;; Font-lock. > > (setq-local treesit-font-lock-settings > > html-ts-mode--font-lock-settings) > > > > - (setq-local treesit-font-lock-feature-list > > - '((comment keyword definition) > > - (property string) > > - () ())) > > + (setq-local treesit-font-lock-feature-list > > html-ts-mode--treesit-font-lock-feature-list)> > > ;; Imenu. > > > > - (setq-local treesit-simple-imenu-settings > > - '(("Element" "\\`tag_name\\'" nil nil))) > > + (setq-local treesit-simple-imenu-settings > > html-ts-mode--treesit-simple-imenu-settings)> > > ;; Outline minor mode. > > (setq-local treesit-outline-predicate "\\`element\\'") > > > > diff --git a/lisp/textmodes/mhtml-ts-mode.el > > b/lisp/textmodes/mhtml-ts-mode.el new file mode 100644 > > index 00000000000..272d00a1ef6 > > --- /dev/null > > +++ b/lisp/textmodes/mhtml-ts-mode.el > > @@ -0,0 +1,600 @@ > > +;;; mhtml-ts-mode.el --- Major mode for HTML using tree-sitter -*- > > lexical-binding: t; -*- + > > +;; Copyright (C) 2024 Free Software Foundation, Inc. > > + > > +;; Author: Vincenzo Pupillo <v.pupillo <at> gmail.com> > > +;; Maintainer: Vincenzo Pupillo <v.pupillo <at> gmail.com> > > +;; Created: Nov 2024 > > +;; Keywords: HTML languages hypermedia tree-sitter > > + > > +;; This file is part of GNU Emacs. > > + > > +;; GNU Emacs 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. > > + > > +;; GNU Emacs 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>. > > + > > +;;; Commentary: > > +;; > > +;; This package provides `mhtml-ts-mode' which is a major mode > > +;; for editing HTML files with embedded JavaScript and CSS. > > +;; Tree Sitter is used to parse each of these languages. > > +;; > > +;; Please note that this package requires `html-ts-mode', which > > +;; registers itself as the major mode for editing HTML. > > +;; > > +;; This package is compatible and has been tested with the following > > +;; tree-sitter grammars: > > +;; * https://github.com/tree-sitter/tree-sitter-html > > +;; * https://github.com/tree-sitter/tree-sitter-javascript > > +;; * https://github.com/tree-sitter/tree-sitter-jsdoc > > +;; * https://github.com/tree-sitter/tree-sitter-css > > +;; > > +;; Features > > +;; > > +;; * Indent > > +;; * Flymake > > +;; * IMenu > > +;; * Navigation > > +;; * Which-function > > +;; * Tree-sitter parser installation helper > > + > > +;;; Code: > > + > > +(require 'treesit) > > +(require 'html-ts-mode) > > +(require 'css-mode) ;; for embed css into html > > +(require 'js) ;; for embed javascript into html > > + > > +(eval-when-compile > > + (require 'rx)) > > + > > +;; This tells the byte-compiler where the functions are defined. > > +;; Is only needed when a file needs to be able to byte-compile > > +;; in a Emacs not built with tree-sitter library. > > +(treesit-declare-unavailable-functions) > > + > > +;; In a multi-language major mode can be useful to have an "installer" to > > +;; simplify the installation of the grammars supported by the major-mode. > > +(defvar mhtml-ts-mode--language-source-alist > > + '((html . ("https://github.com/tree-sitter/tree-sitter-html" > > "v0.23.2")) + (javascript . > > ("https://github.com/tree-sitter/tree-sitter-javascript" "v0.23.1")) + > > (jsdoc . ("https://github.com/tree-sitter/tree-sitter-jsdoc" "v0.23.2")) > > + (css . ("https://github.com/tree-sitter/tree-sitter-css" > > "v0.23.1"))) + "Treesitter language parsers required by `mhtml-ts-mode'. > > +You can customize this variable if you want to stick to a specific > > +commit and/or use different parsers.") > > + > > +(defun mhtml-ts-mode-install-parsers () > > + "Install all the required treesitter parsers. > > +`mhtml-ts-mode--language-source-alist' defines which parsers to install." > > + (interactive) > > + (let ((treesit-language-source-alist > > mhtml-ts-mode--language-source-alist)) + (dolist (item > > mhtml-ts-mode--language-source-alist) > > + (treesit-install-language-grammar (car item))))) > > + > > +;;; Custom variables > > + > > +(defgroup mhtml-ts-mode nil > > + "Major mode for editing HTML files, based on `html-ts-mode'. > > +Works with JS and CSS and for that use `js-ts-mode' and `css-ts-mode'." > > + :prefix "mhtml-ts-mode-" > > + ;; :group 'languages > > + :group 'html) > > + > > +(defcustom mhtml-ts-mode-js-css-indent-offset 2 > > + "JavaScript and CSS indent spaces related to the <script> and <style> > > HTML tags. +By default should have same value as > > `html-ts-mode-indent-offset'." + :tag "HTML javascript or css indent > > offset" > > + :version "31.1" > > + :type 'integer > > + :safe 'integerp) > > + > > +(defcustom mhtml-ts-mode-pretty-print-command > > + ;; prefer tidy because it's used by sgml-mode > > + (let ((executable nil)) > > + (cond ((setq executable (executable-find "tidy")) > > + (format > > + "%s --gnu-emacs yes --wrap 0 --indent-spaces %s -q -i -" > > + executable html-ts-mode-indent-offset)) > > + ((setq executable (executable-find "xmllint")) > > + (format "%s --html --quiet --format -" executable)) > > + (t "Install tidy, ore some other HTML pretty print tool, and > > set `mhtml-ts-mode-pretty-print-command'."))) + "The command to pretty > > print the current HTML buffer." > > + :type 'string > > + :version "31.1") > > + > > +(defvar mhtml-ts-mode--js-css-indent-offset > > + mhtml-ts-mode-js-css-indent-offset > > + "Internal copy of `mhtml-ts-mode-js-css-indent-offset'. > > +The value changes, by `mhtml-ts-mode--tag-relative-indent-offset' > > according to +the value of `mhtml-ts-mode-tag-relative-indent'.") > > + > > +(defun mhtml-ts-mode--tag-relative-indent-offset (sym val) > > + "Custom setter for `mhtml-ts-mode-tag-relative-indent'. > > +Apart from setting the default value of SYM to VAL, also change the > > +value of SYM in `mhtml-ts-mode' buffers to VAL. SYM should be > > +`mhtml-ts-mode-tag-relative-indent', and VAL should be t, nil or > > +`ignore'. When sym is `mhtml-ts-mode-tag-relative-indent' set the > > +value of `mhtml-ts-mode--js-css-indent-offset' to 0 if VAL is t, > > +otherwise to `mhtml-ts-mode-js-css-indent-offset'." > > + (set-default sym val) > > + (when (eq sym 'mhtml-ts-mode-tag-relative-indent) > > + (setq > > + mhtml-ts-mode--js-css-indent-offset > > + (if (eq val t) > > + mhtml-ts-mode-js-css-indent-offset > > + 0)))) > > + > > +(defcustom mhtml-ts-mode-tag-relative-indent t > > + "How <script> and <style> bodies are indented relative to the tag. > > + > > +When t, indentation looks like: > > + > > + <script> > > + code(); > > + </script> > > + > > +When nil, indentation of the tag body starts just below the > > +tag, like: > > + > > + <script> > > + code(); > > + </script> > > + > > +When `ignore', the tag body starts in the first column, like: > > + > > + <script> > > +code(); > > + </script>" > > + :type '(choice (const nil) (const t) (const ignore)) > > + :safe 'symbolp > > + :set #'mhtml-ts-mode--tag-relative-indent-offset > > + :version "31.1") > > + > > +(defcustom mhtml-ts-mode-css-fontify-colors t > > + "Whether CSS colors should be fontified using the color as the > > background. +If non-nil, text representing a CSS color will be fontified > > +such that its background is the color itself. > > +Works like `css--fontify-region'." > > + :tag "HTML colors the CSS properties values." > > + :version "31.1" > > + :type 'boolean > > + :safe 'booleanp) > > + > > +(defvar mhtml-ts-mode-saved-pretty-print-command nil > > + "The command last used to pretty print in this buffer.") > > + > > +(defun mhtml-ts-mode-pretty-print (command) > > + "Prettify the current buffer. > > +Argument COMMAND The command to use." > > + (interactive > > + (list (read-string > > + "Prettify command: " > > + (or mhtml-ts-mode-saved-pretty-print-command > > + (concat mhtml-ts-mode-pretty-print-command " "))))) > > + (setq mhtml-ts-mode-saved-pretty-print-command command) > > + (save-excursion > > + (shell-command-on-region > > + (point-min) (point-max) > > + command (buffer-name) t > > + "*mhtml-ts-mode-pretty-pretty-print-errors*" t))) > > + > > +(defun mhtml-ts-mode--switch-fill-defun (&rest arguments) > > + "Switch between `fill-paragraph' and `prog-fill-reindent-defun'. > > +In an HTML region it calls `fill-paragraph' as does `html-ts-mode', > > +otherwise it calls `prog-fill-reindent-defun'. > > +Optional ARGUMENTS to to be passed to it." > > + (interactive) > > + (if (eq (treesit-language-at (point)) 'html) > > + (funcall-interactively #'fill-paragraph arguments) > > + (funcall-interactively #'prog-fill-reindent-defun arguments))) > > + > > +(defvar-keymap mhtml-ts-mode-map > > + :doc "Keymap for `mhtml-ts-mode' buffers." > > + :parent html-mode-map > > + ;; `mhtml-ts-mode' derive from `html-ts-mode' so the keymap is the > > + ;; same, we need to add some mapping from others languages. > > + "C-c C-f" #'css-cycle-color-format > > + "M-q" #'mhtml-ts-mode--switch-fill-defun) > > + > > +;; Place the CSS menu in the menu bar as well. > > +(easy-menu-define mhtml-ts-mode-menu mhtml-ts-mode-map > > + "Menu bar for `mhtml-ts-mode'." > > + css-mode--menu) > > + > > +;; Not used at the moment. > > +(defun mthml-ts-mode--js-language-at-point (point) > > + "Return the language at POINT assuming the point is within a Javascript > > region." + (let* ((node (treesit-node-at point 'javascript)) > > + (node-type (treesit-node-type node)) > > + (node-start (treesit-node-start node)) > > + (node-end (treesit-node-end node))) > > + (if (not (treesit-ready-p 'jsdoc t)) > > + 'javascript > > + (if (equal node-type "comment") > > + (save-excursion > > + ;; (message "node start = %s , end = %s" node-start node-end) > > + (goto-char node-start) > > + (if (search-forward "/**" node-end t) > > + 'jsdoc > > + 'javascript)) > > + 'javascript)))) > > + > > +;; To enable some basic treesiter functionality, you should define > > +;; a function that recognizes which grammar is used at-point. > > +;; This function should be assigned to > > `treesit-language-at-point-function' +(defun > > mhtml-ts-mode--language-at-point (point) > > + "Return the language at POINT assuming the point is within a HTML > > buffer." + (let* ((node (treesit-node-at point 'html)) > > + (parent (treesit-node-parent node)) > > + (node-query (format "(%s (%s))" > > + (treesit-node-type parent) > > + (treesit-node-type node)))) > > + (cond > > + ((equal "(script_element (raw_text))" node-query) 'javascript) > > + ;; ((equal "(script_element (raw_text))" node-query) > > 'mthml-ts-mode--js-language-at-point) + ((equal "(style_element > > (raw_text))" node-query) 'css) > > + (t 'html)))) > > + > > +;; Custom font-lock function that's used to apply color to css color > > +;; The signature of the function should be conforming to signature > > +;; QUERY-SPEC required by `treesit-font-lock-rules'. > > +(defun mhtml-ts-mode--colorize-css-value (node override start end &rest > > _) > > + "Colorize CSS property value like `css--fontify-region'. > > +For NODE, OVERRIDE, START, and END, see `treesit-font-lock-rules'." > > + (if (and mhtml-ts-mode-css-fontify-colors > > + (string-equal "plain_value" (treesit-node-type node))) > > + (let ((color (css--compute-color start (treesit-node-text node > > t)))) > > + (when color > > + (with-silent-modifications > > + (add-text-properties > > + (treesit-node-start node) (treesit-node-end node) > > + (list 'face (list :background color > > + :foreground (readable-foreground-color > > + color) > > + :box '(:line-width -1))))))) > > + (treesit-fontify-with-override > > + (treesit-node-start node) (treesit-node-end node) > > + 'font-lock-variable-name-face > > + override start end))) > > + > > +;; Embedded languages should be indented according to the language > > +;; that embeds them. > > +;; This function signature complies with `treesit-simple-indent-rules' > > +;; ANCHOR. > > +(defun mhtml-ts-mode--js-css-tag-bol (_node _parent &rest _) > > + "Find the first non-space characters of html tags <script> or <style>. > > +Return `line-beginning-position' when `treesit-node-at' is html, or > > +`mhtml-ts-mode-tag-relative-indent' is equal to ignore. > > +NODE and PARENT are ignored." > > + (if (or (eq (treesit-language-at (point)) 'html) > > + (eq mhtml-ts-mode-tag-relative-indent 'ignore)) > > + (line-beginning-position) > > + ;; Ok, we are in js or css block. > > + (save-excursion > > + (re-search-backward "<script.*>\\|<style.*>" nil t)))) > > + > > +;; Treesit supports 4 level of decoration, `treesit-font-lock-level' > > +;; define which level to use. Major modes categorize their fontification > > +;; features, these categories are defined by `treesit-font-lock-rules' of > > +;; each major-mode using :feature keyword. > > +;; In a multiple language Major mode it's a good idea to provide, for > > each > > +;; level, the union of the :feature of the same level. > > +;; TODO: Since the feature-list is not defined per "parser" (like, for > > +;; example, the thing-settings), the same feature can appear in > > +;; different levels, so the appearance of a multiple main mode can be > > +;; different from the main mode used. For e.g the feature "function" is > > +;; at level 4 for Javascript while it is at level 3 for CSS. > > +(defvar mhtml-ts-mode--treesit-font-lock-feature-list > > + (treesit-merge-font-lock-feature-list > > + html-ts-mode--treesit-font-lock-feature-list > > + (treesit-merge-font-lock-feature-list > > + js--treesit-font-lock-feature-list > > + css--treesit-font-lock-feature-list)) > > + "Settings for `treesit-font-lock-feature-list'.") > > + > > +(defvar mhtml-ts-mode--treesit-font-lock-settings > > + (append html-ts-mode--font-lock-settings > > + js--treesit-font-lock-settings > > + ;; Let's replace a css rule with a new one that adds color to > > + ;; the css value. > > + (treesit-replace-font-lock-feature-settings > > + (treesit-font-lock-rules > > + :language 'css > > + :override t > > + :feature 'variable > > + '((plain_value) @font-lock-variable-name-face > > + (plain_value) @mhtml-ts-mode--colorize-css-value)) > > + css--treesit-settings)) > > + "Settings for `treesit-font-lock-settings'.") > > + > > +(defvar mhtml-ts-mode--treesit-thing-settings > > + ;; In addition to putting together the various definitions, we need to > > + ;; add 'defun' which is used to support `imenu' and 'which-function'. > > + (list > > + ;; HTML thing settings > > + (append > > + (car html-ts-mode--treesit-things-settings) > > + `((defun ,(regexp-opt (list > > html-ts-mode--treesit-defun-type-regexp))))) + ;; Javascript thing > > settings > > + (append > > + (car js--treesit-thing-settings) > > + `((defun ,js--treesit-defun-type-regexp))) > > + ;; CSS thing settings > > + `(css > > + (defun ,(regexp-opt (list css--treesit-defun-type-regexp))))) > > + "Settings for `treesit-thing-settings'.") > > + > > +(defvar mhtml-ts-mode--treesit-indent-rules > > + (treesit--indent-rules-optimize > > + (append html-ts-mode--indent-rules > > + ;; Extended rules for js and css, to > > + ;; indent appropriately when injected > > + ;; into html > > + (treesit-modify-indent-rules > > + `((javascript ((parent-is "program") > > + mhtml-ts-mode--js-css-tag-bol > > + mhtml-ts-mode--js-css-indent-offset))) > > + js--treesit-indent-rules > > + :replace) > > + (treesit-modify-indent-rules > > + `((css ((parent-is "stylesheet") > > + mhtml-ts-mode--js-css-tag-bol > > + mhtml-ts-mode--js-css-indent-offset))) > > + css--treesit-indent-rules 'prepend) > > + :replace)) > > + "Settings for `treesit-simple-indent-rules'.") > > + > > +(defvar mhtml-ts-mode--treesit-aggregated-simple-imenu-settings > > + `((html ,@html-ts-mode--treesit-simple-imenu-settings) > > + (javascript ,@js--treesit-simple-imenu-settings) > > + (css ,@css--treesit-simple-imenu-settings)) > > + "Settings for `treesit-simple-imenu'.") > > + > > +;; TODO: treesit-defun-type-regexp should have an aggregated version, > > +;; like treesit-aggregated-simple-imenu-settings. Otherwise we can't > > +;; reuse the regex defined in the major mode we use. > > +(defvar mhtml-ts-mode--treesit-defun-type-regexp > > + (regexp-opt '("class_declaration" > > + "method_definition" > > + "function_declaration" > > + "lexical_declaration" > > + "element" > > + "rule_set")) > > + "Settings for `treesit-defun-type-regexp'.") > > + > > +;; In order to support `prettify-symbols-mode', just `append' the > > prettify > > +;; alist of all the languages. In our case only javascript defined this > > alist. +(defvar mhtml-ts-mode--prettify-symbols-alist > > js--prettify-symbols-alist + "Alist of symbol prettifications for > > various supported languages.") + > > +;; In order to support `which-fuction-mode' we should define > > +;; a function that return the defun name. > > +;; In a multilingual treesit mode, this can be implemented simply by > > +;; calling language-specific functions. > > +(defun mhtml-ts-mode--defun-name (node) > > + "Return the defun name of NODE. > > +Return nil if there is no name or if NODE is not a defun node." > > + (let ((html-name (html-ts-mode--defun-name node)) > > + (js-name (js--treesit-defun-name node)) > > + (css-name (css--treesit-defun-name node))) > > + (cond > > + (html-name html-name) > > + (js-name js-name) > > + (css-name css-name)))) > > + > > +;;; Flymake integration > > + > > +(defvar-local mhtml-ts-mode--flymake-process nil > > + "Store the Flymake process.") > > + > > +(defun mhtml-ts-mode-flymake-mhtml (report-fn &rest _args) > > + "MHTML backend for Flymake. > > +Calls REPORT-FN directly. Requires tidy." > > + (when (process-live-p mhtml-ts-mode--flymake-process) > > + (kill-process mhtml-ts-mode--flymake-process)) > > + (let ((tidy (executable-find "tidy")) > > + (source (current-buffer)) > > + (diagnostics-pattern (eval-when-compile > > + (rx bol > > + "line " (group (+ num)) ;; :1 line > > + " column " (group (+ num)) ;; :2 > > column > > + " - " (group (+? nonl)) ;; :3 type > > + ": " (group (+? nonl)) ;; :4 msg > > + eol)))) > > + (if (not tidy) > > + (error "Unable to find tidy command") > > + (save-restriction > > + (widen) > > + (setq mhtml-ts-mode--flymake-process > > + (make-process > > + :name "mhtml-ts-mode-flymake" > > + :noquery t > > + :connection-type 'pipe > > + :buffer (generate-new-buffer "*mhtml-ts-mode-flymake*") > > + :command `(,tidy "--gnu-emacs" "yes" "-e" "-q") > > + :sentinel > > + (lambda (proc _event) > > + (when (eq 'exit (process-status proc)) > > + (unwind-protect > > + (if (with-current-buffer source > > + (eq proc mhtml-ts-mode--flymake-process)) > > + (with-current-buffer (process-buffer proc) > > + (goto-char (point-min)) > > + (let (diags) > > + (while (search-forward-regexp > > diagnostics-pattern nil t) + (let* ((pos > > + (flymake-diag-region > > + source > > + (string-to-number (match-string > > 1)) + (string-to-number > > (match-string 2)))) ;; line and column + > > (type (cond ((equal (match-string 3) "Warning") :warning) + > > ((equal (match-string 3) > > "Error") :error))) ;; type of message + > > (msg (match-string 4))) ;; message + > > (push (flymake-make-diagnostic source (car pos) (cdr pos) type msg) + > > diags))) > > + (funcall report-fn diags))) > > + (flymake-log :warning "Canceling obsolete check > > %s" proc)) + (kill-buffer (process-buffer proc))))))) > > + (process-send-region mhtml-ts-mode--flymake-process (point-min) > > (point-max)) + (process-send-eof > > mhtml-ts-mode--flymake-process))))) > > + > > +(define-derived-mode mhtml-ts-mode html-ts-mode > > + '("HTML+" (:eval (let ((lang (mhtml-ts-mode--language-at-point > > (point)))) + (cond ((eq lang 'html) "") > > + ((eq lang 'javascript) "JS") > > + ((eq lang 'css) "CSS"))))) > > + "Major mode for editing HTML with embedded JavaScript and CSS. > > +Powered by tree-sitter." > > + (if (not (and > > + (treesit-ready-p 'html) > > + (treesit-ready-p 'javascript) > > + (treesit-ready-p 'css))) > > + (error "Tree-sitter parsers for HTML isn't available. You can > > + install the parsers with M-x `mhtml-ts-mode-install-parsers'") > > + > > + ;; When an language is embedded, you should initialize some variable > > + ;; just like it's done in the original mode. > > + > > + ;; Comment. > > + ;; indenting settings for js-ts-mode. > > + (c-ts-common-comment-setup) > > + (setq-local comment-multi-line t) > > + > > + ;; Font-lock. > > + > > + ;; There are two ways to handle embedded code: > > + ;; 1. Use a single parser for all the embedded code in the buffer. In > > + ;; this case, the embedded code blocks are concatenated together and > > are + ;; seen as a single continuous document to the parser. > > + ;; 2. Each embedded code block gets its own parser. Each parser only > > sees + ;; that particular code block. > > + > > + ;; If you go with 2 for a language, the local parsers are created and > > + ;; destroyed automatically by Emacs. So don't create a global parser > > for + ;; that embedded language here. > > + > > + ;; Create the parsers, only the global ones. > > + ;; jsdoc is a local parser, don't create a parser for it. > > + (treesit-parser-create 'css) > > + (treesit-parser-create 'javascript) > > + > > + ;; Multi-language modes must set the primary parser. > > + (setq-local treesit-primary-parser (treesit-parser-create 'html)) > > + > > + (setq-local treesit-range-settings > > + (treesit-range-rules > > + :embed 'javascript > > + :host 'html > > + '((script_element > > + (start_tag (tag_name)) > > + (raw_text) @cap)) > > + > > + ;; Another rule could be added that when it matches an > > + ;; attribute_value that has as its parent an > > + ;; attribute_name "style" it captures it and then > > + ;; passes it to the css parser. > > + :embed 'css > > + :host 'html > > + '((style_element > > + (start_tag (tag_name)) > > + (raw_text) @cap)))) > > + > > + ;; jsdoc is not mandatory for js-ts-mode, so we respect this by > > + ;; adding jsdoc range rules only when jsdoc is available. > > + (when (treesit-ready-p 'jsdoc t) > > + (setq-local treesit-range-settings > > + (append treesit-range-settings > > + (treesit-range-rules > > + :embed 'jsdoc > > + :host 'javascript > > + :local t > > + `(((comment) @cap > > + (:match ,js--treesit-jsdoc-beginning-regexp > > @cap)))))) + (setq-local c-ts-common--comment-regexp > > + js--treesit-jsdoc-comment-regexp)) > > + > > + > > + ;; Many treesit fuctions need to know the language at-point. > > + ;; So you should define such a function. > > + (setq-local treesit-language-at-point-function > > #'mhtml-ts-mode--language-at-point) + (setq-local > > prettify-symbols-alist mhtml-ts-mode--prettify-symbols-alist) + > > + ;; Indent. > > + > > + ;; Since `mhtml-ts-mode' inherits indentation rules from > > `html-ts-mode', `js-ts-mode' + ;; and `css-ts-mode', if you want to > > change the offset you have to act on the + ;; *-offset variables > > defined for those languages. > > + > > + ;; JavaScript and CSS must be indented relative to their code block. > > + ;; This is done by inserting a special rule before the normal > > + ;; indentation rules of these languages. > > + ;; The value of `mhtml-ts-mode--js-css-indent-offset' changes based > > on > > + ;; `mhtml-ts-mode-tag-relative-indent' and can be used to indent > > + ;; JavaScript and CSS code relative to the HTML that contains them, > > + ;; just like in mhtml-mode. > > + (setq-local treesit-simple-indent-rules > > mhtml-ts-mode--treesit-indent-rules) + > > + ;; Navigation. > > + > > + ;; This is for which-function-mode. > > + ;; Since mhtml-ts-mode is derived from html-ts-mode, which sets > > + ;; the value of `treesit-defun-type-regexp', you have to reset it to > > nil + ;; otherwise `imenu' and `which-function-mode' will not work. + > > (setq-local treesit-defun-type-regexp nil) > > + > > + ;; This is for finding defun name, it's used by IMenu as default > > + ;; function no specific functions are defined. > > + (setq-local treesit-defun-name-function #'mhtml-ts-mode--defun-name) > > + > > + ;; Define what are 'thing' for treesit. > > + ;; 'Thing' is a symbol representing the thing, like `defun', `sexp', > > or + ;; `sentence'. > > + ;; As an alternative, if you want just defun, you can define a > > `treesit-defun-type-regexp'. + (setq-local treesit-thing-settings > > mhtml-ts-mode--treesit-thing-settings) + > > + ;; Font-lock. > > + > > + ;; In a multi-language scenario, font lock settings are usually a > > + ;; concatenation of language rules. As you can see, it is possible > > + ;; to extend/modify the default rule or use a different set of > > + ;; rules. See `php-ts-mode--custom-html-font-lock-settings' for more > > + ;; advanced usage. > > + (setq-local treesit-font-lock-settings > > mhtml-ts-mode--treesit-font-lock-settings) + > > + ;; Tells treesit the list of features to fontify. > > + (setq-local treesit-font-lock-feature-list > > mhtml-ts-mode--treesit-font-lock-feature-list) + > > + ;; Imenu > > + > > + ;; Setup Imenu: if no function is specified, try to find an object > > + ;; using `treesit-defun-name-function'. > > + (setq-local treesit-aggregated-simple-imenu-settings > > + mhtml-ts-mode--treesit-aggregated-simple-imenu-settings) > > + > > + (treesit-major-mode-setup) > > + > > + ;; This is sort of a prog-mode as well as a text mode. > > + (run-mode-hooks 'prog-mode-hook) > > + > > + ;; Flymake > > + (add-hook 'flymake-diagnostic-functions #'mhtml-ts-mode-flymake-mhtml > > nil 'local))) + > > +;; Add nome extra parents. > > +(derived-mode-add-parents 'mhtml-ts-mode '(css-mode js-mode)) > > + > > +(when (and (treesit-ready-p 'html) (treesit-ready-p 'javascript) > > (treesit-ready-p 'css)) + (add-to-list > > + 'auto-mode-alist '("\\.[sx]?html?\\(\\.[a-zA-Z_]+\\)?\\'" . > > mhtml-ts-mode))) + > > +(provide 'mhtml-ts-mode) > > +;;; mhtml-ts-mode.el ends here > > diff --git a/lisp/treesit.el b/lisp/treesit.el > > index 8d86d142e3f..00b7d266e74 100644 > > --- a/lisp/treesit.el > > +++ b/lisp/treesit.el > > @@ -1297,6 +1297,40 @@ treesit-font-lock-recompute-features > > > > ((memq feature remove-list) nil) > > (t current-value)))))) > > > > +(defun treesit-merge-font-lock-feature-list (features-list-1 > > features-list-2) + "Merge two tree-sitter font lock feature lists. > > +Returns a new font lock feature list with no duplicates in the same > > level. > > +It can be used to merge font lock feature lists in a multi-language major > > mode. +FEATURES-LIST-1 and FEATURES-LIST-2 are list of lists of feature > > symbols." + (let ((result nil) > > + (features-1 (car features-list-1)) > > + (features-2 (car features-list-2))) > > + (while (or features-1 features-2) > > + (cond > > + ((and features-1 (not features-2)) (push features-1 result)) > > + ((and (not features-1) features-2) (push features-2 result)) > > + ((and features-1 features-2) (push (cl-union features-1 > > features-2) result))) + (setq features-list-1 (cdr features-list-1) > > + features-list-2 (cdr features-list-2) > > + features-1 (car features-list-1) > > + features-2 (car features-list-2))) > > + (nreverse result))) > > + > > +(defun treesit-replace-font-lock-feature-settings (new-settings settings) > > + "Replaces :feature in SETTINGS with :feature from NEW-SETTINGS. > > +Both SETTINGS and NEW-SETTINGS must be a value suitable for > > +`treesit-font-lock-settings'. > > +Return a value suitable for `treesit-font-lock-settings'" > > + (let ((result nil)) > > + (dolist (new-setting new-settings) > > + (let ((new-feature (treesit-font-lock-setting-feature > > new-setting))) > > + (dolist (setting settings) > > + (let ((feature (treesit-font-lock-setting-feature setting))) > > + (if (eq new-feature feature) > > + (push new-setting result) > > + (push setting result)))))) > > + (nreverse result))) > > + > > > > (defun treesit-add-font-lock-rules (rules &optional how feature) > > > > "Add font-lock RULES to the current buffer. > > > > @@ -2401,6 +2435,37 @@ treesit--indent-rules-optimize > > > > offset))))) > > > > (cons lang (mapcar #'optimize-rule indent-rules))))) > > > > +(defun treesit-modify-indent-rules (new-rules rules &optional how) > > + "Modify RULES using NEW-RULES. > > +As default replace rules with the same anchor. > > +When HOW is :prepend NEW-RULES are prepend to RULES, when > > +:append NEW-RULES are appended to RULES, when :replace (the default) > > +NEW-RULES replace rule in RULES which the same anchor." > > + (let ((n-lang (car (car new-rules))) > > + (lang (car (car rules)))) > > + (when (not (eq n-lang lang)) > > + (error "The language must be the same")) > > + (let* ((nr (cdr (car new-rules))) > > + (r (cdr (car rules))) > > + (tmp nil) > > + (result > > + (cond > > + ((eq how :prepend) > > + (append nr r)) > > + ((eq how :append) > > + (append r nr)) > > + ((or (eq how :replace) t) > > + (nreverse > > + (progn > > + (dolist (new-rule nr) > > + (dolist (rule r) > > + (if (equal (nth 0 new-rule) (nth 0 rule)) > > + (push new-rule tmp) > > + (push rule tmp)))) > > + tmp)))))) > > + (push lang result) > > + `(,result)))) > > + > > > > ;;; Search > > > > (defun treesit-search-forward-goto
[0001-Add-mhtml-ts-mode.patch (text/x-patch, attachment)]
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Sun, 09 Feb 2025 17:57:01 GMT) Full text and rfc822 format available.Message #76 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Juri Linkov <juri <at> linkov.net> To: Vincenzo Pupillo <v.pupillo <at> gmail.com> Cc: casouri <at> gmail.com, Eli Zaretskii <eliz <at> gnu.org>, 74610 <at> debbugs.gnu.org Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Sun, 09 Feb 2025 19:54:27 +0200
> Ciao Eli, > This attached patch is the third version. Adapted to support the latest > changes introduced in treesit.el and js.el (as described in bug#75456). > @Jury, @Yuan what do you think about this version? Thanks for the patch. I think we need now clarify the relation between mhtml-ts-mode and html-ts-mode. For example, currently I added a new function 'html-ts-mode--outline-predicate' to html-ts-mode.el. Should it be used in mhtml-ts-mode.el as well? What about other settings? Should html-ts-mode and mhtml-ts-mode always be kept in sync? Or html-ts-mode should be obsoleted when it will be superseded by mhtml-ts-mode? Maybe html-ts-mode would be still needed as a separate mode to be used as embedded submode in such files as e.g. Vue single-file component with *.vue files that contain parts from js-ts-mode, css-ts-mode, and html-ts-mode for templates.
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Sun, 09 Feb 2025 21:24:01 GMT) Full text and rfc822 format available.Message #79 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Vincenzo Pupillo <v.pupillo <at> gmail.com> To: Juri Linkov <juri <at> linkov.net> Cc: casouri <at> gmail.com, Eli Zaretskii <eliz <at> gnu.org>, 74610 <at> debbugs.gnu.org Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Sun, 09 Feb 2025 22:23:03 +0100
Ciao Juri, In data domenica 9 febbraio 2025 18:54:27 Ora standard dell’Europa centrale, Juri Linkov ha scritto: > > Ciao Eli, > > This attached patch is the third version. Adapted to support the latest > > changes introduced in treesit.el and js.el (as described in bug#75456). > > @Jury, @Yuan what do you think about this version? > > Thanks for the patch. > > I think we need now clarify the relation > between mhtml-ts-mode and html-ts-mode. > > For example, currently I added a new function > 'html-ts-mode--outline-predicate' to html-ts-mode.el. > Should it be used in mhtml-ts-mode.el as well? I have to try but I think so, mhtml-ts-mode is declared as derived from html- ts-mode (although it is not very clear to me how derived modes work). The treesit-outline-predicate variable is set by html-ts-mode and mhtml-ts-mode inherits the same value. > > What about other settings? Should html-ts-mode and mhtml-ts-mode > always be kept in sync? Or html-ts-mode should be obsoleted > when it will be superseded by mhtml-ts-mode? > > Maybe html-ts-mode would be still needed as a separate mode > to be used as embedded submode in such files as e.g. > Vue single-file component with *.vue files that contain parts > from js-ts-mode, css-ts-mode, and html-ts-mode for templates. I don't know. In general, I think having simple major modes makes it easier to build more complex aggregations, rather than having to disable some features inherited from complex major modes, as in html-ts-mode: " ;; `html-ts-mode' inherits from `html-mode' that sets ;; regexp-based outline variables. So need to restore ;; the default values of outline variables to be able ;; to use `treesit-outline-predicate' above. " Vincenzo
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Thu, 13 Feb 2025 18:04:02 GMT) Full text and rfc822 format available.Message #82 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Juri Linkov <juri <at> linkov.net> To: Vincenzo Pupillo <v.pupillo <at> gmail.com> Cc: casouri <at> gmail.com, Eli Zaretskii <eliz <at> gnu.org>, 74610 <at> debbugs.gnu.org Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Thu, 13 Feb 2025 19:55:59 +0200
>> I think we need now clarify the relation >> between mhtml-ts-mode and html-ts-mode. >> >> For example, currently I added a new function >> 'html-ts-mode--outline-predicate' to html-ts-mode.el. >> Should it be used in mhtml-ts-mode.el as well? > I have to try but I think so, mhtml-ts-mode is declared as derived from html- > ts-mode (although it is not very clear to me how derived modes work). The > treesit-outline-predicate variable is set by html-ts-mode and mhtml-ts-mode > inherits the same value. It seems inheritance doesn't work for embedded ts-modes since even the primary ts-mode should be configured by aggregation like with treesit-aggregated-simple-imenu-settings, not by inheritance. I see that you added TODO for an aggregated version of treesit-defun-type-regexp. Then treesit-outline-predicate also needs an aggregated version, and maybe other settings too. Ok, I could look how to do this with treesit-outline-predicate. >> What about other settings? Should html-ts-mode and mhtml-ts-mode >> always be kept in sync? Or html-ts-mode should be obsoleted >> when it will be superseded by mhtml-ts-mode? >> >> Maybe html-ts-mode would be still needed as a separate mode >> to be used as embedded submode in such files as e.g. >> Vue single-file component with *.vue files that contain parts >> from js-ts-mode, css-ts-mode, and html-ts-mode for templates. > > I don't know. In general, I think having simple major modes makes it easier to > build more complex aggregations, rather than having to disable some features > inherited from complex major modes, as in html-ts-mode: " > ;; `html-ts-mode' inherits from `html-mode' that sets > ;; regexp-based outline variables. So need to restore > ;; the default values of outline variables to be able > ;; to use `treesit-outline-predicate' above. I checked that neither aggregation nor inheritance from html-ts-mode can be used for vue-ts-mode since tree-sitter-vue duplicates HTML grammar in its own grammar. Even tree-sitter-astro incorporates a simplified HTML grammar into its own grammar. This is similar to HTML-like jsx elements in tsx grammar.
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Fri, 14 Feb 2025 17:56:02 GMT) Full text and rfc822 format available.Message #85 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Vincenzo Pupillo <v.pupillo <at> gmail.com> To: Juri Linkov <juri <at> linkov.net> Cc: casouri <at> gmail.com, Eli Zaretskii <eliz <at> gnu.org>, 74610 <at> debbugs.gnu.org Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Fri, 14 Feb 2025 18:55:05 +0100
[Message part 1 (text/plain, inline)]
Ciao Jury, I was just about to write, you anticipated me. The function `html-ts-mode--outline-predicate`, does not work correctly in `mhtml-ts-mode`, the function seems to fail to calculate the end of the tag it is on (see outline_issue_1.png) And, exactly as you wrote, with treesit-outline-predicate set to nil it does not work because the function `treesit-outline-predicate--from-imenu` does not check the variable `treesit-aggregated-simple-imenu-settings` but only `treesit-simple-imenu-settings`. I attach a new patch adapted to the latest commits. Thanks. Vincenzo. In data giovedì 13 febbraio 2025 18:55:59 Ora standard dell’Europa centrale, Juri Linkov ha scritto: > >> I think we need now clarify the relation > >> between mhtml-ts-mode and html-ts-mode. > >> > >> For example, currently I added a new function > >> 'html-ts-mode--outline-predicate' to html-ts-mode.el. > >> Should it be used in mhtml-ts-mode.el as well? > > > > I have to try but I think so, mhtml-ts-mode is declared as derived from > > html- ts-mode (although it is not very clear to me how derived modes > > work). The treesit-outline-predicate variable is set by html-ts-mode and > > mhtml-ts-mode inherits the same value. > > It seems inheritance doesn't work for embedded ts-modes > since even the primary ts-mode should be configured > by aggregation like with treesit-aggregated-simple-imenu-settings, > not by inheritance. > > I see that you added TODO for an aggregated version of > treesit-defun-type-regexp. Then treesit-outline-predicate > also needs an aggregated version, and maybe other settings too. > Ok, I could look how to do this with treesit-outline-predicate. > > >> What about other settings? Should html-ts-mode and mhtml-ts-mode > >> always be kept in sync? Or html-ts-mode should be obsoleted > >> when it will be superseded by mhtml-ts-mode? > >> > >> Maybe html-ts-mode would be still needed as a separate mode > >> to be used as embedded submode in such files as e.g. > >> Vue single-file component with *.vue files that contain parts > >> from js-ts-mode, css-ts-mode, and html-ts-mode for templates. > > > > I don't know. In general, I think having simple major modes makes it > > easier to build more complex aggregations, rather than having to disable > > some features inherited from complex major modes, as in html-ts-mode: " > > > > ;; `html-ts-mode' inherits from `html-mode' that sets > > > > ;; regexp-based outline variables. So need to restore > > ;; the default values of outline variables to be able > > ;; to use `treesit-outline-predicate' above. > > I checked that neither aggregation nor inheritance from html-ts-mode > can be used for vue-ts-mode since tree-sitter-vue duplicates > HTML grammar in its own grammar. Even tree-sitter-astro > incorporates a simplified HTML grammar into its own grammar. > This is similar to HTML-like jsx elements in tsx grammar.
[outline_issue_1.png (image/png, attachment)]
[0001-Add-mhtml-ts-mode.patch (text/x-patch, attachment)]
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Sat, 15 Feb 2025 17:50:02 GMT) Full text and rfc822 format available.Message #88 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Juri Linkov <juri <at> linkov.net> To: Vincenzo Pupillo <v.pupillo <at> gmail.com> Cc: casouri <at> gmail.com, Eli Zaretskii <eliz <at> gnu.org>, 74610 <at> debbugs.gnu.org Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Sat, 15 Feb 2025 19:39:55 +0200
> Ciao Jury, > I was just about to write, you anticipated me. > The function `html-ts-mode--outline-predicate`, does not work correctly in > `mhtml-ts-mode`, the function seems to fail to calculate the end of the tag it > is on (see outline_issue_1.png) > > And, exactly as you wrote, with treesit-outline-predicate set to nil it does > not work because the function `treesit-outline-predicate--from-imenu` does not > check the variable `treesit-aggregated-simple-imenu-settings` but only > `treesit-simple-imenu-settings`. > > I attach a new patch adapted to the latest commits. Thanks for adapting latest changes to your patch! Is it time now to push your patch? Delaying this will hamper the development since after pushing it will be possible to fix more issues such as adapting outline-predicate to `treesit-aggregated-simple-imenu-settings`, etc.
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Sun, 16 Feb 2025 14:27:01 GMT) Full text and rfc822 format available.Message #91 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Vincenzo Pupillo <v.pupillo <at> gmail.com> To: Juri Linkov <juri <at> linkov.net> Cc: casouri <at> gmail.com, Eli Zaretskii <eliz <at> gnu.org>, 74610 <at> debbugs.gnu.org Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Sun, 16 Feb 2025 15:25:51 +0100
Ciao Juri, In data sabato 15 febbraio 2025 18:39:55 Ora standard dell’Europa centrale, Juri Linkov ha scritto: ... > > Is it time now to push your patch? Yes! > > Delaying this will hamper the development > since after pushing it will be possible to > fix more issues such as adapting outline-predicate > to `treesit-aggregated-simple-imenu-settings`, etc. Thanks. Vincenzo
bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Mon, 17 Feb 2025 07:25:02 GMT) Full text and rfc822 format available.Message #94 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Juri Linkov <juri <at> linkov.net> To: Vincenzo Pupillo <v.pupillo <at> gmail.com> Cc: casouri <at> gmail.com, Eli Zaretskii <eliz <at> gnu.org>, 74610 <at> debbugs.gnu.org Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Mon, 17 Feb 2025 09:23:45 +0200
close 74610 31.0.50 thanks >> Is it time now to push your patch? > > Yes! Thank you for this much needed mode! Now pushed to master and closed. Probably would be better to continue its development by creating new feature requests such as for implementing TODO for treesit-defun-type-regexp to be an aggregated version, also aggregation for outlines, etc.
Juri Linkov <juri <at> linkov.net>
to control <at> debbugs.gnu.org
.
(Mon, 17 Feb 2025 07:25:03 GMT) Full text and rfc822 format available.bug-gnu-emacs <at> gnu.org
:bug#74610
; Package emacs
.
(Mon, 17 Feb 2025 09:14:01 GMT) Full text and rfc822 format available.Message #99 received at 74610 <at> debbugs.gnu.org (full text, mbox):
From: Vincenzo Pupillo <v.pupillo <at> gmail.com> To: Juri Linkov <juri <at> linkov.net> Cc: casouri <at> gmail.com, Eli Zaretskii <eliz <at> gnu.org>, 74610 <at> debbugs.gnu.org Subject: Re: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Mon, 17 Feb 2025 10:13:15 +0100
In data lunedì 17 febbraio 2025 08:23:45 Ora standard dell’Europa centrale, Juri Linkov ha scritto: > close 74610 31.0.50 > thanks > > >> Is it time now to push your patch? > > > > Yes! > > Thank you for this much needed mode! Also, thank you and @Yuan for all you've done. > > Now pushed to master and closed. > Probably would be better to continue its development > by creating new feature requests such as for > implementing TODO for treesit-defun-type-regexp to be > an aggregated version, also aggregation for outlines, > etc. Ok. Ciao! Vincenzo
Debbugs Internal Request <help-debbugs <at> gnu.org>
to internal_control <at> debbugs.gnu.org
.
(Mon, 17 Mar 2025 11:24:15 GMT) Full text and rfc822 format available.
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.