How it works
What happens to your document between dropping it in and getting it back.
Six languages are identified by name. Anything else that is clearly code still gets highlighted — just without language-specific rules.
Once a block has been confirmed as code, it is compared against a fingerprint for each supported language and the best match wins — but only if it wins clearly. Evidence for one language is often evidence against another, so a block that is unmistakably one thing tends to be unmistakably not the others, and the answer arrives with a comfortable margin.
When no language wins clearly, the block is labelled Unknown rather than guessed at, and coloured with a shared grammar instead. That is a deliberate outcome, not a failure: Java coloured as JavaScript looks worse than code coloured neutrally.
The fingerprints themselves are not published. They are the part of the tool that took the longest to get right, and knowing them does not help you use it — the label on every block is shown to you, and you can see for yourself whether it is correct. More on that decision.
The easiest of the six to recognise, because its block syntax is unlike the rest: colon-terminated headers and significant indentation instead of braces and semicolons. Decorators, docstrings, f-strings and the dunder names are all strong tells, and the absence of C-family punctuation is as informative as any keyword.
Highlighting covers keywords, built-ins, decorators, all three string forms including
triple-quoted blocks and f-string interpolation, numeric literals, and
# comments.
Recognised by its ceremony: access modifiers, the class-per-file structure,
System.out, the standard-library package names, annotations and the
public static void main signature. Java is rarely confused with anything
else once more than a couple of lines are present.
Highlighting covers keywords, annotations, types, string and character literals,
numeric literals with suffixes, and both // and /* */
comments, including Javadoc blocks — which are treated as part of the block they
document rather than being stranded above it as prose.
Recognised by the preprocessor, the standard-library namespace, stream operators,
templates and the reference and pointer syntax that no other supported language shares.
A listing with std:: in it is emphatically not Java or JavaScript, and the
identification reflects that.
Highlighting covers keywords, preprocessor directives, standard types, string, character and raw-string literals, numeric literals, and both comment forms.
C and C++ share almost everything, so the two are not separated by which scores higher — that would be a coin toss on ordinary C. They are separated by asking whether anything in the listing actually requires C++. If nothing does, the block is C. A listing that would compile as either gets the smaller label, which is the honest answer.
Highlighting covers the C keyword set, the preprocessor, the standard integer and fixed-width types, string and character literals, and both comment forms.
Recognised by const and let, arrow functions, template
literals, async/await, the module syntax, and the browser and
Node globals. The absence of type annotations is what keeps it apart from TypeScript.
Highlighting covers keywords, built-in objects, template literals with their embedded expressions, regular-expression literals, numeric literals, and both comment forms.
Everything JavaScript has, plus the type system: annotations, interfaces, type aliases, generics, enums and the access modifiers on class members. Because TypeScript is a superset, the same rule used for C and C++ applies here — a listing is only called TypeScript if something in it genuinely requires TypeScript. Otherwise it is JavaScript.
Highlighting covers the JavaScript set plus type annotations, interfaces, generics and enum members.
C++ contains C, and TypeScript contains JavaScript. For these two pairs, "whichever matches more" is the wrong question — the larger language matches everything the smaller one does, so the two would sit on top of each other and perfectly ordinary C would come back as Unknown.
Both pairs are settled the same way instead: does the larger language's own exclusive syntax appear at all? If not, the smaller label is used. It is the one that will compile either way.
On a block of any real length — roughly five lines or more — identification is close to a solved problem, and it stays solved even in a document with no formatting hints at all, because a language leaves too many fingerprints across five lines to be mistaken for another.
Ambiguity shows up in short snippets, where there is simply not enough evidence for anything to stand out. Three lines of a C-family language that use nothing language-specific genuinely could be four different languages, and that is exactly when the tool declines to name one. You will see Unknown on the block rather than a confident wrong answer, and the code is still coloured.
Blocks that cannot be identified still receive comment, string, number, keyword, function and type colouring from a shared grammar. In practice that covers Go, Rust, C#, PHP, Kotlin, Swift, SQL, shell and JSON well enough to read comfortably, even though none of them is formally supported.
Terminal output is handled separately and is never given a language at all — it is not source, so it is rendered on its own darker surface without keyword colouring, which is usually the fastest way to see that the tool understood your document correctly.
Adding a language is additive: the existing ones are unaffected. Go, Rust, C# and shell are the most likely next additions. If you need one, say so — requests are the main input to that decision.
What happens to your document between dropping it in and getting it back.
Real documents before and after, in every supported language.
Where identification goes wrong, and what to do about it.
Why a deterministic detector beats a chatbot at this particular job.