diff --git a/src/components/code-diff/code-diff.scss b/src/components/code-diff/code-diff.scss index 36843d886e..393192f862 100644 --- a/src/components/code-diff/code-diff.scss +++ b/src/components/code-diff/code-diff.scss @@ -110,6 +110,42 @@ display: flex; align-items: center; gap: 0.25rem; + // Pushes the toolbar to the right edge regardless of whether the labels + // block is rendered (it isn't in split mode). + margin-left: auto; +} + +// ─── Split-mode column labels ──────────────────────────────────────── +// Renders below the actions toolbar, mirroring the 4-cell layout of +// `.diff-line--split` so the `oldHeading` / `newHeading` text sits +// directly above the columns they describe. +.diff-header__column-labels { + display: flex; + align-items: stretch; + border-bottom: 1px solid var(--diff-border-color); + @include mixins.font-family(sans-serif); + font-size: 0.875rem; +} + +.diff-header__column-gutter { + width: var(--limel-line-number-min-width); + flex-shrink: 0; + background: var(--diff-gutter-bg); +} + +.diff-header__column-label { + flex: 1; + min-width: 0; + padding: 0.375rem 0.75rem; + font-weight: 500; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + + &--old { + // Divider matches the split divider between the diff columns below. + border-right: 1px solid var(--diff-split-divider-color); + } } .search-toggle--active { @@ -158,6 +194,10 @@ flex-grow: 1; } + limel-button-group { + flex-shrink: 0; + } + &__count { color: var(--diff-collapsed-text-color); white-space: nowrap; diff --git a/src/components/code-diff/code-diff.tsx b/src/components/code-diff/code-diff.tsx index e32de84496..233fa811b3 100644 --- a/src/components/code-diff/code-diff.tsx +++ b/src/components/code-diff/code-diff.tsx @@ -10,9 +10,16 @@ import { SplitDiffLine, } from './types'; import { ActionBarItem } from '../action-bar/action-bar.types'; +import { Button } from '../button/button.types'; import { buildSplitLines, computeDiff, normalizeForDiff } from './diff-engine'; import { tokenize, SyntaxToken } from './syntax-highlighter'; -import { buildSearchRegex, navigateMatchIndex } from './search-utils'; +import { + buildSearchRegex, + navigateMatchIndex, + pickDefaultScope, + lineMatchesScope, + SearchScope, +} from './search-utils'; import { extractRemovedContent, extractRemovedContentFromSplit, @@ -140,12 +147,15 @@ export class CodeDiff { @State() private currentMatchIndex: number = 0; + @State() + private searchScope: SearchScope = 'removed'; + private focusedRowIndex: number = -1; private normalizedOldText: string = ''; /** * Render-time counter that increments for each search match - * found while rendering removed lines. Used to determine which + * found while rendering in-scope lines. Used to determine which * match is the "current" one for navigation highlighting. */ private searchMatchCounter: number = 0; @@ -156,10 +166,11 @@ export class CodeDiff { private totalSearchMatches: number = 0; /** - * Whether the current render is inside a removed line, - * so search highlighting knows when to activate. + * Whether the current line being rendered participates in the + * active search scope, so search highlighting knows when to + * activate. */ - private isRenderingRemovedLine: boolean = false; + private isRenderingSearchableLine: boolean = false; /** * Cached search regex for the current render pass. @@ -359,13 +370,16 @@ export class CodeDiff { const { additions, deletions } = this.diffResult; const hasDiff = additions > 0 || deletions > 0; + const isSplit = this.layout === 'split'; - return ( + return [
-
- {oldHeading} - {newHeading} -
+ {!isSplit && ( +
+ {oldHeading} + {newHeading} +
+ )}
{additions > 0 && ( @@ -376,10 +390,25 @@ export class CodeDiff { )}
{hasDiff && this.renderCopyButton()} - {deletions > 0 && this.renderSearchToggle()} + {hasDiff && this.renderSearchToggle()}
-
- ); + , + isSplit && ( + // In split mode the labels live in their own row below the + // actions toolbar, mirroring the 4-cell layout of `.diff-line--split` + // so each label sits above the column it describes. +
+ + + {oldHeading} + + + + {newHeading} + +
+ ), + ]; } private renderCopyButton() { @@ -437,6 +466,14 @@ export class CodeDiff { return (