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
2 changes: 1 addition & 1 deletion static/app/components/issueDiff/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ class IssueDiff extends Component<Props, State> {
key={i}
base={value}
target={targetEvent[i] ?? ''}
type="words"
type="lines"
/>
))}
</StyledIssueDiff>
Expand Down
2 changes: 1 addition & 1 deletion static/app/components/replays/diff/replayTextDiff.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export function ReplayTextDiff() {
</After>
</ContentSliderDiff.Header>
<SplitDiffScrollWrapper>
<SplitDiff base={leftBody ?? ''} target={rightBody ?? ''} type="words" />
<SplitDiff base={leftBody ?? ''} target={rightBody ?? ''} type="lines" />
</SplitDiffScrollWrapper>
</Container>
);
Expand Down
70 changes: 58 additions & 12 deletions static/app/components/splitDiff.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {useMemo} from 'react';
import styled from '@emotion/styled';
import type {Change} from 'diff';
import {diffChars, diffLines, diffWords} from 'diff';
Expand All @@ -23,31 +24,76 @@ type Props = {
type?: keyof typeof diffFnMap;
};

// this function splits the lines from diffLines into words that are diffed
function getDisplayData(
line: Change[],
highlightAdded: Change | undefined,
highlightRemoved: Change | undefined
): Change[] {
if (!highlightAdded && !highlightRemoved) {
return line;
}

const leftText = line.reduce(
(acc, result) => (result.added ? acc : acc + result.value),
''
);
const rightText = line.reduce(
(acc, result) => (result.removed ? acc : acc + result.value),
''
);

if (!leftText && !rightText) {
return line;
}

return diffWords(leftText, rightText);
}

function SplitDiff({className, type = 'lines', base, target}: Props) {
const diffFn = diffFnMap[type];

const baseLines = base.split('\n');
const targetLines = target.split('\n');
const [largerArray] =
baseLines.length > targetLines.length
? [baseLines, targetLines]
: [targetLines, baseLines];
const results = largerArray.map((_line, index) =>
diffFn(baseLines[index] || '', targetLines[index] || '', {newlineIsToken: true})
);
const results = diffFn(base, target, {newlineIsToken: true});

// split one change that includes multiple lines into one change per line (for formatting)
const groupedChanges = useMemo((): Change[][] => {
let currentLine: Change[] = [];
const processedLines: Change[][] = [];
for (const change of results) {
const lines = change.value.split('\n');
for (let i = 0; i < lines.length; i++) {
const lineValue = lines[i];
if (lineValue !== undefined && lineValue !== '') {
currentLine.push({
value: lineValue,
added: change.added,
removed: change.removed,
});
}
if (i < lines.length - 1) {
processedLines.push(currentLine);
currentLine = [];
}
}
}
if (currentLine.length > 0) {
processedLines.push(currentLine);
}
return processedLines;
}, [results]);

return (
<SplitTable className={className} data-test-id="split-diff">
<SplitBody>
{results.map((line, j) => {
{groupedChanges.map((line, j) => {
const highlightAdded = line.find(result => result.added);
const highlightRemoved = line.find(result => result.removed);

return (
<tr key={j}>
<Cell isRemoved={highlightRemoved}>
<Line>
{line
{getDisplayData(line, highlightAdded, highlightRemoved)
.filter(result => !result.added)
.map((result, i) => (
<Word key={i} isRemoved={result.removed}>
Expand All @@ -61,7 +107,7 @@ function SplitDiff({className, type = 'lines', base, target}: Props) {

<Cell isAdded={highlightAdded}>
<Line>
{line
{getDisplayData(line, highlightAdded, highlightRemoved)
.filter(result => !result.removed)
.map((result, i) => (
<Word key={i} isAdded={result.added}>
Expand Down
Loading