From 9e5f89dc26ed2ef67a7de881bc39ba004b33ff20 Mon Sep 17 00:00:00 2001 From: chbk Date: Fri, 6 Jun 2025 23:14:32 +0200 Subject: [PATCH] Improve CSS syntax highlighting (#25326) Release Notes: - Improved CSS syntax highlighting | Zed 0.174.6 | With this PR | | --- | --- | | ![css_0 174 6](https://github.com/user-attachments/assets/d069f20e-5f1f-4d03-a010-81ba4b61b3a0) | ![css_pr](https://github.com/user-attachments/assets/36463ef1-2ead-421d-9825-bd359e7677ab) | - `|`: `operator` - `and`, `or`, `not`, `only`: `operator` -> `keyword.operator`, as defined in other languages - `id_name`, `class_name`: `property`/`attribute` -> `selector`, not a property name. [CSS reference](https://www.w3.org/TR/selectors-3/#class-html) - `namespace_name`: `property` -> `namespace`, not a property name - `property_name`: `constant` -> `property`, like `feature_name` already defined - `(keyword_query)`: `property`, similar to `feature_name`. [CSS reference](https://www.w3.org/TR/mediaqueries-3/#media1) - `keyword_query`: `constant.builtin`, [CSS reference](https://www.w3.org/TR/mediaqueries-3/#media0) - `plain_value`, `keyframes_name`: `constant.builtin`, [CSS reference](https://www.w3.org/TR/css-values-3/#value-defs) - `unit`: `type` -> `type.unit`, [Atom](https://github.com/atom/language-css/blob/9e4afce058b4593edf03ed1dec6033b163c678f0/grammars/tree-sitter-css.cson#L73) and [VS Code](https://github.com/microsoft/vscode/blob/336801752dd09afa76f5429fba846e533bcdb7d9/extensions/css/syntaxes/css.tmLanguage.json#L1393) also have a `unit` scope for this. [CSS reference](https://www.w3.org/TR/css3-values/#dimensions) ```css @media (keyword_query) and keyword_query {} @supports (feature_name: plain_value) {} @namespace namespace_name url("string"); namespace_name|tag_name {} @keyframes keyframes_name { to { top: 200unit; color: #c01045; } } tag_name::before, #id_name:nth-child(even), .class_name[attribute_name=plain_value] { property_name: 2em 1.2em; --variable: rgb(250, 0, 0); color: var(--variable); animation: keyframes_name 5s plain_value; } ``` --- assets/themes/ayu/ayu.json | 45 +++++++++++++ assets/themes/gruvbox/gruvbox.json | 90 +++++++++++++++++++++++++ assets/themes/one/one.json | 30 +++++++++ crates/languages/src/css/highlights.scm | 45 +++++++++---- 4 files changed, 196 insertions(+), 14 deletions(-) diff --git a/assets/themes/ayu/ayu.json b/assets/themes/ayu/ayu.json index de659dbe29..f9f8720729 100644 --- a/assets/themes/ayu/ayu.json +++ b/assets/themes/ayu/ayu.json @@ -261,6 +261,11 @@ "font_style": null, "font_weight": null }, + "namespace": { + "color": "#bfbdb6ff", + "font_style": null, + "font_weight": null + }, "number": { "color": "#d2a6ffff", "font_style": null, @@ -316,6 +321,16 @@ "font_style": null, "font_weight": null }, + "selector": { + "color": "#d2a6ffff", + "font_style": null, + "font_weight": null + }, + "selector.pseudo": { + "color": "#5ac1feff", + "font_style": null, + "font_weight": null + }, "string": { "color": "#a9d94bff", "font_style": null, @@ -632,6 +647,11 @@ "font_style": null, "font_weight": null }, + "namespace": { + "color": "#5c6166ff", + "font_style": null, + "font_weight": null + }, "number": { "color": "#a37accff", "font_style": null, @@ -687,6 +707,16 @@ "font_style": null, "font_weight": null }, + "selector": { + "color": "#a37accff", + "font_style": null, + "font_weight": null + }, + "selector.pseudo": { + "color": "#3b9ee5ff", + "font_style": null, + "font_weight": null + }, "string": { "color": "#86b300ff", "font_style": null, @@ -1003,6 +1033,11 @@ "font_style": null, "font_weight": null }, + "namespace": { + "color": "#cccac2ff", + "font_style": null, + "font_weight": null + }, "number": { "color": "#dfbfffff", "font_style": null, @@ -1058,6 +1093,16 @@ "font_style": null, "font_weight": null }, + "selector": { + "color": "#dfbfffff", + "font_style": null, + "font_weight": null + }, + "selector.pseudo": { + "color": "#72cffeff", + "font_style": null, + "font_weight": null + }, "string": { "color": "#d4fe7fff", "font_style": null, diff --git a/assets/themes/gruvbox/gruvbox.json b/assets/themes/gruvbox/gruvbox.json index fbbec82793..459825c733 100644 --- a/assets/themes/gruvbox/gruvbox.json +++ b/assets/themes/gruvbox/gruvbox.json @@ -270,6 +270,11 @@ "font_style": null, "font_weight": null }, + "namespace": { + "color": "#83a598ff", + "font_style": null, + "font_weight": null + }, "number": { "color": "#d3869bff", "font_style": null, @@ -325,6 +330,16 @@ "font_style": null, "font_weight": null }, + "selector": { + "color": "#fabd2eff", + "font_style": null, + "font_weight": null + }, + "selector.pseudo": { + "color": "#83a598ff", + "font_style": null, + "font_weight": null + }, "string": { "color": "#b8bb25ff", "font_style": null, @@ -655,6 +670,11 @@ "font_style": null, "font_weight": null }, + "namespace": { + "color": "#83a598ff", + "font_style": null, + "font_weight": null + }, "number": { "color": "#d3869bff", "font_style": null, @@ -710,6 +730,16 @@ "font_style": null, "font_weight": null }, + "selector": { + "color": "#fabd2eff", + "font_style": null, + "font_weight": null + }, + "selector.pseudo": { + "color": "#83a598ff", + "font_style": null, + "font_weight": null + }, "string": { "color": "#b8bb25ff", "font_style": null, @@ -1040,6 +1070,11 @@ "font_style": null, "font_weight": null }, + "namespace": { + "color": "#83a598ff", + "font_style": null, + "font_weight": null + }, "number": { "color": "#d3869bff", "font_style": null, @@ -1095,6 +1130,16 @@ "font_style": null, "font_weight": null }, + "selector": { + "color": "#fabd2eff", + "font_style": null, + "font_weight": null + }, + "selector.pseudo": { + "color": "#83a598ff", + "font_style": null, + "font_weight": null + }, "string": { "color": "#b8bb25ff", "font_style": null, @@ -1425,6 +1470,11 @@ "font_style": null, "font_weight": null }, + "namespace": { + "color": "#066578ff", + "font_style": null, + "font_weight": null + }, "number": { "color": "#8f3e71ff", "font_style": null, @@ -1480,6 +1530,16 @@ "font_style": null, "font_weight": null }, + "selector": { + "color": "#b57613ff", + "font_style": null, + "font_weight": null + }, + "selector.pseudo": { + "color": "#0b6678ff", + "font_style": null, + "font_weight": null + }, "string": { "color": "#79740eff", "font_style": null, @@ -1810,6 +1870,11 @@ "font_style": null, "font_weight": null }, + "namespace": { + "color": "#066578ff", + "font_style": null, + "font_weight": null + }, "number": { "color": "#8f3e71ff", "font_style": null, @@ -1865,6 +1930,16 @@ "font_style": null, "font_weight": null }, + "selector": { + "color": "#b57613ff", + "font_style": null, + "font_weight": null + }, + "selector.pseudo": { + "color": "#0b6678ff", + "font_style": null, + "font_weight": null + }, "string": { "color": "#79740eff", "font_style": null, @@ -2195,6 +2270,11 @@ "font_style": null, "font_weight": null }, + "namespace": { + "color": "#066578ff", + "font_style": null, + "font_weight": null + }, "number": { "color": "#8f3e71ff", "font_style": null, @@ -2250,6 +2330,16 @@ "font_style": null, "font_weight": null }, + "selector": { + "color": "#b57613ff", + "font_style": null, + "font_weight": null + }, + "selector.pseudo": { + "color": "#0b6678ff", + "font_style": null, + "font_weight": null + }, "string": { "color": "#79740eff", "font_style": null, diff --git a/assets/themes/one/one.json b/assets/themes/one/one.json index b0455f208a..0163c0958e 100644 --- a/assets/themes/one/one.json +++ b/assets/themes/one/one.json @@ -264,6 +264,11 @@ "font_style": null, "font_weight": null }, + "namespace": { + "color": "#dce0e5ff", + "font_style": null, + "font_weight": null + }, "number": { "color": "#bf956aff", "font_style": null, @@ -319,6 +324,16 @@ "font_style": null, "font_weight": null }, + "selector": { + "color": "#dfc184ff", + "font_style": null, + "font_weight": null + }, + "selector.pseudo": { + "color": "#74ade8ff", + "font_style": null, + "font_weight": null + }, "string": { "color": "#a1c181ff", "font_style": null, @@ -643,6 +658,11 @@ "font_style": null, "font_weight": null }, + "namespace": { + "color": "#242529ff", + "font_style": null, + "font_weight": null + }, "number": { "color": "#ad6e25ff", "font_style": null, @@ -698,6 +718,16 @@ "font_style": null, "font_weight": null }, + "selector": { + "color": "#669f59ff", + "font_style": null, + "font_weight": null + }, + "selector.pseudo": { + "color": "#5c78e2ff", + "font_style": null, + "font_weight": null + }, "string": { "color": "#649f57ff", "font_style": null, diff --git a/crates/languages/src/css/highlights.scm b/crates/languages/src/css/highlights.scm index 4ddfe9a418..8fbb9f47d2 100644 --- a/crates/languages/src/css/highlights.scm +++ b/crates/languages/src/css/highlights.scm @@ -11,6 +11,7 @@ ">" "+" "-" + "|" "*" "/" "=" @@ -19,35 +20,50 @@ "~=" "$=" "*=" +] @operator + +[ "and" "or" "not" "only" -] @operator +] @keyword.operator -(attribute_selector (plain_value) @string) +(id_name) @selector.id +(class_name) @selector.class + +(namespace_name) @namespace +(namespace_selector (tag_name) @namespace "|") (attribute_name) @attribute -(pseudo_element_selector (tag_name) @attribute) -(pseudo_class_selector (class_name) @attribute) +(pseudo_element_selector "::" (tag_name) @selector.pseudo) +(pseudo_class_selector ":" (class_name) @selector.pseudo) [ - (class_name) - (id_name) - (namespace_name) (feature_name) + (property_name) ] @property -(property_name) @constant - (function_name) @function +[ + (plain_value) + (keyframes_name) + (keyword_query) +] @constant.builtin + +(attribute_selector + (plain_value) @string) + +(parenthesized_query + (keyword_query) @property) + ( [ (property_name) (plain_value) - ] @variable.special - (#match? @variable.special "^--") + ] @variable + (#match? @variable "^--") ) [ @@ -61,7 +77,7 @@ (to) (from) (important) -] @keyword +] @keyword (string_value) @string (color_value) @string.special @@ -71,7 +87,7 @@ (float_value) ] @number -(unit) @type +(unit) @type.unit [ "," @@ -79,9 +95,10 @@ "." "::" ";" - "#" ] @punctuation.delimiter +(id_selector "#" @punctuation.delimiter) + [ "{" ")"