99 lines · 3.4 KB
import { ClientOnly } from "@tanstack/react-router";
import { File } from "@pierre/diffs/react";
import type { SelectedLineRange } from "@pierre/diffs";
import { useEffect, useMemo, useRef, useState } from "react";

const FALLBACK_LINES = 40;
const LINE_HASH = /^#L(\d+)(?:-L?(\d+))?$/;
const SCROLL_ATTEMPTS = 20;
const SCROLL_RETRY_MS = 100;

/**
 * `disableFileHeader` leaves the shadow root's <pre> empty (a @pierre/diffs bug), so the built-in
 * header is hidden with CSS instead; the page already shows the file name and size above.
 */
const BASE_OPTIONS = {
  theme: "pierre-dark",
  overflow: "scroll",
  enableLineSelection: true,
  unsafeCSS: "[data-diffs-header] { display: none; }",
} as const;

/** `#L12` or `#L12-L20` (also `#L12-20`), the GitHub-style line anchor. */
export function parseLineHash(hash: string): SelectedLineRange | null {
  const match = LINE_HASH.exec(hash);
  if (!match) return null;
  const start = Number(match[1]);
  const end = match[2] ? Number(match[2]) : start;
  return start > 0 ? { start: Math.min(start, end), end: Math.max(start, end) } : null;
}

function lineHash(range: SelectedLineRange): string {
  return range.start === range.end ? `#L${range.start}` : `#L${range.start}-L${range.end}`;
}

function PlainFallback({ contents }: { contents: string }) {
  return (
    <pre className="overflow-x-auto p-4 font-mono text-xs leading-5 text-kumo-subtle">
      {contents.split("\n").slice(0, FALLBACK_LINES).join("\n")}
    </pre>
  );