import { HighlightStyle } from "@codemirror/language";
import { highlightCode, tags } from "@lezer/highlight";
import { parser } from "@lezer/css";
import { cssVar } from "@webstudio-is/design-system";
// Syntax categories are a visualization layer. Compose them from the shared
// semantic palette so they adapt to both schemes without adding theme knobs.
const syntaxColor = (hueRotation: number) =>
`color-mix(
in oklab,
color(
from oklch(from ${cssVar("--foreground-accent")} l c calc(h + ${hueRotation}))
srgb clamp(0, r, 1) clamp(0, g, 1) clamp(0, b, 1)
) 80%,
${cssVar("--foreground-primary")}
)`;
const syntaxGreen = syntaxColor(-120);
const syntaxRed = syntaxColor(125);
const syntaxYellow = syntaxColor(-155);
const syntaxPurple = syntaxColor(55);
export const codeHighlightStyle = HighlightStyle.define([
{
tag: tags.comment,
color: cssVar("--foreground-secondary"),
},
{
tag: tags.string,
color: syntaxGreen,
},
{
tag: tags.regexp,
color: syntaxRed,
},
{
tag: tags.number,
color: syntaxPurple,
},
{
tag: tags.variableName,
color: cssVar("--foreground-accent"),
},
{
tag: [tags.keyword, tags.operator, tags.punctuation],
color: syntaxGreen,
},
{
tag: [tags.definitionKeyword, tags.modifier],
color: cssVar("--foreground-primary"),
},
{
tag: [tags.self, tags.definition(tags.propertyName)],
color: cssVar("--foreground-accent"),
},
{
tag: tags.function(tags.variableName),
color: cssVar("--foreground-accent"),
},
{
tag: [tags.bool, tags.null],
color: syntaxYellow,
},
{
tag: tags.tagName,
color: cssVar("--foreground-accent"),
},
{
tag: tags.angleBracket,
color: cssVar("--foreground-secondary"),
},
{
tag: tags.attributeName,
color: cssVar("--foreground-secondary"),
},
{
tag: tags.typeName,
color: syntaxGreen,
},
]);
export const highlightCss = (code: string) => {
const styles = codeHighlightStyle.module?.getRules();
// generated classes are scoped to parent
let highlightedCode = ``;
highlightCode(
code,
parser.parse(code),
codeHighlightStyle,
(text, classes) => {
if (classes) {
highlightedCode += `${text}`;
} else {
highlightedCode += text;
}
},
() => {
highlightedCode += "\n";
}
);
return highlightedCode;
};