Commit 245b59d4863d6138cddda626f5a7d902e4f1260d

Michael Schmidt 2019-03-04T22:17:23

CSS: Highlight attribute selector (#1671) This adds highlighting for CSS attributes selectors in CSS Extras

diff --git a/components/prism-css-extras.js b/components/prism-css-extras.js
index cf06b57..6000210 100644
--- a/components/prism-css-extras.js
+++ b/components/prism-css-extras.js
@@ -5,7 +5,37 @@ Prism.languages.css.selector = {
 		'pseudo-class': /:[-\w]+(?:\(.*\))?/,
 		'class': /\.[-:.\w]+/,
 		'id': /#[-:.\w]+/,
-		'attribute': /\[[^\]]+\]/
+		'attribute': {
+			pattern: /\[(?:[^[\]"']|("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1)*\]/,
+			greedy: true,
+			inside: {
+				'punctuation': /^\[|\]$/,
+				'case-sensitivity': {
+					pattern: /(\s)[si]$/i,
+					lookbehind: true,
+					alias: 'keyword'
+				},
+				'namespace': {
+					pattern: /^(\s*)[-*\w\xA0-\uFFFF]*\|(?!=)/,
+					lookbehind: true,
+					inside: {
+						'punctuation': /\|$/
+					}
+				},
+				'attribute': {
+					pattern: /^(\s*)[-\w\xA0-\uFFFF]+/,
+					lookbehind: true
+				},
+				'value': [
+					/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,
+					{
+						pattern: /(=\s*)[-\w\xA0-\uFFFF]+(?=\s*$)/,
+						lookbehind: true
+					}
+				],
+				'operator': /[|~*^$]?=/
+			}
+		}
 	}
 };
 
