87 lines · 2.8 KB · TypeScript
RawDownload
import { useAtomValue } from "@effect/atom-react";import * as Data from "effect/Data";import * as Effect from "effect/Effect";import { AsyncResult, Atom } from "effect/unstable/reactivity";import { useMemo } from "react"; import {  highlightCodeSnippet,  type ReviewDiffTheme,  type ReviewHighlightedToken,} from "../review/shikiReviewHighlighter"; const MARKDOWN_CODE_HIGHLIGHT_IDLE_TTL_MS = 5 * 60_000; export type MarkdownHighlightedCode = ReadonlyArray<ReadonlyArray<ReviewHighlightedToken>>; export interface MarkdownCodeHighlightInput {  readonly code: string;  readonly enabled: boolean;  readonly language: string;  readonly theme: ReviewDiffTheme;} type MarkdownCodeHighlighter = (  input: MarkdownCodeHighlightInput,) => Promise<MarkdownHighlightedCode | null>; class MarkdownCodeHighlightCacheKey extends Data.Class<MarkdownCodeHighlightInput> {} class MarkdownCodeHighlightError extends Data.TaggedError("MarkdownCodeHighlightError")<{  readonly cause: unknown;}> {} export function createMarkdownCodeHighlightAtomFamily(options?: {  readonly highlight?: MarkdownCodeHighlighter;  readonly idleTtlMs?: number;}) {  const highlight =    options?.highlight ??    ((input: MarkdownCodeHighlightInput) =>      input.enabled        ? highlightCodeSnippet({            code: input.code,            language: input.language,            theme: input.theme,          })        : Promise.resolve(null));  const idleTtlMs = options?.idleTtlMs ?? MARKDOWN_CODE_HIGHLIGHT_IDLE_TTL_MS;  const family = Atom.family((request: MarkdownCodeHighlightCacheKey) =>    Atom.make(      Effect.tryPromise({        try: () => highlight(request),        catch: (cause) => new MarkdownCodeHighlightError({ cause }),      }),    ).pipe(      Atom.setIdleTTL(idleTtlMs),      Atom.withLabel(`mobile:thread-markdown-code-highlight:${request.theme}:${request.language}`),    ),  );   return (input: MarkdownCodeHighlightInput) => family(new MarkdownCodeHighlightCacheKey(input));} export const markdownCodeHighlightAtom = createMarkdownCodeHighlightAtomFamily(); export function useMarkdownCodeHighlight(input: {  readonly code: string;  readonly enabled: boolean;  readonly language: string | null | undefined;  readonly theme: ReviewDiffTheme;}): MarkdownHighlightedCode | null {  const normalizedLanguage = input.language?.trim() || "text";  const enabled = input.enabled && Boolean(input.language?.trim());  const atomLanguage = enabled ? normalizedLanguage : "text";  const highlightAtom = useMemo(    () =>      markdownCodeHighlightAtom({        code: enabled ? input.code : "",        enabled,        language: atomLanguage,        theme: input.theme,      }),    [atomLanguage, enabled, input.code, input.theme],  );  const result = useAtomValue(highlightAtom);  return AsyncResult.isSuccess(result) ? result.value : null;}