diff --git a/README.md b/README.md index 4311fdb..546ed39 100644 --- a/README.md +++ b/README.md @@ -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. | diff --git a/examples/src/index.tsx b/examples/src/index.tsx index 3bab216..dcbcee2 100644 --- a/examples/src/index.tsx +++ b/examples/src/index.tsx @@ -181,8 +181,8 @@ class Example extends Component<{}, ExampleState> { + blocks: Block[] +} +export function computeHiddenBlocks(lineInformation: LineInformation[], diffLines: number[], extraLines: number): HiddenBlocks { + let newBlockIndex = 0; + let currentBlock: Block | undefined + let lineBlocks: Record = {} + 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 + } +} diff --git a/src/compute-lines.ts b/src/compute-lines.ts index 9744e98..ba4d657 100644 --- a/src/compute-lines.ts +++ b/src/compute-lines.ts @@ -121,6 +121,7 @@ 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, @@ -128,6 +129,7 @@ const computeLineInformation = ( disableWordDiff: boolean = false, lineCompareMethod: string = DiffMethod.CHARS, linesOffset: number = 0, + showLines: string[] = [], ): ComputedLineInformation => { let diffArray: Diff.Change[] = []; @@ -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; } diff --git a/src/index.tsx b/src/index.tsx index 464e5c8..7cd9468 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -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'); @@ -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. @@ -481,6 +482,8 @@ class DiffViewer extends React.Component< ); }; + + /** * Generates the entire diff view. */ @@ -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 ( + + {this.renderSkippedLineIndicator( + blocks[blockIndex].lines, + blockIndex, + line.left.lineNumber, + line.right.lineNumber, + )} + ); - // 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 } } } @@ -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 ( - - {this.renderSkippedLineIndicator( - length, - diffBlockStart, - line.left.lineNumber, - line.right.lineNumber, - )} - {diffNodes} - - ); - } + return diffNodes; }, );