152 lines · 5.1 KB
import { Link } from "@tanstack/react-router";
import { SNIPPET_CLOSE, SNIPPET_OPEN } from "~/lib/code-intel";
import type { CodeSearchHit, CodeSearchLine } from "~/lib/code-intel";
import { EmptyState } from "~/ui/EmptyState";
import { TextLink } from "~/ui/TextLink";

type Segment = { offset: number; text: string; marked: boolean };

function snippetSegments(text: string): Segment[] {
  const out: Segment[] = [];
  let offset = 0;
  for (const [position, part] of text.split(SNIPPET_OPEN).entries()) {
    const [marked, rest] =
      position === 0 ? ["", part] : [part.split(SNIPPET_CLOSE)[0] ?? "", part.split(SNIPPET_CLOSE)[1] ?? ""];
    if (marked) out.push({ offset, text: marked, marked: true });
    offset += marked.length + 1;
    if (rest) out.push({ offset, text: rest, marked: false });
    offset += rest.length + 1;
  }
  return out;
}

function lineSegments(line: CodeSearchLine): Segment[] {
  const out: Segment[] = [];
  let cursor = 0;
  for (const { start, end } of line.ranges) {
    if (start > cursor) out.push({ offset: cursor, text: line.text.slice(cursor, start), marked: false });
    out.push({ offset: start, text: line.text.slice(start, end), marked: true });
    cursor = end;
  }
  if (cursor < line.text.length) out.push({ offset: cursor, text: line.text.slice(cursor), marked: false });
  return out;
}

function Highlighted({ segments }: { segments: Segment[] }) {
  return segments.map((segment) =>
    segment.marked ? (
      <mark key={segment.offset} className="rounded-sm bg-accent-500/25 text-accent-200">
        {segment.text}
      </mark>