export default function patchTextRangeStyle(node, start, end, patch) {
if (start === end) {
return {
text: node.text,
ranges: node.ranges.map((range) => ({
start: range.start,
end: range.end,
style: { ...range.style },
})),
};
}
const ranges = [];
for (const range of node.ranges) {
if (range.end <= start || range.start >= end) {
ranges.push(copyRange(range));
continue;
}
if (range.start < start) {
ranges.push({
start: range.start,
end: start,
style: { ...range.style },
});
}
ranges.push({
start: Math.max(range.start, start),
end: Math.min(range.end, end),
style: {
...range.style,
...patch,
},
});
if (range.end > end) {
ranges.push({
start: end,
end: range.end,
style: { ...range.style },
});
}
}
return {
text: node.text,
ranges: mergeAdjacentRanges(ranges),
};
}
function copyRange(range) {
return {
start: range.start,
end: range.end,
style: { ...range.style },
};
}
function mergeAdjacentRanges(ranges) {
const merged = [];
for (const range of ranges) {
const last = merged[merged.length - 1];
if (
last &&
last.end === range.start &&
sameStyle(last.style, range.style)
) {
last.end = range.end;
} else {
merged.push(copyRange(range));
}
}
return merged;
}
function sameStyle(a, b) {
return (
a.bold === b.bold &&
a.italic === b.italic &&
a.color === b.color
);
}