Render one diff row.
( row: DiffRow, width: number, lineNumberDigits: number, showLineNumbers: boolean, showHunkHeaders: boolean, wrapLines: boolean, codeHorizontalOffset: number, theme: AppTheme, selected: boolean, copySelectedRowRange: CopySelectedRowRange | undefined, copySelectedSide: "left" | "right" | undefined, anchorId?: string, noteGuideSide?: "old" | "new", showAddNoteBadge = false, onHoverRow?: (rowKey: string) => void, onStartUserNoteAtHunk?: (hunkIndex: number, target?: UserNoteLineTarget) => void, onToggleGap?: (gapKey: string) => void, )
| 1346 | |
| 1347 | /** Render one diff row. */ |
| 1348 | function renderRow( |
| 1349 | row: DiffRow, |
| 1350 | width: number, |
| 1351 | lineNumberDigits: number, |
| 1352 | showLineNumbers: boolean, |
| 1353 | showHunkHeaders: boolean, |
| 1354 | wrapLines: boolean, |
| 1355 | codeHorizontalOffset: number, |
| 1356 | theme: AppTheme, |
| 1357 | selected: boolean, |
| 1358 | copySelectedRowRange: CopySelectedRowRange | undefined, |
| 1359 | copySelectedSide: "left" | "right" | undefined, |
| 1360 | anchorId?: string, |
| 1361 | noteGuideSide?: "old" | "new", |
| 1362 | showAddNoteBadge = false, |
| 1363 | onHoverRow?: (rowKey: string) => void, |
| 1364 | onStartUserNoteAtHunk?: (hunkIndex: number, target?: UserNoteLineTarget) => void, |
| 1365 | onToggleGap?: (gapKey: string) => void, |
| 1366 | ) { |
| 1367 | const hasCopySelection = !!copySelectedRowRange; |
| 1368 | const reserveAddNoteColumn = Boolean(onStartUserNoteAtHunk); |
| 1369 | |
| 1370 | // For split rows, the user's drag is anchored to one column-half of the diff. Apply the |
| 1371 | // selection-highlight blend only to that side so it is clear which file (A or B) the |
| 1372 | // selection represents. |
| 1373 | const hasLeftSelection = hasCopySelection && copySelectedSide !== "right"; |
| 1374 | const hasRightSelection = hasCopySelection && copySelectedSide !== "left"; |
| 1375 | let baseRow: ReactNode; |
| 1376 | |
| 1377 | if (row.type === "collapsed") { |
| 1378 | baseRow = renderHeaderRow( |
| 1379 | row, |
| 1380 | width, |
| 1381 | theme, |
| 1382 | selected || hasCopySelection, |
| 1383 | anchorId, |
| 1384 | showAddNoteBadge, |
| 1385 | onHoverRow, |
| 1386 | onStartUserNoteAtHunk, |
| 1387 | onToggleGap, |
| 1388 | ); |
| 1389 | } else if (row.type === "hunk-header") { |
| 1390 | baseRow = showHunkHeaders |
| 1391 | ? renderHeaderRow( |
| 1392 | row, |
| 1393 | width, |
| 1394 | theme, |
| 1395 | selected || hasCopySelection, |
| 1396 | anchorId, |
| 1397 | showAddNoteBadge, |
| 1398 | onHoverRow, |
| 1399 | onStartUserNoteAtHunk, |
| 1400 | ) |
| 1401 | : null; |
| 1402 | } else if (row.type === "split-line") { |
| 1403 | const guideOnOldSide = noteGuideSide === "old"; |
| 1404 | const guideOnNewSide = noteGuideSide === "new"; |
| 1405 | const addNoteTarget: UserNoteLineTarget | undefined = |
no test coverage detected