From 245b59d4863d6138cddda626f5a7d902e4f1260d Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Mon, 4 Mar 2019 22:17:23 +0100 Subject: [PATCH] CSS: Highlight attribute selector (#1671) This adds highlighting for CSS attributes selectors in CSS Extras --- components/prism-css-extras.js | 32 ++- components/prism-css-extras.min.js | 2 +- .../selector_attribute_feature.test | 269 ++++++++++++++++++ .../css!+css-extras/selector_feature.test | 7 - 4 files changed, 301 insertions(+), 9 deletions(-) create mode 100644 tests/languages/css!+css-extras/selector_attribute_feature.test diff --git a/components/prism-css-extras.js b/components/prism-css-extras.js index cf06b57a16..6000210d59 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 d04698b231..436e552744 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 0000000000..25d1259f2b --- /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 3931a66334..475ed1b7c4 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", "{"] ]