diff --git a/package.json b/package.json index 1801826a6..7aa470523 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "@xstate/react": "^1.0.0-rc.6", "classnames": "^2.2.6", "date-fns": "^2.16.1", + "diff": "^4.0.2", "eslint-plugin-react-hooks": "^4.1.2", "gatsby": "^2.24.2", "gatsby-image": "^2.4.14", diff --git a/src/components/Tutorial.js b/src/components/Tutorial.js index 57b52cb91..edd5848f7 100644 --- a/src/components/Tutorial.js +++ b/src/components/Tutorial.js @@ -2,6 +2,7 @@ import { Children, cloneElement } from 'react'; import PropTypes from 'prop-types'; import parseCodeBlockProps from '../utils/parseCodeBlockProps'; import { isCodeBlock, isShellCommand } from '../utils/codeBlock'; +import { diffLines } from 'diff'; const Tutorial = ({ children }) => { children = Children.toArray(children); @@ -34,12 +35,17 @@ const Tutorial = ({ children }) => { ); const { fileName, code, language } = parseCodeBlockProps(codeBlock); + const { code: prevCode } = previousStep.get(fileName); return [ ...steps, cloneElement(stepElement, { initialSelectedFile: fileName, - step: previousStep.set(fileName, { code, language }), + step: previousStep.set(fileName, { + code, + language, + diff: diffLines(prevCode, code), + }), index: idx, totalSteps: arr.length, children: Children.toArray(stepElement.props.children).filter( diff --git a/src/components/TutorialEditor.js b/src/components/TutorialEditor.js index cf0d9d6b8..b56815d5e 100644 --- a/src/components/TutorialEditor.js +++ b/src/components/TutorialEditor.js @@ -7,7 +7,28 @@ import { darken } from 'polished'; const TutorialEditor = ({ initialSelectedFile, files }) => { const [selectedFile, setSelectedFile] = useState(initialSelectedFile); - const { language, code } = files.get(selectedFile); + const { diff } = files.get(selectedFile); + + const [highlightedLines] = diff.reduce( + ([highlightedLines, lineNumber], change) => { + const { count, added, removed } = change; + // Include current line when counting the end of the range + const rangeEnd = lineNumber + count - 1; + + return [ + added + ? [ + ...highlightedLines, + lineNumber === rangeEnd + ? lineNumber + : `${lineNumber}-${lineNumber + count - 1}`, + ] + : highlightedLines, + removed ? lineNumber : lineNumber + count, + ]; + }, + [[], 1] + ); return (