diff --git a/autotests/folding/highlight.scss.fold b/autotests/folding/highlight.scss.fold index afef111..2b21afb 100644 --- a/autotests/folding/highlight.scss.fold +++ b/autotests/folding/highlight.scss.fold @@ -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/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 - + - + - + - + + + + + + - + - + - + - - - - - - - - - - + +