Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 25 additions & 20 deletions apps/web/src/components/chat/InlineDiffPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ export const InlineDiffPreview = memo(function InlineDiffPreview(props: { hunk:
const highlightVersionRef = useRef(0);

useEffect(() => {
if (collapsed) return;
const version = ++highlightVersionRef.current;
const language = resolveLanguageFromPath(hunk.filePath);
if (language === "text") return;
Expand All @@ -206,28 +207,32 @@ export const InlineDiffPreview = memo(function InlineDiffPreview(props: { hunk:
const code = codeFragments.join("\n");
const themeName = resolveDiffThemeName(resolvedTheme);

getHighlighterPromise(language)
.then((highlighter) => {
if (highlightVersionRef.current !== version) return;
try {
const html = highlighter.codeToHtml(code, { lang: language, theme: themeName });
const extracted = extractLineHtmls(html);
if (extracted.length === codeFragments.length) {
const mapped: (string | null)[] = Array(hunk.lines.length).fill(null) as (
| string
| null
)[];
for (let i = 0; i < codeLineIndices.length; i++) {
mapped[codeLineIndices[i]!] = extracted[i]!;
const timerId = setTimeout(() => {
getHighlighterPromise(language)
.then((highlighter) => {
if (highlightVersionRef.current !== version) return;
try {
const html = highlighter.codeToHtml(code, { lang: language, theme: themeName });
const extracted = extractLineHtmls(html);
if (extracted.length === codeFragments.length) {
const mapped: (string | null)[] = Array(hunk.lines.length).fill(null) as (
| string
| null
)[];
for (let i = 0; i < codeLineIndices.length; i++) {
mapped[codeLineIndices[i]!] = extracted[i]!;
}
setLineHtmls(mapped as string[]);
}
setLineHtmls(mapped as string[]);
} catch {
// noop
}
} catch {
// noop
}
})
.catch(() => {});
}, [hunk.filePath, hunk.lines, resolvedTheme]);
})
.catch(() => {});
}, 150);

return () => clearTimeout(timerId);
}, [collapsed, hunk.filePath, hunk.lines, resolvedTheme]);

const CollapseIcon = collapsed ? ChevronRightIcon : ChevronDownIcon;

Expand Down
34 changes: 33 additions & 1 deletion apps/web/src/components/chat/MessagesTimeline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,38 @@ import { InlineDiffPreview } from "./InlineDiffPreview";
const MAX_VISIBLE_WORK_LOG_ENTRIES = 6;
const ALWAYS_UNVIRTUALIZED_TAIL_ROWS = 8;

const WORK_ROW_BASE_HEIGHT = 112;
const DIFF_PREVIEW_HEADER_HEIGHT = 32;
const DIFF_PREVIEW_LINE_HEIGHT = 18;
const DIFF_PREVIEW_MAX_HEIGHT = 260;

function estimateWorkRowHeight(
groupedEntries: ReadonlyArray<TimelineWorkEntry>,
showInlineDiffs: boolean,
): number {
if (!showInlineDiffs) return WORK_ROW_BASE_HEIGHT;

let diffHeight = 0;
const visibleEntries =
groupedEntries.length > MAX_VISIBLE_WORK_LOG_ENTRIES
? groupedEntries.slice(-MAX_VISIBLE_WORK_LOG_ENTRIES)
: groupedEntries;

for (const entry of visibleEntries) {
const previews = entry.diffPreviews;
if (!previews || previews.length === 0) continue;
for (const hunk of previews) {
const bodyHeight = Math.min(
hunk.lines.length * DIFF_PREVIEW_LINE_HEIGHT,
DIFF_PREVIEW_MAX_HEIGHT,
);
diffHeight += DIFF_PREVIEW_HEADER_HEIGHT + bodyHeight + 8;
}
}

return WORK_ROW_BASE_HEIGHT + diffHeight;
}

interface MessagesTimelineProps {
hasMessages: boolean;
isWorking: boolean;
Expand Down Expand Up @@ -255,7 +287,7 @@ export const MessagesTimeline = memo(function MessagesTimeline({
estimateSize: (index: number) => {
const row = rows[index];
if (!row) return 96;
if (row.kind === "work") return 112;
if (row.kind === "work") return estimateWorkRowHeight(row.groupedEntries, showInlineDiffs);
if (row.kind === "proposed-plan") return estimateTimelineProposedPlanHeight(row.proposedPlan);
if (row.kind === "working") return 40;
return estimateTimelineMessageHeight(row.message, { timelineWidthPx });
Expand Down