diff --git a/autotests/folding/highlight.sass.fold b/autotests/folding/highlight.sass.fold new file mode 100644 index 0000000..7bf5fd8 --- /dev/null +++ b/autotests/folding/highlight.sass.fold @@ -0,0 +1,824 @@ +html, +body, +ul, +ol + margin: 0 + padding: 0 + +@import reset +body + font: 100% Helvetica, sans-serif + background-color: #efefef + +$font-stack: Helvetica, sans-serif +$primary-color: #333 + +body + font: 100% $font-stack + color: $primary-color +.container + width: 100% + +article[role="main"] + float: left + width: 600px / 960px * 100% + +%message-shared + border: 1px solid #ccc + padding: 10px + color: #333 + +.message + @extend %message-shared + +.success + @extend %message-shared + border-color: green + +=transform($property) + -webkit-transform: $property + -ms-transform: $property + transform: $property +.box + +transform(rotate(30deg)) + + // This comment won't be included in the CSS. + This is also commented out. + #a +/* But this comment will, except in compressed mode. + +/* It can also contain interpolation: + 1 + 1 = #{1 + 1} + 1 + 1 = #{1 + 1} + 1 + 1 = #{1 + 1} +#a + +// But this comment will, except in compressed mode. + +// It can also contain interpolation: + 1 + 1 = #{1 + 1} + 1 + 1 = #{1 + 1} + 1 + 1 = #{1 + 1} +#a + +/*! This comment will be included even in compressed mode. + +#a + +/**/ + +p .sans + font: Helvetica, /* Inline comments must be closed. */ sans-serif + +p .sans + font/*comment*/: Helvetica, /* Inline comments must be closed. */ sans-serif // comment + +/// Computes an exponent. +/// +/// @param {number} $base +/// The number to multiply by itself. +/// @param {integer (unitless)} $exponent +/// The number of `$base`s to multiply together. +/// @return {number} `$base` to the power of `$exponent`. +@function pow($base, $exponent) + $result: 1 + @for $_ from 1 through $exponent + $result: $result * $base + + @return $result + +$roboto-font-path: "../fonts/roboto" + +@font-face + // This is parsed as a normal function call that takes a quoted string. + src: url("#{$roboto-font-path}/Roboto-Thin.woff2") format("woff2") + src: url($roboto-font-path + "/Roboto-Light.woff2") format("woff2") + src: url(#{$roboto-font-path}/Roboto-Regular.woff2) format("woff2") + + font-family: "Roboto" + font-weight: 100 + +.logo + $width: 800px + width: $width + position: absolute + left: calc(50% - #{$width / 2}) + top: 0 + +$padding: 12px + +.post + // Since these max() calls don't use any Sass features other than + // interpolation, they're compiled to CSS max() calls. + padding-left: max(#{$padding}, env(safe-area-inset-left)) + padding-right: max(#{$padding}, env(safe-area-inset-right)) + + +.sidebar + // Since these refer to a Sass variable without interpolation, they call + // Sass's built-in max() function. + padding-left: max($padding, 20px) + padding-right: max($padding, 20px) + +.circle + $size: 100px + width: $size + height: $size + border-radius: $size / 2 + +@mixin prefix($property, $value, $prefixes) + @each $prefix in $prefixes + -#{$prefix}-#{$property}: $value + + #{$property}: $value + + +.gray + @include prefix(filter, grayscale(50%), moz webkit) + +.enlarge + font-size: 14px + transition: + property: font-size + duration: 4s + delay: 2s + + &:hover + font-size: 36px + +.info-page + margin: auto + bottom: 10px + top: 2px + +$rounded-corners: false + +.button + border: 1px solid black + border-radius: if($rounded-corners, 5px, null) + +$primary: #81899b +$accent: #ab2e +$warn: #dfa612aa + +:root + --primary: #{$primary} + --accent: #{$accent} + --warn: #{$warn} + + // Even though this looks like a Sass variable, it's valid CSS so it's not + // evaluated. + --consumed-by-js: $primary + +$font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto +$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas + +:root + --font-family-sans-serif: #{inspect($font-family-sans-serif)} + --font-family-monospace: #{inspect($font-family-monospace)} + +.alert + // The parent selector can be used to add pseudo-classes to the outer + // selector. + &:hover + font-weight: bold + + + // It can also be used to style the outer selector in a certain context, such + // as a body set to use a right-to-left language. + [dir=rtl] & + margin-left: 0 + margin-right: 10px + + + // You can even use it as an argument to pseudo-class selectors. + :not(&) + opacity: 0.8 + +@mixin unify-parent($child) + @at-root #{selector-unify(&, $child)} + @content + + + +.wrapper .field + @include unify-parent("input") + +@mixin app-background($color) + #{if(&, '&.app-background', '.app-background')} + background-color: $color + color: rgba(#fff, 0.75) + +@include app-background(#036) + +.sidebar + @include app-background(#c6538c) + +.accordion + max-width: 600px + margin: 4rem auto + + &__copy + display: none + padding: 1rem 1.5rem 2rem 1.5rem + line-height: 1.6 + font-size: 14px + + &--open + display: block + + +.alert:hover, %strong-alert + font-weight: bold + +%strong-alert:hover + color: red + +%toolbelt + box-sizing: border-box + border-top: 1px rgba(#000, .12) solid + + &:hover + border: 2px rgba(#000, .5) solid + +.action-buttons + @extend %toolbelt + color: #4285f4 + +$border-dark: rgba($base-color, 0.88) +$black: #000 !default +$border-radius: 0.25rem !default +$box-shadow: 0 0.5rem 1rem rgba($black, 0.15) !default +$box-shadow: 0 0.5rem 1rem rgba($black, blue($black)) !default +$border-radius: 0.1rem + +@import 'library' + +$global-variable: global value + + // This would fail, because $local-variable isn't in scope: + // local: $local-variable + +$theme-colors: ("success": #28a745, "info": #17a2b8, "warning": #ffc107) + +.alert + // Instead of $theme-color-#{warning} + background-color: map-get($theme-colors, "warning") + +@mixin corner-icon($name, $top-or-bottom, $left-or-right) + .icon-#{$name} + background-image: url("/icons/#{$name}.svg") + position: absolute + #{$top-or-bottom}: 0 + #{$left-or-right}: 0 + +@include corner-icon("mail", top, right) + +@mixin inline-animation($duration) + $name: inline-#{unique-id()} + + @keyframes #{$name} + @content + + animation-name: $name + animation-duration: $duration + animation-iteration-count: infinite + + +.pulse + @include inline-animation(2s) + from + background-color: yellow + to + background-color: red + +.example + unquoted: #{"string"} + + & & + padding: + bottom: 0 + left: 0 + +// style.sass +@import 'foundation/code', 'foundation/lists' + +@import "theme.css" +@import "http://fonts.googleapis.com/css?family=Droid+Sans" +@import url(theme) +@import "landscape" screen and (orientation: landscape) + +@mixin google-font($family) + @import url("http://fonts.googleapis.com/css?family=#{$family}") + +@include google-font("Droid Sans") + +@mixin horizontal-list + @include reset-list + + li + display: inline-block + margin: + left: -2px + right: 2em + +nav ul + @include horizontal-list + +@mixin rtl($property, $ltr-value, $rtl-value) + #{$property}: $ltr-value + + [dir=rtl] & + #{$property}: $rtl-value + +.sidebar + @include rtl(float, left, right) + +@mixin replace-text($image, $x: 50%, $y: 50%) + text-indent: -99999em + overflow: hidden + text-align: left + + background: + image: $image + repeat: no-repeat + position: $x $y + +.mail-icon + @include replace-text(url("/images/mail.svg"), 0) + +@include order(150px, "input.name", "input.address", "input.zip") + +@mixin syntax-colors($args...) + @debug keywords($args) // (string: #080, comment: #800, $variable: $60b) + + @each $name, $color in keywords($args) + pre span.stx-#{$name} + color: $color + +@include syntax-colors($string: #080, $comment: #800, $variable: #60b) + +@mixin media($types...) + @each $type in $types + @media #{$type} + @content($type) + +@include media(screen, print) using ($type) + h1 + font-size: 40px + @if $type == print + font-family: Calluna + +=reset-list + margin: 0 + padding: 0 + list-style: none + +=horizontal-list + +reset-list + + li + display: inline-block + margin: + left: -2px + right: 2em + +nav ul + +horizontal-list +@function pow($base, $exponent) + $result: 1 + @for $_ from 1 through $exponent + $result: $result * $base + + @return $result + +.sidebar + float: left + margin-left: pow(4, 3) * 1px + +@function sum($numbers...) + $sum: 0 + @each $number in $numbers + $sum: $sum + $number + + @return $sum + +.micro + width: sum(50px, 30px, 100px) +@function str-insert($string, $insert, $index) + // Avoid making new strings if we don't need to. + @if str-length($string) == 0 + @return $insert + + $before: str-slice($string, 0, $index) + $after: str-slice($string, $index) + @return $before + $insert + $after + +.error + border: 1px #f00 + background-color: #fdd + + &--serious + @extend .error + border-width: 3px + +@mixin reflexive-position($property, $value) + @if $property != left and $property != right + @error "Property #{$property} must be either left or right." + + $left-value: if($property == right, initial, $value) + $right-value: if($property == right, $value, initial) + + left: $left-value + right: $right-value + [dir=rtl] & + left: $right-value + right: $left-value + +$known-prefixes: webkit, moz, ms, o + +@mixin prefix($property, $value, $prefixes) + @each $prefix in $prefixes + @if not index($known-prefixes, $prefix) + @warn "Unknown prefix #{$prefix}." + + + -#{$prefix}-#{$property}: $value + + #{$property}: $value + + +.tilt + // Oops, we typo'd "webkit" as "wekbit"! + @include prefix(transform, rotate(15deg), wekbit ms) + +@mixin inset-divider-offset($offset, $padding) + $divider-offset: (2 * $padding) + $offset + @debug "divider offset: #{$divider-offset}" + + margin-left: $divider-offset + width: calc(100% - #{$divider-offset}) + +@mixin unify-parent($child) + @at-root #{selector-unify(&, $child)} + @content + + +.square-av + @include avatar(100px, $circle: false) +.circle-av + @include avatar(100px, $circle: true) + +@mixin theme-colors($light-theme: true) + @if $light-theme + background-color: $light-background + color: $light-text + @else + background-color: $dark-background + color: $dark-text + +.banner + @include theme-colors($light-theme: true) + body.dark & + @include theme-colors($light-theme: false) + +@mixin triangle($size, $color, $direction) + height: 0 + width: 0 + + border-color: transparent + border-style: solid + border-width: $size / 2 + + @if $direction == up + border-bottom-color: $color + @else if $direction == right + border-left-color: $color + @else if $direction == down + border-top-color: $color + @else if $direction == left + border-right-color: $color + @else + @error "Unknown direction #{$direction}." + +@each $size in $sizes + .icon-#{$size} + font-size: $size + height: $size + width: $size + +$icons: ("eye": "\f112", "start": "\f12e", "stop": "\f12f") + +@each $name, $glyph in $icons + .icon-#{$name}:before + display: inline-block + font-family: "Icon Font" + content: $glyph + +$icons: "eye" "\f112" 12px, "start" "\f12e" 16px, "stop" "\f12f" 10px + +@each $name, $glyph, $size in $icons + .icon-#{$name}:before + display: inline-block + font-family: "Icon Font" + content: $glyph + font-size: $size + +@for $i from 1 through 3 + ul:nth-child(3n + #{$i}) + background-color: lighten($base-color, $i * 5%) + +/// Divides `$value` by `$ratio` until it's below `$base`. +@function scale-below($value, $base, $ratio: 1.618) + @while $value > $base + $value: $value / $ratio + @return $value + +@namespace svg url(http://www.w3.org/2000/svg) + +@font-face + font-family: "Open Sans" + src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2") + +@counter-style thumbs + system: cyclic + symbols: "\1F44D" + +@mixin sticky-position + position: fixed + @supports (position: sticky) + position: sticky + +@media (hover: hover) + .button:hover + border: 2px solid black + + @media (color) + border-color: #036 + +@keyframes slide-in + from + margin-left: 100% + width: 300% + + + 70% + margin-left: 90% + width: 150% + + + to + margin-left: 0% + width: 100% + +@debug 100 // 100 +@debug 0.8 // 0.8 +@debug 16px // 16px +@debug 5px * 2px // 10px*px (read "square pixels") +@debug 5.2e3 // 5200 +@debug 6e-2 // 0.06 +@debug 4px * 6px // 24px*px (read "square pixels") +@debug 5px / 2s // 2.5px/s (read "pixels per second") +@debug 5px * 30deg / 2s / 24em // 3.125px*deg/s*em +// (read "pixel-degrees per second-em") + +$degrees-per-second: 20deg/1s +@debug $degrees-per-second // 20deg/s +@debug 1 / $degrees-per-second // 0.05s/deg +$transition-speed: 1s/50px + +@debug unquote(".widget:hover") // .widget:hover +@debug quote(bold) // "bold" +@debug 0.012345678912345 // 0.0123456789 +@debug 0.01234567891 == 0.01234567899 // true +@debug 1.00000000009 // 1 +@debug 0.99999999991 // 1 +@debug "\"" // '"' +@debug \.widget // \.widget +@debug "\a" // "\a" (a string containing only a newline) +@debug "line1\a line2" // "line1\a line2" (foo and bar are separated by a newline) +@debug "Nat + Liz \1F46D" // "Nat + Liz 👭" +@debug "Helvetica Neue" // "Helvetica Neue" +@debug "C:\\Program Files" // "C:\\Program Files" +@debug "\"Don't Fear the Reaper\"" // "\"Don't Fear the Reaper\"" +@debug "line1\a line2" // "line1\a line2" + +$roboto-variant: "Mono" +@debug "Roboto #{$roboto-variant}" // "Roboto Mono" +@debug bold // bold +@debug -webkit-flex // -webkit-flex +@debug --123 // --123 + +$prefix: ms +@debug -#{$prefix}-flex // -ms-flex +@debug \1F46D // 👭 +@debug \21 // \! +@debug \7Fx // \7f x +@debug str-length(\7Fx) // 5 +@debug str-index("Helvetica Neue", "Helvetica") // 1 +@debug str-index("Helvetica Neue", "Neue") // 11 +@debug str-slice("Roboto Mono", -4) // "Mono" +@debug #f2ece4 // #f2ece4 +@debug #b37399aa // rgba(179, 115, 153, 67%) +@debug midnightblue // #191970 +@debug rgb(204, 102, 153) // #c69 +@debug rgba(107, 113, 127, 0.8) // rgba(107, 113, 127, 0.8) +@debug hsl(228, 7%, 86%) // #dadbdf +@debug hsla(20, 20%, 85%, 0.7) // rgb(225, 215, 210, 0.7) +$venus: #998099 + +@debug scale-color($venus, $lightness: +15%) // #a893a8 +@debug mix($venus, midnightblue) // #594d85 +@debug nth(10px 12px 16px, 2) // 12px +@debug nth([line1, line2, line3], -1) // line3 +$prefixes-by-browser: ("firefox": moz, "safari": webkit, "ie": ms) + +@function prefixes-for-browsers($browsers) + $prefixes: () + @each $browser in $browsers + $prefixes: append($prefixes, map-get($prefixes-by-browser, $browser)) + + @return $prefixes + +@debug prefixes-for-browsers("firefox" "ie") // moz ms +@mixin syntax-colors($args...) + @debug keywords($args) // (string: #080, comment: #800, $variable: $60b) + + @each $name, $color in keywords($args) + pre span.stx-#{$name} + color: $color + +@include syntax-colors($string: #080, $comment: #800, $variable: #60b); +$font-weights: ("regular": 400, "medium": 500, "bold": 700) + +@debug map-get($font-weights, "medium") // 500 +@debug map-get($font-weights, "extra-bold") // null +$icons: ("eye": "\f112", "start": "\f12e", "stop": "\f12f") + +@each $name, $glyph in $icons + .icon-#{$name}:before + display: inline-block + font-family: "Icon Font" + content: $glyph + +$prefixes-by-browser: ("firefox": moz, "safari": webkit, "ie": ms) + +@mixin add-browser-prefix($browser, $prefix) + $prefixes-by-browser: map-merge($prefixes-by-browser, ($browser: $prefix)) + +@include add-browser-prefix("opera", o) +@debug $prefixes-by-browser +// ("firefox": moz, "safari": webkit, "ie": ms, "opera": o) +@debug 1px == 2px // false +@debug 1px == 1px // true +@debug 10px < 3px // false +@debug comparable(100px, 3in) // true + +@debug str-index("Helvetica Neue", "Roboto") // null +@debug map-get(("large": 20px), "small") // null +@debug & // null +$fonts: ("serif": "Helvetica Neue", "monospace": "Consolas") + +h3 + font: 18px bold map-get($fonts, "sans") + +$fonts: ("serif": "Helvetica Neue", "monospace": "Consolas") + +h3 + font: + size: 18px + weight: bold + family: map-get($fonts, "sans") + +copy of $list with all elements for which $condition returns `true` +/// removed. +@function remove-where($list, $condition) + $new-list: () + $separator: list-separator($list) + @each $element in $list + @if not call($condition, $element) + $new-list: append($new-list, $element, $separator: $separator) + + @return $new-list + +$fonts: Tahoma, Geneva, "Helvetica Neue", Helvetica, Arial, sans-serif + +content + @function contains-helvetica($string) + @return str-index($string, "Helvetica") + + font-family: remove-where($fonts, get-function("contains-helvetica")) + +@debug 1px == 1px // true +@debug 1px != 1em // true +@debug 1 != 1px // true +@debug 96px == 1in // true + +@debug "Helvetica" == Helvetica // true +@debug "Helvetica" != "Arial" // true + +@debug hsl(34, 35%, 92.1%) == #f2ece4 // true +@debug rgba(179, 115, 153, 0.5) != rgba(179, 115, 153, 0.8) // true + +@debug (5px 7px 10px) == (5px 7px 10px) // true +@debug (5px 7px 10px) != (10px 14px 20px) // true +@debug (5px 7px 10px) != (5px, 7px, 10px) // true +@debug (5px 7px 10px) != [5px 7px 10px] // true + +$theme: ("venus": #998099, "nebula": #d2e1dd) +@debug $theme == ("venus": #998099, "nebula": #d2e1dd) // true +@debug $theme != ("venus": #998099, "iron": #dadbdf) // true + +@debug true == true // true +@debug true != false // true +@debug null != false // true + +@debug get-function("rgba") == get-function("rgba") // true +@debug get-function("rgba") != get-function("hsla") // true + +@debug 10s + 15s // 25s +@debug 1in - 10px // 0.8958333333in +@debug 5px * 3px // 15px*px +@debug (12px/4px) // 3 +@debug 1in % 9px // 0.0625in +@debug 15px / 30px // 15px/30px +@debug (10px + 5px) / 30px // 0.5 + +$result: 15px / 30px +@debug $result // 0.5 + +@function fifteen-divided-by-thirty() + @return 15px / 30px + +@debug fifteen-divided-by-thirty() // 0.5 + +@debug (15px/30px) // 0.5 +@debug (bold 15px/30px sans-serif) // bold 15px/30px sans-serif +@debug 15px/30px + 1 // 1.5 + +@debug 4px * 6px // 24px*px (read "square pixels") +@debug 5px / 2s // 2.5px/s (read "pixels per second") +@debug 5px * 30deg / 2s / 24em // 3.125px*deg/s*em +// (read "pixel-degrees per second-em") + +$degrees-per-second: 20deg/1s +@debug $degrees-per-second // 20deg/s +@debug 1 / $degrees-per-second // 0.05s/deg +@debug 100 > 50 // true +@debug 10px < 17px // true +@debug 96px >= 1in // true +@debug 1000ms <= 1s // true +@debug "Helvetica" + " Neue" // "Helvetica Neue" +@debug sans- + serif // sans-serif +@debug #{10px + 5px} / 30px // 15px/30px +@debug sans - serif // sans-serif + +@debug "Elapsed time: " + 10s // "Elapsed time: 10s"; +@debug true + " is a boolean value" // "true is a boolean value"; + +@debug / 15px // /15px +@debug - moz // -moz +@debug not true // false +@debug not false // true + +@debug true and true // true +@debug true and false // false + +@debug true or false // true +@debug false or false // false +@debug var(--main-bg-color) // var(--main-bg-color) + +$primary: #f2ece4 +$accent: #e1d7d2 +@debug radial-gradient($primary, $accent) // radial-gradient(#f2ece4, #e1d7d2) +@debug str-index("Helvetica Neue", "Helvetica") // 1 +@debug str-index("Helvetica Neue", "Neue") // 11 +@debug comparable(2px, 1px) // true +@debug comparable(100px, 3em) // false +@debug comparable(10cm, 3mm) // true +@debug append(10px 20px, 30px) // 10px 20px 30px +@debug append((blue, red), green) // blue, red, green +@debug append(10px 20px, 30px 40px) // 10px 20px (30px 40px) +@debug append(10px, 20px, $separator: comma) // 10px, 20px +@debug append((blue, red), green, $separator: space) // blue red green +@mixin syntax-colors($args...) + @debug keywords($args) // (string: #080, comment: #800, $variable: $60b) + + @each $name, $color in keywords($args) + pre span.stx-#{$name} + color: $color + +@include syntax-colors($string: #080, $comment: #800, $variable: #60b); + +$font-weights: ("regular": 400, "medium": 500, "bold": 700) + +@debug map-values($font-weights) // 400, 500, 700 + +.icon-#{$name} + position: absolute + #{$top-or-bottom}: 0 + -#{$prefix}-#{$property}: $value + .icon-#{$name} + position: absolute + #{$top-or-bottom}: 0 + -#{$prefix}-#{$property}-image: $value diff --git a/autotests/folding/highlight.scss.fold b/autotests/folding/highlight.scss.fold index 2b21afb..4f7a2c1 100644 --- a/autotests/folding/highlight.scss.fold +++ b/autotests/folding/highlight.scss.fold @@ -1,709 +1,719 @@ /** * 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"}; + +.icon-#{$name} { + position: absolute; + #{$top-or-bottom}: 0; + -#{$prefix}-#{$property}: $value; + .icon-#{$name} { + position: absolute; + #{$top-or-bottom}: 0; + -#{$prefix}-#{$property}-image: $value + } } diff --git a/autotests/html/highlight.css.html b/autotests/html/highlight.css.html index a3efe69..21fa094 100644 --- a/autotests/html/highlight.css.html +++ b/autotests/html/highlight.css.html @@ -1,293 +1,293 @@ highlight.css
 /**
  * This is a pseudo CSS file to test Kate's CSS 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;
 	// this is no comment, it's just broken!
 	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 */