diff --git a/components/prism-css-extras.min.js b/components/prism-css-extras.min.js
index d04698b..436e552 100644
--- a/components/prism-css-extras.min.js
+++ b/components/prism-css-extras.min.js
@@ -1 +1 @@
-Prism.languages.css.selector={pattern:Prism.languages.css.selector,inside:{"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/,"pseudo-class":/:[-\w]+(?:\(.*\))?/,"class":/\.[-:.\w]+/,id:/#[-:.\w]+/,attribute:/\[[^\]]+\]/}},Prism.languages.insertBefore("css","property",{variable:{pattern:/(^|[^-\w\xA0-\uFFFF])--[-_a-z\xA0-\uFFFF][-\w\xA0-\uFFFF]*/i,lookbehind:!0}}),Prism.languages.insertBefore("css","function",{operator:{pattern:/(\s)[+\-*\/](?=\s)/,lookbehind:!0},hexcode:/#[\da-f]{3,8}/i,entity:/\\[\da-f]{1,8}/i,unit:{pattern:/(\d)(?:%|[a-z]+)/,lookbehind:!0},number:/-?[\d.]+/});
\ No newline at end of file
+Prism.languages.css.selector={pattern:Prism.languages.css.selector,inside:{"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/,"pseudo-class":/:[-\w]+(?:\(.*\))?/,"class":/\.[-:.\w]+/,id:/#[-:.\w]+/,attribute:{pattern:/\[(?:[^[\]"']|("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1)*\]/,greedy:!0,inside:{punctuation:/^\[|\]$/,"case-sensitivity":{pattern:/(\s)[si]$/i,lookbehind:!0,alias:"keyword"},namespace:{pattern:/^(\s*)[-*\w\xA0-\uFFFF]*\|(?!=)/,lookbehind:!0,inside:{punctuation:/\|$/}},attribute:{pattern:/^(\s*)[-\w\xA0-\uFFFF]+/,lookbehind:!0},value:[/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,{pattern:/(=\s*)[-\w\xA0-\uFFFF]+(?=\s*$)/,lookbehind:!0}],operator:/[|~*^$]?=/}}}},Prism.languages.insertBefore("css","property",{variable:{pattern:/(^|[^-\w\xA0-\uFFFF])--[-_a-z\xA0-\uFFFF][-\w\xA0-\uFFFF]*/i,lookbehind:!0}}),Prism.languages.insertBefore("css","function",{operator:{pattern:/(\s)[+\-*\/](?=\s)/,lookbehind:!0},hexcode:/#[\da-f]{3,8}/i,entity:/\\[\da-f]{1,8}/i,unit:{pattern:/(\d)(?:%|[a-z]+)/,lookbehind:!0},number:/-?[\d.]+/});
\ No newline at end of file
diff --git a/tests/languages/css!+css-extras/selector_attribute_feature.test b/tests/languages/css!+css-extras/selector_attribute_feature.test
new file mode 100644
index 0000000..25d1259
--- /dev/null
+++ b/tests/languages/css!+css-extras/selector_attribute_feature.test
@@ -0,0 +1,269 @@
+[attr] {}
+
+[attr=val] {}
+[attr="val"] {}
+[attr='val'] {}
+[attr|=val] {}
+[attr~=val] {}
+[attr|=val] {}
+[attr^=val] {}
+[attr$=val] {}
+[attr*=val] {}
+
+[foo|attr][*|attr][|attr] {}
+[foo|attr|=val] {}
+
+[attr=val i] {}
+[attr="val" S] {}
+
+[ attr ] {}
+[ attr = val ] {}
+[ attr = val   i] {}
+
+[attr="i#m :not(a.class)"] {}
+
+----------------------------------------------------
+
+[
+	["selector", [
+		["attribute", [
+			["punctuation", "["],
+			["attribute", "attr"],
+			["punctuation", "]"]
+		]]
+	]],
+	["punctuation", "{"],
+	["punctuation", "}"],
+
+	["selector", [
+		["attribute", [
+			["punctuation", "["],
+			["attribute", "attr"],
+			["operator", "="],
+			["value", "val"],
+			["punctuation", "]"]
+		]]
+	]],
+	["punctuation", "{"],
+	["punctuation", "}"],
+
+	["selector", [
+		["attribute", [
+			["punctuation", "["],
+			["attribute", "attr"],
+			["operator", "="],
+			["value", "\"val\""],
+			["punctuation", "]"]
+		]]
+	]],
+	["punctuation", "{"],
+	["punctuation", "}"],
+
+	["selector", [
+		["attribute", [
+			["punctuation", "["],
+			["attribute", "attr"],
+			["operator", "="],
+			["value", "'val'"],
+			["punctuation", "]"]
+		]]
+	]],
+	["punctuation", "{"],
+	["punctuation", "}"],
+
+	["selector", [
+		["attribute", [
+			["punctuation", "["],
+			["attribute", "attr"],
+			["operator", "|="],
+			["value", "val"],
+			["punctuation", "]"]
+		]]
+	]],
+	["punctuation", "{"],
+	["punctuation", "}"],
+
+	["selector", [
+		["attribute", [
+			["punctuation", "["],
+			["attribute", "attr"],
+			["operator", "~="],
+			["value", "val"],
+			["punctuation", "]"]
+		]]
+	]],
+	["punctuation", "{"],
+	["punctuation", "}"],
+
+	["selector", [
+		["attribute", [
+			["punctuation", "["],
+			["attribute", "attr"],
+			["operator", "|="],
+			["value", "val"],
+			["punctuation", "]"]
+		]]
+	]],
+	["punctuation", "{"],
+	["punctuation", "}"],
+
+	["selector", [
+		["attribute", [
+			["punctuation", "["],
+			["attribute", "attr"],
+			["operator", "^="],
+			["value", "val"],
+			["punctuation", "]"]
+		]]
+	]],
+	["punctuation", "{"],
+	["punctuation", "}"],
+
+	["selector", [
+		["attribute", [
+			["punctuation", "["],
+			["attribute", "attr"],
+			["operator", "$="],
+			["value", "val"],
+			["punctuation", "]"]
+		]]
+	]],
+	["punctuation", "{"],
+	["punctuation", "}"],
+
+	["selector", [
+		["attribute", [
+			["punctuation", "["],
+			["attribute", "attr"],
+			["operator", "*="],
+			["value", "val"],
+			["punctuation", "]"]
+		]]
+	]],
+	["punctuation", "{"],
+	["punctuation", "}"],
+
+	["selector", [
+		["attribute", [
+			["punctuation", "["],
+			["namespace", [
+				"foo",
+				["punctuation", "|"]
+			]],
+			["attribute", "attr"],
+			["punctuation", "]"]
+		]],
+		["attribute", [
+			["punctuation", "["],
+			["namespace", [
+				"*",
+				["punctuation", "|"]
+			]],
+			["attribute", "attr"],
+			["punctuation", "]"]
+		]],
+		["attribute", [
+			["punctuation", "["],
+			["namespace", [
+				["punctuation", "|"]
+			]],
+			["attribute", "attr"],
+			["punctuation", "]"]
+		]]
+	]],
+	["punctuation", "{"],
+	["punctuation", "}"],
+
+	["selector", [
+		["attribute", [
+			["punctuation", "["],
+			["namespace", [
+				"foo",
+				["punctuation", "|"]
+			]],
+			["attribute", "attr"],
+			["operator", "|="],
+			["value", "val"],
+			["punctuation", "]"]
+		]]
+	]],
+	["punctuation", "{"],
+	["punctuation", "}"],
+
+	["selector", [
+		["attribute", [
+			["punctuation", "["],
+			["attribute", "attr"],
+			["operator", "="],
+			["value", "val"],
+			["case-sensitivity", "i"],
+			["punctuation", "]"]
+		]]
+	]],
+	["punctuation", "{"],
+	["punctuation", "}"],
+
+	["selector", [
+		["attribute", [
+			["punctuation", "["],
+			["attribute", "attr"],
+			["operator", "="],
+			["value", "\"val\""],
+			["case-sensitivity", "S"],
+			["punctuation", "]"]
+		]]
+	]],
+	["punctuation", "{"],
+	["punctuation", "}"],
+
+	["selector", [
+		["attribute", [
+			["punctuation", "["],
+			["attribute", "attr"],
+			["punctuation", "]"]
+		]]
+	]],
+	["punctuation", "{"],
+	["punctuation", "}"],
+
+	["selector", [
+		["attribute", [
+			["punctuation", "["],
+			["attribute", "attr"],
+			["operator", "="],
+			["value", "val"],
+			["punctuation", "]"]
+		]]
+	]],
+	["punctuation", "{"],
+	["punctuation", "}"],
+
+	["selector", [
+		["attribute", [
+			["punctuation", "["],
+			["attribute", "attr"],
+			["operator", "="],
+			["value", "val"],
+			["case-sensitivity", "i"],
+			["punctuation", "]"]
+		]]
+	]],
+	["punctuation", "{"],
+	["punctuation", "}"],
+
+	["selector", [
+		["attribute", [
+			["punctuation", "["],
+			["attribute", "attr"],
+			["operator", "="],
+			["value", "\"i#m :not(a.class)\""],
+			["punctuation", "]"]
+		]]
+	]],
+	["punctuation", "{"],
+	["punctuation", "}"]
+]
+
+----------------------------------------------------
+
+Checks for attributes inside selectors.
\ No newline at end of file
diff --git a/tests/languages/css!+css-extras/selector_feature.test b/tests/languages/css!+css-extras/selector_feature.test
index 3931a66..475ed1b 100644
--- a/tests/languages/css!+css-extras/selector_feature.test
+++ b/tests/languages/css!+css-extras/selector_feature.test
@@ -9,8 +9,6 @@ foo#bar {
 
 #foo > .bar:not(baz):after {
 
-div[foo="bar"] {
-
 ----------------------------------------------------
 
 [
@@ -45,11 +43,6 @@ div[foo="bar"] {
 		["class", ".bar"],
 		["pseudo-class", ":not(baz)"],
 		["pseudo-element", ":after"]
-	]], ["punctuation", "{"],
-
-	["selector", [
-		"div",
-		["attribute", "[foo=\"bar\"]"]
 	]], ["punctuation", "{"]
 ]