diff --git a/web/src/lib/components/repo/BlobView.svelte b/web/src/lib/components/repo/BlobView.svelte index 734b981fe..b364f6270 100644 --- a/web/src/lib/components/repo/BlobView.svelte +++ b/web/src/lib/components/repo/BlobView.svelte @@ -1,11 +1,15 @@ @@ -87,7 +104,7 @@ data-testid="fileContents" data-filename={name} bind:this={element} - class="diffs-container" + class="diffs-container [--diffs-gap-style:none] [--diffs-selection-base:var(--color-indigo-500)]" > {#if !browser} {@const prerenderedHTML = await prerenderFile(name, contents)} diff --git a/web/src/lib/components/repo/lineAnchor.test.ts b/web/src/lib/components/repo/lineAnchor.test.ts new file mode 100644 index 000000000..26d839a00 --- /dev/null +++ b/web/src/lib/components/repo/lineAnchor.test.ts @@ -0,0 +1,29 @@ +import { describe, expect, it } from "vitest"; +import { lineAnchor, parseLineAnchor } from "#lib/components/repo/lineAnchor.ts"; + +describe("parseLineAnchor", () => { + it("reads one line and a range", () => { + expect(parseLineAnchor("#L12")).toEqual({ start: 12, end: 12 }); + expect(parseLineAnchor("#L12-20")).toEqual({ start: 12, end: 20 }); + expect(parseLineAnchor("#L12-L20")).toEqual({ start: 12, end: 20 }); + }); + + it("orders a backwards range", () => { + expect(parseLineAnchor("#L20-12")).toEqual({ start: 12, end: 20 }); + }); + + it("ignores anything else", () => { + expect(parseLineAnchor("")).toBeNull(); + expect(parseLineAnchor("#L0")).toBeNull(); + expect(parseLineAnchor("#readme")).toBeNull(); + expect(parseLineAnchor("#L12-")).toBeNull(); + }); +}); + +describe("lineAnchor", () => { + it("writes one line and a range", () => { + expect(lineAnchor({ start: 7, end: 7 })).toBe("#L7"); + expect(lineAnchor({ start: 20, end: 12 })).toBe("#L12-20"); + expect(lineAnchor(null)).toBe(""); + }); +}); diff --git a/web/src/lib/components/repo/lineAnchor.ts b/web/src/lib/components/repo/lineAnchor.ts new file mode 100644 index 000000000..a1bf1a397 --- /dev/null +++ b/web/src/lib/components/repo/lineAnchor.ts @@ -0,0 +1,19 @@ +import type { SelectedLineRange } from "@pierre/diffs"; + +const LINE_ANCHOR_RE = /^#L(\d+)(?:-L?(\d+))?$/; + +export const parseLineAnchor = (hash: string): SelectedLineRange | null => { + const match = LINE_ANCHOR_RE.exec(hash); + if (!match) return null; + const first = Number(match[1]); + const last = match[2] === undefined ? first : Number(match[2]); + if (first < 1 || last < 1) return null; + return { start: Math.min(first, last), end: Math.max(first, last) }; +}; + +export const lineAnchor = (range: SelectedLineRange | null): string => { + if (!range) return ""; + const start = Math.min(range.start, range.end); + const end = Math.max(range.start, range.end); + return start === end ? `#L${start}` : `#L${start}-${end}`; +};