Skip to content

Commit c2a4454

Browse files
committed
AG-49656 Add syntax highlighing for the CSS selectors in rules
Squashed commit of the following: commit 53c2dac Author: Kurbanali Ruslan <r.kurbanali@adguard.com> Date: Fri Dec 26 10:27:01 2025 +0500 update changelog date commit 7b65018 Author: Kurbanali Ruslan <r.kurbanali@adguard.com> Date: Thu Dec 25 14:38:22 2025 +0500 added changelog date and version increment commit 20a72c9 Author: Kurbanali Ruslan <r.kurbanali@adguard.com> Date: Thu Dec 25 14:34:15 2025 +0500 added more tests commit dd31031 Author: Kurbanali Ruslan <r.kurbanali@adguard.com> Date: Thu Dec 25 14:34:02 2025 +0500 fix whitespace tokenization of pseudo-classes argument quoted / regexp commit 5ebb224 Author: Kurbanali Ruslan <r.kurbanali@adguard.com> Date: Wed Dec 24 18:29:03 2025 +0500 AG-49656 Add syntax highlighing for the CSS selectors in rules
1 parent 554aae0 commit c2a4454

File tree

5 files changed

+1100
-29
lines changed

5 files changed

+1100
-29
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ The format is based on [Keep a Changelog], and this project adheres to [Semantic
77
[Keep a Changelog]: https://keepachangelog.com/en/1.0.0/
88
[Semantic Versioning]: https://semver.org/spec/v2.0.0.html
99

10+
## [2.1.4] (prerelease) - 2025-12-26
11+
12+
### Added
13+
14+
- Support for CSS selector syntax in HTML filtering and elemhide rules [#140], [#155].
15+
16+
[#140]: https://github.com/AdguardTeam/VscodeAdblockSyntax/issues/140
17+
[#155]: https://github.com/AdguardTeam/VscodeAdblockSyntax/issues/155
18+
[2.1.4]: https://github.com/AdguardTeam/VscodeAdblockSyntax/compare/2.1.3...2.1.4
19+
1020
## [2.1.3] (prerelease) - 2025-12-15
1121

1222
### Changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "adblock",
33
"displayName": "Adblock/AdGuard/uBlock filters grammar",
44
"description": "VS code extension that adds support for ad blocking rules syntax.",
5-
"version": "2.1.3",
5+
"version": "2.1.4",
66
"publisher": "adguard",
77
"icon": "icons/aglint_128x128.png",
88
"main": "./client/out/extension",

syntaxes/adblock.yaml-tmlanguage

Lines changed: 233 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,15 @@ repository:
197197
- include: "#cssStyle"
198198
contentRules:
199199
patterns:
200-
- match: "^(\\[.+?\\])?(.*?)(\\$@?\\$)(.+?)(\\[.+)?$"
200+
- match: |-
201+
(?x)
202+
^ # Start of the line
203+
\s* # Optional leading whitespace
204+
(\[.+?\])? # Group 1. AdGuard modifier list
205+
(.*)? # Group 2. Domain list
206+
(\$@?\$) # Group 3. Cosmetic rule marker
207+
(.+) # Group 4. CSS selector
208+
$ # End of the line
201209
captures:
202210
"1":
203211
patterns:
@@ -208,10 +216,8 @@ repository:
208216
"3":
209217
name: keyword.control.adblock
210218
"4":
211-
name: entity.name.function.adblock
212-
"5":
213219
patterns:
214-
- include: "#contentAttributes"
220+
- include: "#cssSelector"
215221
scriptletRules:
216222
patterns:
217223
- include: "#exceptionScriptletRules"
@@ -603,22 +609,6 @@ repository:
603609
match: ".*"
604610
"3":
605611
name: keyword.control.adblock
606-
contentAttributes:
607-
patterns:
608-
- match: (\[)([^"=]+?)(\=)(".+?")(\])
609-
captures:
610-
"1":
611-
name: punctuation.section.adblock
612-
"2":
613-
name: keyword.other.adblock
614-
"3":
615-
name: keyword.operator.adblock
616-
"4":
617-
name: string.quoted.adblock
618-
"5":
619-
name: punctuation.section.adblock
620-
- name: invalid.illegal.adblock
621-
match: ".*"
622612
emptyScriptletFunction:
623613
patterns:
624614
- match: \s*\z
@@ -675,8 +665,229 @@ repository:
675665
match: ".*"
676666
cssSelector:
677667
patterns:
678-
- name: entity.name.function.adblock
679-
match: ".+"
668+
# ID selector
669+
- match: |-
670+
(?x)
671+
(\#) # Group 1: Prefix (#)
672+
-? # Optional leading hyphen
673+
[A-Za-z_] # Followed by letter or underscore
674+
[A-Za-z0-9_-]* # Followed by letters, digits, underscores, hyphens
675+
captures:
676+
"1":
677+
name: punctuation.definition.entity.css
678+
name: entity.other.attribute-name.id.css
679+
680+
# Class selector
681+
- match: |-
682+
(?x)
683+
(\.) # Group 1: Prefix (.)
684+
-? # Optional leading hyphen
685+
[A-Za-z_] # Followed by letter or underscore
686+
[A-Za-z0-9_-]* # Followed by letters, digits, underscores, hyphens
687+
captures:
688+
"1":
689+
name: punctuation.definition.entity.css
690+
name: entity.other.attribute-name.class.css
691+
692+
# Universal type selector (*)
693+
- match: "\\*"
694+
name: entity.name.tag.wildcard.css
695+
696+
# Type selector (order is important here, it must come after ID and class selectors)
697+
- match: |-
698+
(?x)
699+
-? # Optional leading hyphen
700+
[A-Za-z_] # Followed by letter or underscore
701+
[A-Za-z0-9_-]* # Followed by letters, digits, underscores, hyphens
702+
name: entity.name.tag.css
703+
704+
# Attribute selector
705+
- match: |-
706+
(?x)
707+
(\[) # Group 1: Opening bracket ([)
708+
\s* # Optional whitespace after opening bracket
709+
( # Group 2: Attribute name
710+
-? # Optional leading hyphen
711+
[A-Za-z_] # Followed by letter or underscore
712+
[A-Za-z0-9_-]* # Followed by letters, digits, underscores, hyphens
713+
)
714+
\s* # Optional whitespace after attribute name
715+
(?: # Optional operator + value + flag
716+
( # Group 3: Operator (=, ~=, |=, ^=, $=, *=)
717+
[~|^$*]? # Optional operator prefix (~, |, ^, $, *)
718+
= # Equal sign (=)
719+
)
720+
\s* # Optional whitespace after operator
721+
(?: # Attribute value
722+
( # Group 4: double quoted value
723+
(") # Group 5: opening double quote
724+
(?:\\.|""|[^"\\])* # Value is 0 or more non-double-quote characters, escaped characters or escaped double quotes ("")
725+
(") # Group 6: closing double quote
726+
)
727+
|( # Group 7: single quoted value
728+
(') # Group 8: opening single quote
729+
(?:\\.|[^'\\])* # Value is 0 or more non-single-quote characters or escaped characters
730+
(') # Group 9: closing single quote
731+
)
732+
|( # Group 10: unquoted value
733+
[^\]\s]+ # Value is 1 or more non-whitespace, non-] characters
734+
)
735+
)
736+
\s* # Optional whitespace after value
737+
([is])? # Group 11: optional flags i or s
738+
)?
739+
\s* # Optional whitespace after operator + value + flag
740+
(\]) # Group 12: Closing bracket (])
741+
captures:
742+
"1":
743+
name: punctuation.definition.entity.begin.bracket.square.css
744+
"2":
745+
name: entity.other.attribute-name.css
746+
"3":
747+
name: keyword.operator.pattern.css
748+
"4":
749+
name: string.quoted.double.css
750+
"5":
751+
name: punctuation.definition.string.begin.css
752+
"6":
753+
name: punctuation.definition.string.end.css
754+
"7":
755+
name: string.quoted.single.css
756+
"8":
757+
name: punctuation.definition.string.begin.css
758+
"9":
759+
name: punctuation.definition.string.end.css
760+
"10":
761+
name: string.unquoted.attribute-value.css
762+
"11":
763+
name: keyword.other.flag.css
764+
"12":
765+
name: punctuation.definition.entity.end.bracket.square.css
766+
name: meta.attribute-selector.css
767+
768+
# Pseudo-element selector with double colon (::)
769+
- match: |-
770+
(?x)
771+
(::) # Group 1: Prefix (::)
772+
(?: # Pseudo-element name
773+
-? # Optional leading hyphen
774+
[A-Za-z_] # Followed by letter or underscore
775+
[A-Za-z0-9_-]* # Followed by letters, digits, underscores, hyphens
776+
)
777+
captures:
778+
"1":
779+
name: punctuation.definition.entity.css
780+
name: entity.other.attribute-name.pseudo-element.css
781+
782+
# Pseudo-class selector and pseudo-element selector with single colon (:)
783+
- match: |-
784+
(?x)
785+
(:) # Group 1: Prefix (:)
786+
(?: # Pseudo-class or pseudo-element name
787+
-? # Optional leading hyphen
788+
[A-Za-z_] # Followed by letter or underscore
789+
[A-Za-z0-9_-]* # Followed by letters, digits, underscores, hyphens
790+
)
791+
(?: # Optional function part
792+
(\() # Group 2: Opening parenthesis
793+
(?: # Function arguments
794+
(?: # Double quoted value
795+
\s* # Optional whitespace after opening parenthesis
796+
( # Group 3: double quoted value
797+
(") # Group 4: opening double quote
798+
(?:\\.|[^"\\])* # Value is 0 or more non-double-quote characters or escaped characters
799+
(") # Group 5: closing double quote
800+
)
801+
\s* # Optional whitespace after double quoted value
802+
)
803+
|(?: # Single quoted value
804+
\s* # Optional whitespace after opening parenthesis
805+
( # Group 6: single quoted value
806+
(') # Group 7: opening single quote
807+
(?:\\.|[^'\\])* # Value is 0 or more non-single-quote characters or escaped characters
808+
(') # Group 8: closing single quote
809+
)
810+
\s* # Optional whitespace after single quoted value
811+
)
812+
|(?: # Regexp value
813+
\s* # Optional whitespace after opening parenthesis
814+
( # Group 9: regexp value
815+
(\/) # Group 10: opening slash
816+
(?:\\.|[^/\\])* # Value is 0 or more non-slash or escaped characters
817+
(\/) # Group 11: closing slash
818+
([dgimsuy]*) # Group 12: optional flags
819+
)
820+
\s* # Optional whitespace after regexp value
821+
)
822+
|( # Group 13: unquoted value
823+
[^\)]+ # Value is 1 or more non-) characters
824+
)
825+
)?
826+
(\)) # Group 14: Closing parenthesis
827+
)?
828+
captures:
829+
"1":
830+
name: punctuation.definition.entity.css
831+
"2":
832+
name: punctuation.section.function.begin.bracket.round.css
833+
"3":
834+
name: string.quoted.double.css
835+
"4":
836+
name: punctuation.definition.string.begin.css
837+
"5":
838+
name: punctuation.definition.string.end.css
839+
"6":
840+
name: string.quoted.single.css
841+
"7":
842+
name: punctuation.definition.string.begin.css
843+
"8":
844+
name: punctuation.definition.string.end.css
845+
"9":
846+
name: string.regexp.js
847+
"10":
848+
name: punctuation.definition.string.begin.js
849+
"11":
850+
name: punctuation.definition.string.end.js
851+
"12":
852+
name: keyword.other.regex
853+
"13":
854+
name: constant.numeric.css
855+
"14":
856+
name: punctuation.section.function.end.bracket.round.css
857+
name: entity.other.attribute-name.pseudo-class.css
858+
859+
# Combinators (>, +, ~)
860+
- match: |-
861+
(?x)
862+
\s* # Optional leading whitespace
863+
([>+~]) # Group 1: Combinator character (>, +, ~)
864+
\s* # Optional trailing whitespace
865+
captures:
866+
"1":
867+
name: keyword.operator.combinator.css
868+
869+
# Descendant combinator (whitespace)
870+
- match: |-
871+
(?x)
872+
(\s+) # Group 1: One or more whitespace characters
873+
captures:
874+
"1":
875+
name: keyword.operator.combinator.css
876+
877+
# Grouping combinator (,)
878+
- match: |-
879+
(?x)
880+
\s* # Optional leading whitespace
881+
(\,) # Group 1: Combinator character (,)
882+
\s* # Optional trailing whitespace
883+
captures:
884+
"1":
885+
name: punctuation.separator.list.comma.css
886+
887+
# Anything else is invalid
888+
- match: ".*"
889+
name: invalid.illegal.adblock
890+
680891
domainListCommaSeparated:
681892
patterns:
682893
- match: "(~?)([^,]+)(,?)"

0 commit comments

Comments
 (0)