]> git.eshelyaron.com Git - emacs.git/commitdiff
Expand css-ts-mode and merge it into css-mode
authorYuan Fu <casouri@gmail.com>
Sat, 19 Nov 2022 23:27:07 +0000 (15:27 -0800)
committerYuan Fu <casouri@gmail.com>
Sat, 19 Nov 2022 23:43:36 +0000 (15:43 -0800)
* lisp/progmodes/css-ts-mode.el: Deleted.
* lisp/textmodes/css-mode.el (css--treesit-indent-rules)
(css--treesit-settings): New variables.
(css--treesit-imenu-1)
(css--treesit-imenu): New functions.
* lisp/textmodes/css-mode.el (css-base-mode): New mode inherited by
both css-mode and css-ts-mode.
(css-ts-mode): New mode.
(css-mode): Inherit from css-base-mode, and move some setup to
css-base-mode.

lisp/progmodes/css-ts-mode.el [deleted file]
lisp/textmodes/css-mode.el

diff --git a/lisp/progmodes/css-ts-mode.el b/lisp/progmodes/css-ts-mode.el
deleted file mode 100644 (file)
index d0f104e..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-;;; css-ts-mode.el --- tree-sitter support for CSS  -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2022 Free Software Foundation, Inc.
-
-;; Author     : Theodor Thornhill <theo@thornhill.no>
-;; Maintainer : Theodor Thornhill <theo@thornhill.no>
-;; Created    : November 2022
-;; Keywords   : css languages tree-sitter
-
-;; This file is part of GNU Emacs.
-
-;; This program 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.
-
-;; This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
-
-
-;;; Commentary:
-;;
-
-;;; Code:
-
-(require 'treesit)
-(require 'rx)
-(require 'css-mode)
-
-(defcustom css-ts-mode-indent-offset 2
-  "Number of spaces for each indentation step in `ts-mode'."
-  :version "29.1"
-  :type 'integer
-  :safe 'integerp
-  :group 'css)
-
-(defvar css-ts-mode--indent-rules
-  `((css
-     ((node-is "}") parent-bol 0)
-     ((node-is ")") parent-bol 0)
-     ((node-is "]") parent-bol 0)
-
-     ((parent-is "block") parent-bol css-ts-mode-indent-offset)
-     ((parent-is "arguments") parent-bol css-ts-mode-indent-offset)
-     ((parent-is "declaration") parent-bol css-ts-mode-indent-offset))))
-
-(defvar css-ts-mode--settings
-  (treesit-font-lock-rules
-   :language 'css
-   :feature 'basic
-   :override t
-   `((unit) @font-lock-constant-face
-     (integer_value) @font-lock-builtin-face
-     (float_value) @font-lock-builtin-face
-     (plain_value) @font-lock-variable-name-face
-     (comment) @font-lock-comment-face
-     (class_selector) @css-selector
-     (child_selector) @css-selector
-     (id_selector) @css-selector
-     (tag_name) @css-selector
-     (property_name) @css-property
-     (class_name) @css-selector
-     (function_name) @font-lock-function-name-face)))
-
-(defun css-ts-mode--imenu-1 (node)
-  "Helper for `css-ts-mode--imenu'.
-Find string representation for NODE and set marker, then recurse
-the subtrees."
-  (let* ((ts-node (car node))
-         (subtrees (mapcan #'css-ts-mode--imenu-1 (cdr node)))
-         (name (when ts-node
-                 (if (equal (treesit-node-type ts-node) "tag_name")
-                     (treesit-node-text ts-node)
-                   (treesit-node-text (treesit-node-child ts-node 1) t))))
-         (marker (when ts-node
-                   (set-marker (make-marker)
-                               (treesit-node-start ts-node)))))
-    (cond
-     ((null ts-node) subtrees)
-     (subtrees
-      `((,name ,(cons name marker) ,@subtrees)))
-     (t
-      `((,name . ,marker))))))
-
-(defun css-ts-mode--imenu ()
-  "Return Imenu alist for the current buffer."
-  (let* ((node (treesit-buffer-root-node))
-         (tree (treesit-induce-sparse-tree
-                node (rx (or "class_selector"
-                             "id_selector"
-                             "tag_name")))))
-    (css-ts-mode--imenu-1 tree)))
-
-(define-derived-mode css-ts-mode prog-mode "CSS"
-  "Major mode for editing CSS."
-  :group 'css
-  :syntax-table css-mode-syntax-table
-
-  (unless (treesit-ready-p nil 'css)
-    (error "Tree-sitter for CSS isn't available"))
-
-  (treesit-parser-create 'css)
-
-  ;; Comments
-  (setq-local comment-start "/*")
-  (setq-local comment-start-skip "/\\*+[ \t]*")
-  (setq-local comment-end "*/")
-  (setq-local comment-end-skip "[ \t]*\\*+/")
-
-  ;; Indent.
-  (setq-local treesit-simple-indent-rules css-ts-mode--indent-rules)
-
-  ;; Electric
-  (setq-local electric-indent-chars
-              (append "{}():;," electric-indent-chars))
-
-  ;; Navigation.
-  (setq-local treesit-defun-type-regexp "rule_set")
-  ;; Font-lock.
-  (setq-local treesit-font-lock-settings css-ts-mode--settings)
-  (setq treesit-font-lock-feature-list '((basic) () ()))
-
-  ;; Imenu.
-  (setq-local imenu-create-index-function #'css-ts-mode--imenu)
-  (setq-local which-func-functions nil) ;; Piggyback on imenu
-
-  (treesit-major-mode-setup))
-
-(provide 'css-ts-mode)
-
-;;; css-ts-mode.el ends here
index d2a35bd550f2e3d17e14ff4229ed2b3c6f90aa2e..34380c05a00265e2862cce0ef91f9e5b149a70c6 100644 (file)
@@ -40,7 +40,9 @@
 (require 'sgml-mode)
 (require 'smie)
 (require 'thingatpt)
-(eval-when-compile (require 'subr-x))
+(eval-when-compile (require 'subr-x)
+                   (require 'rx))
+(require 'treesit)
 
 (defgroup css nil
   "Cascading Style Sheets (CSS) editing mode."
@@ -1319,6 +1321,94 @@ for determining whether point is within a selector."
      (when (smie-rule-hanging-p)
        css-indent-offset))))
 
+;;; Tree-sitter
+
+(defvar css--treesit-indent-rules
+  '((css
+     ((node-is "}") parent-bol 0)
+     ((node-is ")") parent-bol 0)
+     ((node-is "]") parent-bol 0)
+
+     ((parent-is "block") parent-bol css-indent-offset)
+     ((parent-is "arguments") parent-bol css-indent-offset)
+     ((match nil "declaration" nil 0 3) parent-bol css-indent-offset)
+     ((match nil "declaration" nil 3) (nth-sibling 2) 0)))
+  "Tree-sitter indentation rules for `css-ts-mode'.")
+
+(defvar css--treesit-settings
+  (treesit-font-lock-rules
+   :feature 'comment
+   :language 'css
+   '((comment) @font-lock-comment-face)
+
+   :feature 'string
+   :language 'css
+   '((string_value) @font-lock-string-face)
+
+   :feature 'variable
+   :language 'css
+   '((plain_value) @font-lock-variable-name-face)
+
+   :feature 'selector
+   :language 'css
+   '((class_selector) @css-selector
+     (child_selector) @css-selector
+     (id_selector) @css-selector
+     (tag_name) @css-selector
+     (class_name) @css-selector)
+
+   :feature 'property
+   :language 'css
+   `((property_name) @css-property)
+
+   :feature 'function
+   :language 'css
+   '((function_name) @font-lock-function-name-face)
+
+   :feature 'constant
+   :language 'css
+   '((integer_value) @font-lock-number-face
+     (float_value) @font-lock-number-face
+     (unit) @font-lock-constant-face)
+
+   :feature 'error
+   :language 'css
+   '((ERROR) @error))
+  "Tree-sitter font-lock settings for `css-ts-mode'.")
+
+(defun css--treesit-imenu-1 (node)
+  "Helper for `css--treesit-imenu'.
+Find string representation for NODE and set marker, then recurse
+the subtrees."
+  (let* ((ts-node (car node))
+         (subtrees (mapcan #'css--treesit-imenu-1 (cdr node)))
+         (name (when ts-node
+                 (pcase (treesit-node-type ts-node)
+                   ("rule_set" (treesit-node-text
+                                (treesit-node-child ts-node 0) t))
+                   ("media_statement"
+                    (let ((block (treesit-node-child ts-node -1)))
+                      (string-trim
+                       (buffer-substring-no-properties
+                        (treesit-node-start ts-node)
+                        (treesit-node-start block))))))))
+         (marker (when ts-node
+                   (set-marker (make-marker)
+                               (treesit-node-start ts-node)))))
+    (cond
+     ((or (null ts-node) (null name)) subtrees)
+     (subtrees
+      `((,name ,(cons name marker) ,@subtrees)))
+     (t
+      `((,name . ,marker))))))
+
+(defun css--treesit-imenu ()
+  "Return Imenu alist for the current buffer."
+  (let* ((node (treesit-buffer-root-node))
+         (tree (treesit-induce-sparse-tree
+                node (rx (or "rule_set" "media_statement")))))
+    (css--treesit-imenu-1 tree)))
+
 ;;; Completion
 
 (defun css--complete-property ()
@@ -1657,8 +1747,67 @@ rgb()/rgba()."
               (replace-regexp-in-string "[\n ]+" " " s)))
            res)))))))
 
+(define-derived-mode css-base-mode prog-mode "CSS"
+  "Generic mode to edit Cascading Style Sheets (CSS).
+
+This is a generic major mode intended to be inherited by a
+concrete implementation.  Currently there two concrete
+implementations: `css-mode' and `css-ts-mode'."
+  (setq-local comment-start "/*")
+  (setq-local comment-start-skip "/\\*+[ \t]*")
+  (setq-local comment-end "*/")
+  (setq-local comment-end-skip "[ \t]*\\*+/")
+  (setq-local electric-indent-chars
+              (append css-electric-keys electric-indent-chars))
+  ;; The default "." creates ambiguity with class selectors.
+  (setq-local imenu-space-replacement " "))
+
+;;;###autoload
+(define-derived-mode css-ts-mode css-base-mode "CSS"
+  "Major mode to edit Cascading Style Sheets (CSS).
+\\<css-ts-mode-map>
+
+This mode provides syntax highlighting, indentation, completion,
+and documentation lookup for CSS, based on the tree-sitter
+library.
+
+Use `\\[completion-at-point]' to complete CSS properties,
+property values, pseudo-elements, pseudo-classes, at-rules,
+bang-rules, and HTML tags, classes and IDs.  Completion
+candidates for HTML class names and IDs are found by looking
+through open HTML mode buffers.
+
+Use `\\[info-lookup-symbol]' to look up documentation of CSS
+properties, at-rules, pseudo-classes, and pseudo-elements on the
+Mozilla Developer Network (MDN).
+
+Use `\\[fill-paragraph]' to reformat CSS declaration blocks.  It
+can also be used to fill comments.
+
+\\{css-mode-map}"
+  (when (treesit-ready-p 'css-mode 'css)
+    ;; Borrowed from `css-native-mode'.
+    (add-hook 'completion-at-point-functions
+              #'css-completion-at-point nil 'local)
+    (setq-local fill-paragraph-function #'css-fill-paragraph)
+    (setq-local adaptive-fill-function #'css-adaptive-fill)
+    (setq-local add-log-current-defun-function #'css-current-defun-name)
+
+    ;; Tree-sitter specific setup.
+    (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-font-lock-settings css--treesit-settings)
+    (setq-local treesit-font-lock-feature-list
+                '((selector comment)
+                  (property constant string)
+                  (error variable function)))
+    (setq-local imenu-create-index-function #'css--treesit-imenu)
+    (setq-local which-func-functions nil)
+    (treesit-major-mode-setup)))
+
 ;;;###autoload
-(define-derived-mode css-mode prog-mode "CSS"
+(define-derived-mode css-mode css-base-mode "CSS"
   "Major mode to edit Cascading Style Sheets (CSS).
 \\<css-mode-map>
 This mode provides syntax highlighting, indentation, completion,
@@ -1679,10 +1828,6 @@ be used to fill comments.
 
 \\{css-mode-map}"
   (setq-local font-lock-defaults css-font-lock-defaults)
-  (setq-local comment-start "/*")
-  (setq-local comment-start-skip "/\\*+[ \t]*")
-  (setq-local comment-end "*/")
-  (setq-local comment-end-skip "[ \t]*\\*+/")
   (setq-local syntax-propertize-function
               css-syntax-propertize-function)
   (setq-local fill-paragraph-function #'css-fill-paragraph)
@@ -1691,13 +1836,9 @@ be used to fill comments.
   (smie-setup css-smie-grammar #'css-smie-rules
               :forward-token #'css-smie--forward-token
               :backward-token #'css-smie--backward-token)
-  (setq-local electric-indent-chars
-              (append css-electric-keys electric-indent-chars))
   (setq-local font-lock-fontify-region-function #'css--fontify-region)
   (add-hook 'completion-at-point-functions
             #'css-completion-at-point nil 'local)
-  ;; The default "." creates ambiguity with class selectors.
-  (setq-local imenu-space-replacement " ")
   (setq-local imenu-prev-index-position-function
               #'css--prev-index-position)
   (setq-local imenu-extract-index-name-function