Files
website/node_modules/@expressive-code/plugin-text-markers/dist/index.js
2024-05-06 17:15:30 -04:00

590 lines
22 KiB
JavaScript

var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
// ../../../node_modules/.pnpm/parse-numeric-range@1.3.0/node_modules/parse-numeric-range/index.js
var require_parse_numeric_range = __commonJS({
"../../../node_modules/.pnpm/parse-numeric-range@1.3.0/node_modules/parse-numeric-range/index.js"(exports, module) {
"use strict";
function parsePart(string) {
let res = [];
let m;
for (let str of string.split(",").map((str2) => str2.trim())) {
if (/^-?\d+$/.test(str)) {
res.push(parseInt(str, 10));
} else if (m = str.match(/^(-?\d+)(-|\.\.\.?|\u2025|\u2026|\u22EF)(-?\d+)$/)) {
let [_, lhs, sep, rhs] = m;
if (lhs && rhs) {
lhs = parseInt(lhs);
rhs = parseInt(rhs);
const incr = lhs < rhs ? 1 : -1;
if (sep === "-" || sep === ".." || sep === "\u2025")
rhs += incr;
for (let i = lhs; i !== rhs; i += incr)
res.push(i);
}
}
}
return res;
}
exports.default = parsePart;
module.exports = parsePart;
}
});
// src/index.ts
var import_parse_numeric_range = __toESM(require_parse_numeric_range(), 1);
import {
AnnotationRenderPhaseOrder,
InlineStyleAnnotation,
ensureColorContrastOnBackground,
getStaticBackgroundColor,
isInlineStyleAnnotation,
onBackground
} from "@expressive-code/core";
// src/marker-types.ts
var MarkerTypeOrder = ["mark", "del", "ins"];
function markerTypeFromString(input) {
if (input === "add")
input = "ins";
if (input === "rem")
input = "del";
const markerType = input;
return MarkerTypeOrder.includes(markerType) ? markerType : void 0;
}
// src/styles.ts
import { PluginStyleSettings, codeLineClass, toHexColor } from "@expressive-code/core";
var textMarkersStyleSettings = new PluginStyleSettings({
defaultValues: {
textMarkers: {
lineMarkerAccentMargin: "0rem",
lineMarkerAccentWidth: "0.15rem",
lineMarkerLabelPaddingInline: "0.2rem",
lineMarkerLabelColor: "white",
lineDiffIndicatorMarginLeft: "0.3rem",
inlineMarkerBorderWidth: "1.5px",
inlineMarkerBorderRadius: "0.2rem",
inlineMarkerPadding: "0.15rem",
// Define base colors for all markers in the LCH color space,
// which leads to consistent perceived brightness independent of hue
markHue: "284",
insHue: "136",
delHue: "33",
defaultChroma: "40",
defaultLuminance: ["32%", "75%"],
backgroundOpacity: "50%",
borderLuminance: "48%",
borderOpacity: "81.6%",
indicatorLuminance: ["67%", "40%"],
indicatorOpacity: "81.6%",
// You can use these to override the diff indicator content
insDiffIndicatorContent: "'+'",
delDiffIndicatorContent: "'-'",
// The settings below will be calculated based on the settings above
markBackground: (context) => resolveBg(context, "textMarkers.markHue"),
markBorderColor: (context) => resolveBorder(context, "textMarkers.markHue"),
insBackground: (context) => resolveBg(context, "textMarkers.insHue"),
insBorderColor: (context) => resolveBorder(context, "textMarkers.insHue"),
insDiffIndicatorColor: (context) => resolveIndicator(context, "textMarkers.insHue"),
delBackground: (context) => resolveBg(context, "textMarkers.delHue"),
delBorderColor: (context) => resolveBorder(context, "textMarkers.delHue"),
delDiffIndicatorColor: (context) => resolveIndicator(context, "textMarkers.delHue")
}
},
cssVarExclusions: [
// Exclude all settings from CSS variable output that will not be used directly in styles,
// but instead be used to calculate other settings
"textMarkers.markHue",
"textMarkers.insHue",
"textMarkers.delHue",
"textMarkers.defaultChroma",
"textMarkers.defaultLuminance",
"textMarkers.backgroundOpacity",
"textMarkers.borderLuminance",
"textMarkers.borderOpacity",
"textMarkers.indicatorLuminance",
"textMarkers.indicatorOpacity"
]
});
function getTextMarkersBaseStyles({ cssVar }) {
const result = `
.${codeLineClass} {
/* Support line-level mark/ins/del */
&.mark {
--tmLineBgCol: ${cssVar("textMarkers.markBackground")};
& .code {
--ecLineBrdCol: ${cssVar("textMarkers.markBorderColor")};
}
}
&.ins {
--tmLineBgCol: ${cssVar("textMarkers.insBackground")};
--tmLabel: ${cssVar("textMarkers.insDiffIndicatorContent")};
& .code {
--ecLineBrdCol: ${cssVar("textMarkers.insBorderColor")};
&::before {
color: ${cssVar("textMarkers.insDiffIndicatorColor")};
}
}
}
&.del {
--tmLineBgCol: ${cssVar("textMarkers.delBackground")};
--tmLabel: ${cssVar("textMarkers.delDiffIndicatorContent")};
& .code {
--ecLineBrdCol: ${cssVar("textMarkers.delBorderColor")};
&::before {
color: ${cssVar("textMarkers.delDiffIndicatorColor")};
}
}
}
&.mark,
&.ins,
&.del {
background: var(--tmLineBgCol);
& .code {
--ecGtrBrdWd: ${cssVar("textMarkers.lineMarkerAccentWidth")};
}
& .code::before {
display: block;
position: absolute;
left: 0;
box-sizing: border-box;
content: var(--tmLabel, ' ');
padding-inline-start: ${cssVar("textMarkers.lineDiffIndicatorMarginLeft")};
text-align: center;
/* Prevent long labels from wrapping to avoid overlapping the code */
white-space: pre;
}
&.tm-label {
& .code::before {
background: var(--ecLineBrdCol);
padding: 0 calc(${cssVar("textMarkers.lineMarkerLabelPaddingInline")} + ${cssVar("textMarkers.lineMarkerAccentWidth")}) 0 ${cssVar("textMarkers.lineMarkerLabelPaddingInline")};
color: ${cssVar("textMarkers.lineMarkerLabelColor")};
}
}
}
/* Support inline mark/ins/del */
& mark {
--tmInlineBgCol: ${cssVar("textMarkers.markBackground")};
--tmInlineBrdCol: ${cssVar("textMarkers.markBorderColor")};
}
& ins {
--tmInlineBgCol: ${cssVar("textMarkers.insBackground")};
--tmInlineBrdCol: ${cssVar("textMarkers.insBorderColor")};
}
& del {
--tmInlineBgCol: ${cssVar("textMarkers.delBackground")};
--tmInlineBrdCol: ${cssVar("textMarkers.delBorderColor")};
}
& mark,
& ins,
& del {
all: unset;
display: inline-block;
position: relative;
--tmBrdL: ${cssVar("textMarkers.inlineMarkerBorderWidth")};
--tmBrdR: ${cssVar("textMarkers.inlineMarkerBorderWidth")};
--tmRadL: ${cssVar("textMarkers.inlineMarkerBorderRadius")};
--tmRadR: ${cssVar("textMarkers.inlineMarkerBorderRadius")};
margin-inline: 0.025rem;
padding-inline: ${cssVar("textMarkers.inlineMarkerPadding")};
border-radius: var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);
background: var(--tmInlineBgCol);
background-clip: padding-box;
&.open-start {
margin-inline-start: 0;
padding-inline-start: 0;
--tmBrdL: 0px;
--tmRadL: 0;
}
&.open-end {
margin-inline-end: 0;
padding-inline-end: 0;
--tmBrdR: 0px;
--tmRadR: 0;
}
&::before {
content: '';
position: absolute;
pointer-events: none;
display: inline-block;
inset: 0;
border-radius: var(--tmRadL) var(--tmRadR) var(--tmRadR) var(--tmRadL);
border: ${cssVar("textMarkers.inlineMarkerBorderWidth")} solid var(--tmInlineBrdCol);
border-inline-width: var(--tmBrdL) var(--tmBrdR);
}
}
}
`;
return result;
}
var markerBgColorPaths = {
mark: "textMarkers.markBackground",
ins: "textMarkers.insBackground",
del: "textMarkers.delBackground"
};
function resolveBg({ resolveSetting: r }, hue) {
return toHexColor(`lch(${r("textMarkers.defaultLuminance")} ${r("textMarkers.defaultChroma")} ${r(hue)} / ${r("textMarkers.backgroundOpacity")})`);
}
function resolveBorder({ resolveSetting: r }, hue) {
return toHexColor(`lch(${r("textMarkers.borderLuminance")} ${r("textMarkers.defaultChroma")} ${r(hue)} / ${r("textMarkers.borderOpacity")})`);
}
function resolveIndicator({ resolveSetting: r }, hue) {
return toHexColor(`lch(${r("textMarkers.indicatorLuminance")} ${r("textMarkers.defaultChroma")} ${r(hue)} / ${r("textMarkers.indicatorOpacity")})`);
}
// src/utils.ts
function getGroupIndicesFromRegExpMatch(match) {
let groupIndices = match.indices;
if (groupIndices?.length)
return groupIndices;
const fullMatchIndex = match.index;
groupIndices = match.map((groupValue) => {
const groupIndex = groupValue ? match[0].indexOf(groupValue) : -1;
if (groupIndex === -1)
return null;
const groupStart = fullMatchIndex + groupIndex;
const groupEnd = groupStart + groupValue.length;
return [groupStart, groupEnd];
});
return groupIndices;
}
function toDefinitionsArray(value) {
if (value === void 0)
return [];
return Array.isArray(value) ? value : [value];
}
// src/inline-markers.ts
function getInlineSearchTermMatches(lineText, codeBlock) {
const markerMatches = [];
MarkerTypeOrder.forEach((markerType) => {
toDefinitionsArray(codeBlock.props[markerType]).forEach((definition) => {
if (typeof definition === "string") {
let idx = lineText.indexOf(definition, 0);
while (idx > -1) {
markerMatches.push({
markerType,
start: idx,
end: idx + definition.length
});
idx = lineText.indexOf(definition, idx + definition.length);
}
}
if (definition instanceof RegExp) {
const matches = lineText.matchAll(definition);
for (const match of matches) {
const rawGroupIndices = getGroupIndicesFromRegExpMatch(match);
let groupIndices = rawGroupIndices.flatMap((range) => range ? [range] : []);
if (!groupIndices.length) {
const fullMatchIndex = match.index;
groupIndices = [[fullMatchIndex, fullMatchIndex + match[0].length]];
}
if (groupIndices.length > 1) {
groupIndices.shift();
}
groupIndices.forEach((range) => {
markerMatches.push({
markerType,
start: range[0],
end: range[1]
});
});
}
}
});
});
return markerMatches;
}
function flattenInlineMarkerRanges(markerRanges) {
const flattenedRanges = [];
const addRange = (newRange) => {
for (let idx = flattenedRanges.length - 1; idx >= 0; idx--) {
const curRange = flattenedRanges[idx];
if (newRange.end <= curRange.start || newRange.start >= curRange.end)
continue;
if (newRange.start <= curRange.start && newRange.end >= curRange.end) {
flattenedRanges.splice(idx, 1);
continue;
}
if (newRange.markerType === curRange.markerType) {
flattenedRanges.splice(idx, 1);
newRange = {
...newRange,
start: Math.min(newRange.start, curRange.start),
end: Math.max(newRange.end, curRange.end)
};
continue;
}
if (newRange.start > curRange.start && newRange.end < curRange.end) {
flattenedRanges.splice(idx, 1, { ...curRange, end: newRange.start }, { ...curRange, start: newRange.end });
continue;
}
if (newRange.start > curRange.start) {
curRange.end = newRange.start;
}
if (newRange.end < curRange.end) {
curRange.start = newRange.end;
}
}
flattenedRanges.push(newRange);
flattenedRanges.sort((a, b) => a.start - b.start);
};
MarkerTypeOrder.forEach((markerType) => {
markerRanges.filter((range) => range.markerType === markerType).forEach(addRange);
});
return flattenedRanges;
}
// src/annotations.ts
import { ExpressiveCodeAnnotation } from "@expressive-code/core";
import { addClassName, h, setInlineStyle } from "@expressive-code/core/hast";
var TextMarkerAnnotation = class extends ExpressiveCodeAnnotation {
markerType;
backgroundColor;
label;
constructor({ markerType, backgroundColor, label, ...baseOptions }) {
super(baseOptions);
this.markerType = markerType;
this.backgroundColor = backgroundColor;
this.label = label;
}
render(options) {
if (!this.inlineRange)
return this.renderFullLineMarker(options);
return this.renderInlineMarker(options);
}
renderFullLineMarker({ nodesToTransform }) {
return nodesToTransform.map((node) => {
if (node.type === "element") {
addClassName(node, "highlight");
addClassName(node, this.markerType);
if (this.label) {
addClassName(node, "tm-label");
setInlineStyle(node, "--tmLabel", this.label, "string");
}
}
return node;
});
}
renderInlineMarker({ nodesToTransform }) {
return nodesToTransform.map((node, idx) => {
const transformedNode = h(this.markerType, node);
if (nodesToTransform.length > 0 && idx > 0) {
addClassName(transformedNode, "open-start");
}
if (nodesToTransform.length > 0 && idx < nodesToTransform.length - 1) {
addClassName(transformedNode, "open-end");
}
return transformedNode;
});
}
};
// src/index.ts
function pluginTextMarkers() {
return {
name: "TextMarkers",
styleSettings: textMarkersStyleSettings,
baseStyles: (context) => getTextMarkersBaseStyles(context),
hooks: {
preprocessLanguage: ({ codeBlock }) => {
const lang = codeBlock.metaOptions.getString("lang");
if (lang && codeBlock.language === "diff") {
codeBlock.language = lang;
codeBlock.props.useDiffSyntax = true;
}
},
preprocessMetadata: ({ codeBlock, cssVar }) => {
const addDefinition = (target, definition) => {
const definitions = toDefinitionsArray(codeBlock.props[target]);
definitions.push(definition);
codeBlock.props[target] = definitions;
};
codeBlock.metaOptions.list([...MarkerTypeOrder, "", "add", "rem"]).forEach((option) => {
const { kind, key, value } = option;
const markerType = markerTypeFromString(key || "mark");
if (!markerType)
return;
if (kind === "string" || kind === "regexp")
addDefinition(markerType, value);
if (kind === "range") {
let label = void 0;
const range = value.replace(/^\s*?(["'])([^\1]+?)\1:\s*?/, (_match, _quote, labelValue) => {
label = labelValue;
return "";
});
addDefinition(markerType, { range, label });
}
});
codeBlock.props.useDiffSyntax = codeBlock.metaOptions.getBoolean("useDiffSyntax") ?? codeBlock.props.useDiffSyntax;
MarkerTypeOrder.forEach((markerType) => {
toDefinitionsArray(codeBlock.props[markerType]).forEach((definition) => {
if (typeof definition === "string" || definition instanceof RegExp)
return;
const objDefinition = typeof definition === "number" ? { range: `${definition}` } : definition;
const { range = "", label } = objDefinition;
const lineNumbers = (0, import_parse_numeric_range.default)(range);
lineNumbers.forEach((lineNumber, idx) => {
const lineIndex = lineNumber - 1;
codeBlock.getLine(lineIndex)?.addAnnotation(
new TextMarkerAnnotation({
markerType,
backgroundColor: cssVar(markerBgColorPaths[markerType]),
// Add a label to the first line of each consecutive range
label: idx === 0 || lineNumber - lineNumbers[idx - 1] !== 1 ? label : void 0
})
);
});
});
});
},
preprocessCode: ({ codeBlock, cssVar }) => {
if (codeBlock.language === "diff" || codeBlock.props.useDiffSyntax) {
const lines = codeBlock.getLines();
const couldBeRealDiffFile = lines.slice(0, 4).some((line) => line.text.match(/^([*+-]{3}\s|@@\s|[0-9,]+[acd][0-9,]+\s*$)/));
if (!couldBeRealDiffFile) {
let minIndentation = Infinity;
const parsedLines = lines.map((line) => {
const [, indentation, marker, content] = line.text.match(/^(([+-](?![+-]))?\s*)(.*)$/) || [];
const markerType = marker === "+" ? "ins" : marker === "-" ? "del" : void 0;
if (content.trim().length > 0 && indentation.length < minIndentation)
minIndentation = indentation.length;
return {
line,
markerType
};
});
parsedLines.forEach(({ line, markerType }) => {
const colsToRemove = minIndentation || (markerType ? 1 : 0);
if (colsToRemove > 0)
line.editText(0, colsToRemove, "");
if (markerType) {
line.addAnnotation(
new TextMarkerAnnotation({
markerType,
backgroundColor: cssVar(markerBgColorPaths[markerType])
})
);
}
});
}
}
},
annotateCode: ({ codeBlock, cssVar }) => {
codeBlock.getLines().forEach((line) => {
const markerRanges = getInlineSearchTermMatches(line.text, codeBlock);
if (!markerRanges.length)
return;
const flattenedRanges = flattenInlineMarkerRanges(markerRanges);
flattenedRanges.forEach(({ markerType, start, end }) => {
line.addAnnotation(
new TextMarkerAnnotation({
markerType,
backgroundColor: cssVar(markerBgColorPaths[markerType]),
inlineRange: {
columnStart: start,
columnEnd: end
}
})
);
});
});
},
postprocessAnnotations: ({ codeBlock, styleVariants, config }) => {
if (config.minSyntaxHighlightingColorContrast <= 0)
return;
codeBlock.getLines().forEach((line) => {
const annotations = line.getAnnotations();
const markers = [];
let fullLineMarker = void 0;
for (const annotation of annotations) {
if (!(annotation instanceof TextMarkerAnnotation))
continue;
if (annotation.inlineRange) {
markers.push(annotation);
continue;
}
if (fullLineMarker) {
if (MarkerTypeOrder.indexOf(annotation.markerType) < MarkerTypeOrder.indexOf(fullLineMarker.markerType))
continue;
if (AnnotationRenderPhaseOrder.indexOf(annotation.renderPhase || "normal") < AnnotationRenderPhaseOrder.indexOf(fullLineMarker.renderPhase || "normal"))
continue;
}
fullLineMarker = annotation;
}
if (fullLineMarker)
markers.unshift(fullLineMarker);
styleVariants.forEach((styleVariant, styleVariantIndex) => {
const fullLineMarkerBgColor = fullLineMarker && styleVariant.resolvedStyleSettings.get(markerBgColorPaths[fullLineMarker.markerType]) || "transparent";
const lineBgColor = onBackground(fullLineMarkerBgColor, getStaticBackgroundColor(styleVariant));
const textColors = annotations.filter(
(annotation) => isInlineStyleAnnotation(annotation) && annotation.color && // Only consider annotations that apply to the current style variant
(annotation.styleVariantIndex === void 0 || annotation.styleVariantIndex === styleVariantIndex)
);
textColors.forEach((textColor) => {
const textFgColor = textColor.color;
const textStart = textColor.inlineRange?.columnStart;
const textEnd = textColor.inlineRange?.columnEnd;
if (textFgColor === void 0 || textStart === void 0 || textEnd === void 0)
return;
markers.forEach((marker) => {
const markerStart = marker.inlineRange?.columnStart ?? 0;
const markerEnd = marker.inlineRange?.columnEnd ?? line.text.length;
if (markerStart > textEnd || markerEnd < textStart)
return;
const inlineMarkerBgColor = marker.inlineRange && styleVariant.resolvedStyleSettings.get(markerBgColorPaths[marker.markerType]) || "transparent";
const combinedBgColor = onBackground(inlineMarkerBgColor, lineBgColor);
const readableTextColor = ensureColorContrastOnBackground(textFgColor, combinedBgColor, config.minSyntaxHighlightingColorContrast);
if (readableTextColor.toLowerCase() === textFgColor.toLowerCase())
return;
line.addAnnotation(
new InlineStyleAnnotation({
styleVariantIndex,
inlineRange: {
columnStart: Math.max(textStart, markerStart),
columnEnd: Math.min(textEnd, markerEnd)
},
color: readableTextColor,
renderPhase: "earlier"
})
);
});
});
});
});
}
}
};
}
export {
pluginTextMarkers
};
//# sourceMappingURL=index.js.map