diff --git a/core/util/ranges.test.ts b/core/util/ranges.test.ts index 84d1c8d54a2..e16a33d9a15 100644 --- a/core/util/ranges.test.ts +++ b/core/util/ranges.test.ts @@ -301,8 +301,7 @@ describe("intersection", () => { expect(result).toBeNull(); }); - // TODO - test.skip("returns correct intersection for single line overlap", () => { + test("returns correct intersection for single line overlap", () => { rangeA = { start: { line: 1, character: 0 }, end: { line: 1, character: 5 }, @@ -320,6 +319,42 @@ describe("intersection", () => { }); }); + test("returns correct intersection when both ranges start on the first line", () => { + rangeA = { + start: { line: 1, character: 0 }, + end: { line: 5, character: 0 }, + }; + + rangeB = { + start: { line: 1, character: 7 }, + end: { line: 3, character: 2 }, + }; + + const result = intersection(rangeA, rangeB); + expect(result).toEqual({ + start: { line: 1, character: 7 }, + end: { line: 3, character: 2 }, + }); + }); + + test("returns correct intersection when both ranges end on the last line", () => { + rangeA = { + start: { line: 1, character: 0 }, + end: { line: 3, character: 8 }, + }; + + rangeB = { + start: { line: 2, character: 0 }, + end: { line: 3, character: 4 }, + }; + + const result = intersection(rangeA, rangeB); + expect(result).toEqual({ + start: { line: 2, character: 0 }, + end: { line: 3, character: 4 }, + }); + }); + test("returns null for single line non-overlapping ranges", () => { rangeA = { start: { line: 1, character: 0 }, diff --git a/core/util/ranges.ts b/core/util/ranges.ts index a9bf5e97242..6fdc8134089 100644 --- a/core/util/ranges.ts +++ b/core/util/ranges.ts @@ -32,25 +32,23 @@ export function intersection(a: Range, b: Range): Range | null { return null; } - if (startLine === endLine) { - const startCharacter = Math.max(a.start.character, b.start.character); - const endCharacter = Math.min(a.end.character, b.end.character); - - if (startCharacter > endCharacter) { - return null; - } - - return { - start: { line: startLine, character: startCharacter }, - end: { line: endLine, character: endCharacter }, - }; + // A range only constrains the characters of the boundary line if it actually + // starts/ends there - otherwise it spans the whole line. + const startCharacter = Math.max( + ...[a.start, b.start] + .filter((position) => position.line === startLine) + .map((position) => position.character), + ); + const endCharacter = Math.min( + ...[a.end, b.end] + .filter((position) => position.line === endLine) + .map((position) => position.character), + ); + + if (startLine === endLine && startCharacter > endCharacter) { + return null; } - const startCharacter = - startLine === a.start.line ? a.start.character : b.start.character; - const endCharacter = - endLine === a.end.line ? a.end.character : b.end.character; - return { start: { line: startLine, character: startCharacter }, end: { line: endLine, character: endCharacter },