+	--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 }
 }
 
diff --git a/autotests/html/highlight.sass.html b/autotests/html/highlight.sass.html new file mode 100644 index 0000000..c26666e --- /dev/null +++ b/autotests/html/highlight.sass.html @@ -0,0 +1,831 @@ + + + +highlight.sass + +
+html,
+body,
+ul,
+ol
+  margin:  0
+  padding: 0
+
+@import reset
+body
+  font: 100% Helvetica, sans-serif
+  background-color: #efefef
+
+$font-stack:    Helvetica, sans-serif
+$primary-color: #333
+
+body
+  font: 100% $font-stack
+  color: $primary-color
+.container
+  width: 100%
+
+article[role="main"]
+  float: left
+  width: 600px / 960px * 100%
+
+%message-shared
+  border: 1px solid #ccc
+  padding: 10px
+  color: #333
+
+.message
+  @extend %message-shared
+
+.success
+  @extend %message-shared
+  border-color: green
+
+=transform($property)
+  -webkit-transform: $property
+  -ms-transform: $property
+  transform: $property
+.box
+  +transform(rotate(30deg))
+
+  // This comment won't be included in the CSS.
+   This is also commented out.
+  #a
+/* But this comment will, except in compressed mode.
+
+/* It can also contain interpolation:
+   1 + 1 = #{1 + 1}
+  1 + 1 = #{1 + 1}
+ 1 + 1 = #{1 + 1}
+#a
+
+// But this comment will, except in compressed mode.
+
+// It can also contain interpolation:
+   1 + 1 = #{1 + 1}
+  1 + 1 = #{1 + 1}
+ 1 + 1 = #{1 + 1}
+#a
+
+/*! This comment will be included even in compressed mode.
+
+#a
+
+/**/
+
+p .sans
+  font: Helvetica, /* Inline comments must be closed. */ sans-serif
+
+p .sans
+  font/*comment*/: Helvetica, /* Inline comments must be closed. */ sans-serif // comment
+
+/// Computes an exponent.
+///
+/// @param {number} $base
+///   The number to multiply by itself.
+/// @param {integer (unitless)} $exponent
+///   The number of `$base`s to multiply together.
+/// @return {number} `$base` to the power of `$exponent`.
+@function pow($base, $exponent)
+  $result: 1
+  @for $_ from 1 through $exponent
+    $result: $result * $base
+
+  @return $result
+
+$roboto-font-path: "../fonts/roboto"
+
+@font-face
+    // This is parsed as a normal function call that takes a quoted string.
+    src: url("#{$roboto-font-path}/Roboto-Thin.woff2") format("woff2")
+    src: url($roboto-font-path + "/Roboto-Light.woff2") format("woff2")
+    src: url(#{$roboto-font-path}/Roboto-Regular.woff2) format("woff2")
+
+    font-family: "Roboto"
+    font-weight: 100
+
+.logo
+  $width: 800px
+  width: $width
+  position: absolute
+  left: calc(50% - #{$width / 2})
+  top: 0
+
+$padding: 12px
+
+.post
+  // Since these max() calls don't use any Sass features other than
+  // interpolation, they're compiled to CSS max() calls.
+  padding-left: max(#{$padding}, env(safe-area-inset-left))
+  padding-right: max(#{$padding}, env(safe-area-inset-right))
+
+
+.sidebar
+  // Since these refer to a Sass variable without interpolation, they call
+  // Sass's built-in max() function.
+  padding-left: max($padding, 20px)
+  padding-right: max($padding, 20px)
+
+.circle
+  $size: 100px
+  width: $size
+  height: $size
+  border-radius: $size / 2
+
+@mixin prefix($property, $value, $prefixes)
+  @each $prefix in $prefixes
+    -#{$prefix}-#{$property}: $value
+
+  #{$property}: $value
+
+
+.gray
+  @include prefix(filter, grayscale(50%), moz webkit)
+
+.enlarge
+  font-size: 14px
+  transition:
+    property: font-size
+    duration: 4s
+    delay: 2s
+
+  &:hover
+    font-size: 36px
+
+.info-page
+  margin: auto
+    bottom: 10px
+    top: 2px
+
+$rounded-corners: false
+
+.button
+  border: 1px solid black
+  border-radius: if($rounded-corners, 5px, null)
+
+$primary: #81899b
+$accent: #ab2e
+$warn: #dfa612aa
+
+:root
+  --primary: #{$primary}
+  --accent: #{$accent}
+  --warn: #{$warn}
+
+  // Even though this looks like a Sass variable, it's valid CSS so it's not
+  // evaluated.
+  --consumed-by-js: $primary
+
+$font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto
+$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas
+
+:root
+  --font-family-sans-serif: #{inspect($font-family-sans-serif)}
+  --font-family-monospace: #{inspect($font-family-monospace)}
+
+.alert
+  // The parent selector can be used to add pseudo-classes to the outer
+  // selector.
+  &:hover
+    font-weight: bold
+
+
+  // It can also be used to style the outer selector in a certain context, such
+  // as a body set to use a right-to-left language.
+  [dir=rtl] &
+    margin-left: 0
+    margin-right: 10px
+
+
+  // You can even use it as an argument to pseudo-class selectors.
+  :not(&)
+    opacity: 0.8
+
+@mixin unify-parent($child)
+  @at-root #{selector-unify(&, $child)}
+    @content
+
+
+
+.wrapper .field
+  @include unify-parent("input")
+
+@mixin app-background($color)
+  #{if(&, '&.app-background', '.app-background')}
+    background-color: $color
+    color: rgba(#fff, 0.75)
+
+@include app-background(#036)
+
+.sidebar
+  @include app-background(#c6538c)
+
+.accordion
+  max-width: 600px
+  margin: 4rem auto
+
+  &__copy
+    display: none
+    padding: 1rem 1.5rem 2rem 1.5rem
+    line-height: 1.6
+    font-size: 14px
+
+    &--open
+      display: block
+
+
+.alert:hover, %strong-alert
+  font-weight: bold
+
+%strong-alert:hover
+  color: red
+
+%toolbelt
+  box-sizing: border-box
+  border-top: 1px rgba(#000, .12) solid
+
+  &:hover
+    border: 2px rgba(#000, .5) solid
+
+.action-buttons
+  @extend %toolbelt
+  color: #4285f4
+
+$border-dark: rgba($base-color, 0.88)
+$black: #000 !default
+$border-radius: 0.25rem !default
+$box-shadow: 0 0.5rem 1rem rgba($black, 0.15) !default
+$box-shadow: 0 0.5rem 1rem rgba($black, blue($black)) !default
+$border-radius: 0.1rem
+
+@import 'library'
+
+$global-variable: global value
+
+  // This would fail, because $local-variable isn't in scope:
+  // local: $local-variable
+
+$theme-colors: ("success": #28a745, "info": #17a2b8, "warning": #ffc107)
+
+.alert
+  // Instead of $theme-color-#{warning}
+  background-color: map-get($theme-colors, "warning")
+
+@mixin corner-icon($name, $top-or-bottom, $left-or-right)
+  .icon-#{$name}
+    background-image: url("/icons/#{$name}.svg")
+    position: absolute
+    #{$top-or-bottom}: 0
+    #{$left-or-right}: 0
+
+@include corner-icon("mail", top, right)
+
+@mixin inline-animation($duration)
+  $name: inline-#{unique-id()}
+
+  @keyframes #{$name}
+    @content
+
+  animation-name: $name
+  animation-duration: $duration
+  animation-iteration-count: infinite
+
+
+.pulse
+  @include inline-animation(2s)
+    from
+      background-color: yellow
+    to
+      background-color: red
+
+.example
+  unquoted: #{"string"}
+
+  & &
+    padding:
+      bottom: 0
+      left: 0
+
+// style.sass
+@import 'foundation/code', 'foundation/lists'
+
+@import "theme.css"
+@import "http://fonts.googleapis.com/css?family=Droid+Sans"
+@import url(theme)
+@import "landscape" screen and (orientation: landscape)
+
+@mixin google-font($family)
+  @import url("http://fonts.googleapis.com/css?family=#{$family}")
+
+@include google-font("Droid Sans")
+
+@mixin horizontal-list
+  @include reset-list
+
+  li
+    display: inline-block
+    margin:
+      left: -2px
+      right: 2em
+
+nav ul
+  @include horizontal-list
+
+@mixin rtl($property, $ltr-value, $rtl-value)
+  #{$property}: $ltr-value
+
+  [dir=rtl] &
+    #{$property}: $rtl-value
+
+.sidebar
+  @include rtl(float, left, right)
+
+@mixin replace-text($image, $x: 50%, $y: 50%)
+  text-indent: -99999em
+  overflow: hidden
+  text-align: left
+
+  background:
+    image: $image
+    repeat: no-repeat
+    position: $x $y
+
+.mail-icon
+  @include replace-text(url("/images/mail.svg"), 0)
+
+@include order(150px, "input.name", "input.address", "input.zip")
+
+@mixin syntax-colors($args...)
+  @debug keywords($args)  // (string: #080, comment: #800, $variable: $60b)
+
+  @each $name, $color in keywords($args)
+    pre span.stx-#{$name}
+      color: $color
+
+@include syntax-colors($string: #080, $comment: #800, $variable: #60b)
+
+@mixin media($types...)
+  @each $type in $types
+    @media #{$type}
+      @content($type)
+
+@include media(screen, print) using ($type)
+  h1
+    font-size: 40px
+    @if $type == print
+      font-family: Calluna
+
+=reset-list
+  margin: 0
+  padding: 0
+  list-style: none
+
+=horizontal-list
+  +reset-list
+
+  li
+    display: inline-block
+    margin:
+      left: -2px
+      right: 2em
+
+nav ul
+  +horizontal-list
+@function pow($base, $exponent)
+  $result: 1
+  @for $_ from 1 through $exponent
+    $result: $result * $base
+
+  @return $result
+
+.sidebar
+  float: left
+  margin-left: pow(4, 3) * 1px
+
+@function sum($numbers...)
+  $sum: 0
+  @each $number in $numbers
+    $sum: $sum + $number
+
+  @return $sum
+
+.micro
+  width: sum(50px, 30px, 100px)
+@function str-insert($string, $insert, $index)
+  // Avoid making new strings if we don't need to.
+  @if str-length($string) == 0
+    @return $insert
+
+  $before: str-slice($string, 0, $index)
+  $after: str-slice($string, $index)
+  @return $before + $insert + $after
+
+.error
+  border: 1px #f00
+  background-color: #fdd
+
+  &--serious
+    @extend .error
+    border-width: 3px
+
+@mixin reflexive-position($property, $value)
+  @if $property != left and $property != right
+    @error "Property #{$property} must be either left or right."
+
+  $left-value: if($property == right, initial, $value)
+  $right-value: if($property == right, $value, initial)
+
+  left: $left-value
+  right: $right-value
+  [dir=rtl] &
+    left: $right-value
+    right: $left-value
+
+$known-prefixes: webkit, moz, ms, o
+
+@mixin prefix($property, $value, $prefixes)
+  @each $prefix in $prefixes
+    @if not index($known-prefixes, $prefix)
+      @warn "Unknown prefix #{$prefix}."
+
+
+    -#{$prefix}-#{$property}: $value
+
+  #{$property}: $value
+
+
+.tilt
+  // Oops, we typo'd "webkit" as "wekbit"!
+  @include prefix(transform, rotate(15deg), wekbit ms)
+
+@mixin inset-divider-offset($offset, $padding)
+  $divider-offset: (2 * $padding) + $offset
+  @debug "divider offset: #{$divider-offset}"
+
+  margin-left: $divider-offset
+  width: calc(100% - #{$divider-offset})
+
+@mixin unify-parent($child)
+  @at-root #{selector-unify(&, $child)}
+    @content
+
+
+.square-av
+  @include avatar(100px, $circle: false)
+.circle-av
+  @include avatar(100px, $circle: true)
+
+@mixin theme-colors($light-theme: true)
+  @if $light-theme
+    background-color: $light-background
+    color: $light-text
+  @else
+    background-color: $dark-background
+    color: $dark-text
+
+.banner
+  @include theme-colors($light-theme: true)
+  body.dark &
+    @include theme-colors($light-theme: false)
+
+@mixin triangle($size, $color, $direction)
+  height: 0
+  width: 0
+
+  border-color: transparent
+  border-style: solid
+  border-width: $size / 2
+
+  @if $direction == up
+    border-bottom-color: $color
+  @else if $direction == right
+    border-left-color: $color
+  @else if $direction == down
+    border-top-color: $color
+  @else if $direction == left
+    border-right-color: $color
+  @else
+    @error "Unknown direction #{$direction}."
+
+@each $size in $sizes
+  .icon-#{$size}
+    font-size: $size
+    height: $size
+    width: $size
+
+$icons: ("eye": "\f112", "start": "\f12e", "stop": "\f12f")
+
+@each $name, $glyph in $icons
+  .icon-#{$name}:before
+    display: inline-block
+    font-family: "Icon Font"
+    content: $glyph
+
+$icons: "eye" "\f112" 12px, "start" "\f12e" 16px, "stop" "\f12f" 10px
+
+@each $name, $glyph, $size in $icons
+  .icon-#{$name}:before
+    display: inline-block
+    font-family: "Icon Font"
+    content: $glyph
+    font-size: $size
+
+@for $i from 1 through 3
+  ul:nth-child(3n + #{$i})
+    background-color: lighten($base-color, $i * 5%)
+
+/// Divides `$value` by `$ratio` until it's below `$base`.
+@function scale-below($value, $base, $ratio: 1.618)
+  @while $value > $base
+    $value: $value / $ratio
+  @return $value
+
+@namespace svg url(http://www.w3.org/2000/svg)
+
+@font-face
+  font-family: "Open Sans"
+  src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2")
+
+@counter-style thumbs
+  system: cyclic
+  symbols: "\1F44D"
+
+@mixin sticky-position
+  position: fixed
+  @supports (position: sticky)
+    position: sticky
+
+@media (hover: hover)
+  .button:hover
+    border: 2px solid black
+
+    @media (color)
+      border-color: #036
+
+@keyframes slide-in
+  from
+    margin-left: 100%
+    width: 300%
+
+
+  70%
+    margin-left: 90%
+    width: 150%
+
+
+  to
+    margin-left: 0%
+    width: 100%
+
+@debug 100  // 100
+@debug 0.8  // 0.8
+@debug 16px  // 16px
+@debug 5px * 2px  // 10px*px (read "square pixels")
+@debug 5.2e3  // 5200
+@debug 6e-2  // 0.06
+@debug 4px * 6px  // 24px*px (read "square pixels")
+@debug 5px / 2s  // 2.5px/s (read "pixels per second")
+@debug 5px * 30deg / 2s / 24em  // 3.125px*deg/s*em
+//                                 (read "pixel-degrees per second-em")
+
+$degrees-per-second: 20deg/1s
+@debug $degrees-per-second  // 20deg/s
+@debug 1 / $degrees-per-second  // 0.05s/deg
+$transition-speed: 1s/50px
+
+@debug unquote(".widget:hover")  // .widget:hover
+@debug quote(bold)  // "bold"
+@debug 0.012345678912345  // 0.0123456789
+@debug 0.01234567891 == 0.01234567899  // true
+@debug 1.00000000009  // 1
+@debug 0.99999999991  // 1
+@debug "\""  // '"'
+@debug \.widget  // \.widget
+@debug "\a"  // "\a" (a string containing only a newline)
+@debug "line1\a line2"  // "line1\a line2" (foo and bar are separated by a newline)
+@debug "Nat + Liz \1F46D"  // "Nat + Liz 👭"
+@debug "Helvetica Neue"  // "Helvetica Neue"
+@debug "C:\\Program Files"  // "C:\\Program Files"
+@debug "\"Don't Fear the Reaper\""  // "\"Don't Fear the Reaper\""
+@debug "line1\a line2"  // "line1\a line2"
+
+$roboto-variant: "Mono"
+@debug "Roboto #{$roboto-variant}"  // "Roboto Mono"
+@debug bold  // bold
+@debug -webkit-flex  // -webkit-flex
+@debug --123  // --123
+
+$prefix: ms
+@debug -#{$prefix}-flex  // -ms-flex
+@debug \1F46D  // 👭
+@debug \21  // \!
+@debug \7Fx  // \7f x
+@debug str-length(\7Fx)  // 5
+@debug str-index("Helvetica Neue", "Helvetica")  // 1
+@debug str-index("Helvetica Neue", "Neue")  // 11
+@debug str-slice("Roboto Mono", -4)  // "Mono"
+@debug #f2ece4 // #f2ece4
+@debug #b37399aa // rgba(179, 115, 153, 67%)
+@debug midnightblue // #191970
+@debug rgb(204, 102, 153) // #c69
+@debug rgba(107, 113, 127, 0.8) // rgba(107, 113, 127, 0.8)
+@debug hsl(228, 7%, 86%) // #dadbdf
+@debug hsla(20, 20%, 85%, 0.7) // rgb(225, 215, 210, 0.7)
+$venus: #998099
+
+@debug scale-color($venus, $lightness: +15%) // #a893a8
+@debug mix($venus, midnightblue) // #594d85
+@debug nth(10px 12px 16px, 2)  // 12px
+@debug nth([line1, line2, line3], -1)  // line3
+$prefixes-by-browser: ("firefox": moz, "safari": webkit, "ie": ms)
+
+@function prefixes-for-browsers($browsers)
+  $prefixes: ()
+  @each $browser in $browsers
+    $prefixes: append($prefixes, map-get($prefixes-by-browser, $browser))
+
+  @return $prefixes
+
+@debug prefixes-for-browsers("firefox" "ie")  // moz ms
+@mixin syntax-colors($args...)
+  @debug keywords($args)  // (string: #080, comment: #800, $variable: $60b)
+
+  @each $name, $color in keywords($args)
+    pre span.stx-#{$name}
+      color: $color
+
+@include syntax-colors($string: #080, $comment: #800, $variable: #60b);
+$font-weights: ("regular": 400, "medium": 500, "bold": 700)
+
+@debug map-get($font-weights, "medium")  // 500
+@debug map-get($font-weights, "extra-bold")  // null
+$icons: ("eye": "\f112", "start": "\f12e", "stop": "\f12f")
+
+@each $name, $glyph in $icons
+  .icon-#{$name}:before
+    display: inline-block
+    font-family: "Icon Font"
+    content: $glyph
+
+$prefixes-by-browser: ("firefox": moz, "safari": webkit, "ie": ms)
+
+@mixin add-browser-prefix($browser, $prefix)
+  $prefixes-by-browser: map-merge($prefixes-by-browser, ($browser: $prefix))
+
+@include add-browser-prefix("opera", o)
+@debug $prefixes-by-browser
+// ("firefox": moz, "safari": webkit, "ie": ms, "opera": o)
+@debug 1px == 2px  // false
+@debug 1px == 1px  // true
+@debug 10px < 3px  // false
+@debug comparable(100px, 3in)  // true
+
+@debug str-index("Helvetica Neue", "Roboto")  // null
+@debug map-get(("large": 20px), "small")  // null
+@debug &  // null
+$fonts: ("serif": "Helvetica Neue", "monospace": "Consolas")
+
+h3
+  font: 18px bold map-get($fonts, "sans")
+
+$fonts: ("serif": "Helvetica Neue", "monospace": "Consolas")
+
+h3
+  font:
+    size: 18px
+    weight: bold
+    family: map-get($fonts, "sans")
+
+copy of $list with all elements for which $condition returns `true`
+/// removed.
+@function remove-where($list, $condition)
+  $new-list: ()
+  $separator: list-separator($list)
+  @each $element in $list
+    @if not call($condition, $element)
+      $new-list: append($new-list, $element, $separator: $separator)
+
+  @return $new-list
+
+$fonts: Tahoma, Geneva, "Helvetica Neue", Helvetica, Arial, sans-serif
+
+content
+  @function contains-helvetica($string)
+    @return str-index($string, "Helvetica")
+
+  font-family: remove-where($fonts, get-function("contains-helvetica"))
+
+@debug 1px == 1px  // true
+@debug 1px != 1em  // true
+@debug 1 != 1px  // true
+@debug 96px == 1in  // true
+
+@debug "Helvetica" == Helvetica  // true
+@debug "Helvetica" != "Arial"  // true
+
+@debug hsl(34, 35%, 92.1%) == #f2ece4  // true
+@debug rgba(179, 115, 153, 0.5) != rgba(179, 115, 153, 0.8)  // true
+
+@debug (5px 7px 10px) == (5px 7px 10px)  // true
+@debug (5px 7px 10px) != (10px 14px 20px)  // true
+@debug (5px 7px 10px) != (5px, 7px, 10px)  // true
+@debug (5px 7px 10px) != [5px 7px 10px]  // true
+
+$theme: ("venus": #998099, "nebula": #d2e1dd)
+@debug $theme == ("venus": #998099, "nebula": #d2e1dd)  // true
+@debug $theme != ("venus": #998099, "iron": #dadbdf)  // true
+
+@debug true == true  // true
+@debug true != false  // true
+@debug null != false  // true
+
+@debug get-function("rgba") == get-function("rgba")  // true
+@debug get-function("rgba") != get-function("hsla")  // true
+
+@debug 10s + 15s  // 25s
+@debug 1in - 10px  // 0.8958333333in
+@debug 5px * 3px  // 15px*px
+@debug (12px/4px)  // 3
+@debug 1in % 9px  // 0.0625in
+@debug 15px / 30px  // 15px/30px
+@debug (10px + 5px) / 30px  // 0.5
+
+$result: 15px / 30px
+@debug $result  // 0.5
+
+@function fifteen-divided-by-thirty()
+  @return 15px / 30px
+
+@debug fifteen-divided-by-thirty()  // 0.5
+
+@debug (15px/30px)  // 0.5
+@debug (bold 15px/30px sans-serif)  // bold 15px/30px sans-serif
+@debug 15px/30px + 1  // 1.5
+
+@debug 4px * 6px  // 24px*px (read "square pixels")
+@debug 5px / 2s  // 2.5px/s (read "pixels per second")
+@debug 5px * 30deg / 2s / 24em  // 3.125px*deg/s*em
+//                                 (read "pixel-degrees per second-em")
+
+$degrees-per-second: 20deg/1s
+@debug $degrees-per-second  // 20deg/s
+@debug 1 / $degrees-per-second  // 0.05s/deg
+@debug 100 > 50  // true
+@debug 10px < 17px  // true
+@debug 96px >= 1in  // true
+@debug 1000ms <= 1s  // true
+@debug "Helvetica" + " Neue"  // "Helvetica Neue"
+@debug sans- + serif  // sans-serif
+@debug #{10px + 5px} / 30px  // 15px/30px
+@debug sans - serif  // sans-serif
+
+@debug "Elapsed time: " + 10s  // "Elapsed time: 10s";
+@debug true + " is a boolean value"  // "true is a boolean value";
+
+@debug / 15px  // /15px
+@debug - moz  // -moz
+@debug not true  // false
+@debug not false  // true
+
+@debug true and true  // true
+@debug true and false  // false
+
+@debug true or false  // true
+@debug false or false  // false
+@debug var(--main-bg-color)  // var(--main-bg-color)
+
+$primary: #f2ece4
+$accent: #e1d7d2
+@debug radial-gradient($primary, $accent)  // radial-gradient(#f2ece4, #e1d7d2)
+@debug str-index("Helvetica Neue", "Helvetica")  // 1
+@debug str-index("Helvetica Neue", "Neue")  // 11
+@debug comparable(2px, 1px)  // true
+@debug comparable(100px, 3em)  // false
+@debug comparable(10cm, 3mm)  // true
+@debug append(10px 20px, 30px)  // 10px 20px 30px
+@debug append((blue, red), green)  // blue, red, green
+@debug append(10px 20px, 30px 40px)  // 10px 20px (30px 40px)
+@debug append(10px, 20px, $separator: comma)  // 10px, 20px
+@debug append((blue, red), green, $separator: space)  // blue red green
+@mixin syntax-colors($args...)
+  @debug keywords($args)  // (string: #080, comment: #800, $variable: $60b)
+
+  @each $name, $color in keywords($args)
+    pre span.stx-#{$name}
+      color: $color
+
+@include syntax-colors($string: #080, $comment: #800, $variable: #60b);
+
+$font-weights: ("regular": 400, "medium": 500, "bold": 700)
+
+@debug map-values($font-weights)  // 400, 500, 700
+
+.icon-#{$name}
+  position: absolute
+  #{$top-or-bottom}: 0
+  -#{$prefix}-#{$property}: $value
+  .icon-#{$name}
+    position: absolute
+    #{$top-or-bottom}: 0
+    -#{$prefix}-#{$property}-image: $value
+
diff --git a/autotests/html/highlight.scss.html b/autotests/html/highlight.scss.html index baef4c2..23305ce 100644 --- a/autotests/html/highlight.scss.html +++ b/autotests/html/highlight.scss.html @@ -1,716 +1,726 @@ 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 */
+	--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)}');
+  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;
+$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...);
+  @include colors($values...);
 }
 
 $value-map: (text: #00ff00, background: #0000ff, border: #ff0000);
 .secondary {
-  @include colors($value-map...);
+  @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"};
+
+.icon-#{$name} {
+  position: absolute;
+  #{$top-or-bottom}: 0;
+  -#{$prefix}-#{$property}: $value;
+  .icon-#{$name} {
+    position: absolute;
+    #{$top-or-bottom}: 0;
+    -#{$prefix}-#{$property}-image: $value
+  }
 }
 
diff --git a/autotests/html/review128925-1.scss.html b/autotests/html/review128925-1.scss.html index 79db0f9..d9b0f96 100644 --- a/autotests/html/review128925-1.scss.html +++ b/autotests/html/review128925-1.scss.html @@ -1,218 +1,218 @@ review128925-1.scss
 /*
  * SCSS Syntax Highlight Sample File (Standard)
  *
  * This file contains most SCSS syntax, CSS3 properties, advanced code structure.
  * It is NOT a valid SCSS file that can be compiled by SCSS preprocessors.
  *
  * @author  Guo Yunhe guoyunhebrave@gmail.com
  * @date    2016-09-15
  */
 
 /*
  * Block comment
  *
  * Alert keywords:
  * TODO BUG FIXME
  */
 
 @charset "UTF-8";
 
 @import "mixins/button";
 
 // Variable define
 
 $image-path:            "../../static/images";
 $default-text-color:    #333 !default; // Default can be overrided
 $default-font-size:     16px !default;
 $default-font-family:   Roboto, "Droid Sans", sans-serif;
 $default-font-weight:   400;
 $default-line-height:   $default-font-size * 1.8;
 $shadow-transparence:   0.25;
 $box-shadow:            0 0 3px rgba(0,0,0,$shadow-transparence);
 $page-width:            100rem; // kabab-case
 $gapOfArticle:          20px;   // camelCase
 $body_background_color: white;  // snake_case
 
 // Mixins
 
 @mixin border-radius($radius) {
   -webkit-border-radius: $radius;
      -moz-border-radius: $radius;
       -ms-border-radius: $radius;
           border-radius: $radius;
 }
 
 .box { @include border-radius(10px); }
 
 // Nesting
 
 #home-page {
 
     header {
         width: 80%;
         margin: 0 auto;
 
         .cover {
             @include border-radius(20px);
             max-width: 100%;
 
             &:hover {
                 background: #ffffff;
             }
 
             .like-button {
                 font-size: $default-font-size * 0.8;
 
                 @media (max-width: 300px) and (min-width: 200px) {
                     font-size: $default-font-size * 0.8;
 
                     .icon {
                         width: 20px;
                         height: 20px;
                     }
                 }
 
                 @media print {
                     display: none;
                 }
             }
         }
     }
 }
 
 // Extend and inheritance
 
 .message {
     border: $border-light;
     background-color: #f0f0f0;
 }
 
 .message-danger {
     @extend .message;
 }
 
 
 // Control structures
 
 @mixin does-parent-exist {
     @if & {
         &:hover {
             color: red;
         }
     } @else {
         a {
             color: red;
         }
     }
 }
 
 
 // Operators
 
 .container { width: 100%; }
 
 article[role="main"] {
   float: left;
   width: 600px / 960px * 100%;
 }
 
 aside[role="complementary"] {
   float: right;
   width: 300px / 960px * 100%;
 }
 
 
 // Functions - see http://sass-lang.com/documentation/Sass/Script/Functions.html
 
 $color1: hsl(120deg, 100%, 50%);
-$color2: rgb($red, $green, blue($color1));
+$color2: rgb($red, $green, blue($color1));
 $color3: mix($color1, $color2, [$weight]);
 
 
 // Properties
 
 html, body {
     font-family: "Droid Sans", Arial, sans-serif;
     font-size: 11pt;
     line-height: 1.5em;
     max-width: 300px + $page-width - $gap / 2;
     background: $bg_color;
     text-shadow: 0 0 2px rgba(0,0,0, $transparence);
     box-sizing: border-box;
 }
 
 
 // Selectors
 
 blockquote {
     margin: 0;
 }
 
 header #logo {
     width: 100px;
 }
 
 div#footer .link {
     color: blue;
 }
 
 sidebar #subscribe .subscribe_form input[type="text"] {
     font-size: 20px;
 }
 
 sidebar #subscribe .subscribe_form:nth-child(2n + 1):hover input[class*="small-"] {
     font-weight: bold;
 }
 
 
 // Media Queries
 
 @media print {
     .container {
         width: 100%;
     }
 }
 
 @media screen and (min-width: 768px) {
     .container {
         width: 600px;
     }
 }
 
 @media screen and (min-width: 768px) and (max-width: 960px) {
     .container {
         width: 720px;
     }
 }
 
 
 // Fontface
 
 @font-face {
     font-family: MyHelvetica;
     src: local("Helvetica Neue Bold"),
         local("HelveticaNeue-Bold"),
         url(MgOpenModernaBold.ttf);
     font-weight: bold;
 }
 
 // Animation (Keyframes)
 
 @keyframes slidein {
     from {
         margin-left: 100%;
         width: 300%;
     }
 
     to {
         margin-left: 0%;
         width: 100%;
     }
 }
 
diff --git a/autotests/input/highlight.sass b/autotests/input/highlight.sass new file mode 100644 index 0000000..3776aca --- /dev/null +++ b/autotests/input/highlight.sass @@ -0,0 +1,824 @@ +html, +body, +ul, +ol + margin: 0 + padding: 0 + +@import reset +body + font: 100% Helvetica, sans-serif + background-color: #efefef + +$font-stack: Helvetica, sans-serif +$primary-color: #333 + +body + font: 100% $font-stack + color: $primary-color +.container + width: 100% + +article[role="main"] + float: left + width: 600px / 960px * 100% + +%message-shared + border: 1px solid #ccc + padding: 10px + color: #333 + +.message + @extend %message-shared + +.success + @extend %message-shared + border-color: green + +=transform($property) + -webkit-transform: $property + -ms-transform: $property + transform: $property +.box + +transform(rotate(30deg)) + + // This comment won't be included in the CSS. + This is also commented out. + #a +/* But this comment will, except in compressed mode. + +/* It can also contain interpolation: + 1 + 1 = #{1 + 1} + 1 + 1 = #{1 + 1} + 1 + 1 = #{1 + 1} +#a + +// But this comment will, except in compressed mode. + +// It can also contain interpolation: + 1 + 1 = #{1 + 1} + 1 + 1 = #{1 + 1} + 1 + 1 = #{1 + 1} +#a + +/*! This comment will be included even in compressed mode. + +#a + +/**/ + +p .sans + font: Helvetica, /* Inline comments must be closed. */ sans-serif + +p .sans + font/*comment*/: Helvetica, /* Inline comments must be closed. */ sans-serif // comment + +/// Computes an exponent. +/// +/// @param {number} $base +/// The number to multiply by itself. +/// @param {integer (unitless)} $exponent +/// The number of `$base`s to multiply together. +/// @return {number} `$base` to the power of `$exponent`. +@function pow($base, $exponent) + $result: 1 + @for $_ from 1 through $exponent + $result: $result * $base + + @return $result + +$roboto-font-path: "../fonts/roboto" + +@font-face + // This is parsed as a normal function call that takes a quoted string. + src: url("#{$roboto-font-path}/Roboto-Thin.woff2") format("woff2") + src: url($roboto-font-path + "/Roboto-Light.woff2") format("woff2") + src: url(#{$roboto-font-path}/Roboto-Regular.woff2) format("woff2") + + font-family: "Roboto" + font-weight: 100 + +.logo + $width: 800px + width: $width + position: absolute + left: calc(50% - #{$width / 2}) + top: 0 + +$padding: 12px + +.post + // Since these max() calls don't use any Sass features other than + // interpolation, they're compiled to CSS max() calls. + padding-left: max(#{$padding}, env(safe-area-inset-left)) + padding-right: max(#{$padding}, env(safe-area-inset-right)) + + +.sidebar + // Since these refer to a Sass variable without interpolation, they call + // Sass's built-in max() function. + padding-left: max($padding, 20px) + padding-right: max($padding, 20px) + +.circle + $size: 100px + width: $size + height: $size + border-radius: $size / 2 + +@mixin prefix($property, $value, $prefixes) + @each $prefix in $prefixes + -#{$prefix}-#{$property}: $value + + #{$property}: $value + + +.gray + @include prefix(filter, grayscale(50%), moz webkit) + +.enlarge + font-size: 14px + transition: + property: font-size + duration: 4s + delay: 2s + + &:hover + font-size: 36px + +.info-page + margin: auto + bottom: 10px + top: 2px + +$rounded-corners: false + +.button + border: 1px solid black + border-radius: if($rounded-corners, 5px, null) + +$primary: #81899b +$accent: #ab2e +$warn: #dfa612aa + +:root + --primary: #{$primary} + --accent: #{$accent} + --warn: #{$warn} + + // Even though this looks like a Sass variable, it's valid CSS so it's not + // evaluated. + --consumed-by-js: $primary + +$font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto +$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas + +:root + --font-family-sans-serif: #{inspect($font-family-sans-serif)} + --font-family-monospace: #{inspect($font-family-monospace)} + +.alert + // The parent selector can be used to add pseudo-classes to the outer + // selector. + &:hover + font-weight: bold + + + // It can also be used to style the outer selector in a certain context, such + // as a body set to use a right-to-left language. + [dir=rtl] & + margin-left: 0 + margin-right: 10px + + + // You can even use it as an argument to pseudo-class selectors. + :not(&) + opacity: 0.8 + +@mixin unify-parent($child) + @at-root #{selector-unify(&, $child)} + @content + + + +.wrapper .field + @include unify-parent("input") + +@mixin app-background($color) + #{if(&, '&.app-background', '.app-background')} + background-color: $color + color: rgba(#fff, 0.75) + +@include app-background(#036) + +.sidebar + @include app-background(#c6538c) + +.accordion + max-width: 600px + margin: 4rem auto + + &__copy + display: none + padding: 1rem 1.5rem 2rem 1.5rem + line-height: 1.6 + font-size: 14px + + &--open + display: block + + +.alert:hover, %strong-alert + font-weight: bold + +%strong-alert:hover + color: red + +%toolbelt + box-sizing: border-box + border-top: 1px rgba(#000, .12) solid + + &:hover + border: 2px rgba(#000, .5) solid + +.action-buttons + @extend %toolbelt + color: #4285f4 + +$border-dark: rgba($base-color, 0.88) +$black: #000 !default +$border-radius: 0.25rem !default +$box-shadow: 0 0.5rem 1rem rgba($black, 0.15) !default +$box-shadow: 0 0.5rem 1rem rgba($black, blue($black)) !default +$border-radius: 0.1rem + +@import 'library' + +$global-variable: global value + + // This would fail, because $local-variable isn't in scope: + // local: $local-variable + +$theme-colors: ("success": #28a745, "info": #17a2b8, "warning": #ffc107) + +.alert + // Instead of $theme-color-#{warning} + background-color: map-get($theme-colors, "warning") + +@mixin corner-icon($name, $top-or-bottom, $left-or-right) + .icon-#{$name} + background-image: url("/icons/#{$name}.svg") + position: absolute + #{$top-or-bottom}: 0 + #{$left-or-right}: 0 + +@include corner-icon("mail", top, right) + +@mixin inline-animation($duration) + $name: inline-#{unique-id()} + + @keyframes #{$name} + @content + + animation-name: $name + animation-duration: $duration + animation-iteration-count: infinite + + +.pulse + @include inline-animation(2s) + from + background-color: yellow + to + background-color: red + +.example + unquoted: #{"string"} + + & & + padding: + bottom: 0 + left: 0 + +// style.sass +@import 'foundation/code', 'foundation/lists' + +@import "theme.css" +@import "http://fonts.googleapis.com/css?family=Droid+Sans" +@import url(theme) +@import "landscape" screen and (orientation: landscape) + +@mixin google-font($family) + @import url("http://fonts.googleapis.com/css?family=#{$family}") + +@include google-font("Droid Sans") + +@mixin horizontal-list + @include reset-list + + li + display: inline-block + margin: + left: -2px + right: 2em + +nav ul + @include horizontal-list + +@mixin rtl($property, $ltr-value, $rtl-value) + #{$property}: $ltr-value + + [dir=rtl] & + #{$property}: $rtl-value + +.sidebar + @include rtl(float, left, right) + +@mixin replace-text($image, $x: 50%, $y: 50%) + text-indent: -99999em + overflow: hidden + text-align: left + + background: + image: $image + repeat: no-repeat + position: $x $y + +.mail-icon + @include replace-text(url("/images/mail.svg"), 0) + +@include order(150px, "input.name", "input.address", "input.zip") + +@mixin syntax-colors($args...) + @debug keywords($args) // (string: #080, comment: #800, $variable: $60b) + + @each $name, $color in keywords($args) + pre span.stx-#{$name} + color: $color + +@include syntax-colors($string: #080, $comment: #800, $variable: #60b) + +@mixin media($types...) + @each $type in $types + @media #{$type} + @content($type) + +@include media(screen, print) using ($type) + h1 + font-size: 40px + @if $type == print + font-family: Calluna + +=reset-list + margin: 0 + padding: 0 + list-style: none + +=horizontal-list + +reset-list + + li + display: inline-block + margin: + left: -2px + right: 2em + +nav ul + +horizontal-list +@function pow($base, $exponent) + $result: 1 + @for $_ from 1 through $exponent + $result: $result * $base + + @return $result + +.sidebar + float: left + margin-left: pow(4, 3) * 1px + +@function sum($numbers...) + $sum: 0 + @each $number in $numbers + $sum: $sum + $number + + @return $sum + +.micro + width: sum(50px, 30px, 100px) +@function str-insert($string, $insert, $index) + // Avoid making new strings if we don't need to. + @if str-length($string) == 0 + @return $insert + + $before: str-slice($string, 0, $index) + $after: str-slice($string, $index) + @return $before + $insert + $after + +.error + border: 1px #f00 + background-color: #fdd + + &--serious + @extend .error + border-width: 3px + +@mixin reflexive-position($property, $value) + @if $property != left and $property != right + @error "Property #{$property} must be either left or right." + + $left-value: if($property == right, initial, $value) + $right-value: if($property == right, $value, initial) + + left: $left-value + right: $right-value + [dir=rtl] & + left: $right-value + right: $left-value + +$known-prefixes: webkit, moz, ms, o + +@mixin prefix($property, $value, $prefixes) + @each $prefix in $prefixes + @if not index($known-prefixes, $prefix) + @warn "Unknown prefix #{$prefix}." + + + -#{$prefix}-#{$property}: $value + + #{$property}: $value + + +.tilt + // Oops, we typo'd "webkit" as "wekbit"! + @include prefix(transform, rotate(15deg), wekbit ms) + +@mixin inset-divider-offset($offset, $padding) + $divider-offset: (2 * $padding) + $offset + @debug "divider offset: #{$divider-offset}" + + margin-left: $divider-offset + width: calc(100% - #{$divider-offset}) + +@mixin unify-parent($child) + @at-root #{selector-unify(&, $child)} + @content + + +.square-av + @include avatar(100px, $circle: false) +.circle-av + @include avatar(100px, $circle: true) + +@mixin theme-colors($light-theme: true) + @if $light-theme + background-color: $light-background + color: $light-text + @else + background-color: $dark-background + color: $dark-text + +.banner + @include theme-colors($light-theme: true) + body.dark & + @include theme-colors($light-theme: false) + +@mixin triangle($size, $color, $direction) + height: 0 + width: 0 + + border-color: transparent + border-style: solid + border-width: $size / 2 + + @if $direction == up + border-bottom-color: $color + @else if $direction == right + border-left-color: $color + @else if $direction == down + border-top-color: $color + @else if $direction == left + border-right-color: $color + @else + @error "Unknown direction #{$direction}." + +@each $size in $sizes + .icon-#{$size} + font-size: $size + height: $size + width: $size + +$icons: ("eye": "\f112", "start": "\f12e", "stop": "\f12f") + +@each $name, $glyph in $icons + .icon-#{$name}:before + display: inline-block + font-family: "Icon Font" + content: $glyph + +$icons: "eye" "\f112" 12px, "start" "\f12e" 16px, "stop" "\f12f" 10px + +@each $name, $glyph, $size in $icons + .icon-#{$name}:before + display: inline-block + font-family: "Icon Font" + content: $glyph + font-size: $size + +@for $i from 1 through 3 + ul:nth-child(3n + #{$i}) + background-color: lighten($base-color, $i * 5%) + +/// Divides `$value` by `$ratio` until it's below `$base`. +@function scale-below($value, $base, $ratio: 1.618) + @while $value > $base + $value: $value / $ratio + @return $value + +@namespace svg url(http://www.w3.org/2000/svg) + +@font-face + font-family: "Open Sans" + src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2") + +@counter-style thumbs + system: cyclic + symbols: "\1F44D" + +@mixin sticky-position + position: fixed + @supports (position: sticky) + position: sticky + +@media (hover: hover) + .button:hover + border: 2px solid black + + @media (color) + border-color: #036 + +@keyframes slide-in + from + margin-left: 100% + width: 300% + + + 70% + margin-left: 90% + width: 150% + + + to + margin-left: 0% + width: 100% + +@debug 100 // 100 +@debug 0.8 // 0.8 +@debug 16px // 16px +@debug 5px * 2px // 10px*px (read "square pixels") +@debug 5.2e3 // 5200 +@debug 6e-2 // 0.06 +@debug 4px * 6px // 24px*px (read "square pixels") +@debug 5px / 2s // 2.5px/s (read "pixels per second") +@debug 5px * 30deg / 2s / 24em // 3.125px*deg/s*em +// (read "pixel-degrees per second-em") + +$degrees-per-second: 20deg/1s +@debug $degrees-per-second // 20deg/s +@debug 1 / $degrees-per-second // 0.05s/deg +$transition-speed: 1s/50px + +@debug unquote(".widget:hover") // .widget:hover +@debug quote(bold) // "bold" +@debug 0.012345678912345 // 0.0123456789 +@debug 0.01234567891 == 0.01234567899 // true +@debug 1.00000000009 // 1 +@debug 0.99999999991 // 1 +@debug "\"" // '"' +@debug \.widget // \.widget +@debug "\a" // "\a" (a string containing only a newline) +@debug "line1\a line2" // "line1\a line2" (foo and bar are separated by a newline) +@debug "Nat + Liz \1F46D" // "Nat + Liz 👭" +@debug "Helvetica Neue" // "Helvetica Neue" +@debug "C:\\Program Files" // "C:\\Program Files" +@debug "\"Don't Fear the Reaper\"" // "\"Don't Fear the Reaper\"" +@debug "line1\a line2" // "line1\a line2" + +$roboto-variant: "Mono" +@debug "Roboto #{$roboto-variant}" // "Roboto Mono" +@debug bold // bold +@debug -webkit-flex // -webkit-flex +@debug --123 // --123 + +$prefix: ms +@debug -#{$prefix}-flex // -ms-flex +@debug \1F46D // 👭 +@debug \21 // \! +@debug \7Fx // \7f x +@debug str-length(\7Fx) // 5 +@debug str-index("Helvetica Neue", "Helvetica") // 1 +@debug str-index("Helvetica Neue", "Neue") // 11 +@debug str-slice("Roboto Mono", -4) // "Mono" +@debug #f2ece4 // #f2ece4 +@debug #b37399aa // rgba(179, 115, 153, 67%) +@debug midnightblue // #191970 +@debug rgb(204, 102, 153) // #c69 +@debug rgba(107, 113, 127, 0.8) // rgba(107, 113, 127, 0.8) +@debug hsl(228, 7%, 86%) // #dadbdf +@debug hsla(20, 20%, 85%, 0.7) // rgb(225, 215, 210, 0.7) +$venus: #998099 + +@debug scale-color($venus, $lightness: +15%) // #a893a8 +@debug mix($venus, midnightblue) // #594d85 +@debug nth(10px 12px 16px, 2) // 12px +@debug nth([line1, line2, line3], -1) // line3 +$prefixes-by-browser: ("firefox": moz, "safari": webkit, "ie": ms) + +@function prefixes-for-browsers($browsers) + $prefixes: () + @each $browser in $browsers + $prefixes: append($prefixes, map-get($prefixes-by-browser, $browser)) + + @return $prefixes + +@debug prefixes-for-browsers("firefox" "ie") // moz ms +@mixin syntax-colors($args...) + @debug keywords($args) // (string: #080, comment: #800, $variable: $60b) + + @each $name, $color in keywords($args) + pre span.stx-#{$name} + color: $color + +@include syntax-colors($string: #080, $comment: #800, $variable: #60b); +$font-weights: ("regular": 400, "medium": 500, "bold": 700) + +@debug map-get($font-weights, "medium") // 500 +@debug map-get($font-weights, "extra-bold") // null +$icons: ("eye": "\f112", "start": "\f12e", "stop": "\f12f") + +@each $name, $glyph in $icons + .icon-#{$name}:before + display: inline-block + font-family: "Icon Font" + content: $glyph + +$prefixes-by-browser: ("firefox": moz, "safari": webkit, "ie": ms) + +@mixin add-browser-prefix($browser, $prefix) + $prefixes-by-browser: map-merge($prefixes-by-browser, ($browser: $prefix)) + +@include add-browser-prefix("opera", o) +@debug $prefixes-by-browser +// ("firefox": moz, "safari": webkit, "ie": ms, "opera": o) +@debug 1px == 2px // false +@debug 1px == 1px // true +@debug 10px < 3px // false +@debug comparable(100px, 3in) // true + +@debug str-index("Helvetica Neue", "Roboto") // null +@debug map-get(("large": 20px), "small") // null +@debug & // null +$fonts: ("serif": "Helvetica Neue", "monospace": "Consolas") + +h3 + font: 18px bold map-get($fonts, "sans") + +$fonts: ("serif": "Helvetica Neue", "monospace": "Consolas") + +h3 + font: + size: 18px + weight: bold + family: map-get($fonts, "sans") + +copy of $list with all elements for which $condition returns `true` +/// removed. +@function remove-where($list, $condition) + $new-list: () + $separator: list-separator($list) + @each $element in $list + @if not call($condition, $element) + $new-list: append($new-list, $element, $separator: $separator) + + @return $new-list + +$fonts: Tahoma, Geneva, "Helvetica Neue", Helvetica, Arial, sans-serif + +content + @function contains-helvetica($string) + @return str-index($string, "Helvetica") + + font-family: remove-where($fonts, get-function("contains-helvetica")) + +@debug 1px == 1px // true +@debug 1px != 1em // true +@debug 1 != 1px // true +@debug 96px == 1in // true + +@debug "Helvetica" == Helvetica // true +@debug "Helvetica" != "Arial" // true + +@debug hsl(34, 35%, 92.1%) == #f2ece4 // true +@debug rgba(179, 115, 153, 0.5) != rgba(179, 115, 153, 0.8) // true + +@debug (5px 7px 10px) == (5px 7px 10px) // true +@debug (5px 7px 10px) != (10px 14px 20px) // true +@debug (5px 7px 10px) != (5px, 7px, 10px) // true +@debug (5px 7px 10px) != [5px 7px 10px] // true + +$theme: ("venus": #998099, "nebula": #d2e1dd) +@debug $theme == ("venus": #998099, "nebula": #d2e1dd) // true +@debug $theme != ("venus": #998099, "iron": #dadbdf) // true + +@debug true == true // true +@debug true != false // true +@debug null != false // true + +@debug get-function("rgba") == get-function("rgba") // true +@debug get-function("rgba") != get-function("hsla") // true + +@debug 10s + 15s // 25s +@debug 1in - 10px // 0.8958333333in +@debug 5px * 3px // 15px*px +@debug (12px/4px) // 3 +@debug 1in % 9px // 0.0625in +@debug 15px / 30px // 15px/30px +@debug (10px + 5px) / 30px // 0.5 + +$result: 15px / 30px +@debug $result // 0.5 + +@function fifteen-divided-by-thirty() + @return 15px / 30px + +@debug fifteen-divided-by-thirty() // 0.5 + +@debug (15px/30px) // 0.5 +@debug (bold 15px/30px sans-serif) // bold 15px/30px sans-serif +@debug 15px/30px + 1 // 1.5 + +@debug 4px * 6px // 24px*px (read "square pixels") +@debug 5px / 2s // 2.5px/s (read "pixels per second") +@debug 5px * 30deg / 2s / 24em // 3.125px*deg/s*em +// (read "pixel-degrees per second-em") + +$degrees-per-second: 20deg/1s +@debug $degrees-per-second // 20deg/s +@debug 1 / $degrees-per-second // 0.05s/deg +@debug 100 > 50 // true +@debug 10px < 17px // true +@debug 96px >= 1in // true +@debug 1000ms <= 1s // true +@debug "Helvetica" + " Neue" // "Helvetica Neue" +@debug sans- + serif // sans-serif +@debug #{10px + 5px} / 30px // 15px/30px +@debug sans - serif // sans-serif + +@debug "Elapsed time: " + 10s // "Elapsed time: 10s"; +@debug true + " is a boolean value" // "true is a boolean value"; + +@debug / 15px // /15px +@debug - moz // -moz +@debug not true // false +@debug not false // true + +@debug true and true // true +@debug true and false // false + +@debug true or false // true +@debug false or false // false +@debug var(--main-bg-color) // var(--main-bg-color) + +$primary: #f2ece4 +$accent: #e1d7d2 +@debug radial-gradient($primary, $accent) // radial-gradient(#f2ece4, #e1d7d2) +@debug str-index("Helvetica Neue", "Helvetica") // 1 +@debug str-index("Helvetica Neue", "Neue") // 11 +@debug comparable(2px, 1px) // true +@debug comparable(100px, 3em) // false +@debug comparable(10cm, 3mm) // true +@debug append(10px 20px, 30px) // 10px 20px 30px +@debug append((blue, red), green) // blue, red, green +@debug append(10px 20px, 30px 40px) // 10px 20px (30px 40px) +@debug append(10px, 20px, $separator: comma) // 10px, 20px +@debug append((blue, red), green, $separator: space) // blue red green +@mixin syntax-colors($args...) + @debug keywords($args) // (string: #080, comment: #800, $variable: $60b) + + @each $name, $color in keywords($args) + pre span.stx-#{$name} + color: $color + +@include syntax-colors($string: #080, $comment: #800, $variable: #60b); + +$font-weights: ("regular": 400, "medium": 500, "bold": 700) + +@debug map-values($font-weights) // 400, 500, 700 + +.icon-#{$name} + position: absolute + #{$top-or-bottom}: 0 + -#{$prefix}-#{$property}: $value + .icon-#{$name} + position: absolute + #{$top-or-bottom}: 0 + -#{$prefix}-#{$property}-image: $value diff --git a/autotests/input/highlight.scss b/autotests/input/highlight.scss index aa5b386..9c0bb7e 100644 --- a/autotests/input/highlight.scss +++ b/autotests/input/highlight.scss @@ -1,709 +1,719 @@ /** * 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"}; + +.icon-#{$name} { + position: absolute; + #{$top-or-bottom}: 0; + -#{$prefix}-#{$property}: $value; + .icon-#{$name} { + position: absolute; + #{$top-or-bottom}: 0; + -#{$prefix}-#{$property}-image: $value + } } diff --git a/autotests/reference/highlight.css.ref b/autotests/reference/highlight.css.ref index a262282..cd17f06 100644 --- a/autotests/reference/highlight.css.ref +++ b/autotests/reference/highlight.css.ref @@ -1,286 +1,286 @@ /**
* This is a pseudo CSS file to test Kate's CSS 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;
// this is no comment, it's just broken!
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 */
+ --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 }
}
diff --git a/autotests/reference/highlight.sass.ref b/autotests/reference/highlight.sass.ref new file mode 100644 index 0000000..ae45695 --- /dev/null +++ b/autotests/reference/highlight.sass.ref @@ -0,0 +1,824 @@ +html,
+body,
+ul,
+ol
+ margin: 0
+ padding: 0
+
+@import reset
+body
+ font: 100% Helvetica, sans-serif
+ background-color: #efefef
+
+$font-stack: Helvetica, sans-serif
+$primary-color: #333
+
+body
+ font: 100% $font-stack
+ color: $primary-color
+.container
+ width: 100%
+
+article[role="main"]
+ float: left
+ width: 600px / 960px * 100%
+
+%message-shared
+ border: 1px solid #ccc
+ padding: 10px
+ color: #333
+
+.message
+ @extend %message-shared
+
+.success
+ @extend %message-shared
+ border-color: green
+
+=transform($property)
+ -webkit-transform: $property
+ -ms-transform: $property
+ transform: $property
+.box
+ +transform(rotate(30deg))
+
+ // This comment won't be included in the CSS.
+ This is also commented out.
+ #a
+/* But this comment will, except in compressed mode.
+
+/* It can also contain interpolation:
+ 1 + 1 = #{1 + 1}
+ 1 + 1 = #{1 + 1}
+ 1 + 1 = #{1 + 1}
+#a
+
+// But this comment will, except in compressed mode.
+
+// It can also contain interpolation:
+ 1 + 1 = #{1 + 1}
+ 1 + 1 = #{1 + 1}
+ 1 + 1 = #{1 + 1}
+#a
+
+/*! This comment will be included even in compressed mode.
+
+#a
+
+/**/
+
+p .sans
+ font: Helvetica, /* Inline comments must be closed. */ sans-serif
+
+p .sans
+ font/*comment*/: Helvetica, /* Inline comments must be closed. */ sans-serif // comment
+
+/// Computes an exponent.
+///
+/// @param {number} $base
+/// The number to multiply by itself.
+/// @param {integer (unitless)} $exponent
+/// The number of `$base`s to multiply together.
+/// @return {number} `$base` to the power of `$exponent`.
+@function pow($base, $exponent)
+ $result: 1
+ @for $_ from 1 through $exponent
+ $result: $result * $base
+
+ @return $result
+
+$roboto-font-path: "../fonts/roboto"
+
+@font-face
+ // This is parsed as a normal function call that takes a quoted string.
+ src: url("#{$roboto-font-path}/Roboto-Thin.woff2") format("woff2")
+ src: url($roboto-font-path + "/Roboto-Light.woff2") format("woff2")
+ src: url(#{$roboto-font-path}/Roboto-Regular.woff2) format("woff2")
+
+ font-family: "Roboto"
+ font-weight: 100
+
+.logo
+ $width: 800px
+ width: $width
+ position: absolute
+ left: calc(50% - #{$width / 2})
+ top: 0
+
+$padding: 12px
+
+.post
+ // Since these max() calls don't use any Sass features other than
+ // interpolation, they're compiled to CSS max() calls.
+ padding-left: max(#{$padding}, env(safe-area-inset-left))
+ padding-right: max(#{$padding}, env(safe-area-inset-right))
+
+
+.sidebar
+ // Since these refer to a Sass variable without interpolation, they call
+ // Sass's built-in max() function.
+ padding-left: max($padding, 20px)
+ padding-right: max($padding, 20px)
+
+.circle
+ $size: 100px
+ width: $size
+ height: $size
+ border-radius: $size / 2
+
+@mixin prefix($property, $value, $prefixes)
+ @each $prefix in $prefixes
+ -#{$prefix}-#{$property}: $value
+
+ #{$property}: $value
+
+
+.gray
+ @include prefix(filter, grayscale(50%), moz webkit)
+
+.enlarge
+ font-size: 14px
+ transition:
+ property: font-size
+ duration: 4s
+ delay: 2s
+
+ &:hover
+ font-size: 36px
+
+.info-page
+ margin: auto
+ bottom: 10px
+ top: 2px
+
+$rounded-corners: false
+
+.button
+ border: 1px solid black
+ border-radius: if($rounded-corners, 5px, null)
+
+$primary: #81899b
+$accent: #ab2e
+$warn: #dfa612aa
+
+:root
+ --primary: #{$primary}
+ --accent: #{$accent}
+ --warn: #{$warn}
+
+ // Even though this looks like a Sass variable, it's valid CSS so it's not
+ // evaluated.
+ --consumed-by-js: $primary
+
+$font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto
+$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas
+
+:root
+ --font-family-sans-serif: #{inspect($font-family-sans-serif)}
+ --font-family-monospace: #{inspect($font-family-monospace)}
+
+.alert
+ // The parent selector can be used to add pseudo-classes to the outer
+ // selector.
+ &:hover
+ font-weight: bold
+
+
+ // It can also be used to style the outer selector in a certain context, such
+ // as a body set to use a right-to-left language.
+ [dir=rtl] &
+ margin-left: 0
+ margin-right: 10px
+
+
+ // You can even use it as an argument to pseudo-class selectors.
+ :not(&)
+ opacity: 0.8
+
+@mixin unify-parent($child)
+ @at-root #{selector-unify(&, $child)}
+ @content
+
+
+
+.wrapper .field
+ @include unify-parent("input")
+
+@mixin app-background($color)
+ #{if(&, '&.app-background', '.app-background')}
+ background-color: $color
+ color: rgba(#fff, 0.75)
+
+@include app-background(#036)
+
+.sidebar
+ @include app-background(#c6538c)
+
+.accordion
+ max-width: 600px
+ margin: 4rem auto
+
+ &__copy
+ display: none
+ padding: 1rem 1.5rem 2rem 1.5rem
+ line-height: 1.6
+ font-size: 14px
+
+ &--open
+ display: block
+
+
+.alert:hover, %strong-alert
+ font-weight: bold
+
+%strong-alert:hover
+ color: red
+
+%toolbelt
+ box-sizing: border-box
+ border-top: 1px rgba(#000, .12) solid
+
+ &:hover
+ border: 2px rgba(#000, .5) solid
+
+.action-buttons
+ @extend %toolbelt
+ color: #4285f4
+
+$border-dark: rgba($base-color, 0.88)
+$black: #000 !default
+$border-radius: 0.25rem !default
+$box-shadow: 0 0.5rem 1rem rgba($black, 0.15) !default
+$box-shadow: 0 0.5rem 1rem rgba($black, blue($black)) !default
+$border-radius: 0.1rem
+
+@import 'library'
+
+$global-variable: global value
+
+ // This would fail, because $local-variable isn't in scope:
+ // local: $local-variable
+
+$theme-colors: ("success": #28a745, "info": #17a2b8, "warning": #ffc107)
+
+.alert
+ // Instead of $theme-color-#{warning}
+ background-color: map-get($theme-colors, "warning")
+
+@mixin corner-icon($name, $top-or-bottom, $left-or-right)
+ .icon-#{$name}
+ background-image: url("/icons/#{$name}.svg")
+ position: absolute
+ #{$top-or-bottom}: 0
+ #{$left-or-right}: 0
+
+@include corner-icon("mail", top, right)
+
+@mixin inline-animation($duration)
+ $name: inline-#{unique-id()}
+
+ @keyframes #{$name}
+ @content
+
+ animation-name: $name
+ animation-duration: $duration
+ animation-iteration-count: infinite
+
+
+.pulse
+ @include inline-animation(2s)
+ from
+ background-color: yellow
+ to
+ background-color: red
+
+.example
+ unquoted: #{"string"}
+
+ & &
+ padding:
+ bottom: 0
+ left: 0
+
+// style.sass
+@import 'foundation/code', 'foundation/lists'
+
+@import "theme.css"
+@import "http://fonts.googleapis.com/css?family=Droid+Sans"
+@import url(theme)
+@import "landscape" screen and (orientation: landscape)
+
+@mixin google-font($family)
+ @import url("http://fonts.googleapis.com/css?family=#{$family}")
+
+@include google-font("Droid Sans")
+
+@mixin horizontal-list
+ @include reset-list
+
+ li
+ display: inline-block
+ margin:
+ left: -2px
+ right: 2em
+
+nav ul
+ @include horizontal-list
+
+@mixin rtl($property, $ltr-value, $rtl-value)
+ #{$property}: $ltr-value
+
+ [dir=rtl] &
+ #{$property}: $rtl-value
+
+.sidebar
+ @include rtl(float, left, right)
+
+@mixin replace-text($image, $x: 50%, $y: 50%)
+ text-indent: -99999em
+ overflow: hidden
+ text-align: left
+
+ background:
+ image: $image
+ repeat: no-repeat
+ position: $x $y
+
+.mail-icon
+ @include replace-text(url("/images/mail.svg"), 0)
+
+@include order(150px, "input.name", "input.address", "input.zip")
+
+@mixin syntax-colors($args...)
+ @debug keywords($args) // (string: #080, comment: #800, $variable: $60b)
+
+ @each $name, $color in keywords($args)
+ pre span.stx-#{$name}
+ color: $color
+
+@include syntax-colors($string: #080, $comment: #800, $variable: #60b)
+
+@mixin media($types...)
+ @each $type in $types
+ @media #{$type}
+ @content($type)
+
+@include media(screen, print) using ($type)
+ h1
+ font-size: 40px
+ @if $type == print
+ font-family: Calluna
+
+=reset-list
+ margin: 0
+ padding: 0
+ list-style: none
+
+=horizontal-list
+ +reset-list
+
+ li
+ display: inline-block
+ margin:
+ left: -2px
+ right: 2em
+
+nav ul
+ +horizontal-list
+@function pow($base, $exponent)
+ $result: 1
+ @for $_ from 1 through $exponent
+ $result: $result * $base
+
+ @return $result
+
+.sidebar
+ float: left
+ margin-left: pow(4, 3) * 1px
+
+@function sum($numbers...)
+ $sum: 0
+ @each $number in $numbers
+ $sum: $sum + $number
+
+ @return $sum
+
+.micro
+ width: sum(50px, 30px, 100px)
+@function str-insert($string, $insert, $index)
+ // Avoid making new strings if we don't need to.
+ @if str-length($string) == 0
+ @return $insert
+
+ $before: str-slice($string, 0, $index)
+ $after: str-slice($string, $index)
+ @return $before + $insert + $after
+
+.error
+ border: 1px #f00
+ background-color: #fdd
+
+ &--serious
+ @extend .error
+ border-width: 3px
+
+@mixin reflexive-position($property, $value)
+ @if $property != left and $property != right
+ @error "Property #{$property} must be either left or right."
+
+ $left-value: if($property == right, initial, $value)
+ $right-value: if($property == right, $value, initial)
+
+ left: $left-value
+ right: $right-value
+ [dir=rtl] &
+ left: $right-value
+ right: $left-value
+
+$known-prefixes: webkit, moz, ms, o
+
+@mixin prefix($property, $value, $prefixes)
+ @each $prefix in $prefixes
+ @if not index($known-prefixes, $prefix)
+ @warn "Unknown prefix #{$prefix}."
+
+
+ -#{$prefix}-#{$property}: $value
+
+ #{$property}: $value
+
+
+.tilt
+ // Oops, we typo'd "webkit" as "wekbit"!
+ @include prefix(transform, rotate(15deg), wekbit ms)
+
+@mixin inset-divider-offset($offset, $padding)
+ $divider-offset: (2 * $padding) + $offset
+ @debug "divider offset: #{$divider-offset}"
+
+ margin-left: $divider-offset
+ width: calc(100% - #{$divider-offset})
+
+@mixin unify-parent($child)
+ @at-root #{selector-unify(&, $child)}
+ @content
+
+
+.square-av
+ @include avatar(100px, $circle: false)
+.circle-av
+ @include avatar(100px, $circle: true)
+
+@mixin theme-colors($light-theme: true)
+ @if $light-theme
+ background-color: $light-background
+ color: $light-text
+ @else
+ background-color: $dark-background
+ color: $dark-text
+
+.banner
+ @include theme-colors($light-theme: true)
+ body.dark &
+ @include theme-colors($light-theme: false)
+
+@mixin triangle($size, $color, $direction)
+ height: 0
+ width: 0
+
+ border-color: transparent
+ border-style: solid
+ border-width: $size / 2
+
+ @if $direction == up
+ border-bottom-color: $color
+ @else if $direction == right
+ border-left-color: $color
+ @else if $direction == down
+ border-top-color: $color
+ @else if $direction == left
+ border-right-color: $color
+ @else
+ @error "Unknown direction #{$direction}."
+
+@each $size in $sizes
+ .icon-#{$size}
+ font-size: $size
+ height: $size
+ width: $size
+
+$icons: ("eye": "\f112", "start": "\f12e", "stop": "\f12f")
+
+@each $name, $glyph in $icons
+ .icon-#{$name}:before
+ display: inline-block
+ font-family: "Icon Font"
+ content: $glyph
+
+$icons: "eye" "\f112" 12px, "start" "\f12e" 16px, "stop" "\f12f" 10px
+
+@each $name, $glyph, $size in $icons
+ .icon-#{$name}:before
+ display: inline-block
+ font-family: "Icon Font"
+ content: $glyph
+ font-size: $size
+
+@for $i from 1 through 3
+ ul:nth-child(3n + #{$i})
+ background-color: lighten($base-color, $i * 5%)
+
+/// Divides `$value` by `$ratio` until it's below `$base`.
+@function scale-below($value, $base, $ratio: 1.618)
+ @while $value > $base
+ $value: $value / $ratio
+ @return $value
+
+@namespace svg url(http://www.w3.org/2000/svg)
+
+@font-face
+ font-family: "Open Sans"
+ src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2")
+
+@counter-style thumbs
+ system: cyclic
+ symbols: "\1F44D"
+
+@mixin sticky-position
+ position: fixed
+ @supports (position: sticky)
+ position: sticky
+
+@media (hover: hover)
+ .button:hover
+ border: 2px solid black
+
+ @media (color)
+ border-color: #036
+
+@keyframes slide-in
+ from
+ margin-left: 100%
+ width: 300%
+
+
+ 70%
+ margin-left: 90%
+ width: 150%
+
+
+ to
+ margin-left: 0%
+ width: 100%
+
+@debug 100 // 100
+@debug 0.8 // 0.8
+@debug 16px // 16px
+@debug 5px * 2px // 10px*px (read "square pixels")
+@debug 5.2e3 // 5200
+@debug 6e-2 // 0.06
+@debug 4px * 6px // 24px*px (read "square pixels")
+@debug 5px / 2s // 2.5px/s (read "pixels per second")
+@debug 5px * 30deg / 2s / 24em // 3.125px*deg/s*em
+// (read "pixel-degrees per second-em")
+
+$degrees-per-second: 20deg/1s
+@debug $degrees-per-second // 20deg/s
+@debug 1 / $degrees-per-second // 0.05s/deg
+$transition-speed: 1s/50px
+
+@debug unquote(".widget:hover") // .widget:hover
+@debug quote(bold) // "bold"
+@debug 0.012345678912345 // 0.0123456789
+@debug 0.01234567891 == 0.01234567899 // true
+@debug 1.00000000009 // 1
+@debug 0.99999999991 // 1
+@debug "\"" // '"'
+@debug \.widget // \.widget
+@debug "\a" // "\a" (a string containing only a newline)
+@debug "line1\a line2" // "line1\a line2" (foo and bar are separated by a newline)
+@debug "Nat + Liz \1F46D" // "Nat + Liz 👭"
+@debug "Helvetica Neue" // "Helvetica Neue"
+@debug "C:\\Program Files" // "C:\\Program Files"
+@debug "\"Don't Fear the Reaper\"" // "\"Don't Fear the Reaper\""
+@debug "line1\a line2" // "line1\a line2"
+
+$roboto-variant: "Mono"
+@debug "Roboto #{$roboto-variant}" // "Roboto Mono"
+@debug bold // bold
+@debug -webkit-flex // -webkit-flex
+@debug --123 // --123
+
+$prefix: ms
+@debug -#{$prefix}-flex // -ms-flex
+@debug \1F46D // 👭
+@debug \21 // \!
+@debug \7Fx // \7f x
+@debug str-length(\7Fx) // 5
+@debug str-index("Helvetica Neue", "Helvetica") // 1
+@debug str-index("Helvetica Neue", "Neue") // 11
+@debug str-slice("Roboto Mono", -4) // "Mono"
+@debug #f2ece4 // #f2ece4
+@debug #b37399aa // rgba(179, 115, 153, 67%)
+@debug midnightblue // #191970
+@debug rgb(204, 102, 153) // #c69
+@debug rgba(107, 113, 127, 0.8) // rgba(107, 113, 127, 0.8)
+@debug hsl(228, 7%, 86%) // #dadbdf
+@debug hsla(20, 20%, 85%, 0.7) // rgb(225, 215, 210, 0.7)
+$venus: #998099
+
+@debug scale-color($venus, $lightness: +15%) // #a893a8
+@debug mix($venus, midnightblue) // #594d85
+@debug nth(10px 12px 16px, 2) // 12px
+@debug nth([line1, line2, line3], -1) // line3
+$prefixes-by-browser: ("firefox": moz, "safari": webkit, "ie": ms)
+
+@function prefixes-for-browsers($browsers)
+ $prefixes: ()
+ @each $browser in $browsers
+ $prefixes: append($prefixes, map-get($prefixes-by-browser, $browser))
+
+ @return $prefixes
+
+@debug prefixes-for-browsers("firefox" "ie") // moz ms
+@mixin syntax-colors($args...)
+ @debug keywords($args) // (string: #080, comment: #800, $variable: $60b)
+
+ @each $name, $color in keywords($args)
+ pre span.stx-#{$name}
+ color: $color
+
+@include syntax-colors($string: #080, $comment: #800, $variable: #60b);
+$font-weights: ("regular": 400, "medium": 500, "bold": 700)
+
+@debug map-get($font-weights, "medium") // 500
+@debug map-get($font-weights, "extra-bold") // null
+$icons: ("eye": "\f112", "start": "\f12e", "stop": "\f12f")
+
+@each $name, $glyph in $icons
+ .icon-#{$name}:before
+ display: inline-block
+ font-family: "Icon Font"
+ content: $glyph
+
+$prefixes-by-browser: ("firefox": moz, "safari": webkit, "ie": ms)
+
+@mixin add-browser-prefix($browser, $prefix)
+ $prefixes-by-browser: map-merge($prefixes-by-browser, ($browser: $prefix))
+
+@include add-browser-prefix("opera", o)
+@debug $prefixes-by-browser
+// ("firefox": moz, "safari": webkit, "ie": ms, "opera": o)
+@debug 1px == 2px // false
+@debug 1px == 1px // true
+@debug 10px < 3px // false
+@debug comparable(100px, 3in) // true
+
+@debug str-index("Helvetica Neue", "Roboto") // null
+@debug map-get(("large": 20px), "small") // null
+@debug & // null
+$fonts: ("serif": "Helvetica Neue", "monospace": "Consolas")
+
+h3
+ font: 18px bold map-get($fonts, "sans")
+
+$fonts: ("serif": "Helvetica Neue", "monospace": "Consolas")
+
+h3
+ font:
+ size: 18px
+ weight: bold
+ family: map-get($fonts, "sans")
+
+copy of $list with all elements for which $condition returns `true`
+/// removed.
+@function remove-where($list, $condition)
+ $new-list: ()
+ $separator: list-separator($list)
+ @each $element in $list
+ @if not call($condition, $element)
+ $new-list: append($new-list, $element, $separator: $separator)
+
+ @return $new-list
+
+$fonts: Tahoma, Geneva, "Helvetica Neue", Helvetica, Arial, sans-serif
+
+content
+ @function contains-helvetica($string)
+ @return str-index($string, "Helvetica")
+
+ font-family: remove-where($fonts, get-function("contains-helvetica"))
+
+@debug 1px == 1px // true
+@debug 1px != 1em // true
+@debug 1 != 1px // true
+@debug 96px == 1in // true
+
+@debug "Helvetica" == Helvetica // true
+@debug "Helvetica" != "Arial" // true
+
+@debug hsl(34, 35%, 92.1%) == #f2ece4 // true
+@debug rgba(179, 115, 153, 0.5) != rgba(179, 115, 153, 0.8) // true
+
+@debug (5px 7px 10px) == (5px 7px 10px) // true
+@debug (5px 7px 10px) != (10px 14px 20px) // true
+@debug (5px 7px 10px) != (5px, 7px, 10px) // true
+@debug (5px 7px 10px) != [5px 7px 10px] // true
+
+$theme: ("venus": #998099, "nebula": #d2e1dd)
+@debug $theme == ("venus": #998099, "nebula": #d2e1dd) // true
+@debug $theme != ("venus": #998099, "iron": #dadbdf) // true
+
+@debug true == true // true
+@debug true != false // true
+@debug null != false // true
+
+@debug get-function("rgba") == get-function("rgba") // true
+@debug get-function("rgba") != get-function("hsla") // true
+
+@debug 10s + 15s // 25s
+@debug 1in - 10px // 0.8958333333in
+@debug 5px * 3px // 15px*px
+@debug (12px/4px) // 3
+@debug 1in % 9px // 0.0625in
+@debug 15px / 30px // 15px/30px
+@debug (10px + 5px) / 30px // 0.5
+
+$result: 15px / 30px
+@debug $result // 0.5
+
+@function fifteen-divided-by-thirty()
+ @return 15px / 30px
+
+@debug fifteen-divided-by-thirty() // 0.5
+
+@debug (15px/30px) // 0.5
+@debug (bold 15px/30px sans-serif) // bold 15px/30px sans-serif
+@debug 15px/30px + 1 // 1.5
+
+@debug 4px * 6px // 24px*px (read "square pixels")
+@debug 5px / 2s // 2.5px/s (read "pixels per second")
+@debug 5px * 30deg / 2s / 24em // 3.125px*deg/s*em
+// (read "pixel-degrees per second-em")
+
+$degrees-per-second: 20deg/1s
+@debug $degrees-per-second // 20deg/s
+@debug 1 / $degrees-per-second // 0.05s/deg
+@debug 100 > 50 // true
+@debug 10px < 17px // true
+@debug 96px >= 1in // true
+@debug 1000ms <= 1s // true
+@debug "Helvetica" + " Neue" // "Helvetica Neue"
+@debug sans- + serif // sans-serif
+@debug #{10px + 5px} / 30px // 15px/30px
+@debug sans - serif // sans-serif
+
+@debug "Elapsed time: " + 10s // "Elapsed time: 10s";
+@debug true + " is a boolean value" // "true is a boolean value";
+
+@debug / 15px // /15px
+@debug - moz // -moz
+@debug not true // false
+@debug not false // true
+
+@debug true and true // true
+@debug true and false // false
+
+@debug true or false // true
+@debug false or false // false
+@debug var(--main-bg-color) // var(--main-bg-color)
+
+$primary: #f2ece4
+$accent: #e1d7d2
+@debug radial-gradient($primary, $accent) // radial-gradient(#f2ece4, #e1d7d2)
+@debug str-index("Helvetica Neue", "Helvetica") // 1
+@debug str-index("Helvetica Neue", "Neue") // 11
+@debug comparable(2px, 1px) // true
+@debug comparable(100px, 3em) // false
+@debug comparable(10cm, 3mm) // true
+@debug append(10px 20px, 30px) // 10px 20px 30px
+@debug append((blue, red), green) // blue, red, green
+@debug append(10px 20px, 30px 40px) // 10px 20px (30px 40px)
+@debug append(10px, 20px, $separator: comma) // 10px, 20px
+@debug append((blue, red), green, $separator: space) // blue red green
+@mixin syntax-colors($args...)
+ @debug keywords($args) // (string: #080, comment: #800, $variable: $60b)
+
+ @each $name, $color in keywords($args)
+ pre span.stx-#{$name}
+ color: $color
+
+@include syntax-colors($string: #080, $comment: #800, $variable: #60b);
+
+$font-weights: ("regular": 400, "medium": 500, "bold": 700)
+
+@debug map-values($font-weights) // 400, 500, 700
+
+.icon-#{$name}
+ position: absolute
+ #{$top-or-bottom}: 0
+ -#{$prefix}-#{$property}: $value
+ .icon-#{$name}
+ position: absolute
+ #{$top-or-bottom}: 0
+ -#{$prefix}-#{$property}-image: $value
diff --git a/autotests/reference/highlight.scss.ref b/autotests/reference/highlight.scss.ref index ce0cd66..79ec820 100644 --- a/autotests/reference/highlight.scss.ref +++ b/autotests/reference/highlight.scss.ref @@ -1,709 +1,719 @@ /**
* 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 */
+ --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)}');
+ 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;
+$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...);
+ @include colors($values...);
}

$value-map: (text: #00ff00, background: #0000ff, border: #ff0000);
.secondary {
- @include colors($value-map...);
+ @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"};
+
+.icon-#{$name} {
+ position: absolute;
+ #{$top-or-bottom}: 0;
+ -#{$prefix}-#{$property}: $value;
+ .icon-#{$name} {
+ position: absolute;
+ #{$top-or-bottom}: 0;
+ -#{$prefix}-#{$property}-image: $value
+ }
}
diff --git a/autotests/reference/review128925-1.scss.ref b/autotests/reference/review128925-1.scss.ref index fee32c7..78a1d5b 100644 --- a/autotests/reference/review128925-1.scss.ref +++ b/autotests/reference/review128925-1.scss.ref @@ -1,211 +1,211 @@ /*
* SCSS Syntax Highlight Sample File (Standard)
*
* This file contains most SCSS syntax, CSS3 properties, advanced code structure.
* It is NOT a valid SCSS file that can be compiled by SCSS preprocessors.
*
* @author Guo Yunhe guoyunhebrave@gmail.com
* @date 2016-09-15
*/

/*
* Block comment
*
* Alert keywords:
* TODO BUG FIXME
*/

@charset "UTF-8";

@import "mixins/button";

// Variable define

$image-path: "../../static/images";
$default-text-color: #333 !default; // Default can be overrided
$default-font-size: 16px !default;
$default-font-family: Roboto, "Droid Sans", sans-serif;
$default-font-weight: 400;
$default-line-height: $default-font-size * 1.8;
$shadow-transparence: 0.25;
$box-shadow: 0 0 3px rgba(0,0,0,$shadow-transparence);
$page-width: 100rem; // kabab-case
$gapOfArticle: 20px; // camelCase
$body_background_color: white; // snake_case

// Mixins

@mixin border-radius($radius) {
-webkit-border-radius: $radius;
-moz-border-radius: $radius;
-ms-border-radius: $radius;
border-radius: $radius;
}

.box { @include border-radius(10px); }

// Nesting

#home-page {

header {
width: 80%;
margin: 0 auto;

.cover {
@include border-radius(20px);
max-width: 100%;

&:hover {
background: #ffffff;
}

.like-button {
font-size: $default-font-size * 0.8;

@media (max-width: 300px) and (min-width: 200px) {
font-size: $default-font-size * 0.8;

.icon {
width: 20px;
height: 20px;
}
}

@media print {
display: none;
}
}
}
}
}

// Extend and inheritance

.message {
border: $border-light;
background-color: #f0f0f0;
}

.message-danger {
@extend .message;
}


// Control structures

@mixin does-parent-exist {
@if & {
&:hover {
color: red;
}
} @else {
a {
color: red;
}
}
}


// Operators

.container { width: 100%; }

article[role="main"] {
float: left;
width: 600px / 960px * 100%;
}

aside[role="complementary"] {
float: right;
width: 300px / 960px * 100%;
}


// Functions - see http://sass-lang.com/documentation/Sass/Script/Functions.html

$color1: hsl(120deg, 100%, 50%);
-$color2: rgb($red, $green, blue($color1));
+$color2: rgb($red, $green, blue($color1));
$color3: mix($color1, $color2, [$weight]);


// Properties

html, body {
font-family: "Droid Sans", Arial, sans-serif;
font-size: 11pt;
line-height: 1.5em;
max-width: 300px + $page-width - $gap / 2;
background: $bg_color;
text-shadow: 0 0 2px rgba(0,0,0, $transparence);
box-sizing: border-box;
}


// Selectors

blockquote {
margin: 0;
}

header #logo {
width: 100px;
}

div#footer .link {
color: blue;
}

sidebar #subscribe .subscribe_form input[type="text"] {
font-size: 20px;
}

sidebar #subscribe .subscribe_form:nth-child(2n + 1):hover input[class*="small-"] {
font-weight: bold;
}


// Media Queries

@media print {
.container {
width: 100%;
}
}

@media screen and (min-width: 768px) {
.container {
width: 600px;
}
}

@media screen and (min-width: 768px) and (max-width: 960px) {
.container {
width: 720px;
}
}


// Fontface

@font-face {
font-family: MyHelvetica;
src: local("Helvetica Neue Bold"),
local("HelveticaNeue-Bold"),
url(MgOpenModernaBold.ttf);
font-weight: bold;
}

// Animation (Keyframes)

@keyframes slidein {
from {
margin-left: 100%;
width: 300%;
}

to {
margin-left: 0%;
width: 100%;
}
}
diff --git a/data/syntax/css.xml b/data/syntax/css.xml index 25a614e..228bb45 100644 --- a/data/syntax/css.xml +++ b/data/syntax/css.xml @@ -1,1735 +1,1738 @@ ]> - + + align-content align-items alignment-baseline align-self all animation animation-delay animation-direction animation-duration animation-fill-mode animation-iteration-count animation-name animation-play-state animation-timing-function appearance azimuth backface-visibility background background-attachment background-blend-mode background-clip background-color background-image background-image-transform background-origin background-position background-repeat background-size baseline-shift block-size block-step block-step-align block-step-insert block-step-round block-step-size bookmark-label bookmark-level bookmark-state border border-block border-block-color border-block-end border-block-end-color border-block-end-style border-block-end-width border-block-start border-block-start-color border-block-start-style border-block-start-width border-block-style border-block-width border-bottom border-bottom-color border-bottom-left-radius border-bottom-right-radius border-bottom-style border-bottom-width border-boundary border-collapse border-color border-image border-image-outset border-image-repeat border-image-slice border-image-source border-image-transform border-image-width border-inline border-inline-color border-inline-end border-inline-end-color border-inline-end-style border-inline-end-width border-inline-start border-inline-start-color border-inline-start-style border-inline-start-width border-inline-style border-inline-width border-left border-left-color border-left-style border-left-width border-radius border-right border-right-color border-right-style border-right-width border-spacing border-style border-top border-top-color border-top-left-radius border-top-right-radius border-top-style border-top-width border-width bottom box-decoration-break box-shadow box-sizing box-snap break-after break-before break-inside caption-side caret caret-color caret-shape clear clip clip-path clip-rule color color-adjust color-interpolation-filters columns column-count column-fill column-gap column-rule column-rule-color column-rule-style column-rule-width column-span column-width contain content continue counter-increment counter-reset counter-set cue cue-after cue-before cursor direction display dominant-baseline elevation empty-cells fill fill-break fill-color fill-image fill-opacity fill-origin fill-position fill-repeat fill-rule fill-size filter flex flex-basis flex-direction flex-flow flex-grow flex-shrink flex-wrap float float-defer float-offset float-reference flood-color flood-opacity flow-from flow-into font font-family font-feature-settings font-kerning font-language-override font-max-size font-min-size font-optical-sizing font-palette font-size font-size-adjust font-stretch font-style font-synthesis font-variant font-variant-alternates font-variant-caps font-variant-east-asian font-variant-emoji font-variant-ligatures font-variant-numeric font-variant-position font-variation-settings font-weight footnote-display footnote-policy gap glyph-orientation-vertical grid grid-area grid-auto-columns grid-auto-flow grid-auto-rows grid-column grid-column-end grid-column-gap grid-column-start grid-gap grid-row grid-row-end grid-row-gap grid-row-start grid-template grid-template-areas grid-template-columns grid-template-rows hanging-punctuation height hyphenate-character hyphenate-limit-chars hyphenate-limit-last hyphenate-limit-lines hyphenate-limit-zone hyphens image-orientation image-rendering image-resolution initial-letter initial-letter-align initial-letter-wrap inline-size inset inset-block inset-block-end inset-block-start inset-inline inset-inline-end inset-inline-start isolation justify-content justify-items justify-self left letter-spacing lighting-color line-break line-grid line-height line-height-step line-snap list-style list-style-image list-style-position list-style-type margin margin-block margin-block-end margin-block-start margin-bottom margin-inline margin-inline-end margin-inline-start margin-left margin-right margin-top marker marker-end marker-knockout-left marker-knockout-right marker-mid marker-pattern marker-segment marker-side marker-start marquee-direction marquee-loop marquee-speed marquee-style mask mask-border mask-border-mode mask-border-outset mask-border-repeat mask-border-slice mask-border-source mask-border-width mask-clip mask-composite mask-image mask-mode mask-origin mask-position mask-repeat mask-size mask-type max-block-size max-height max-inline-size max-lines max-width min-block-size min-height min-inline-size min-width mix-blend-mode nav-up nav-down nav-left nav-right object-fit object-position offset offset-after offset-anchor offset-before offset-distance offset-end offset-path offset-position offset-rotate offset-start opacity order orphans outline outline-color outline-offset outline-style outline-width overflow overflow-style overflow-wrap overflow-x overflow-y padding padding-block padding-block-end padding-block-start padding-bottom padding-inline padding-inline-end padding-inline-start padding-left padding-right padding-top page page-break-after page-break-before page-break-inside pause pause-after pause-before perspective perspective-origin pitch pitch-range place-content place-items place-self play-during pointer-events position quotes region-fragment resize richness right rotation rotation-point row-gap ruby-align ruby-merge ruby-position running scrollbar-gutter shape-image-threshold shape-inside shape-margin shape-outside size speak speak-header speak-numeral speak-punctuation speech-rate stress string-set table-layout tab-size text-align-all text-align text-align-last text-combine-upright text-decoration-color text-decoration text-decoration-line text-decoration-skip text-decoration-skip-ink text-decoration-style text-decoration-width text-emphasis text-emphasis-color text-emphasis-position text-emphasis-skip text-emphasis-style text-indent text-justify text-orientation text-overflow text-shadow text-space-collapse text-space-trim text-spacing text-transform text-underline-offset text-underline-position text-wrap top transform transform-box transform-origin transform-style transition transition-delay transition-duration transition-property transition-timing-function unicode-bidi user-select vertical-align visibility voice-family volume white-space widows width will-change word-break word-spacing word-wrap wrap-after wrap-before wrap-flow wrap-inside wrap-through writing-mode z-index -moz-animation -moz-animation-delay -moz-animation-direction -moz-animation-duration -moz-animation-fill-mode -moz-animation-iteration-count -moz-animation-name -moz-animation-play-state -moz-animation-timing-function -moz-appearance -moz-background-clip -moz-background-origin -moz-background-size -moz-border-image -moz-border-radius -moz-border-radius-bottomleft -moz-border-radius-bottomright -moz-border-radius-topleft -moz-border-radius-topright -moz-box-align -moz-box-direction -moz-box-flex -moz-box-flex-group -moz-box-ordinal-group -moz-box-orient -moz-box-pack -moz-box-shadow -moz-box-sizing -moz-box -moz-column-count -moz-column-fill -moz-column-gap -moz-column-rule -moz-column-rule-color -moz-column-rule-style -moz-column-rule-width -moz-columns -moz-column-width -moz-hyphens -moz-opacity -moz-outline-style -moz-perspective -moz-resize -moz-text-align-last -moz-text-decoration-color -moz-text-decoration-line -moz-text-decoration-style -moz-transform -moz-transform-origin -moz-transform-style -moz-transition -moz-transition-delay -moz-transition-duration -moz-transition-property -moz-transition-timing-function -moz-user-select -o-background-size -o-linear-gradient -o-text-overflow -o-transition -o-transform-origin konq_bgpos_x konq_bgpos_y -khtml-background-size -khtml-border-top-left-radius -khtml-border-top-right-radius -khtml-border-bottom-left-radius -khtml-border-bottom-right-radius -khtml-border-radius -khtml-box-shadow -khtml-opacity -webkit-appearance -webkit-animation -webkit-animation-name -webkit-animation-duration -webkit-animation-iteration -webkit-animation-direction -webkit-animation-delay -webkit-animation-play-state -webkit-animation-fill-mode -webkit-background-size -webkit-backface-visibility -webkit-border-image -webkit-border-bottom-colors -webkit-border-left-colors -webkit-border-radius -webkit-border-right-colors -webkit-border-top-colors -webkit-border-top-left-radius -webkit-border-top-right-radius -webkit-border-bottom-left-radius -webkit-border-bottom-right-radius -webkit-border-radius-bottomleft -webkit-border-radius-bottomright -webkit-box-align -webkit-box-direction -webkit-box-flex -webkit-box-ordinal-group -webkit-box-orient -webkit-box-pack -webkit-box-reflect -webkit-box-shadow -webkit-box-sizing -webkit-column-count -webkit-column-gap -webkit-hyphens -webkit-linear-gradient -webkit-gradient -webkit-overflow-scrolling -webkit-perspective -webkit-text-decoration -webkit-text-decoration-skip -webkit-text-fill-color -webkit-text-stroke-color -webkit-text-stroke-width -webkit-text-size-adjust -webkit-tap-highlight-color -webkit-transform -webkit-transform-origin -webkit-transform-style -webkit-transition -webkit-transition-property -webkit-transition-delay -webkit-transition-duration -webkit-user-select zoom -ms-animation-name -ms-animation-duration -ms-animation-iteration -ms-animation-direction -ms-animation-delay -ms-animation-play-state -ms-animation-fill-mode -ms-box-sizing -ms-filter -ms-flex -ms-flex-align -ms-flex-direction -ms-flex-flow -ms-flex-item-align -ms-flex-line-pack -ms-flex-negative -ms-flex-order -ms-flex-pack -ms-flex-positive -ms-flex-position -ms-flex-preferred-size -ms-flex-wrap -ms-interpolation-mode -ms-linear-gradient -ms-overflow-style -ms-text-size-adjust -ms-transform -ms-transition -ms-user-select inherit unset auto none hidden dotted dashed solid double groove ridge inset outset xx-small x-small small medium large x-large xx-large smaller larger italic oblique small-caps normal bold bolder lighter light transparent repeat repeat-x repeat-y no-repeat baseline sub super top text-top middle bottom text-bottom left right center justify konq-center disc circle square box decimal decimal-leading-zero lower-roman upper-roman lower-greek lower-alpha lower-latin upper-alpha upper-latin hebrew armenian georgian cjk-ideographic hiragana katakana hiragana-iroha katakana-iroha inline inline-block block list-item run-in compact marker table inline-table table-row-group table-header-group table-footer-group table-row table-column-group table-column table-cell table-caption crosshair default pointer move e-resize ne-resize nw-resize n-resize se-resize sw-resize s-resize w-resize text wait help above absolute always avoid below bidi-override blink both capitalize caption clip close-quote collapse condensed crop cross ellipsis ellipsis-word embed expanded extra-condensed extra-expanded fixed hand hide higher icon inside invert landscape level line-through loud lower lowercase ltr menu message-box mix narrower no-close-quote no-open-quote nowrap open-quote outside overline portrait pre pre-line pre-wrap relative rtl scroll semi-condensed semi-expanded separate show small-caption static static-position status-bar thick thin ultra-condensed ultra-expanded underline uppercase visible wider break serif sans-serif cursive fantasy monospace border-box content-box -epub-hyphens contain cover all ease ease-in ease-out ease-in-out step-start step-end linear infinite reverse alternate alternate-reverse forwards backwards running paused black silver gray white maroon red purple fuchsia green lime olive yellow navy blue teal aqua orange aliceblue antiquewhite aquamarine azure beige bisque blanchedalmond blueviolet brown burlywood cadetblue chartreuse chocolate coral cornflowerblue cornsilk crimson cyan aqua darkblue darkcyan darkgoldenrod darkgray darkgreen darkgrey darkkhaki darkmagenta darkolivegreen darkorange darkorchid darkred darksalmon darkseagreen darkslateblue darkslategray darkslategrey darkturquoise darkviolet deeppink deepskyblue dimgray dimgrey dodgerblue firebrick floralwhite forestgreen gainsboro ghostwhite gold goldenrod greenyellow grey honeydew hotpink indianred indigo ivory khaki lavender lavenderblush lawngreen lemonchiffon lightblue lightcoral lightcyan lightgoldenrodyellow lightgray lightgreen lightgrey lightpink lightsalmon lightseagreen lightskyblue lightslategray lightslategrey lightsteelblue lightyellow limegreen linen magenta fuchsia mediumaquamarine mediumblue mediumorchid mediumpurple mediumseagreen mediumslateblue mediumspringgreen mediumturquoise mediumvioletred midnightblue mintcream mistyrose moccasin navajowhite oldlace olivedrab orangered orchid palegoldenrod palegreen paleturquoise palevioletred papayawhip peachpuff peru pink plum powderblue rosybrown royalblue saddlebrown salmon sandybrown seagreen seashell sienna skyblue slateblue slategray slategrey snow springgreen steelblue tan thistle tomato turquoise violet wheat whitesmoke yellowgreen rebeccapurple ActiveBorder ActiveCaption AppWorkspace Background ButtonFace ButtonHighlight ButtonShadow ButtonText CaptionText GrayText Highlight HighlightText InactiveBorder InactiveCaption InactiveCaptionText InfoBackground InfoText Menu MenuText Scrollbar ThreeDDarkShadow ThreeDFace ThreeDHighlight ThreeDLightShadow ThreeDShadow Window WindowFrame WindowText attr calc hsl hsla linear-gradient radial-gradient repeating-linear-gradient repeating-radial-gradient rgb rgba var url rect inset circle ellipse polygon blur brightness contrast drop-shadow grayscale hue-rotate invert opacity saturate sepia max-content min-content minmax fix-content repeat cubic-bezier frames steps matrix matrix3d perspective rotate rotate3d rotateX rotateY rotateZ scale scale3d scaleX scaleY scaleZ skew skewX skewY translate translate3d translateX translateY translateZ local format all print screen speech any-pointer any-hover aspect-ratio color color-gamut color-index display-mode grid height hover max-aspect-ratio max-color max-color-index max-device-aspect-ratio max-device-height max-device-width max-height max-monochrome max-resolution max-width min-aspect-ratio min-color min-color-index min-device-aspect-ratio min-device-height min-device-width min-height min-monochrome min-resolution min-width monochrome orientation pointer resolution scan update width after before cue first-letter first-line selection backdrop placeholder slotted value choices repeat-item repeat-index -moz-progress-bar -moz-range-progress -moz-range-thumb -moz-range-track -moz-selection -ms-fill -ms-fill-lower -ms-fill-upper -ms-thumb -ms-track -webkit-progress-bar -webkit-progress-value -webkit-slider-runnable-track -webkit-slider-thumb active any-link checked default defined disabled empty enabled first-child first-of-type fullscreen focus focus-within host hover in-range indeterminate invalid lang last-child last-of-type link not nth-child nth-last-child nth-last-of-type nth-of-type only-child only-of-type optional out-of-range placeholder-shown read-only read-write required root scope target valid visited after before cue first-letter first-line selection - + not + matches blank first left recto right verso @character @charset @import @namespace @document @media @supports @viewport min-width max-width width min-height max-height height zoom min-zoom max-zoom user-zoom orientation viewport-fit @page size marks bleed @font-face font-display font-family font-stretch font-style font-weight font-variant font-feature-settings font-variation-settings src unicode-range @keyframes from to and only not - - + + - + + - + diff --git a/data/syntax/sass.xml b/data/syntax/sass.xml new file mode 100644 index 0000000..bd99a71 --- /dev/null +++ b/data/syntax/sass.xml @@ -0,0 +1,467 @@ + + + + +]> + + + + + + properties##SCSS + sub-properties##SCSS + + special values##SCSS + value keywords##SCSS + values##SCSS + colors##SCSS + functions##SCSS + medias##SCSS + pseudoelements##SCSS + pseudoclasses##SCSS + pseudoclass-selector##SCSS + pseudoclasses-@page##SCSS + at-rules##SCSS + nested at-rules##SCSS + inline and nested at-rules##SCSS + @extend##SCSS + @if##SCSS + @else##SCSS + @mixin##SCSS + @viewport##SCSS + @page##SCSS + + @font-face##SCSS + @keyframes##SCSS + + media operators##SCSS + operators##SCSS + annotations##SCSS + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/syntax/scss.xml b/data/syntax/scss.xml index 434b5e2..5fca275 100644 --- a/data/syntax/scss.xml +++ b/data/syntax/scss.xml @@ -1,1020 +1,1038 @@ ]> - + 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 + + pseudoclass-selector##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 - - + - + - + + + + + + + + + + + + + + + + + - - + + + - + - + - + - + + +