The problem: SE asks Highlight.js to autodetect the language when it knows there isn’t any optimal/correct choice for us to make - resulting in very poor outcomes.
Disclaimer: I say this as the current Highlight.js maintainer
Example: SE currently does not load our groovy
grammar. When one adds a Groovy block of code and hints it as ```groovy
or <!-- language: groovy -->
, SE will still ask Highlight.js to auto-detect the language - even knowing the language is groovy
and that they've purposely chosen not to enable our Groovy grammar.
This results in poor and inconsistent highlighting for many snippets and encourages bad user behavior that will only make the situation worse long-term. Auto-detect is not intended to be used to find "next best" matches for built-in grammars purposely excluded from a build. This will frequently result in highlighting that appears entirely random (based on variable names that match keywords, etc.).
List of reasons the existing behaviour is bad:
- It makes users think a language is supported when it is not (this confusion is obvious in many threads following the switch to Highlight.js)
- It results in incorrect/poor highlighting here and now (since the correct grammar is not available).
- It results in seemingly random highlighting (different snippets of a single language end up highlighted with many different languages based on the exact content of the snippet).
- Worse, this can encourage people to mis-hint or mistag posts consistently (i.e., always using
java
instead ofgroovy
) just to get more consistent highlighting. This has already been mentioned/suggested in other threads (see Groovy discussion). - This mis-hinting/mistagging is not future-proof... if one day SO decides to add proper Groovy support, but older posts are tagged/hinted
java
(as a workaround)... those posts will not receive the new highlighting that would be possible if they had been hinted properly.
- Worse, this can encourage people to mis-hint or mistag posts consistently (i.e., always using
- It can encourage hinting snippets with
none
(to avoid terrible auto-formatting) or even picking a random language just to find something that looks "better".- This is also not future proof in that if the missing language is ever added in the future the incorrect suboptimal hint will continue to be used indefinitely.
- It can encourage users to endlessly fiddle with their snippet just to see if they can "push" the highlighter towards a better choice.
What should happen instead:
If it's known that the language requested is not supported then one of several things should happen:
- No highlighting should be used, i.e. alias to
none
orplaintext
. Unfortunate, but consistent. - The next closest match should be hard-coded as an alias. You're already doing this for some languages, like your VBScript → VB.NET mapping.
- This results in consistent behaviour (keywords will always be highlighted the same from snippet to snippet).
- Users can learn the pros and cons of this behaviour (i.e., its quirks, etc...)
- If/when additional language support added in the future, the alias is removed and all existing posts that are correctly hinted are immediately "upgraded" will full and correct highlighting.
- Lazy-load individual grammars (if it's not part of the default bundle) via a CDN and then perform highlighting as normal.
In summary:
No highlighting should be preferred over random highlighting for hinted snippets where SE has purposely chosen not to load a grammar module. Lazy-loading of grammars or manual hinting of alternatives (i.e., "java is a reasonable approx. of groovy") are some other options.
Also: no formatting may be a better choice for all snippets that have an explicit hint than cannot be resolved to any known language - though that's likely a larger discussion.
This was prompted by the Groovy discussion among others: What happened to Groovy syntax highlighting?
A small auto-detect primer and why this is a "worst-case" scenario for auto-detect.
Highlight.js auto-detection is based on analyzing a code snippet with all available language grammars and scoring its relevancy with each. The highest score "wins". While the keyword class
or a variable named $blah
is somewhat relevant in indicating a given piece of code might be PHP - the tag <?php
is highly relevant, as it only ever appears in PHP templates. We're looking for which language seems to be the most "relevant" for a particular code snippet.
Let’s say we're asked to auto-detect the language and we find (in a perfect world) relevance scores something like:
C++: 9
SQL: 10
Java: 11
Groovy: 102
The code in question registers as 10x more "relevant" for Groovy, so it is highly likely this is a Groovy snippet. So what happens if the Groovy grammar isn't loaded - if we have no idea what Groovy code even is? You often end up with scoring much more like:
C++: 10
SQL: 9
Java: 10
Dart: 8
Go: 11
Our code now poorly matches whatever is left (since the correct answer [of Groovy] is no longer possible). The exact relevance values will of course change (depending on the snippet of code) and may not be this dramatic - but without the correct grammar loaded it's far more likely there is no clear winner... making the final language auto-detected much more of a coin toss.
This isn't a perfect example, but hopefully it is illustrative.
groovy is not a supported language currently - [link to supported list]
. They could even do this during composition.javascript
than saysql
. (Though SE still has tons of room to improve here also.) I'm not suggesting we remove ALL auto-detection, only auto-detect where it's known in advance the outcome is likely to be poor. (such as when a grammar is requested that SE has chosen not to load)array
). I think you nailed it in your comment- the best case scenario from a usage POV would be to lazy load it if the language specified/ detected wasn't already loaded.groovy
then SE could choose to lazy load Groovy and use that explicitly. Or if a post was taggedgroovy
(among other things) then SE could lazy load groovy before highlighting and then auto-detect would consider groovy as a possibility when doing the analysis.groovy
a language tag or a generic concept tag"? And if it's a language (one that's simply not in the default bundle) then that would either key the lazy-load - or simply turn off highlighting for that block.lang-X
identifier (rather than a tag), however, it does succeed in highlighting languages currently unsupported by SE.