Skip to content

Commit

Permalink
feat: add ability to always show certain lines
Browse files Browse the repository at this point in the history
Also revise the method that calculates the lines to hide in the diff
  • Loading branch information
Aeolun committed Oct 17, 2023
1 parent c4b317a commit 896eb32
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 49 deletions.
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,17 +68,18 @@ class Diff extends PureComponent {
## Props

| Prop | Type | Default | Description |
| ------------------------- | ------------------------- | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| oldValue | `string | Object` | `''` | Old value as string (or Object if using `diffJson`). |
| newValue | `string | Object` | `''` | New value as string (or Object if using `diffJson`). |
|---------------------------|---------------------------|--------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| oldValue | `string | Object` | `''` | Old value as string (or Object if using `diffJson`). |
| newValue | `string | Object` | `''` | New value as string (or Object if using `diffJson`). |
| splitView | `boolean` | `true` | Switch between `unified` and `split` view. |
| disableWordDiff | `boolean` | `false` | Show and hide word diff in a diff line. |
| compareMethod | `DiffMethod` | `DiffMethod.CHARS` | JsDiff text diff method used for diffing strings. Check out the [guide](https://github.com/praneshr/react-diff-viewer/tree/v3.0.0#text-block-diff-comparison) to use different methods. |
| renderGutter | `(diffData) => ReactNode` | `undefined` | Function that can be used to render an extra gutter with various information next to the line number. |
| hideLineNumbers | `boolean` | `false` | Show and hide line numbers. |
| alwaysShowLines | `string[]` | `[]` | List of lines to always be shown, regardless of diff status. Line number are prefixed with `L` and `R` for the left and right section of the diff viewer, respectively. For example, `L-20` means 20th line in the left pane. `extraLinesSurroundingDiff` applies to these lines as well. |
| renderContent | `function` | `undefined` | Render Prop API to render code in the diff viewer. Helpful for [syntax highlighting](#syntax-highlighting) |
| onLineNumberClick | `function` | `undefined` | Event handler for line number click. `(lineId: string) => void` |
| highlightLines | `array[string]` | `[]` | List of lines to be highlighted. Works together with `onLineNumberClick`. Line number are prefixed with `L` and `R` for the left and right section of the diff viewer, respectively. For example, `L-20` means 20th line in the left pane. To highlight a range of line numbers, pass the prefixed line number as an array. For example, `[L-2, L-3, L-4, L-5]` will highlight the lines `2-5` in the left pane. |
| highlightLines | `string[]` | `[]` | List of lines to be highlighted. Works together with `onLineNumberClick`. Line number are prefixed with `L` and `R` for the left and right section of the diff viewer, respectively. For example, `L-20` means 20th line in the left pane. To highlight a range of line numbers, pass the prefixed line number as an array. For example, `[L-2, L-3, L-4, L-5]` will highlight the lines `2-5` in the left pane. |
| showDiffOnly | `boolean` | `true` | Shows only the diffed lines and folds the unchanged lines |
| extraLinesSurroundingDiff | `number` | `3` | Number of extra unchanged lines surrounding the diff. Works along with `showDiffOnly`. |
| codeFoldMessageRenderer | `function` | `Expand {number} of lines ...` | Render Prop API to render code fold message. |
Expand Down
4 changes: 2 additions & 2 deletions examples/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,8 @@ class Example extends Component<{}, ExampleState> {
<ReactDiff
highlightLines={this.state.highlightLine}
onLineNumberClick={this.onLineNumberClick}
showLines={['R30']}
extraLinesSurroundingDiff={2}
alwaysShowLines={['L-30']}
extraLinesSurroundingDiff={1}
oldValue={this.state.compareMethod === DiffMethod.JSON ? oldJson : oldJs}
compareMethod={this.state.compareMethod}
splitView={this.state.splitView}
Expand Down
47 changes: 47 additions & 0 deletions src/compute-hidden-blocks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {DiffType, LineInformation} from "./compute-lines";
import {ReactElement} from "react";

interface Block {
index: number
startLine: number
endLine: number
lines: number
}
interface HiddenBlocks {
lineBlocks: Record<number, number>
blocks: Block[]
}
export function computeHiddenBlocks(lineInformation: LineInformation[], diffLines: number[], extraLines: number): HiddenBlocks {
let newBlockIndex = 0;
let currentBlock: Block | undefined
let lineBlocks: Record<number, number> = {}
let blocks: Block[] = []
lineInformation.forEach((line, lineIndex) => {
const isDiffLine = diffLines.some(diffLine => diffLine >= lineIndex - extraLines && diffLine <= lineIndex + extraLines)
if (!isDiffLine && currentBlock == undefined) {
// block begins
currentBlock = {
index: newBlockIndex,
startLine: lineIndex,
endLine: lineIndex,
lines: 1
}
blocks.push(currentBlock)
lineBlocks[lineIndex] = currentBlock.index
newBlockIndex++;
} else if (!isDiffLine) {
// block continues
currentBlock!.endLine = lineIndex
currentBlock!.lines++
lineBlocks[lineIndex] = currentBlock.index
} else {
// not a block anymore
currentBlock = undefined
}
})

return {
lineBlocks,
blocks: blocks
}
}
6 changes: 6 additions & 0 deletions src/compute-lines.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,15 @@ const computeDiff = (
* @param disableWordDiff Flag to enable/disable word diff.
* @param lineCompareMethod JsDiff text diff method from https://github.com/kpdecker/jsdiff/tree/v4.0.1#api
* @param linesOffset line number to start counting from
* @param showLines lines that are always shown, regardless of diff
*/
const computeLineInformation = (
oldString: string | Object,
newString: string | Object,
disableWordDiff: boolean = false,
lineCompareMethod: string = DiffMethod.CHARS,
linesOffset: number = 0,
showLines: string[] = [],
): ComputedLineInformation => {
let diffArray: Diff.Change[] = [];

Expand Down Expand Up @@ -253,6 +255,10 @@ const computeLineInformation = (
right.value = line;
}

if (showLines?.includes(`L-${left.lineNumber}`) || showLines?.includes(`R-${right.lineNumber}`) && !diffLines.includes(counter)) {
diffLines.push(counter)
}

if (!evaluateOnlyFirstLine) {
counter += 1;
}
Expand Down
69 changes: 26 additions & 43 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import cn from 'classnames';
import {computeLineInformation, DiffInformation, DiffMethod, DiffType, LineInformation,} from './compute-lines';
import computeStyles, {ReactDiffViewerStyles, ReactDiffViewerStylesOverride,} from './styles';
import {ReactElement} from "react";
import {computeHiddenBlocks} from "./compute-hidden-blocks";

const m = require('memoize-one');

Expand Down Expand Up @@ -35,7 +36,7 @@ export interface ReactDiffViewerProps {
/**
* Show the lines indicated here. Specified as L20 or R18 for respectively line 20 on the left or line 18 on the right.
*/
showLines?: string[]
alwaysShowLines?: string[]
// Show only diff between the two values.
showDiffOnly?: boolean;
// Render prop to format final string before displaying them in the UI.
Expand Down Expand Up @@ -481,6 +482,8 @@ class DiffViewer extends React.Component<
);
};



/**
* Generates the entire diff view.
*/
Expand All @@ -499,43 +502,37 @@ class DiffViewer extends React.Component<
disableWordDiff,
compareMethod,
linesOffset,
this.props.alwaysShowLines
);

const extraLines =
this.props.extraLinesSurroundingDiff < 0
? 0
: Math.round(this.props.extraLinesSurroundingDiff);
let skippedLines: number[] = [];

const { lineBlocks, blocks } = computeHiddenBlocks(lineInformation, diffLines, extraLines)

return lineInformation.map(
(line: LineInformation, lineIndex: number): ReactElement => {

const diffBlockStart = diffLines[0];
const currentPosition = diffBlockStart - lineIndex;

if (this.props.showDiffOnly) {

if (currentPosition === -extraLines) {
skippedLines = [];
diffLines.shift();
}
if (
line.left.type === DiffType.DEFAULT &&
(currentPosition > extraLines ||
diffBlockStart === undefined) &&
!this.state.expandedBlocks.includes(diffBlockStart)
) {
skippedLines.push(lineIndex + 1);

// show skipped line indicator only if there is more than one line to hide
if (diffBlockStart === lineIndex + 1 && skippedLines.length > 1) {
return this.renderSkippedLineIndicator(
skippedLines.length,
diffBlockStart,
line.left.lineNumber,
line.right.lineNumber,
const blockIndex = lineBlocks[lineIndex]

if (blockIndex !== undefined) {
const lastLineOfBlock = blocks[blockIndex].endLine === lineIndex;
if (!this.state.expandedBlocks.includes(blockIndex) && lastLineOfBlock) {
return (
<React.Fragment key={lineIndex}>
{this.renderSkippedLineIndicator(
blocks[blockIndex].lines,
blockIndex,
line.left.lineNumber,
line.right.lineNumber,
)}
</React.Fragment>
);
// if we are trying to hide the last line, just show it
} else if (lineIndex < lineInformation.length - 1) {
return null;
} else if (!this.state.expandedBlocks.includes(blockIndex)) {
return null
}
}
}
Expand All @@ -544,21 +541,7 @@ class DiffViewer extends React.Component<
? this.renderSplitView(line, lineIndex)
: this.renderInlineView(line, lineIndex);

if (currentPosition === extraLines && skippedLines.length > 0) {
const { length } = skippedLines;
skippedLines = [];
return (
<React.Fragment key={lineIndex}>
{this.renderSkippedLineIndicator(
length,
diffBlockStart,
line.left.lineNumber,
line.right.lineNumber,
)}
{diffNodes}
</React.Fragment>
);
}

return diffNodes;
},
);
Expand Down

0 comments on commit 896eb32

Please sign in to comment.