Files
voidraft/frontend/src/views/editor/extensions/minimap/lineGeometry.ts
2025-12-10 00:41:24 +08:00

86 lines
1.7 KiB
TypeScript

import { Lines } from "./linesState";
const DEFAULT_LINE_NUMBER = 0;
function lineBoundary(spans: Lines[number]) {
if (!spans || spans.length === 0) {
return { start: 0, end: 0 };
}
const start = spans[0].from;
const end = spans[spans.length - 1].to;
return { start, end };
}
export function lineNumberAt(lines: Lines, position: number): number {
if (!lines.length) {
return DEFAULT_LINE_NUMBER;
}
const first = lineBoundary(lines[0]);
const last = lineBoundary(lines[lines.length - 1]);
let target = position;
if (target < first.start) {
target = first.start;
} else if (target > last.end) {
target = last.end;
}
let low = 0;
let high = lines.length - 1;
while (low <= high) {
const mid = (low + high) >> 1;
const spans = lines[mid];
const { start, end } = lineBoundary(spans);
if (target < start) {
high = mid - 1;
continue;
}
if (target > end) {
low = mid + 1;
continue;
}
return mid + 1;
}
return Math.max(1, Math.min(lines.length, low + 1));
}
export function lineLength(spans: Lines[number]) {
if (!spans) {
return 1;
}
let length = 0;
for (const span of spans) {
length += span.folded ? 1 : Math.max(0, span.to - span.from);
}
return Math.max(1, length);
}
export function offsetWithinLine(pos: number, spans: Lines[number]) {
if (!spans) {
return 0;
}
let offset = 0;
for (const span of spans) {
const spanLength = span.folded ? 1 : Math.max(0, span.to - span.from);
if (!span.folded && pos < span.to) {
return offset + Math.max(0, pos - span.from);
}
if (span.folded && pos <= span.to) {
return offset;
}
offset += spanLength;
}
return offset;
}