diff --git a/lib/controllers/file-patch-controller.js b/lib/controllers/file-patch-controller.js
index 1ba40a897d..a0953eba60 100644
--- a/lib/controllers/file-patch-controller.js
+++ b/lib/controllers/file-patch-controller.js
@@ -1,3 +1,5 @@
+import path from 'path';
+
import React from 'react';
import PropTypes from 'prop-types';
@@ -10,6 +12,7 @@ import FilePatchView from '../views/file-patch-view';
export default class FilePatchController extends React.Component {
static propTypes = {
+ largeDiffLineThreshold: PropTypes.number,
activeWorkingDirectory: PropTypes.string,
repository: PropTypes.object.isRequired,
commandRegistry: PropTypes.object.isRequired,
@@ -27,9 +30,16 @@ export default class FilePatchController extends React.Component {
}
static defaultProps = {
+ largeDiffLineThreshold: 1000,
switchboard: new Switchboard(),
}
+ static confirmedLargeFilePatches = new Set()
+
+ static resetConfirmedLargeFilePatches() {
+ this.confirmedLargeFilePatches = new Set();
+ }
+
constructor(props, context) {
super(props, context);
@@ -55,6 +65,13 @@ export default class FilePatchController extends React.Component {
File has no contents
);
+ } else if (!this.shouldDisplayLargeDiff(this.props.filePatch)) {
+ return (
+
+
This is a large diff. For performance reasons, it is not rendered by default.
+
+
+ );
} else {
// NOTE: Outer div is required for etch to render elements correctly
const filePath = this.props.filePatch.getPath();
@@ -83,6 +100,16 @@ export default class FilePatchController extends React.Component {
}
}
+ shouldDisplayLargeDiff(filePatch) {
+ const fullPath = path.join(this.props.repository.getWorkingDirectoryPath(), this.props.filePatch.getPath());
+ if (FilePatchController.confirmedLargeFilePatches.has(fullPath)) {
+ return true;
+ }
+
+ const lineCount = filePatch.getHunks().reduce((acc, hunk) => hunk.getLines().length, 0);
+ return lineCount < this.props.largeDiffLineThreshold;
+ }
+
onDidChangeTitle(callback) {
return this.emitter.on('did-change-title', callback);
}
@@ -91,6 +118,15 @@ export default class FilePatchController extends React.Component {
return this.emitter.on('did-destroy', callback);
}
+ @autobind
+ handleShowDiffClick() {
+ if (this.props.repository) {
+ const fullPath = path.join(this.props.repository.getWorkingDirectoryPath(), this.props.filePatch.getPath());
+ FilePatchController.confirmedLargeFilePatches.add(fullPath);
+ this.forceUpdate();
+ }
+ }
+
async stageHunk(hunk) {
this.props.switchboard.didBeginStageOperation({stage: true, hunk: true});
diff --git a/styles/pane-view.less b/styles/pane-view.less
index d5160d6b09..e18fdf118d 100644
--- a/styles/pane-view.less
+++ b/styles/pane-view.less
@@ -5,11 +5,15 @@
display: flex;
height: 100%;
- &.is-blank {
+ &.is-blank, &.large-file-patch {
align-items: center;
justify-content: center;
text-align: center;
font-size: 1.2em;
padding: @component-padding;
}
+
+ &.large-file-patch {
+ flex-direction: column;
+ }
}
diff --git a/test/controllers/file-patch-controller.test.js b/test/controllers/file-patch-controller.test.js
index 3641e36546..bc5e1e4ef4 100644
--- a/test/controllers/file-patch-controller.test.js
+++ b/test/controllers/file-patch-controller.test.js
@@ -33,8 +33,11 @@ describe('FilePatchController', function() {
const filePatch = new FilePatch('a.txt', 'a.txt', 'modified', [new Hunk(1, 1, 1, 3, '', [])]);
const repository = Repository.absent();
+ sinon.stub(repository, 'getWorkingDirectoryPath').returns('/absent');
const resolutionProgress = new ResolutionProgress();
+ FilePatchController.resetConfirmedLargeFilePatches();
+
component = (