From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Vincenzo Pupillo Newsgroups: gmane.emacs.bugs Subject: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Fri, 29 Nov 2024 22:57:05 +0100 Message-ID: <3532547.LZWGnKmheA@fedora> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="nextPart7111894.9J7NaK4W3v" Content-Transfer-Encoding: 7Bit Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="18003"; mail-complaints-to="usenet@ciao.gmane.io" To: 74610@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Fri Nov 29 22:58:27 2024 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1tH90M-0004Xs-Rn for geb-bug-gnu-emacs@m.gmane-mx.org; Fri, 29 Nov 2024 22:58:27 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tH900-0001lJ-U1; Fri, 29 Nov 2024 16:58:04 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tH8zz-0001lA-Fi for bug-gnu-emacs@gnu.org; Fri, 29 Nov 2024 16:58:03 -0500 Original-Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1tH8zz-0002ay-1Y for bug-gnu-emacs@gnu.org; Fri, 29 Nov 2024 16:58:03 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debbugs.gnu.org; s=debbugs-gnu-org; h=MIME-Version:Date:From:To:Subject; bh=TSZHXXS2F6tL/d5AC4xAGWw8oryh1RYjICXZxAucJNc=; b=iWBqIYWzQjpDj6xRBPU6c/ZSL3ANgOItKtzdBfztC443mGH5WCKQ/Y6YtNet+ct9wbfRkxfuSy57hrGXyNXIP1dx6yR0MCezh2ZQc8x6TNbzZE42Pz+IwANeWeghC9ahcZsygYBXfk7X+HRqO9h9VdJAcyXD5T8ZUENZPdhy32w1Gy75vJweNlbifUbicPw/PBIZCLNJkNYPvn0MLD1legYzr5vtXSRQbgsY4kS8dJQ6CYZuHjU73ARm5mSMlyuzerza2YIAkQ5qxZdpcD8eABSiMrLCwPyWMvOL+N3sDGdaHdNC6Eo326HnHCT2axklYhFFFf8wLJ241vdj2PEWxg==; Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1tH8zx-00039m-Vi for bug-gnu-emacs@gnu.org; Fri, 29 Nov 2024 16:58:02 -0500 X-Loop: help-debbugs@gnu.org Resent-From: Vincenzo Pupillo Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Fri, 29 Nov 2024 21:58:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 74610 X-GNU-PR-Package: emacs X-Debbugs-Original-To: Bug Emacs Original-Received: via spool by submit@debbugs.gnu.org id=B.173291743912058 (code B ref -1); Fri, 29 Nov 2024 21:58:01 +0000 Original-Received: (at submit) by debbugs.gnu.org; 29 Nov 2024 21:57:19 +0000 Original-Received: from localhost ([127.0.0.1]:44641 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1tH8zF-00038O-B9 for submit@debbugs.gnu.org; Fri, 29 Nov 2024 16:57:18 -0500 Original-Received: from lists.gnu.org ([209.51.188.17]:58814) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1tH8zC-00038C-5e for submit@debbugs.gnu.org; Fri, 29 Nov 2024 16:57:15 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tH8zB-0001j5-Ic for bug-gnu-emacs@gnu.org; Fri, 29 Nov 2024 16:57:13 -0500 Original-Received: from mail-ed1-x52d.google.com ([2a00:1450:4864:20::52d]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1tH8z8-0002KQ-Lo for bug-gnu-emacs@gnu.org; Fri, 29 Nov 2024 16:57:13 -0500 Original-Received: by mail-ed1-x52d.google.com with SMTP id 4fb4d7f45d1cf-5d0ca0f67b6so154789a12.3 for ; Fri, 29 Nov 2024 13:57:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1732917429; x=1733522229; darn=gnu.org; h=content-transfer-encoding:mime-version:message-id:date:subject:to :from:from:to:cc:subject:date:message-id:reply-to; bh=TSZHXXS2F6tL/d5AC4xAGWw8oryh1RYjICXZxAucJNc=; b=WIsvZAyp/uFYH1LZPUdGRy4mNurJZu+y+LYLe6E07nnWrzNtOy1j+g9fGrLZsPqER4 XxYL18abNouC7eSKSWV3zcimM1VP+SM7dCOzr28nei4Ay+rD6vknFvi3AQCnk2+PSxfr Rk2ABmpZoW3e3FTC37ek+uJIM/mIqpg4o6JAjM8fT4q5P25kNiHNV3kx1lDDR+2BcXEx CU/2RMW4XryRlfOximvxiz9RutYqEyZO7xc7kGN25cDWT1cwvUFHgKUt7hre6r9d0OpY vhpOcx/wr2N5M4IZRZQYYdHO/QsGQZdBHeRCJ2f2T9w2LY6hwPYytlN8AIs6imVGp1Bd RGPg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1732917429; x=1733522229; h=content-transfer-encoding:mime-version:message-id:date:subject:to :from:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=TSZHXXS2F6tL/d5AC4xAGWw8oryh1RYjICXZxAucJNc=; b=USNOtTrN1l6afBjTau2p2+SKH9GEITJ/InkbuCc74V3tvDvgkxJFEb9HSHlgCOkKLs C0k4YRbzrl/eZNmdTip6B9eRpHtszNk0ujeCjtIQIBu25/AI5c6WF1rafBEqku1GZ3Hc 1Ym1jX+R+2Nzs0wTsH6t4sn0TPGc2kB8VqJq2jMmIxNgQW5n5vUAb/sO554wgPeLUoOD zN3wRkgMTOp49mNOXxnZtv9m/j+PWEtzUGJaWEh7cZcB9d4nuo78wemYTa5Fz5u21cUK RbF3G+CdfJoAj97tMMn3n4oDkZfv9aeQ5/zHyrDBIGpkb2GCMr7nP4/sDvsVLZKkzndK 6RxQ== X-Gm-Message-State: AOJu0Yxlyikx3h3fT7BvZnUXTO58/ADJIq+ZmhNNMrSxQp1AUYGZZTe8 7ErBzb8DsBFLuQOJ/dOY1Sqd0+cGUsOIdjRvxnJz02TviNodqj/Rx0Frfg== X-Gm-Gg: ASbGnctCSqoHDcDm52rX9Do8aJictERB3WIJdnYCm7G0dCrMOUwhKy5QxYO3rtNBJ8a tyRwf5+03XT3r/+YEhvfz9F5Y60iMgF0Ohk5w9n9lxETynKfaleKu5GIX9Mir0t88LDdDD97ypE 11slbKFxlrqte3XjIMjJIqqo46pq5HXAB74P5Hh2Z0MNWN/KZBR5lvVZ0GHSsz4B5m68nR0Ggmg TVZuILhyNxGCAudEmDJt32ncJHvtAFZSUAn9NyoSe0mVftEtLNNKZb6jnBs7WIT+hDieb5IuQ2g yLesY4H5ghv33w== X-Google-Smtp-Source: AGHT+IEIvr0y9vWyKTO6diUHgQPrjGnbVQdgdIotmvBPbH/h3qga1vL3sFlvcfmYnazMudLtyDfECA== X-Received: by 2002:a17:906:cc5e:b0:aa5:317b:3a0 with SMTP id a640c23a62f3a-aa58108f995mr1148569566b.57.1732917428770; Fri, 29 Nov 2024 13:57:08 -0800 (PST) Original-Received: from fedora.localnet (2-230-139-124.ip202.fastwebnet.it. [2.230.139.124]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-aa5996c1207sm215626866b.22.2024.11.29.13.57.06 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 29 Nov 2024 13:57:07 -0800 (PST) Received-SPF: pass client-ip=2a00:1450:4864:20::52d; envelope-from=v.pupillo@gmail.com; helo=mail-ed1-x52d.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, WEIRD_QUOTING=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:296104 Archived-At: This is a multi-part message in MIME format. --nextPart7111894.9J7NaK4W3v Content-Transfer-Encoding: 7Bit Content-Type: text/plain; charset="utf-8" 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. --nextPart7111894.9J7NaK4W3v Content-Disposition: attachment; filename="0001-Add-mhtml-ts-mode.patch" Content-Transfer-Encoding: quoted-printable Content-Type: text/x-patch; charset="UTF-8"; name="0001-Add-mhtml-ts-mode.patch" =46rom 8a1c792aaddf4daef2808f5a74212a2fb8b0a01e Mon Sep 17 00:00:00 2001 =46rom: Vincenzo Pupillo 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. =2D-- 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 =2D-- a/etc/NEWS +++ b/etc/NEWS @@ -797,6 +797,14 @@ destination window is chosen using 'display-buffer-ali= st'. Example: =0C * New Modes and Packages in Emacs 31.1 =20 +** 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. + =0C * Incompatible Lisp Changes in Emacs 31.1 =20 diff --git a/lisp/textmodes/mhtml-ts-mode.el b/lisp/textmodes/mhtml-ts-mode= =2Eel new file mode 100644 index 00000000000..b6b220663e3 =2D-- /dev/null +++ b/lisp/textmodes/mhtml-ts-mode.el @@ -0,0 +1,462 @@ +;;; mhtml-ts-mode.el --- Major mode for HTML using tree-sitter -*- lexical= =2Dbinding: t; -*- + +;; Copyright (C) 2024 Free Software Foundation, Inc. + +;; Author: Vincenzo Pupillo +;; Maintainer: Vincenzo Pupillo +;; 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 . + +;;; 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-alis= t)) + (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 + +When nil, indentation of the script body starts just below the +tag, like: + + + +When `ignore', the script body starts in the first column, like: + + " + :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 backgroun= d. +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= =2E" + (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'. +(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 =E2=80=8B=E2=80=8Bshould be indented according to th= e 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