From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Yuan Fu Newsgroups: gmane.emacs.bugs Subject: bug#74610: 31.0.50; Submitting mhtml-ts-mode, treesitter alternative to mhtml-mode Date: Sat, 30 Nov 2024 22:01:21 -0800 Message-ID: <7067C127-FE4E-4E1A-8FFC-2BAB221E5B45@gmail.com> References: <3532547.LZWGnKmheA@fedora> Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3776.700.51\)) Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="16222"; mail-complaints-to="usenet@ciao.gmane.io" Cc: 74610@debbugs.gnu.org To: Vincenzo Pupillo Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Sun Dec 01 07:03:10 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 1tHd30-00042t-AC for geb-bug-gnu-emacs@m.gmane-mx.org; Sun, 01 Dec 2024 07:03:10 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tHd2w-0003Az-E8; Sun, 01 Dec 2024 01:03:06 -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 1tHd2t-0003Am-Ee for bug-gnu-emacs@gnu.org; Sun, 01 Dec 2024 01:03:04 -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 1tHd2t-0005hy-5W for bug-gnu-emacs@gnu.org; Sun, 01 Dec 2024 01:03:03 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debbugs.gnu.org; s=debbugs-gnu-org; h=References:Date:In-Reply-To:From:Mime-Version:To:Subject; bh=i+iqHSOYSG5Pcf3cX+boARTe5iSNHixVcljrHnh8jGQ=; b=ukxA7PTkkVmnOOWYNInVGirjgtR6xjRLPmRkVNrKKpvKjCM6VOTm3bHGdSRr+OTPHRW8gjpHp79XOJegaU9TVgyTQuGaEQQQ8mAPmqcrqDC9/VCbSHl8UYAlRlZUPjrfXogal7bKJqSSKIKfl3reRp+a3SHgHTZtqOzQ7tJUKUiaofYLlTFaHgBlvNHnpLcsPaQ+F2zUVM/4qq/Ug/teAvwsARiKDaL7grOlW1cLj+HftoEDvsX8+/2d9EjXi0sFi7QPZQjgGQ6p03VzY4AaJZnpWhlL4VW0uawqduIhSSLO2xzVnPECwnEeG/C4U/k1Qz+N/onnVJbUTNfYPa3plQ==; Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1tHd2r-0002xz-Q4 for bug-gnu-emacs@gnu.org; Sun, 01 Dec 2024 01:03:01 -0500 X-Loop: help-debbugs@gnu.org Resent-From: Yuan Fu Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 01 Dec 2024 06:03:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 74610 X-GNU-PR-Package: emacs Original-Received: via spool by 74610-submit@debbugs.gnu.org id=B74610.173303296511372 (code B ref 74610); Sun, 01 Dec 2024 06:03:01 +0000 Original-Received: (at 74610) by debbugs.gnu.org; 1 Dec 2024 06:02:45 +0000 Original-Received: from localhost ([127.0.0.1]:49920 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1tHd2a-0002xK-8Y for submit@debbugs.gnu.org; Sun, 01 Dec 2024 01:02:45 -0500 Original-Received: from mail-pl1-f171.google.com ([209.85.214.171]:61714) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1tHd2W-0002wy-RT for 74610@debbugs.gnu.org; Sun, 01 Dec 2024 01:02:42 -0500 Original-Received: by mail-pl1-f171.google.com with SMTP id d9443c01a7336-21527bb7eb0so20369465ad.3 for <74610@debbugs.gnu.org>; Sat, 30 Nov 2024 22:02:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1733032895; x=1733637695; darn=debbugs.gnu.org; h=to:references:message-id:content-transfer-encoding:cc:date :in-reply-to:from:subject:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=i+iqHSOYSG5Pcf3cX+boARTe5iSNHixVcljrHnh8jGQ=; b=CzDMrlParvNRZ0UosCZNfjztEMdjU/cdN/sXyGcOIWxARt9WSeZC39SIUB9Wy00gb4 5v0RzLQI7ZRD4Y30gCmLAV27hmGKjBc6iLiAqobqaapK3h1vEdtWZzoHBWXyjmcKdeo4 A03KFXq1dHd4G+1nRtKuFCkx4Je844Dk/ltiiCbeBvv4vWX8b0cdGVEfUyweURNVSKZV B+Of4fa00fFqr4BLdloliAVTUVzoQ1q0+nK84sjgxePaF+ZKEHUQNqYRLv2oQeZ4MVF1 nEjzQq4YUGXw+GjdGAmAKaK1S3UWJSvqzOBJpLsT1zoty2UICBJvkyn501SzmiVG1I9p mxLA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733032895; x=1733637695; h=to:references:message-id:content-transfer-encoding:cc:date :in-reply-to:from:subject:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=i+iqHSOYSG5Pcf3cX+boARTe5iSNHixVcljrHnh8jGQ=; b=e2LVfCN6OqUndBb0vh53ekjhZ9XheBat8hUdR0vcFKljMl/rACE5FyXRJfvvYKOtkw yQVrbcsaymyGaEO6GAFlJrWJ0uSUBKDh9I93ina2/C9SSS+qxQO9ietPhw/kerrkcj7v IHhKCgP7OLoqGDCnVBn+dRhwmbN5M7DKBupqApUjO44w1ve7b3Dt8PZSEaEUdPgi4jFo GHq/Y/rX/MMZmNg9se3PAoNB318/HxVPZQwBSiX9PcVAu9ch9V0toDLRUXkjiSWvamIa v657+Rh2KtwiExC2sx2QcuPnQAyPx5xnr8s/XA9MrXRkb/YnNkYkl9Jcf4u5WtpLF6rP LCqg== X-Gm-Message-State: AOJu0YzLLuzSf62e+5bjOSYVU14p73B+q+yqX/1Es4uG5SLQ3GknOme3 zX6LExsKoURqmyHognCsnqF0mEvVMO1KZk6CVlnfv/RpLgeVngnH X-Gm-Gg: ASbGncuz5Y9Ju5xBs5ACew2LMPkqyGnTkcoPzRPMsoge4zKYymTCPkaCwt5DzO8wIj8 ptivCxBmjwTqUnQQF3LZa1KXLYwChMnWsUGgDazLZaqdkotj0KKlfMaeQmIrv4XePXvv7zEqPH+ amwb2r6O2jN9hJ4LyDmxJ0cmPboSqWkTMcpWbsl7zWMhhfpLnFADvesyxlL7BTCwJObNEaSbzW/ 0Yb86VhEAA/o6pCzrxKRCS+G8FLMAE2QEeouNsTxF2SIlMFw0W+NmKcOJyxoMZl2HtZZpYHBg== X-Google-Smtp-Source: AGHT+IGduerqz4HwLU8yqXXh5UFvotqGhUDYsYljuuphk5RBq6MApx2qcHhGgCrQMBt7SFaYrmLhYw== X-Received: by 2002:a17:903:1c8:b0:215:44fe:1640 with SMTP id d9443c01a7336-21544fe1859mr93469975ad.3.1733032894823; Sat, 30 Nov 2024 22:01:34 -0800 (PST) Original-Received: from smtpclient.apple ([2601:646:8f81:6120:71b7:718f:7faa:8436]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-72541761523sm6088939b3a.1.2024.11.30.22.01.32 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sat, 30 Nov 2024 22:01:33 -0800 (PST) In-Reply-To: <3532547.LZWGnKmheA@fedora> X-Mailer: Apple Mail (2.3776.700.51) 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:296217 Archived-At: > On Nov 29, 2024, at 1:57=E2=80=AFPM, Vincenzo Pupillo = wrote: >=20 > Ciao, > following the discussion=20 > https://lists.gnu.org/archive/html/emacs-devel/2024-11/msg00079.html I = would=20 > like to ask if it would be possible to add to emacs this new mode for = editing=20 > html files alternative to mhtml-mode. >=20 > Thank you. >=20 > Vincenzo.<0001-Add-mhtml-ts-mode.patch> Thank you so much! This will be very helpful for others. Here=E2=80=99re = some comments. Yuan =46rom 8a1c792aaddf4daef2808f5a74212a2fb8b0a01e Mon Sep 17 00:00:00 2001 From: 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. --- 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: =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.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 +;; 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-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 + +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 = 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 =E2=80=8B=E2=80=8Bshould 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