highlight.js icon indicating copy to clipboard operation
highlight.js copied to clipboard

CSS, SASS(SCSS), LESS, STYLUS highlighting differences.

Open w3suli opened this issue 6 years ago • 77 comments

img

A list of things to keep in sync:

See the css_consistency branch.

  • [x] vendor specific prefixes (attributes) https://github.com/highlightjs/highlight.js/pull/2425
  • [x] vendor specific prefixes (at-rules) https://github.com/highlightjs/highlight.js/pull/2425
  • [x] tag selectors https://github.com/highlightjs/highlight.js/pull/2425 (just adds tests)
  • [x] class selectors
  • [x] ID selectors
  • [x] pseudo selectors : https://github.com/highlightjs/highlight.js/pull/2425
  • [x] pseudo selectors :: https://github.com/highlightjs/highlight.js/pull/2425
  • [x] top level psuedo-selector :lang(de)
  • [x] selection attribute, i.e. a[href*="example" I] (See: #2243)
  • [ ] function highlighting, ie (grayscale(0.5))
  • [ ] at-rules @import, etc.
  • [x] media at-rules highlighting ("@media", "not", "only" and "and")
  • [x] selection of @media attributes ("(orientation: landscape)" or "(min-width: 600px)")
  • [ ] variables
  • [ ] attributes
  • [ ] What are we missing?
  • [x] use uniform TAG list
  • [x] use uniform PSUEDO-SELECTOR list
  • [x] use uniform ATTRIBUTE list
  • [x] !important

Sass bug list:

  • [x] attribute prefix -I like it but different from css and less - unfortunately bad (-webkit-animation-name:)
  • [x] for the selection attribute, the string is not highlighted (a[href*="example" I])
  • [ ] lack of function highlighting (grayscale(0.5))
  • [ ] at-rules with highlighting difference (@keyframes "from" "to")
  • [x] lack of selection of @media attributes ("(orientation: landscape)" or "(min-width: 600px)")
  • [x] other differences: ":lang(de)"

Less bug list:

  • [x] for the selection attribute, the string is not highlighted (a[href*="example" I])
  • [x] lack of pseudo selectors highlighting (q::after)
  • [ ] lack of function highlighting (grayscale(0.5))
  • [x] lack of selection of @media attributes ("not", "only" and "and")
  • [x] other differences: ":lang(de)"

Stylus bug list:

  • [x] attribute prefix -I like it but different from css and less - unfortunately bad (-webkit-animation-name:)
  • [x] lack of attribute selectors highlighting (a[href*="example" I])
  • [x] lack of pseudo selectors highlighting (q::after)
  • [ ] lack of function highlighting (grayscale(0.5))
  • [ ] lack of at-rules highlighting ("@font-face" "@keyframes", "from", "to")
  • [x] lack of media at-rules highlighting ("@media", "not", "only" and "and")
  • [x] lack of selection of @media attributes ("(orientation: landscape)" or "(min-width: 600px)")
  • [x] other differences: ":lang(de)"

There is a lot of difference. If I have enough time, I'll make examples one by one. I welcome any help. Thanks in advance for all your help!

w3suli avatar Nov 10 '19 18:11 w3suli

I'll make examples one by one

Of each bug with each grammar? I'm not sure that's a great use of time. What really should happen here is to look at how to consolidate all of these, reuse some matchers, merge grammars where possible, etc. That might start to look like more of a ground-level rewrite - and then this exact list of bugs wouldn't be useful at all. It's be more useful to rebuild things on a solid foundation and then see where we stood.

It's possible Less/CSS/SCSS could likely become a single grammar... (or very close)... and SASS and Stylus are very similar also.

Optimally someone (with a lot of time) needs to dig in here and think about this at a very high level. If we can do something like build 5 on 2 core grammars... or 5 on 1... then keeping the features in sync with future improvements becomes much simpler.

Otherwise we could spend a bunch of effort today just to have them get out of sync again in the future.

joshgoebel avatar Nov 12 '19 05:11 joshgoebel

Your side by side is also potentially not accurate as you used the same source-source code... SASS and Stylus (at least) are an entirely different grammars AFAIK. They don't expect/require brackets or semi-colons, etc... so it's possible some of the issues you're seeing are because they aren't intended to highlight RAW css code, which is what it appears you're using.

To actually test them properly you'd need the same CSS, but converted to each actual language, though some of them might be interchangeable.

joshgoebel avatar Nov 12 '19 05:11 joshgoebel

Stylus sounds fun:

Stylus uses the .styl file extension and it allows us to write code in many different ways. We can use the standard CSS syntax, but we can also omit brackets, colons, and/or semicolons or leave out all punctuation altogether.

LOL.

joshgoebel avatar Nov 12 '19 05:11 joshgoebel

I'd really love to avoid having to include ALL the TAGS and ATTRIBUTES if possible.

joshgoebel avatar Nov 12 '19 05:11 joshgoebel

You might start by looking at which rules are "generic" in the sense that we could have them in a single place (like CSS) and then pull into the other grammars from there. And then CSS would become a requirement of the other grammars and common things (like list of tags, or attributes, if necessary) would live in CSS grammar.

CSS's FUNCTION_LIKE might be one example.

joshgoebel avatar Nov 12 '19 05:11 joshgoebel

attribute prefix -I like it but different from css and less

Not so much a feature as side-effect because it's only highlighting attributes it's heard of... but this shouldn't probably be "fixed" to highlight the whole attribute like elsewhere since (as discussed elsewhere) we don't really have a class for highlighting prefixes differently.

joshgoebel avatar Nov 12 '19 05:11 joshgoebel

Almost everything that came to my mind the last day was said. I looked at the codes and saw that it was possible to set up dependencies. I do not know all css preprocessors well enough. I know Sass and SCSS well. I am less familiar with LESS, STYLUS and PostCSS. As far as I know, all of them use the default css code and add more options. Therefore, they all depend on CSS.

The css preprocessors require thorough study for proper work. the difficulty is how to solve it so that everything is highlighted correctly, without having to specify each language element separately.

It would be good to solve this, but it takes a lot of work. However, if we did, we would get a more compact and efficient code.

In addition, the appearance of css highlights could show a consistent image, which improves clarity and looks nicer.

I would be happy if this could be solved.

w3suli avatar Nov 12 '19 17:11 w3suli

@yyyc514 Is it possible to call a language in another language by modifying its elements?

I started to create scss by rewriting the original css. goes well so far, but in many places you have to go into the original code.

What do you think would be a good solution? The original recognition of css should be retained, since you can use css in scss as well. However, scss adds new elements to css, so the original css code needs to be modified in many places. However, it would be a bad idea to re-include the original css highlighter description everywhere.

It could be possible to highlight multiple languages within a language file if it is possible to resolve the add-on code snippets only for that alias scss stylus etc. switch on. If the CSS language constants from another language are available. You could then inherit these constants by modifying the required parts.

What is possible in hljs?

w3suli avatar Nov 20 '19 19:11 w3suli

Take a look at arduino and CPP. One way to do this is to make them all depend on CSS and put all the "core" rules there (as much as makes sense)... then you build all the syntaxes based on those rules... For example if we REALLY need a list of all CSS attributes you'd put it in inside CSS then do:

var cssLang = hljs.getLanguage("css").exports
cssLang.attributeNames
// etc

Or some such...

This might be a lot easier to solve after we switch to modules and the new build system, which is why I wasn't in a rush to solve it. :-)

Honestly I wondered if CSS/SCSS could be a single language... but I"m not sure how feasible that is.

joshgoebel avatar Nov 20 '19 21:11 joshgoebel

There is also sublanguage support, but I don't think that's what we want to do.

joshgoebel avatar Nov 20 '19 21:11 joshgoebel

I'd start with VERY small snippets and then make your new grammars work with them, then expand.. and keep iterating... like start with:

body {
  background: green;
}

That is SCSS and CSS. Get it highlighting... then add another layer:

body {
  header {
    background: blue;
  } 
  background: green;
}

Make sure that works for both... then maybe more onto pseudo selectors, or @ rules, etc. I'm assuming trying to start from scratch.

joshgoebel avatar Nov 20 '19 21:11 joshgoebel

And if you also did Stylus and Less side by side then you'd see how they were all working at once... and if you did all this in a PR we could provide thoughts and advice as you went.

Then after you covered the basics you'd move on to extension specific things like variables, etc... though I guess variables are also part of CSS now too, lol... but you get the point I hope.

joshgoebel avatar Nov 20 '19 21:11 joshgoebel

Thanks for the help!

I'm exploring the possibilities. I hope I can put together a single compact solution and avoid duplication.

w3suli avatar Nov 20 '19 23:11 w3suli

@yyyc514 I'm still thinking about what to do with stylus. If you need to add css properties, which solution is good?

Currently used:

border-width|border-top-width|border-top-style|border-top-right-radius|border-top-left-radius|border-top-color|border-top|border-style|border-spacing|border-right-width|border-right-style|border-right-color|border-right|border-radius|border-left-width|border-left-style|border-left-color|border-left|border-image-width|border-image-source|border-image-slice|border-image-repeat|border-image-outset|border-image|border-color|border-collapse|border-bottom-width|border-bottom-style|border-bottom-right-radius|border-bottom-left-radius|border-bottom-color|border-bottom|border

Shorter version:

border-(bottom|top)-(left|right)-radius|border-image-(outset|repeat|slice|source|width)|border-(bottom|left|right|top)-(color|style|width)|border-(bottom|collapse|color|image|left|radius|right|spacing|style|top|width)|border

Most compact version:

border-((bottom|top)-(left|right)-radius|image-(outset|repeat|slice|source|width)|(bottom|left|right|top)-(color|style|width)|(bottom|color|collapse|image|left|radius|right|spacing|style|top|width))|border

The file size can thus be reduced. Because there are many such css properties.

I don't know how much it affects the speed, but it worsens the purity with the introduction of a new css feature. It will be slightly more labor intensive to add a new feature in some cases.

w3suli avatar Nov 22 '19 14:11 w3suli

List them all out, the other just makes future maintenance hard. This is what gzip is for (saving bytes)... But I'd do even further and list then in array form now a string... I have a feeling we'll want to use them outside of keywords...

joshgoebel avatar Nov 22 '19 14:11 joshgoebel

I don't mind being smart for certain individual attribute though, such as for border:

border-(left|right|top|bottom)-(style|radius|width) etc...

That might actually make it easier to see what is going on and doesn't make maintenance harder since it's really part of a single attribute "border", so it's well grouped.

joshgoebel avatar Nov 22 '19 14:11 joshgoebel

I also saw a block solution, but there it finally generates a regular expression full of treasures out of the array with extra steps. In your opinion, which solution should be used?

w3suli avatar Nov 22 '19 14:11 w3suli

If I was doing it I'd probably do a mix in an array:

PROPERTIES = [
 [string], 
 [string],
 [regex],
 ... 
]

Then you could use regex to describe some of the attributes that lended themselves well to that... or else just an array of literal strings.

joshgoebel avatar Nov 22 '19 14:11 joshgoebel

Though I still debate if you need an actual list. It seems you could just match something: as a property, no? CSS does just fine now without having any lists at all.

joshgoebel avatar Nov 22 '19 14:11 joshgoebel

So let's use it like this: PROPERTIES.join('|')

It's not good this way:

border-(left|right|top|bottom)-(style|radius|width)

In this case, non-existent properties are also formed.

w3suli avatar Nov 22 '19 14:11 w3suli

In this case, non-existent properties are also formed.

Properties that will never appear in CSS files anyways. And how much easier to maintain is that that writing out 100 different possibilities? Many of our grammars cheat in the same way.

But again, why not avoid the list completely?

joshgoebel avatar Nov 22 '19 14:11 joshgoebel

Yes css is good. The problem is the stylus. The list is important there. The language is so simplistic that the point of simplification is that you know the list. With a stylus, you will surely need a list.

w3suli avatar Nov 22 '19 14:11 w3suli

The problem is the stylus.

How so? All the examples I see still have properties ending in :

Oh I see you can also write:

body
  color white

Ugh :-) Still isn't the first word always a property?

