elements */
body :not(div):not(span) {
font-weight: bold;
}
/* Elements that are not `.crazy` or `.fancy` */
/* Note that this syntax is not well supported yet. */
body :not(.crazy, .fancy) {
font-family: sans-serif;
}
:nth-child(odd) { color: lime; }
:nth-child(even) { color: lime; }
:nth-child(4) { color: lime; }
:nth-child(4n) { color: lime; }
:nth-child(3n+4) { color: lime; }
:nth-child(-n+3) { color: lime; }
:nth-child(n+8):nth-child(-n+15) { color: lime; }
.first span:nth-child(2n+1),
.second span:nth-child(2n+1),
.third span:nth-of-type(2n+1) {
background-color: lime;
unknown-property: lime;
}
:root{
--foo: if(x > 5) this.width = 10; /* valid custom property, invalid in any normal property */
}
:root,
:root:lang(en) {--external-link: "external link";}
:root:lang(de) {--external-link: "externer Link";}
a[href^="http"]::after {content: " (" var(--external-link) ")"}
one { --foo: 10px; }
two { --bar: calc(var(--foo) + 10px); }
three { --foo: calc(var(--bar) + 10px); }
.foo {
--gap: 20;
margin-top: var(--gap)px; /*20 px*/
margin-top: calc(var(--gap) * 1px); /*20px*/
}
foo {
width: calc(50% -8px); /* invalid */
width: calc(50%- 8px); /* invalid */
width: calc(50% +8px); /* invalid */
width: calc(50%+ 8px); /* invalid */
width: calc(2px -var(--a)); /* invalid */
width: calc(50%*-8px);
width: calc(50% - 8px);
width: calc(50% + -8px);
width: calc(50% +(8px));
width: calc(2px -(var(--a)));
}
sweet-alert input:focus::-moz-placeholder {
-webkit-transition: opacity 0.3s 0.03s ease;
transition: opacity 0.3s 0.03s ease;
opacity: 0.5;
}
@font-feature-values Font One {
@styleset {
nice-style: 12;
}
}
@font-feature-values Font Two {
@styleset {
nice-style: 4;
}
}
@counter-style thumbs {
system: cyclic;
symbols: "\1F44D";
suffix: " ";
}
@font-face {
font-family: "Open Sans";
src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2"),
url("/fonts/OpenSans-Regular-webfont.woff") format("woff");
}
@page {
margin: 1cm;
}
@page :first {
margin: 2cm;
/* comments */
marks: crop cross;
}
@page :unknown {
margin: 2cm;
}
@font-face {
unknown: 2px;
/* comments */
font-family: "Bitstream Vera Serif Bold";
src: url("/static/styles/libs/font-awesome/fonts/fontawesome-webfont.fdf491ce5ff5.woff");
}
@viewport {
zoom: 0.75;
/* comments */
min-zoom: 0.5;
max-zoom: 0.9;
}
@viewport {
orientation: landscape;
/* comments */
orientation: landscape;
}
@document url("https://www.example.com/") {
h1 {
color: green;
}
}
@supports (display: grid) {
div {
display: grid;
}
}
@media (max-width: 600px) {
.sidebar {
display: none;
}
}
@import url("fineprint.css") print;
@import url(fineprint.css) print;
@import url('bluish.css') speech;
@import 'custom.css';
@import url("chrome://communicator/skin/");
@import "common.css" screen;
@import url('landscape.css') screen and (orientation:landscape);
@namespace url(http://www.w3.org/1999/xhtml);
@namespace svg url(http://www.w3.org/2000/svg);
@keyframes important1 {
from { margin-top: 50px; }
50% { margin-top: 150px !important; } /* ignored */
to { margin-top: 100px; }
}
@keyframes important2 {
from { margin-top: 50px;
margin-bottom: 100px; }
to { margin-top: 150px !important; /* ignored */
margin-bottom: 50px; }
}
@keyframes slidein {
from {
margin-left: 100%;
width: 300%;
}
to {
margin-left: 0%;
width: 100%;
}
}
@media print {
a:hover { color: red }
/* comments */
a:hover { color: red }
}
/**
* SCSS https://sass-lang.com/documentation/file.SASS_REFERENCE.html
*/
#main p {
color: #00ff00;
width: 97%;
.redbox {
background-color: #ff0000;
color: #000000;
}
}
a {
font-weight: bold;
text-decoration: none;
&:hover { text-decoration: underline; }
body.firefox & { font-weight: normal; }
}
#main {
color: black;
a {
font-weight: bold;
&:hover { color: red; }
}
}
#main {
color: black;
&-sidebar { border: 1px solid; }
}
.funky {
font: {
family: fantasy;
size: 30em;
weight: bold;
}
}
.funky {
font: 20px/24px fantasy {
weight: bold;
}
}
/* This comment is
* several lines long.
* since it uses the CSS comment syntax,
* it will appear in the CSS output. */
body { color: black; }
// These comments are only one line long each.
// They won't appear in the CSS output,
// since they use the single-line comment syntax.
a { color: green; }
$version: "1.2.3";
/* This CSS is generated by My Snazzy Framework version #{$version}. */
$width: 5em;
#main {
width: $width;
}
#main {
$width: 5em !global;
width: $width;
}
#sidebar {
width: $width;
}
@mixin firefox-message($selector) {
body.firefox #{$selector}:before {
content: "Hi, Firefox users!";
}
}
@include firefox-message(".header");
$map: (key1: value1, key2: value2, key3: value3);
p {
font: 10px/8px; // Plain CSS, no division
$width: 1000px;
width: $width/2; // Uses a variable, does division
width: round(1.5)/2; // Uses a function, does division
height: (500px/2); // Uses parentheses, does division
margin-left: 5px + 8px/2px; // Uses +, does division
font: (italic bold 10px/8px); // In a list, parentheses don't count
}
p {
$font-size: 12px;
$line-height: 30px;
font: #{$font-size}/#{$line-height};
}
p {
color: #010203 + #040506;
color: rgba(255, 0, 0, 0.75) + rgba(0, 255, 0, 0.75);
}
$translucent-red: rgba(255, 0, 0, 0.5);
p {
color: opacify($translucent-red, 0.3);
background-color: transparentize($translucent-red, 0.25);
}
$translucent-red: rgba(255, 0, 0, 0.5);
$green: #00ff00;
div {
filter: progid:DXImageTransform.Microsoft.gradient(enabled='false', startColorstr='#{ie-hex-str($green)}', endColorstr='#{ie-hex-str($translucent-red)}');
}
p {
cursor: e + -resize;
}
p:before {
content: "Foo " + Bar;
font-family: sans- + "serif";
}
p:before {
content: "I ate #{5 + 10} pies!";
}
$value: null;
p:before {
content: "I ate #{$value} pies!";
}
p {
width: 1em + (2em * 3);
}
p {
color: hsl($hue: 0, $saturation: 100%, $lightness: 50%);
}
$name: foo;
$attr: border;
p.#{$name} {
#{$attr}-color: blue;
}
p {
$font-size: 12px;
$line-height: 30px;
font: #{$font-size}/#{$line-height};
}
.foo.bar .baz.bang, .bip.qux {
$selector: &;
}
@mixin does-parent-exist {
@if & {
&:hover {
color: red;
}
} @else {
a {
color: red;
}
}
}
$content: "First content";
$content: "Second content?" !default;
$new_content: "First time reference" !default;
#main {
content: $content;
new-content: $new_content;
}
@import "foo.css";
@import "foo" screen;
@import "http://foo.com/bar";
@import url(foo);
$family: unquote("Droid+Sans");
@import url("http://fonts.googleapis.com/css?family=#{$family}");
#main {
@import "example";
}
.sidebar {
width: 300px;
@media screen and (orientation: landscape) {
width: 500px;
}
}
@media screen {
.sidebar {
@media (orientation: landscape) {
width: 500px;
}
}
}
$media: screen;
$feature: -webkit-min-device-pixel-ratio;
$value: 1.5;
@media #{$media} and ($feature: $value) {
.sidebar {
width: 500px;
}
}
.error {
border: 1px #f00;
background-color: #fdd;
}
.seriousError {
@extend .error;
border-width: 3px;
}
.hoverlink {
@extend a:hover;
}
a:hover {
text-decoration: underline;
}
#context a%extreme a %extreme {
color: blue;
font-weight: bold;
font-size: 2em;
}
.notice {
@extend %extreme;
}
a.important {
@extend .notice !optional;
}
@media print {
.page {
width: 8in;
@at-root (without: media) {
color: red;
}
}
}
@debug 10em + 12em;
@mixin adjust-location($x, $y) {
@if unitless($x) {
@warn "Assuming #{$x} to be in pixels";
$x: 1px * $x;
}
@if unitless($y) {
@warn "Assuming #{$y} to be in pixels";
$y: 1px * $y;
}
position: relative; left: $x; top: $y;
}
@mixin adjust-location($x, $y) {
@if unitless($x) {
@error "$x may not be unitless, was #{$x}.";
}
@if unitless($y) {
@error "$y may not be unitless, was #{$y}.";
}
position: relative; left: $x; top: $y;
}
p {
@if 1 + 1 == 2 { border: 1px solid; }
@if 5 < 3 { border: 2px dotted; }
@if null { border: 3px double; }
}
$type: monster;
p {
@if $type == ocean {
color: blue;
} @else if $type == matador {
color: red;
} @else if $type == monster {
color: green;
} @else {
color: black;
}
}
@for $i from 1 through 3 {
.item-#{$i} { width: 2em * $i; }
}
@each $animal in puma, sea-slug, egret, salamander {
.#{$animal}-icon {
background-image: url('/images/#{$animal}.png');
}
}
@each $animal, $color, $cursor in (puma, black, default),
(sea-slug, blue, pointer),
(egret, white, move) {
.#{$animal}-icon {
background-image: url('/images/#{$animal}.png');
border: 2px solid $color;
cursor: $cursor;
}
}
@each $header, $size in (h1: 2em, h2: 1.5em, h3: 1.2em) {
#{$header} {
font-size: $size;
}
}
$i: 6;
@while $i > 0 {
.item-#{$i} { width: 2em * $i; }
$i: $i - 2;
}
@mixin large-text {
font: {
family: Arial;
size: 20px;
weight: bold;
}
color: #ff0000;
}
@mixin clearfix {
display: inline-block;
&:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
* html & { height: 1px }
}
.page-title {
@include large-text;
padding: 4px;
margin-top: 10px;
}
@mixin compound {
@include highlighted-background;
@include header-text;
}
@mixin highlighted-background { background-color: #fc0; }
@mixin header-text { font-size: 20px; }
@mixin sexy-border($color, $width) {
border: {
color: $color;
width: $width;
style: dashed;
}
}
p { @include sexy-border(blue, 1in); }
p { @include sexy-border($color: blue); }
h1 { @include sexy-border($color: blue, $width: 2in); }
@mixin colors($text, $background, $border) {
color: $text;
background-color: $background;
border-color: $border;
}
$values: #ff0000, #00ff00, #0000ff;
.primary {
@include colors($values...);
}
$value-map: (text: #00ff00, background: #0000ff, border: #ff0000);
.secondary {
@include colors($value-map...);
}
@mixin apply-to-ie6-only {
* html {
@content;
}
}
@include apply-to-ie6-only {
#logo {
background-image: url(/logo.gif);
}
}
$grid-width: 40px;
$gutter-width: 10px;
@function grid-width($n) {
@return $n * $grid-width + ($n - 1) * $gutter-width;
}
#sidebar { width: grid-width(5); }
+
+@mixin unify-parent($child) {
+ @at-root #{selector-unify(&, $child)} {
+ @content;
+ }
+}
+
+:root {
+ --font-family-sans-serif: #{inspect($font-family-sans-serif)};
+ --font-family-monospace: #{inspect($font-family-monospace)};
+}
+
+div {
+ background-image: url("/icons/#{$name}.svg");
+ font: #{"string"};
+}
diff --git a/autotests/html/highlight.scss.html b/autotests/html/highlight.scss.html
index ec36e31..baef4c2 100644
--- a/autotests/html/highlight.scss.html
+++ b/autotests/html/highlight.scss.html
@@ -1,700 +1,716 @@
highlight.scss
/**
* This is a pseudo SCSS file to test Kate's SCSS syntax highlighting.
*/
@import url("othersheet.css") screen, tv;
body {
font-size: 15pt;
font-family: Verdana, Helvetica, "Bitstream Vera Sans", sans-serif;
margin-top: 0px; /* yet another comment */
margin-bottom: 0px;
margin-left: 0px;
margin-right: 0px;
}
.something
{
margin-right: 0px;
color: #cdd;
color: #AAFE04;
color: rgb(10%,30%,43%);
background: maroon;
}
a:hover {
}
#header,
p.intro:first-letter,
p:lang(nl),
img[align="right"]
{
border: 1px solid Qt::red !important;
-moz-border-radius: 15px; /* unknown properties render italic */
}
@media print {
#header
{
display: none;
}
}
/*
TODO: add more tests, e.g. media
*/
.nice-look {
font-variant-alternates: styleset(nice-style);
}
ul {
list-style: thumbs;
}
/* SVG <a> */
svg|a {}
/* XHTML and SVG <a> */
*|a {}
*{}
.class{}
#id{}
:hover{}
:lang(fr){}
E{}
E F{}
E>F{}
E > F{}
E~F{}
E ~ F{}
E:first-child{}
E:visited{}
E::after{}
E:lang(c){}
E:lang(fr-ca){}
E + F{}
E+F{}
E[foo]{}
E[foo=warning]{}
E[foo="warning"]{}
E[foo~="warning"]{}
E[foo^="warning"]{}
E[foo$="warning"]{}
E[foo*="warning"]{}
E[lang|="en"]{}
DIV.warning{}
DIV .warning{}
E#myid{}
E #myid{}
E,E{}
E, E{}
E ,E{}
E , E{}
p:nth-child(2) {
background: red;
}
/* Elements that are not <div> or <span> elements */
body :not(div):not(span) {
font-weight: bold;
}
/* Elements that are not `.crazy` or `.fancy` */
/* Note that this syntax is not well supported yet. */
body :not(.crazy, .fancy) {
font-family: sans-serif;
}
:nth-child(odd) { color: lime; }
:nth-child(even) { color: lime; }
:nth-child(4) { color: lime; }
:nth-child(4n) { color: lime; }
:nth-child(3n+4) { color: lime; }
:nth-child(-n+3) { color: lime; }
:nth-child(n+8):nth-child(-n+15) { color: lime; }
.first span:nth-child(2n+1),
.second span:nth-child(2n+1),
.third span:nth-of-type(2n+1) {
background-color: lime;
unknown-property: lime;
}
:root{
--foo: if(x > 5) this.width = 10; /* valid custom property, invalid in any normal property */
}
:root,
:root:lang(en) {--external-link: "external link";}
:root:lang(de) {--external-link: "externer Link";}
a[href^="http"]::after {content: " (" var(--external-link) ")"}
one { --foo: 10px; }
two { --bar: calc(var(--foo) + 10px); }
three { --foo: calc(var(--bar) + 10px); }
.foo {
--gap: 20;
margin-top: var(--gap)px; /*20 px*/
margin-top: calc(var(--gap) * 1px); /*20px*/
}
foo {
width: calc(50% -8px); /* invalid */
width: calc(50%- 8px); /* invalid */
width: calc(50% +8px); /* invalid */
width: calc(50%+ 8px); /* invalid */
width: calc(2px -var(--a)); /* invalid */
width: calc(50%*-8px);
width: calc(50% - 8px);
width: calc(50% + -8px);
width: calc(50% +(8px));
width: calc(2px -(var(--a)));
}
sweet-alert input:focus::-moz-placeholder {
-webkit-transition: opacity 0.3s 0.03s ease;
transition: opacity 0.3s 0.03s ease;
opacity: 0.5;
}
@font-feature-values Font One {
@styleset {
nice-style: 12;
}
}
@font-feature-values Font Two {
@styleset {
nice-style: 4;
}
}
@counter-style thumbs {
system: cyclic;
symbols: "\1F44D";
suffix: " ";
}
@font-face {
font-family: "Open Sans";
src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2"),
url("/fonts/OpenSans-Regular-webfont.woff") format("woff");
}
@page {
margin: 1cm;
}
@page :first {
margin: 2cm;
/* comments */
marks: crop cross;
}
@page :unknown {
margin: 2cm;
}
@font-face {
unknown: 2px;
/* comments */
font-family: "Bitstream Vera Serif Bold";
src: url("/static/styles/libs/font-awesome/fonts/fontawesome-webfont.fdf491ce5ff5.woff");
}
@viewport {
zoom: 0.75;
/* comments */
min-zoom: 0.5;
max-zoom: 0.9;
}
@viewport {
orientation: landscape;
/* comments */
orientation: landscape;
}
@document url("https://www.example.com/") {
h1 {
color: green;
}
}
@supports (display: grid) {
div {
display: grid;
}
}
@media (max-width: 600px) {
.sidebar {
display: none;
}
}
@import url("fineprint.css") print;
@import url(fineprint.css) print;
@import url('bluish.css') speech;
@import 'custom.css';
@import url("chrome://communicator/skin/");
@import "common.css" screen;
@import url('landscape.css') screen and (orientation:landscape);
@namespace url(http://www.w3.org/1999/xhtml);
@namespace svg url(http://www.w3.org/2000/svg);
@keyframes important1 {
from { margin-top: 50px; }
50% { margin-top: 150px !important; } /* ignored */
to { margin-top: 100px; }
}
@keyframes important2 {
from { margin-top: 50px;
margin-bottom: 100px; }
to { margin-top: 150px !important; /* ignored */
margin-bottom: 50px; }
}
@keyframes slidein {
from {
margin-left: 100%;
width: 300%;
}
to {
margin-left: 0%;
width: 100%;
}
}
@media print {
a:hover { color: red }
/* comments */
a:hover { color: red }
}
/**
* SCSS https://sass-lang.com/documentation/file.SASS_REFERENCE.html
*/
#main p {
color: #00ff00;
width: 97%;
.redbox {
background-color: #ff0000;
color: #000000;
}
}
a {
font-weight: bold;
text-decoration: none;
&:hover { text-decoration: underline; }
body.firefox & { font-weight: normal; }
}
#main {
color: black;
a {
font-weight: bold;
&:hover { color: red; }
}
}
#main {
color: black;
&-sidebar { border: 1px solid; }
}
.funky {
font: {
family: fantasy;
size: 30em;
weight: bold;
}
}
.funky {
font: 20px/24px fantasy {
weight: bold;
}
}
/* This comment is
* several lines long.
* since it uses the CSS comment syntax,
* it will appear in the CSS output. */
body { color: black; }
// These comments are only one line long each.
// They won't appear in the CSS output,
// since they use the single-line comment syntax.
a { color: green; }
$version: "1.2.3";
/* This CSS is generated by My Snazzy Framework version #{$version}. */
$width: 5em;
#main {
width: $width;
}
#main {
$width: 5em !global;
width: $width;
}
#sidebar {
width: $width;
}
@mixin firefox-message($selector) {
- body.firefox #{$selector}:before {
+ body.firefox #{$selector}:before {
content: "Hi, Firefox users!";
}
}
@include firefox-message(".header");
$map: (key1: value1, key2: value2, key3: value3);
p {
font: 10px/8px; // Plain CSS, no division
$width: 1000px;
width: $width/2; // Uses a variable, does division
width: round(1.5)/2; // Uses a function, does division
height: (500px/2); // Uses parentheses, does division
margin-left: 5px + 8px/2px; // Uses +, does division
font: (italic bold 10px/8px); // In a list, parentheses don't count
}
p {
$font-size: 12px;
$line-height: 30px;
- font: #{$font-size}/#{$line-height};
+ font: #{$font-size}/#{$line-height};
}
p {
color: #010203 + #040506;
color: rgba(255, 0, 0, 0.75) + rgba(0, 255, 0, 0.75);
}
$translucent-red: rgba(255, 0, 0, 0.5);
p {
color: opacify($translucent-red, 0.3);
background-color: transparentize($translucent-red, 0.25);
}
$translucent-red: rgba(255, 0, 0, 0.5);
$green: #00ff00;
div {
- filter: progid:DXImageTransform.Microsoft.gradient(enabled='false', startColorstr='#{ie-hex-str($green)}', endColorstr='#{ie-hex-str($translucent-red)}');
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled='false', startColorstr='#{ie-hex-str($green)}', endColorstr='#{ie-hex-str($translucent-red)}');
}
p {
cursor: e + -resize;
}
p:before {
content: "Foo " + Bar;
font-family: sans- + "serif";
}
p:before {
- content: "I ate #{5 + 10} pies!";
+ content: "I ate #{5 + 10} pies!";
}
$value: null;
p:before {
- content: "I ate #{$value} pies!";
+ content: "I ate #{$value} pies!";
}
p {
width: 1em + (2em * 3);
}
p {
color: hsl($hue: 0, $saturation: 100%, $lightness: 50%);
}
$name: foo;
$attr: border;
-p.#{$name} {
- #{$attr}-color: blue;
+p.#{$name} {
+ #{$attr}-color: blue;
}
p {
$font-size: 12px;
$line-height: 30px;
- font: #{$font-size}/#{$line-height};
+ font: #{$font-size}/#{$line-height};
}
.foo.bar .baz.bang, .bip.qux {
$selector: &;
}
@mixin does-parent-exist {
@if & {
&:hover {
color: red;
}
} @else {
a {
color: red;
}
}
}
$content: "First content";
$content: "Second content?" !default;
$new_content: "First time reference" !default;
#main {
content: $content;
new-content: $new_content;
}
@import "foo.css";
@import "foo" screen;
@import "http://foo.com/bar";
@import url(foo);
$family: unquote("Droid+Sans");
-@import url("http://fonts.googleapis.com/css?family=#{$family}");
+@import url("http://fonts.googleapis.com/css?family=#{$family}");
#main {
@import "example";
}
.sidebar {
width: 300px;
@media screen and (orientation: landscape) {
width: 500px;
}
}
@media screen {
.sidebar {
@media (orientation: landscape) {
width: 500px;
}
}
}
$media: screen;
$feature: -webkit-min-device-pixel-ratio;
$value: 1.5;
-@media #{$media} and ($feature: $value) {
+@media #{$media} and ($feature: $value) {
.sidebar {
width: 500px;
}
}
.error {
border: 1px #f00;
background-color: #fdd;
}
.seriousError {
@extend .error;
border-width: 3px;
}
.hoverlink {
@extend a:hover;
}
a:hover {
text-decoration: underline;
}
#context a%extreme a %extreme {
color: blue;
font-weight: bold;
font-size: 2em;
}
.notice {
@extend %extreme;
}
a.important {
@extend .notice !optional;
}
@media print {
.page {
width: 8in;
@at-root (without: media) {
color: red;
}
}
}
@debug 10em + 12em;
@mixin adjust-location($x, $y) {
@if unitless($x) {
- @warn "Assuming #{$x} to be in pixels";
+ @warn "Assuming #{$x} to be in pixels";
$x: 1px * $x;
}
@if unitless($y) {
- @warn "Assuming #{$y} to be in pixels";
+ @warn "Assuming #{$y} to be in pixels";
$y: 1px * $y;
}
position: relative; left: $x; top: $y;
}
@mixin adjust-location($x, $y) {
@if unitless($x) {
- @error "$x may not be unitless, was #{$x}.";
+ @error "$x may not be unitless, was #{$x}.";
}
@if unitless($y) {
- @error "$y may not be unitless, was #{$y}.";
+ @error "$y may not be unitless, was #{$y}.";
}
position: relative; left: $x; top: $y;
}
p {
@if 1 + 1 == 2 { border: 1px solid; }
@if 5 < 3 { border: 2px dotted; }
@if null { border: 3px double; }
}
$type: monster;
p {
@if $type == ocean {
color: blue;
} @else if $type == matador {
color: red;
} @else if $type == monster {
color: green;
} @else {
color: black;
}
}
@for $i from 1 through 3 {
- .item-#{$i} { width: 2em * $i; }
+ .item-#{$i} { width: 2em * $i; }
}
@each $animal in puma, sea-slug, egret, salamander {
- .#{$animal}-icon {
- background-image: url('/images/#{$animal}.png');
+ .#{$animal}-icon {
+ background-image: url('/images/#{$animal}.png');
}
}
@each $animal, $color, $cursor in (puma, black, default),
(sea-slug, blue, pointer),
(egret, white, move) {
- .#{$animal}-icon {
- background-image: url('/images/#{$animal}.png');
+ .#{$animal}-icon {
+ background-image: url('/images/#{$animal}.png');
border: 2px solid $color;
cursor: $cursor;
}
}
@each $header, $size in (h1: 2em, h2: 1.5em, h3: 1.2em) {
- #{$header} {
+ #{$header} {
font-size: $size;
}
}
$i: 6;
@while $i > 0 {
- .item-#{$i} { width: 2em * $i; }
+ .item-#{$i} { width: 2em * $i; }
$i: $i - 2;
}
@mixin large-text {
font: {
family: Arial;
size: 20px;
weight: bold;
}
color: #ff0000;
}
@mixin clearfix {
display: inline-block;
&:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
* html & { height: 1px }
}
.page-title {
@include large-text;
padding: 4px;
margin-top: 10px;
}
@mixin compound {
@include highlighted-background;
@include header-text;
}
@mixin highlighted-background { background-color: #fc0; }
@mixin header-text { font-size: 20px; }
@mixin sexy-border($color, $width) {
border: {
color: $color;
width: $width;
style: dashed;
}
}
p { @include sexy-border(blue, 1in); }
p { @include sexy-border($color: blue); }
h1 { @include sexy-border($color: blue, $width: 2in); }
@mixin colors($text, $background, $border) {
color: $text;
background-color: $background;
border-color: $border;
}
$values: #ff0000, #00ff00, #0000ff;
.primary {
@include colors($values...);
}
$value-map: (text: #00ff00, background: #0000ff, border: #ff0000);
.secondary {
@include colors($value-map...);
}
@mixin apply-to-ie6-only {
* html {
@content;
}
}
@include apply-to-ie6-only {
#logo {
background-image: url(/logo.gif);
}
}
$grid-width: 40px;
$gutter-width: 10px;
@function grid-width($n) {
@return $n * $grid-width + ($n - 1) * $gutter-width;
}
#sidebar { width: grid-width(5); }
+
+@mixin unify-parent($child) {
+ @at-root #{selector-unify(&, $child)} {
+ @content;
+ }
+}
+
+:root {
+ --font-family-sans-serif: #{inspect($font-family-sans-serif)};
+ --font-family-monospace: #{inspect($font-family-monospace)};
+}
+
+div {
+ background-image: url("/icons/#{$name}.svg");
+ font: #{"string"};
+}
diff --git a/autotests/html/review128925-2.scss.html b/autotests/html/review128925-2.scss.html
index 3c6d98e..1df3ba3 100644
--- a/autotests/html/review128925-2.scss.html
+++ b/autotests/html/review128925-2.scss.html
@@ -1,88 +1,88 @@
review128925-2.scss
/*
* SCSS Syntax Highlight Sample File (Complex)
*
* This file contains complex SCSS syntax that can test unexpected situations.
* It is NOT a valid SCSS file that can be compiled by SCSS preprocessors.
*
* @author Guo Yunhe guoyunhebrave@gmail.com
* @date 2016-09-16
*/
// Comments with special content
// .class-selector #id "string" 'comment' // comment {} [] () /* comment */ text
/*
* .class-selector #id "string" 'comment' // comment {} [] () /* comment
* TODO BUG DEBUG
* body {
* margin: 0 !important;
* }
*/
// Comments in special positions
$color: black /* comment here */;
header/* comment here */.active /* comment here */ {
/* comment here */ color : /* comment here */ blue/* comment here */;
font-family: Arial /* comment here */,
"Droid Sans", /* comment here */
sans-serif/* comment here */;
}
@media screen /* comment here */ and (max-width: 300px /* comment here */) /* comment here */ {/* comment here */}
// Strings with special content
@import "{} $variable /* comment */";
@import "{}";
// Without extra breaklines and spaces
pre.primary:hover.large:nth-child(2n-1){font-size:$default-font-size;font-family:"Noto Sans";-webkit-box-shadow:1px 1px 3px rgba(0,0,0,0.3)}
// With unnecessary breaklines and spaces
blockquote .ref
{
flex : 0 1 30%;
flex-wrap : wrap;
}
.sidebar {
width: 300px; }
@media screen and (orientation: landscape) {
.sidebar {
width: 500px; } }
// Variable interpolation: #{}
$name: foo;
$attr: border;
-p.#{$name} {
- #{$attr}-color: blue;
+p.#{$name} {
+ #{$attr}-color: blue;
}
p {
$font-size: 12px;
$line-height: 30px;
- font: #{$font-size}/#{$line-height};
+ font: #{$font-size}/#{$line-height};
}
// Special selectors: HTML5 allows user defined tags
header {
flex {
width: 300px;
}
}
diff --git a/autotests/input/highlight.scss b/autotests/input/highlight.scss
index 11a4028..aa5b386 100644
--- a/autotests/input/highlight.scss
+++ b/autotests/input/highlight.scss
@@ -1,693 +1,709 @@
/**
* This is a pseudo SCSS file to test Kate's SCSS syntax highlighting.
*/
@import url("othersheet.css") screen, tv;
body {
font-size: 15pt;
font-family: Verdana, Helvetica, "Bitstream Vera Sans", sans-serif;
margin-top: 0px; /* yet another comment */
margin-bottom: 0px;
margin-left: 0px;
margin-right: 0px;
}
.something
{
margin-right: 0px;
color: #cdd;
color: #AAFE04;
color: rgb(10%,30%,43%);
background: maroon;
}
a:hover {
}
#header,
p.intro:first-letter,
p:lang(nl),
img[align="right"]
{
border: 1px solid Qt::red !important;
-moz-border-radius: 15px; /* unknown properties render italic */
}
@media print {
#header
{
display: none;
}
}
/*
TODO: add more tests, e.g. media
*/
.nice-look {
font-variant-alternates: styleset(nice-style);
}
ul {
list-style: thumbs;
}
/* SVG */
svg|a {}
/* XHTML and SVG */
*|a {}
*{}
.class{}
#id{}
:hover{}
:lang(fr){}
E{}
E F{}
E>F{}
E > F{}
E~F{}
E ~ F{}
E:first-child{}
E:visited{}
E::after{}
E:lang(c){}
E:lang(fr-ca){}
E + F{}
E+F{}
E[foo]{}
E[foo=warning]{}
E[foo="warning"]{}
E[foo~="warning"]{}
E[foo^="warning"]{}
E[foo$="warning"]{}
E[foo*="warning"]{}
E[lang|="en"]{}
DIV.warning{}
DIV .warning{}
E#myid{}
E #myid{}
E,E{}
E, E{}
E ,E{}
E , E{}
p:nth-child(2) {
background: red;
}
/* Elements that are not or
elements */
body :not(div):not(span) {
font-weight: bold;
}
/* Elements that are not `.crazy` or `.fancy` */
/* Note that this syntax is not well supported yet. */
body :not(.crazy, .fancy) {
font-family: sans-serif;
}
:nth-child(odd) { color: lime; }
:nth-child(even) { color: lime; }
:nth-child(4) { color: lime; }
:nth-child(4n) { color: lime; }
:nth-child(3n+4) { color: lime; }
:nth-child(-n+3) { color: lime; }
:nth-child(n+8):nth-child(-n+15) { color: lime; }
.first span:nth-child(2n+1),
.second span:nth-child(2n+1),
.third span:nth-of-type(2n+1) {
background-color: lime;
unknown-property: lime;
}
:root{
--foo: if(x > 5) this.width = 10; /* valid custom property, invalid in any normal property */
}
:root,
:root:lang(en) {--external-link: "external link";}
:root:lang(de) {--external-link: "externer Link";}
a[href^="http"]::after {content: " (" var(--external-link) ")"}
one { --foo: 10px; }
two { --bar: calc(var(--foo) + 10px); }
three { --foo: calc(var(--bar) + 10px); }
.foo {
--gap: 20;
margin-top: var(--gap)px; /*20 px*/
margin-top: calc(var(--gap) * 1px); /*20px*/
}
foo {
width: calc(50% -8px); /* invalid */
width: calc(50%- 8px); /* invalid */
width: calc(50% +8px); /* invalid */
width: calc(50%+ 8px); /* invalid */
width: calc(2px -var(--a)); /* invalid */
width: calc(50%*-8px);
width: calc(50% - 8px);
width: calc(50% + -8px);
width: calc(50% +(8px));
width: calc(2px -(var(--a)));
}
sweet-alert input:focus::-moz-placeholder {
-webkit-transition: opacity 0.3s 0.03s ease;
transition: opacity 0.3s 0.03s ease;
opacity: 0.5;
}
@font-feature-values Font One {
@styleset {
nice-style: 12;
}
}
@font-feature-values Font Two {
@styleset {
nice-style: 4;
}
}
@counter-style thumbs {
system: cyclic;
symbols: "\1F44D";
suffix: " ";
}
@font-face {
font-family: "Open Sans";
src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2"),
url("/fonts/OpenSans-Regular-webfont.woff") format("woff");
}
@page {
margin: 1cm;
}
@page :first {
margin: 2cm;
/* comments */
marks: crop cross;
}
@page :unknown {
margin: 2cm;
}
@font-face {
unknown: 2px;
/* comments */
font-family: "Bitstream Vera Serif Bold";
src: url("/static/styles/libs/font-awesome/fonts/fontawesome-webfont.fdf491ce5ff5.woff");
}
@viewport {
zoom: 0.75;
/* comments */
min-zoom: 0.5;
max-zoom: 0.9;
}
@viewport {
orientation: landscape;
/* comments */
orientation: landscape;
}
@document url("https://www.example.com/") {
h1 {
color: green;
}
}
@supports (display: grid) {
div {
display: grid;
}
}
@media (max-width: 600px) {
.sidebar {
display: none;
}
}
@import url("fineprint.css") print;
@import url(fineprint.css) print;
@import url('bluish.css') speech;
@import 'custom.css';
@import url("chrome://communicator/skin/");
@import "common.css" screen;
@import url('landscape.css') screen and (orientation:landscape);
@namespace url(http://www.w3.org/1999/xhtml);
@namespace svg url(http://www.w3.org/2000/svg);
@keyframes important1 {
from { margin-top: 50px; }
50% { margin-top: 150px !important; } /* ignored */
to { margin-top: 100px; }
}
@keyframes important2 {
from { margin-top: 50px;
margin-bottom: 100px; }
to { margin-top: 150px !important; /* ignored */
margin-bottom: 50px; }
}
@keyframes slidein {
from {
margin-left: 100%;
width: 300%;
}
to {
margin-left: 0%;
width: 100%;
}
}
@media print {
a:hover { color: red }
/* comments */
a:hover { color: red }
}
/**
* SCSS https://sass-lang.com/documentation/file.SASS_REFERENCE.html
*/
#main p {
color: #00ff00;
width: 97%;
.redbox {
background-color: #ff0000;
color: #000000;
}
}
a {
font-weight: bold;
text-decoration: none;
&:hover { text-decoration: underline; }
body.firefox & { font-weight: normal; }
}
#main {
color: black;
a {
font-weight: bold;
&:hover { color: red; }
}
}
#main {
color: black;
&-sidebar { border: 1px solid; }
}
.funky {
font: {
family: fantasy;
size: 30em;
weight: bold;
}
}
.funky {
font: 20px/24px fantasy {
weight: bold;
}
}
/* This comment is
* several lines long.
* since it uses the CSS comment syntax,
* it will appear in the CSS output. */
body { color: black; }
// These comments are only one line long each.
// They won't appear in the CSS output,
// since they use the single-line comment syntax.
a { color: green; }
$version: "1.2.3";
/* This CSS is generated by My Snazzy Framework version #{$version}. */
$width: 5em;
#main {
width: $width;
}
#main {
$width: 5em !global;
width: $width;
}
#sidebar {
width: $width;
}
@mixin firefox-message($selector) {
body.firefox #{$selector}:before {
content: "Hi, Firefox users!";
}
}
@include firefox-message(".header");
$map: (key1: value1, key2: value2, key3: value3);
p {
font: 10px/8px; // Plain CSS, no division
$width: 1000px;
width: $width/2; // Uses a variable, does division
width: round(1.5)/2; // Uses a function, does division
height: (500px/2); // Uses parentheses, does division
margin-left: 5px + 8px/2px; // Uses +, does division
font: (italic bold 10px/8px); // In a list, parentheses don't count
}
p {
$font-size: 12px;
$line-height: 30px;
font: #{$font-size}/#{$line-height};
}
p {
color: #010203 + #040506;
color: rgba(255, 0, 0, 0.75) + rgba(0, 255, 0, 0.75);
}
$translucent-red: rgba(255, 0, 0, 0.5);
p {
color: opacify($translucent-red, 0.3);
background-color: transparentize($translucent-red, 0.25);
}
$translucent-red: rgba(255, 0, 0, 0.5);
$green: #00ff00;
div {
filter: progid:DXImageTransform.Microsoft.gradient(enabled='false', startColorstr='#{ie-hex-str($green)}', endColorstr='#{ie-hex-str($translucent-red)}');
}
p {
cursor: e + -resize;
}
p:before {
content: "Foo " + Bar;
font-family: sans- + "serif";
}
p:before {
content: "I ate #{5 + 10} pies!";
}
$value: null;
p:before {
content: "I ate #{$value} pies!";
}
p {
width: 1em + (2em * 3);
}
p {
color: hsl($hue: 0, $saturation: 100%, $lightness: 50%);
}
$name: foo;
$attr: border;
p.#{$name} {
#{$attr}-color: blue;
}
p {
$font-size: 12px;
$line-height: 30px;
font: #{$font-size}/#{$line-height};
}
.foo.bar .baz.bang, .bip.qux {
$selector: &;
}
@mixin does-parent-exist {
@if & {
&:hover {
color: red;
}
} @else {
a {
color: red;
}
}
}
$content: "First content";
$content: "Second content?" !default;
$new_content: "First time reference" !default;
#main {
content: $content;
new-content: $new_content;
}
@import "foo.css";
@import "foo" screen;
@import "http://foo.com/bar";
@import url(foo);
$family: unquote("Droid+Sans");
@import url("http://fonts.googleapis.com/css?family=#{$family}");
#main {
@import "example";
}
.sidebar {
width: 300px;
@media screen and (orientation: landscape) {
width: 500px;
}
}
@media screen {
.sidebar {
@media (orientation: landscape) {
width: 500px;
}
}
}
$media: screen;
$feature: -webkit-min-device-pixel-ratio;
$value: 1.5;
@media #{$media} and ($feature: $value) {
.sidebar {
width: 500px;
}
}
.error {
border: 1px #f00;
background-color: #fdd;
}
.seriousError {
@extend .error;
border-width: 3px;
}
.hoverlink {
@extend a:hover;
}
a:hover {
text-decoration: underline;
}
#context a%extreme a %extreme {
color: blue;
font-weight: bold;
font-size: 2em;
}
.notice {
@extend %extreme;
}
a.important {
@extend .notice !optional;
}
@media print {
.page {
width: 8in;
@at-root (without: media) {
color: red;
}
}
}
@debug 10em + 12em;
@mixin adjust-location($x, $y) {
@if unitless($x) {
@warn "Assuming #{$x} to be in pixels";
$x: 1px * $x;
}
@if unitless($y) {
@warn "Assuming #{$y} to be in pixels";
$y: 1px * $y;
}
position: relative; left: $x; top: $y;
}
@mixin adjust-location($x, $y) {
@if unitless($x) {
@error "$x may not be unitless, was #{$x}.";
}
@if unitless($y) {
@error "$y may not be unitless, was #{$y}.";
}
position: relative; left: $x; top: $y;
}
p {
@if 1 + 1 == 2 { border: 1px solid; }
@if 5 < 3 { border: 2px dotted; }
@if null { border: 3px double; }
}
$type: monster;
p {
@if $type == ocean {
color: blue;
} @else if $type == matador {
color: red;
} @else if $type == monster {
color: green;
} @else {
color: black;
}
}
@for $i from 1 through 3 {
.item-#{$i} { width: 2em * $i; }
}
@each $animal in puma, sea-slug, egret, salamander {
.#{$animal}-icon {
background-image: url('/images/#{$animal}.png');
}
}
@each $animal, $color, $cursor in (puma, black, default),
(sea-slug, blue, pointer),
(egret, white, move) {
.#{$animal}-icon {
background-image: url('/images/#{$animal}.png');
border: 2px solid $color;
cursor: $cursor;
}
}
@each $header, $size in (h1: 2em, h2: 1.5em, h3: 1.2em) {
#{$header} {
font-size: $size;
}
}
$i: 6;
@while $i > 0 {
.item-#{$i} { width: 2em * $i; }
$i: $i - 2;
}
@mixin large-text {
font: {
family: Arial;
size: 20px;
weight: bold;
}
color: #ff0000;
}
@mixin clearfix {
display: inline-block;
&:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
* html & { height: 1px }
}
.page-title {
@include large-text;
padding: 4px;
margin-top: 10px;
}
@mixin compound {
@include highlighted-background;
@include header-text;
}
@mixin highlighted-background { background-color: #fc0; }
@mixin header-text { font-size: 20px; }
@mixin sexy-border($color, $width) {
border: {
color: $color;
width: $width;
style: dashed;
}
}
p { @include sexy-border(blue, 1in); }
p { @include sexy-border($color: blue); }
h1 { @include sexy-border($color: blue, $width: 2in); }
@mixin colors($text, $background, $border) {
color: $text;
background-color: $background;
border-color: $border;
}
$values: #ff0000, #00ff00, #0000ff;
.primary {
@include colors($values...);
}
$value-map: (text: #00ff00, background: #0000ff, border: #ff0000);
.secondary {
@include colors($value-map...);
}
@mixin apply-to-ie6-only {
* html {
@content;
}
}
@include apply-to-ie6-only {
#logo {
background-image: url(/logo.gif);
}
}
$grid-width: 40px;
$gutter-width: 10px;
@function grid-width($n) {
@return $n * $grid-width + ($n - 1) * $gutter-width;
}
#sidebar { width: grid-width(5); }
+
+@mixin unify-parent($child) {
+ @at-root #{selector-unify(&, $child)} {
+ @content;
+ }
+}
+
+:root {
+ --font-family-sans-serif: #{inspect($font-family-sans-serif)};
+ --font-family-monospace: #{inspect($font-family-monospace)};
+}
+
+div {
+ background-image: url("/icons/#{$name}.svg");
+ font: #{"string"};
+}
diff --git a/autotests/reference/highlight.scss.ref b/autotests/reference/highlight.scss.ref
index 081743f..ce0cd66 100644
--- a/autotests/reference/highlight.scss.ref
+++ b/autotests/reference/highlight.scss.ref
@@ -1,693 +1,709 @@
/**
* This is a pseudo SCSS file to test Kate's SCSS syntax highlighting.
*/
@import url("othersheet.css") screen, tv;
body {
font-size: 15pt;
font-family: Verdana, Helvetica, "Bitstream Vera Sans", sans-serif;
margin-top: 0px; /* yet another comment */
margin-bottom: 0px;
margin-left: 0px;
margin-right: 0px;
}
.something
{
margin-right: 0px;
color: #cdd;
color: #AAFE04;
color: rgb(10%,30%,43%);
background: maroon;
}
a:hover {
}
#header,
p.intro:first-letter,
p:lang(nl),
img[align="right"]
{
border: 1px solid Qt::red !important;
-moz-border-radius: 15px; /* unknown properties render italic */
}
@media print {
#header
{
display: none;
}
}
/*
TODO: add more tests, e.g. media
*/
.nice-look {
font-variant-alternates: styleset(nice-style);
}
ul {
list-style: thumbs;
}
/* SVG */
svg|a {}
/* XHTML and SVG */
*|a {}
*{}
.class{}
#id{}
:hover{}
:lang(fr){}
E{}
E F{}
E>F{}
E > F{}
E~F{}
E ~ F{}
E:first-child{}
E:visited{}
E::after{}
E:lang(c){}
E:lang(fr-ca){}
E + F{}
E+F{}
E[foo]{}
E[foo=warning]{}
E[foo="warning"]{}
E[foo~="warning"]{}
E[foo^="warning"]{}
E[foo$="warning"]{}
E[foo*="warning"]{}
E[lang|="en"]{}
DIV.warning{}
DIV .warning{}
E#myid{}
E #myid{}
E,E{}
E, E{}
E ,E{}
E , E{}
p:nth-child(2) {
background: red;
}
/* Elements that are not or
elements */
body :not(div):not(span) {
font-weight: bold;
}
/* Elements that are not `.crazy` or `.fancy` */
/* Note that this syntax is not well supported yet. */
body :not(.crazy, .fancy) {
font-family: sans-serif;
}
:nth-child(odd) { color: lime; }
:nth-child(even) { color: lime; }
:nth-child(4) { color: lime; }
:nth-child(4n) { color: lime; }
:nth-child(3n+4) { color: lime; }
:nth-child(-n+3) { color: lime; }
:nth-child(n+8):nth-child(-n+15) { color: lime; }
.first span:nth-child(2n+1),
.second span:nth-child(2n+1),
.third span:nth-of-type(2n+1) {
background-color: lime;
unknown-property: lime;
}
:root{
--foo: if(x > 5) this.width = 10; /* valid custom property, invalid in any normal property */
}
:root,
:root:lang(en) {--external-link: "external link";}
:root:lang(de) {--external-link: "externer Link";}
a[href^="http"]::after {content: " (" var(--external-link) ")"}
one { --foo: 10px; }
two { --bar: calc(var(--foo) + 10px); }
three { --foo: calc(var(--bar) + 10px); }
.foo {
--gap: 20;
margin-top: var(--gap)px; /*20 px*/
margin-top: calc(var(--gap) * 1px); /*20px*/
}
foo {
width: calc(50% -8px); /* invalid */
width: calc(50%- 8px); /* invalid */
width: calc(50% +8px); /* invalid */
width: calc(50%+ 8px); /* invalid */
width: calc(2px -var(--a)); /* invalid */
width: calc(50%*-8px);
width: calc(50% - 8px);
width: calc(50% + -8px);
width: calc(50% +(8px));
width: calc(2px -(var(--a)));
}
sweet-alert input:focus::-moz-placeholder {
-webkit-transition: opacity 0.3s 0.03s ease;
transition: opacity 0.3s 0.03s ease;
opacity: 0.5;
}
@font-feature-values Font One {
@styleset {
nice-style: 12;
}
}
@font-feature-values Font Two {
@styleset {
nice-style: 4;
}
}
@counter-style thumbs {
system: cyclic;
symbols: "\1F44D";
suffix: " ";
}
@font-face {
font-family: "Open Sans";
src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2"),
url("/fonts/OpenSans-Regular-webfont.woff") format("woff");
}
@page {
margin: 1cm;
}
@page :first {
margin: 2cm;
/* comments */
marks: crop cross;
}
@page :unknown {
margin: 2cm;
}
@font-face {
unknown: 2px;
/* comments */
font-family: "Bitstream Vera Serif Bold";
src: url("/static/styles/libs/font-awesome/fonts/fontawesome-webfont.fdf491ce5ff5.woff");
}
@viewport {
zoom: 0.75;
/* comments */
min-zoom: 0.5;
max-zoom: 0.9;
}
@viewport {
orientation: landscape;
/* comments */
orientation: landscape;
}
@document url("https://www.example.com/") {
h1 {
color: green;
}
}
@supports (display: grid) {
div {
display: grid;
}
}
@media (max-width: 600px) {
.sidebar {
display: none;
}
}
@import url("fineprint.css") print;
@import url(fineprint.css) print;
@import url('bluish.css') speech;
@import 'custom.css';
@import url("chrome://communicator/skin/");
@import "common.css" screen;
@import url('landscape.css') screen and (orientation:landscape);
@namespace url(http://www.w3.org/1999/xhtml);
@namespace svg url(http://www.w3.org/2000/svg);
@keyframes important1 {
from { margin-top: 50px; }
50% { margin-top: 150px !important; } /* ignored */
to { margin-top: 100px; }
}
@keyframes important2 {
from { margin-top: 50px;
margin-bottom: 100px; }
to { margin-top: 150px !important; /* ignored */
margin-bottom: 50px; }
}
@keyframes slidein {
from {
margin-left: 100%;
width: 300%;
}
to {
margin-left: 0%;
width: 100%;
}
}
@media print {
a:hover { color: red }
/* comments */
a:hover { color: red }
}
/**
* SCSS https://sass-lang.com/documentation/file.SASS_REFERENCE.html
*/
#main p {
color: #00ff00;
width: 97%;
.redbox {
background-color: #ff0000;
color: #000000;
}
}
a {
font-weight: bold;
text-decoration: none;
&:hover { text-decoration: underline; }
body.firefox & { font-weight: normal; }
}
#main {
color: black;
a {
font-weight: bold;
&:hover { color: red; }
}
}
#main {
color: black;
&-sidebar { border: 1px solid; }
}
.funky {
font: {
family: fantasy;
size: 30em;
weight: bold;
}
}
.funky {
font: 20px/24px fantasy {
weight: bold;
}
}
/* This comment is
* several lines long.
* since it uses the CSS comment syntax,
* it will appear in the CSS output. */
body { color: black; }
// These comments are only one line long each.
// They won't appear in the CSS output,
// since they use the single-line comment syntax.
a { color: green; }
$version: "1.2.3";
/* This CSS is generated by My Snazzy Framework version #{$version}. */
$width: 5em;
#main {
width: $width;
}
#main {
$width: 5em !global;
width: $width;
}
#sidebar {
width: $width;
}
@mixin firefox-message($selector) {
- body.firefox #{$selector}:before {
+ body.firefox #{$selector}:before {
content: "Hi, Firefox users!";
}
}
@include firefox-message(".header");
$map: (key1: value1, key2: value2, key3: value3);
p {
font: 10px/8px; // Plain CSS, no division
$width: 1000px;
width: $width/2; // Uses a variable, does division
width: round(1.5)/2; // Uses a function, does division
height: (500px/2); // Uses parentheses, does division
margin-left: 5px + 8px/2px; // Uses +, does division
font: (italic bold 10px/8px); // In a list, parentheses don't count
}
p {
$font-size: 12px;
$line-height: 30px;
- font: #{$font-size}/#{$line-height};
+ font: #{$font-size}/#{$line-height};
}
p {
color: #010203 + #040506;
color: rgba(255, 0, 0, 0.75) + rgba(0, 255, 0, 0.75);
}
$translucent-red: rgba(255, 0, 0, 0.5);
p {
color: opacify($translucent-red, 0.3);
background-color: transparentize($translucent-red, 0.25);
}
$translucent-red: rgba(255, 0, 0, 0.5);
$green: #00ff00;
div {
- filter: progid:DXImageTransform.Microsoft.gradient(enabled='false', startColorstr='#{ie-hex-str($green)}', endColorstr='#{ie-hex-str($translucent-red)}');
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled='false', startColorstr='#{ie-hex-str($green)}', endColorstr='#{ie-hex-str($translucent-red)}');
}
p {
cursor: e + -resize;
}
p:before {
content: "Foo " + Bar;
font-family: sans- + "serif";
}
p:before {
- content: "I ate #{5 + 10} pies!";
+ content: "I ate #{5 + 10} pies!";
}
$value: null;
p:before {
- content: "I ate #{$value} pies!";
+ content: "I ate #{$value} pies!";
}
p {
width: 1em + (2em * 3);
}
p {
color: hsl($hue: 0, $saturation: 100%, $lightness: 50%);
}
$name: foo;
$attr: border;
-p.#{$name} {
- #{$attr}-color: blue;
+p.#{$name} {
+ #{$attr}-color: blue;
}
p {
$font-size: 12px;
$line-height: 30px;
- font: #{$font-size}/#{$line-height};
+ font: #{$font-size}/#{$line-height};
}
.foo.bar .baz.bang, .bip.qux {
$selector: &;
}
@mixin does-parent-exist {
@if & {
&:hover {
color: red;
}
} @else {
a {
color: red;
}
}
}
$content: "First content";
$content: "Second content?" !default;
$new_content: "First time reference" !default;
#main {
content: $content;
new-content: $new_content;
}
@import "foo.css";
@import "foo" screen;
@import "http://foo.com/bar";
@import url(foo);
$family: unquote("Droid+Sans");
-@import url("http://fonts.googleapis.com/css?family=#{$family}");
+@import url("http://fonts.googleapis.com/css?family=#{$family}");
#main {
@import "example";
}
.sidebar {
width: 300px;
@media screen and (orientation: landscape) {
width: 500px;
}
}
@media screen {
.sidebar {
@media (orientation: landscape) {
width: 500px;
}
}
}
$media: screen;
$feature: -webkit-min-device-pixel-ratio;
$value: 1.5;
-@media #{$media} and ($feature: $value) {
+@media #{$media} and ($feature: $value) {
.sidebar {
width: 500px;
}
}
.error {
border: 1px #f00;
background-color: #fdd;
}
.seriousError {
@extend .error;
border-width: 3px;
}
.hoverlink {
@extend a:hover;
}
a:hover {
text-decoration: underline;
}
#context a%extreme a %extreme {
color: blue;
font-weight: bold;
font-size: 2em;
}
.notice {
@extend %extreme;
}
a.important {
@extend .notice !optional;
}
@media print {
.page {
width: 8in;
@at-root (without: media) {
color: red;
}
}
}
@debug 10em + 12em;
@mixin adjust-location($x, $y) {
@if unitless($x) {
- @warn "Assuming #{$x} to be in pixels";
+ @warn "Assuming #{$x} to be in pixels";
$x: 1px * $x;
}
@if unitless($y) {
- @warn "Assuming #{$y} to be in pixels";
+ @warn "Assuming #{$y} to be in pixels";
$y: 1px * $y;
}
position: relative; left: $x; top: $y;
}
@mixin adjust-location($x, $y) {
@if unitless($x) {
- @error "$x may not be unitless, was #{$x}.";
+ @error "$x may not be unitless, was #{$x}.";
}
@if unitless($y) {
- @error "$y may not be unitless, was #{$y}.";
+ @error "$y may not be unitless, was #{$y}.";
}
position: relative; left: $x; top: $y;
}
p {
@if 1 + 1 == 2 { border: 1px solid; }
@if 5 < 3 { border: 2px dotted; }
@if null { border: 3px double; }
}
$type: monster;
p {
@if $type == ocean {
color: blue;
} @else if $type == matador {
color: red;
} @else if $type == monster {
color: green;
} @else {
color: black;
}
}
@for $i from 1 through 3 {
- .item-#{$i} { width: 2em * $i; }
+ .item-#{$i} { width: 2em * $i; }
}
@each $animal in puma, sea-slug, egret, salamander {
- .#{$animal}-icon {
- background-image: url('/images/#{$animal}.png');
+ .#{$animal}-icon {
+ background-image: url('/images/#{$animal}.png');
}
}
@each $animal, $color, $cursor in (puma, black, default),
(sea-slug, blue, pointer),
(egret, white, move) {
- .#{$animal}-icon {
- background-image: url('/images/#{$animal}.png');
+ .#{$animal}-icon {
+ background-image: url('/images/#{$animal}.png');
border: 2px solid $color;
cursor: $cursor;
}
}
@each $header, $size in (h1: 2em, h2: 1.5em, h3: 1.2em) {
- #{$header} {
+ #{$header} {
font-size: $size;
}
}
$i: 6;
@while $i > 0 {
- .item-#{$i} { width: 2em * $i; }
+ .item-#{$i} { width: 2em * $i; }
$i: $i - 2;
}
@mixin large-text {
font: {
family: Arial;
size: 20px;
weight: bold;
}
color: #ff0000;
}
@mixin clearfix {
display: inline-block;
&:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
* html & { height: 1px }
}
.page-title {
@include large-text;
padding: 4px;
margin-top: 10px;
}
@mixin compound {
@include highlighted-background;
@include header-text;
}
@mixin highlighted-background { background-color: #fc0; }
@mixin header-text { font-size: 20px; }
@mixin sexy-border($color, $width) {
border: {
color: $color;
width: $width;
style: dashed;
}
}
p { @include sexy-border(blue, 1in); }
p { @include sexy-border($color: blue); }
h1 { @include sexy-border($color: blue, $width: 2in); }
@mixin colors($text, $background, $border) {
color: $text;
background-color: $background;
border-color: $border;
}
$values: #ff0000, #00ff00, #0000ff;
.primary {
@include colors($values...);
}
$value-map: (text: #00ff00, background: #0000ff, border: #ff0000);
.secondary {
@include colors($value-map...);
}
@mixin apply-to-ie6-only {
* html {
@content;
}
}
@include apply-to-ie6-only {
#logo {
background-image: url(/logo.gif);
}
}
$grid-width: 40px;
$gutter-width: 10px;
@function grid-width($n) {
@return $n * $grid-width + ($n - 1) * $gutter-width;
}
#sidebar { width: grid-width(5); }
+
+@mixin unify-parent($child) {
+ @at-root #{selector-unify(&, $child)} {
+ @content;
+ }
+}
+
+:root {
+ --font-family-sans-serif: #{inspect($font-family-sans-serif)};
+ --font-family-monospace: #{inspect($font-family-monospace)};
+}
+
+div {
+ background-image: url("/icons/#{$name}.svg");
+ font: #{"string"};
+}
diff --git a/autotests/reference/review128925-2.scss.ref b/autotests/reference/review128925-2.scss.ref
index 082c1e4..94524c0 100644
--- a/autotests/reference/review128925-2.scss.ref
+++ b/autotests/reference/review128925-2.scss.ref
@@ -1,81 +1,81 @@
/*
* SCSS Syntax Highlight Sample File (Complex)
*
* This file contains complex SCSS syntax that can test unexpected situations.
* It is NOT a valid SCSS file that can be compiled by SCSS preprocessors.
*
* @author Guo Yunhe guoyunhebrave@gmail.com
* @date 2016-09-16
*/
// Comments with special content
// .class-selector #id "string" 'comment' // comment {} [] () /* comment */ text
/*
* .class-selector #id "string" 'comment' // comment {} [] () /* comment
* TODO BUG DEBUG
* body {
* margin: 0 !important;
* }
*/
// Comments in special positions
$color: black /* comment here */;
header/* comment here */.active /* comment here */ {
/* comment here */ color : /* comment here */ blue/* comment here */;
font-family: Arial /* comment here */,
"Droid Sans", /* comment here */
sans-serif/* comment here */;
}
@media screen /* comment here */ and (max-width: 300px /* comment here */) /* comment here */ {/* comment here */}
// Strings with special content
@import "{} $variable /* comment */";
@import "{}";
// Without extra breaklines and spaces
pre.primary:hover.large:nth-child(2n-1){font-size:$default-font-size;font-family:"Noto Sans";-webkit-box-shadow:1px 1px 3px rgba(0,0,0,0.3)}
// With unnecessary breaklines and spaces
blockquote .ref
{
flex : 0 1 30%;
flex-wrap : wrap;
}
.sidebar {
width: 300px; }
@media screen and (orientation: landscape) {
.sidebar {
width: 500px; } }
// Variable interpolation: #{}
$name: foo;
$attr: border;
-p.#{$name} {
- #{$attr}-color: blue;
+p.#{$name} {
+ #{$attr}-color: blue;
}
p {
$font-size: 12px;
$line-height: 30px;
- font: #{$font-size}/#{$line-height};
+ font: #{$font-size}/#{$line-height};
}
// Special selectors: HTML5 allows user defined tags
header {
flex {
width: 300px;
}
}
diff --git a/data/syntax/scss.xml b/data/syntax/scss.xml
index 67efb8a..434b5e2 100644
--- a/data/syntax/scss.xml
+++ b/data/syntax/scss.xml
@@ -1,1023 +1,1020 @@
]>
-
+
properties##CSS
- adjust
- after
- align-all
- align
- align-last
- alternates
- anchor
- area
- areas
- attachment
- auto-columns
- auto-flow
- auto-rows
- baseline
- basis
- before
- bidi
- blend-mode
- block-color
- block-end-color
- block-end
- block-end-style
- block-end-width
- block
- block-start-color
- block-start
- block-start-style
- block-start-width
- block-style
- block-width
- border-mode
- border-outset
- border-repeat
- border-slice
- border-source
- bottom-color
- bottom-left-radius
- bottom-right-radius
- bottom-style
- bottom-width
- boundary
- box
- break
- caps
- cells
- change
- character
- chars
- collapse
- column-end
- column
- column-start
- combine-upright
- composite
- count
- decoration-break
- decoration-color
- decoration
- decoration-line
- decoration-skip-ink
- decoration-skip
- decoration-style
- decoration-width
- defer
- delay
- distance
- down
- duration
- during
- east-asian
- emoji
- emphasis-color
- emphasis
- emphasis-position
- emphasis-skip
- emphasis-style
- end-color
- end
- end-style
- end-width
- events
- family
- feature-settings
- fill-mode
- filters
- fit
- flow
- fragment
- from
- function
- grow
- gutter
- header
- height-step
- image
- image-outset
- image-repeat
- image-slice
- image-source
- image-threshold
- image-transform
- image-width
- increment
- indent
- inline-color
- inline-end-color
- inline-end
- inline-end-style
- inline-end-width
- inline
- inline-start-color
- inline-start
- inline-start-style
- inline-start-width
- inline-style
- inline-width
- insert
- inside
- interpolation-filters
- into
- items
- iteration-count
- justify
- kerning
- knockout-left
- knockout-right
- label
- language-override
- last
- layout
- left-color
- left-radius
- left-style
- left-width
- letter-align
- letter
- letter-wrap
- level
- ligatures
- limit-chars
- limit-last
- limit-lines
- limit-zone
- line
- lines
- loop
- max-size
- merge
- mid
- min-size
- mode
- name
- numeral
- numeric
- optical-sizing
- orientation
- orientation-vertical
- origin
- outset
- outside
- override
- palette
- path
- pattern
- play-state
- point
- policy
- property
- punctuation
- radius
- range
- rate
- reference
- rendering
- repeat
- reset
- resolution
- right-color
- right-radius
- right-style
- right-width
- rotate
- round
- row-end
- row
- rows
- row-start
- rule-color
- rule
- rule-style
- rule-width
- segment
- select
- self
- set
- settings
- shadow
- shape
- shift
- shrink
- side
- size-adjust
- sizing
- skip-ink
- skip
- slice
- snap
- source
- space-collapse
- space
- space-trim
- spacing
- span
- speed
- start-color
- start
- start-style
- start-width
- state
- step-align
- step-insert
- step
- step-round
- step-size
- stretch
- style-image
- style
- style-position
- style-type
- synthesis
- template-areas
- template-columns
- template
- template-rows
- threshold
- through
- timing-function
- top-color
- top-left-radius
- top-right-radius
- top-style
- top-width
- trim
- type
- underline-offset
- underline-position
- up
- upright
- variant-alternates
- variant-caps
- variant-east-asian
- variant-emoji
- variant
- variant-ligatures
- variant-numeric
- variant-position
- variation-settings
- vertical
- weight
- wrap
- x
- y
- zone
- true
- false
- null
value keywords##CSS
values##CSS
colors##CSS
functions##CSS
- red
- green
- blue
- mix
- hue
- saturation
- lightness
- adjust-hue
- lighten
- darken
- saturate
- desaturate
- grayscale
- complement
- invert
- alpha
- opacify
- transparentize
- adjust-color
- scale-color
- change-color
- ie-hex-str
- unquote
- quote
- str-length
- str-insert
- str-index
- str-slice
- to-upper-case
- to-lower-case
- percentage
- round
- ceil
- floor
- abs
- min
- max
- random
- length
- nth
- set-nth
- join
- append
- zip
- index
- list-separator
- is-bracketed
- map-get
- map-merge
- map-remove
- map-keys
- map-values
- map-has-key
- keywords
- selector-nest
- selector-append
- selector-extend
- selector-replace
- selector-unify
- is-superselector
- simple-selectors
- selector-parse
- feature-exists
- variable-exists
- global-variable-exists
- function-exists
- mixin-exists
- content-exists
- inspect
- type-of
- unit
- unitless
- comparable
- call
- get-function
- if
- unique-id
medias##CSS
pseudoelements##CSS
pseudoclasses##CSS
pseudoclass-not##CSS
pseudoclasses-@page##CSS
at-rules##CSS
- @debug
- @warn
- @error
- @content
- @return
nested at-rules##CSS
- @at-rule
- @for
- @each
- @while
- @include
- @extend
- @if
- @else
- @mixin
- @function
- @viewport
within-@viewport##CSS
- @page
within-@page##CSS
- @font-face
within-@font-face##CSS
- @keyframes
within-@keyframes##CSS
media operators##CSS
- and
- or
- not
- important
- default
- global
-
+
-
+
-
+
-
+
+
+
+
+
+
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
+
+