fix(read): enforced exact line selector bounds
- Removed implicit padding and syntactic boundary expansion from explicit ranges. - Covered local, converted, multi-range, and artifact reads. Fixes #5802
This commit is contained in:
@@ -266,27 +266,24 @@ export function findBlockContextLines(
|
||||
return nativeBlockContext(fullLines, visible, source) ?? lexicalBracketContext(fullLines, visible);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build display entries for `visibleSpans` plus any off-window block-boundary
|
||||
* lines, in source order, with `{ kind: "ellipsis" }` markers inserted across
|
||||
* non-contiguous gaps. `options.lineText` lets callers substitute display text
|
||||
* (e.g. column-truncated lines) for a given line number.
|
||||
*/
|
||||
export function buildLineEntriesWithBlockContext(
|
||||
fullLines: readonly string[],
|
||||
visibleSpans: readonly LineSpan[],
|
||||
source: BlockContextSource = {},
|
||||
options: {
|
||||
lineText?: (lineNumber: number, sourceText: string, context: boolean) => string;
|
||||
} = {},
|
||||
): LineEntry[] {
|
||||
const spans = normalizeLineSpans(visibleSpans, fullLines.length);
|
||||
const visible = visibleLineNumbers(spans);
|
||||
const context = findBlockContextLines(fullLines, visible, source);
|
||||
const allLines = new Set<number>(visible);
|
||||
for (const lineNumber of context.keys()) allLines.add(lineNumber);
|
||||
interface LineEntryOptions {
|
||||
lineText?: (lineNumber: number, sourceText: string, context: boolean) => string;
|
||||
}
|
||||
|
||||
function buildEntries(
|
||||
fullLines: readonly string[],
|
||||
visible: ReadonlySet<number>,
|
||||
context: ReadonlyMap<number, string> | undefined,
|
||||
options: LineEntryOptions,
|
||||
): LineEntry[] {
|
||||
const sorted = [...visible];
|
||||
if (context) {
|
||||
for (const lineNumber of context.keys()) {
|
||||
if (!visible.has(lineNumber)) sorted.push(lineNumber);
|
||||
}
|
||||
}
|
||||
sorted.sort((left, right) => left - right);
|
||||
|
||||
const sorted = [...allLines].sort((left, right) => left - right);
|
||||
const entries: LineEntry[] = [];
|
||||
let previousLine: number | undefined;
|
||||
for (const lineNumber of sorted) {
|
||||
@@ -294,7 +291,7 @@ export function buildLineEntriesWithBlockContext(
|
||||
entries.push({ kind: "ellipsis" });
|
||||
}
|
||||
const sourceText = fullLines[lineNumber - 1] ?? "";
|
||||
const isContext = context.has(lineNumber);
|
||||
const isContext = context?.has(lineNumber) === true;
|
||||
entries.push({
|
||||
kind: "line",
|
||||
lineNumber,
|
||||
@@ -307,6 +304,33 @@ export function buildLineEntriesWithBlockContext(
|
||||
return entries;
|
||||
}
|
||||
|
||||
/** Build display entries for exactly the requested spans, separated by ellipses. */
|
||||
export function buildLineEntries(
|
||||
fullLines: readonly string[],
|
||||
visibleSpans: readonly LineSpan[],
|
||||
options: LineEntryOptions = {},
|
||||
): LineEntry[] {
|
||||
const spans = normalizeLineSpans(visibleSpans, fullLines.length);
|
||||
return buildEntries(fullLines, visibleLineNumbers(spans), undefined, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build display entries for `visibleSpans` plus any off-window block-boundary
|
||||
* lines, in source order, with `{ kind: "ellipsis" }` markers inserted across
|
||||
* non-contiguous gaps. `options.lineText` lets callers substitute display text
|
||||
* (e.g. column-truncated lines) for a given line number.
|
||||
*/
|
||||
export function buildLineEntriesWithBlockContext(
|
||||
fullLines: readonly string[],
|
||||
visibleSpans: readonly LineSpan[],
|
||||
source: BlockContextSource = {},
|
||||
options: LineEntryOptions = {},
|
||||
): LineEntry[] {
|
||||
const spans = normalizeLineSpans(visibleSpans, fullLines.length);
|
||||
const visible = visibleLineNumbers(spans);
|
||||
return buildEntries(fullLines, visible, findBlockContextLines(fullLines, visible, source), options);
|
||||
}
|
||||
|
||||
export function lineEntriesToPlainText(entries: readonly LineEntry[], ellipsis = "…"): string {
|
||||
return entries.map(entry => (entry.kind === "ellipsis" ? ellipsis : entry.text)).join("\n");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user