joshgoebel avatar Nov 22 '19 14:11 joshgoebel

The stylus leaves everything out, so incorrectly marked elements can be formed if there is no list. Unfortunately for Stylus, the list of html members also seems to be necessary :(.

w3suli avatar Nov 22 '19 14:11 w3suli

Unfortunately for Stylus, the list of html members also seems to be necessary

I'm not sure this is true, but it MIGHT be. It's definitely easier if you have a list.

Isn't [single word] (, [single word])* always a list of tags?

[spacing][single word] [another word] is a property assignment.

joshgoebel avatar Nov 22 '19 14:11 joshgoebel

Seems 100% possible:

https://github.com/PrismJS/prism/blob/master/components/prism-stylus.js

If we can avoid a list that also means the syntax is always stays up-to-date... and we don't need to keep adding new CSS/HTML tags to it over the years. That's a big win.

joshgoebel avatar Nov 22 '19 15:11 joshgoebel

If possible, I'd like to avoid the list. But I wouldn't get a wrong selection either. The most interesting are the nested elements where you have to decide whether a new selector or a property is the word.

nav
    margin 10px

    ul
        list-style-type none

        > li
            display inline-block

            &.current
                background-color lightblue

or

xy = red
nav
    margin 10px
    ul
        list-style-type none
        > li
            display inline-block
            background xy
            color green
            span
              padding 10px
            &.current
                background-color lightblue

Thanks for the link. I'm investigating the solution.

w3suli avatar Nov 22 '19 15:11 w3suli

In that sample every "more than one word" is an property/value pair. The only "edge case" is > li and that's pretty easy to detect as a selector... (since it includes >)

By word I mean "contiguous sequence of characters".

joshgoebel avatar Nov 22 '19 18:11 joshgoebel

The prism: As I see it examines the lines above each other. If the indentation of the top row is less than that of the bottom row, it marks the top row as a selector while the property below it becomes.

But you can't do anything with variables. In the declaration, it could still be highlighted for the equal sign. However, the property values and the variables used there are indistinguishable.

This could be solved if hljs was able to retrieve the variable names before the equality sign and store it. Then the variable names could be searched from the properties. Is this possible?

w3suli avatar Nov 22 '19 18:11 w3suli

In the prism, blank lines cause problems. The compiler does not deal with them, but in highlighting the prism will spoil the highlighting if there is an empty line between a selector and a property.

w3suli avatar Nov 22 '19 19:11 w3suli