UNPKG

atom-nuclide

Version:

A unified developer experience for web and mobile development, built as a suite of features on top of Atom to provide hackability and the support of an active community.

599 lines (517 loc) 24.3 kB
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; /* * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the license found in the LICENSE file in * the root directory of this source tree. */ function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { var callNext = step.bind(null, 'next'); var callThrow = step.bind(null, 'throw'); function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(callNext, callThrow); } } callNext(); }); }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } var _assert2; function _assert() { return _assert2 = _interopRequireDefault(require('assert')); } var _atom2; function _atom() { return _atom2 = require('atom'); } var _reactForAtom2; function _reactForAtom() { return _reactForAtom2 = require('react-for-atom'); } var _DiffViewEditorPane2; function _DiffViewEditorPane() { return _DiffViewEditorPane2 = _interopRequireDefault(require('./DiffViewEditorPane')); } var _DiffViewTree2; function _DiffViewTree() { return _DiffViewTree2 = _interopRequireDefault(require('./DiffViewTree')); } var _SyncScroll2; function _SyncScroll() { return _SyncScroll2 = _interopRequireDefault(require('./SyncScroll')); } var _DiffTimelineView2; function _DiffTimelineView() { return _DiffTimelineView2 = _interopRequireDefault(require('./DiffTimelineView')); } var _DiffViewToolbar2; function _DiffViewToolbar() { return _DiffViewToolbar2 = _interopRequireDefault(require('./DiffViewToolbar')); } var _DiffNavigationBar2; function _DiffNavigationBar() { return _DiffNavigationBar2 = _interopRequireDefault(require('./DiffNavigationBar')); } var _DiffCommitView2; function _DiffCommitView() { return _DiffCommitView2 = _interopRequireDefault(require('./DiffCommitView')); } var _DiffPublishView2; function _DiffPublishView() { return _DiffPublishView2 = _interopRequireDefault(require('./DiffPublishView')); } var _diffUtils2; function _diffUtils() { return _diffUtils2 = require('./diff-utils'); } var _commonsAtomCreatePaneContainer2; function _commonsAtomCreatePaneContainer() { return _commonsAtomCreatePaneContainer2 = _interopRequireDefault(require('../../commons-atom/create-pane-container')); } var _commonsAtomTextEditor2; function _commonsAtomTextEditor() { return _commonsAtomTextEditor2 = require('../../commons-atom/text-editor'); } var _constants2; function _constants() { return _constants2 = require('./constants'); } var _commonsNodePassesGK2; function _commonsNodePassesGK() { return _commonsNodePassesGK2 = _interopRequireDefault(require('../../commons-node/passesGK')); } function initialEditorState() { return { revisionTitle: '', text: '', offsets: new Map(), highlightedLines: { added: [], removed: [] }, inlineElements: [] }; } var EMPTY_FUNCTION = function EMPTY_FUNCTION() {}; var SCROLL_FIRST_CHANGE_DELAY_MS = 100; var DiffViewComponent = (function (_React$Component) { _inherits(DiffViewComponent, _React$Component); function DiffViewComponent(props) { _classCallCheck(this, DiffViewComponent); _get(Object.getPrototypeOf(DiffViewComponent.prototype), 'constructor', this).call(this, props); this.state = { mode: (_constants2 || _constants()).DiffMode.BROWSE_MODE, filePath: '', toolbarVisible: true, oldEditorState: initialEditorState(), newEditorState: initialEditorState() }; this._onModelStateChange = this._onModelStateChange.bind(this); this._updateLineDiffState = this._updateLineDiffState.bind(this); this._onChangeNewTextEditor = this._onChangeNewTextEditor.bind(this); this._onTimelineChangeRevision = this._onTimelineChangeRevision.bind(this); this._onNavigationClick = this._onNavigationClick.bind(this); this._onDidUpdateTextEditorElement = this._onDidUpdateTextEditorElement.bind(this); this._onChangeMode = this._onChangeMode.bind(this); this._onSwitchToEditor = this._onSwitchToEditor.bind(this); this._readonlyBuffer = new (_atom2 || _atom()).TextBuffer(); this._subscriptions = new (_atom2 || _atom()).CompositeDisposable(); } _createClass(DiffViewComponent, [{ key: 'componentDidMount', value: function componentDidMount() { var _this = this; var _props = this.props; var diffModel = _props.diffModel; var tryTriggerNux = _props.tryTriggerNux; this._subscriptions.add(diffModel.onActiveFileUpdates(function (activeFileState) { _this._updateLineDiffState(activeFileState); // The diff tree needs to update the active diffed file. // TODO(most): merge ActiveFileState into DiffModel's State. _this._renderTree(); })); this._subscriptions.add(diffModel.onDidUpdateState(this._onModelStateChange)); this._subscriptions.add(atom.workspace.onDidChangeActivePaneItem(function (activeItem) { if (activeItem != null && activeItem.tagName === 'NUCLIDE-DIFF-VIEW') { // Re-render on activation. _this._updateLineDiffState(diffModel.getActiveFileState()); } })); this._paneContainer = (0, (_commonsAtomCreatePaneContainer2 || _commonsAtomCreatePaneContainer()).default)(); // The changed files status tree takes 1/5 of the width and lives on the right most, // while being vertically splt with the revision timeline stack pane. var topPane = this._newEditorPane = this._paneContainer.getActivePane(); this._bottomRightPane = topPane.splitDown({ flexScale: 0.3 }); this._treePane = this._bottomRightPane.splitLeft({ flexScale: 0.35 }); this._navigationPane = topPane.splitRight({ flexScale: 0.045 }); this._oldEditorPane = topPane.splitLeft({ flexScale: 1 }); this._renderDiffView(); this._subscriptions.add(this._destroyPaneDisposable(this._oldEditorPane), this._destroyPaneDisposable(this._newEditorPane), this._destroyPaneDisposable(this._navigationPane), this._destroyPaneDisposable(this._treePane), this._destroyPaneDisposable(this._bottomRightPane)); (_reactForAtom2 || _reactForAtom()).ReactDOM.findDOMNode(this.refs.paneContainer).appendChild(atom.views.getView(this._paneContainer)); this._updateLineDiffState(diffModel.getActiveFileState()); tryTriggerNux(); } }, { key: '_onModelStateChange', value: function _onModelStateChange() { this.setState({}); } }, { key: '_setupSyncScroll', value: function _setupSyncScroll() { if (this._oldEditorComponent == null || this._newEditorComponent == null) { return; } var oldTextEditorElement = this._oldEditorComponent.getEditorDomElement(); var newTextEditorElement = this._newEditorComponent.getEditorDomElement(); var syncScroll = this._syncScroll; if (syncScroll != null) { syncScroll.dispose(); this._subscriptions.remove(syncScroll); } this._syncScroll = new (_SyncScroll2 || _SyncScroll()).default(oldTextEditorElement, newTextEditorElement); this._subscriptions.add(this._syncScroll); } }, { key: '_scrollToFirstHighlightedLine', value: function _scrollToFirstHighlightedLine() { var _this2 = this; // Schedule scroll to first line after all lines have been rendered. var _state = this.state; var oldEditorState = _state.oldEditorState; var newEditorState = _state.newEditorState; var filePath = _state.filePath; var removedLines = oldEditorState.highlightedLines.removed; var addedLines = newEditorState.highlightedLines.added; if (addedLines.length === 0 && removedLines.length === 0) { return; } var firstRemovedLine = (0, (_diffUtils2 || _diffUtils()).getOffsetLineNumber)(removedLines[0] || 0, oldEditorState.offsets); var firstAddedLine = (0, (_diffUtils2 || _diffUtils()).getOffsetLineNumber)(addedLines[0] || 0, newEditorState.offsets); var scrollTimeout = setTimeout(function () { _this2._subscriptions.remove(clearScrollTimeoutSubscription); if (_this2.state.filePath !== filePath) { return; } if (addedLines.length === 0 || removedLines.length > 0 && firstRemovedLine < firstAddedLine) { _this2._oldEditorComponent.scrollToScreenLine(firstRemovedLine); } else { _this2._newEditorComponent.scrollToScreenLine(firstAddedLine); } }, SCROLL_FIRST_CHANGE_DELAY_MS); var clearScrollTimeoutSubscription = new (_atom2 || _atom()).Disposable(function () { clearTimeout(scrollTimeout); }); this._subscriptions.add(clearScrollTimeoutSubscription); } }, { key: '_onChangeMode', value: function _onChangeMode(mode) { this.props.diffModel.setViewMode(mode); } }, { key: '_renderDiffView', value: function _renderDiffView() { this._renderTree(); this._renderEditors(); this._renderNavigation(); this._renderBottomRightPane(); } }, { key: '_renderBottomRightPane', value: function _renderBottomRightPane() { var _props$diffModel$getState = this.props.diffModel.getState(); var viewMode = _props$diffModel$getState.viewMode; switch (viewMode) { case (_constants2 || _constants()).DiffMode.BROWSE_MODE: this._renderTimelineView(); this._publishComponent = null; break; case (_constants2 || _constants()).DiffMode.COMMIT_MODE: this._renderCommitView(); this._timelineComponent = null; this._publishComponent = null; break; case (_constants2 || _constants()).DiffMode.PUBLISH_MODE: this._renderPublishView(); this._timelineComponent = null; break; default: throw new Error('Invalid Diff Mode: ' + viewMode); } } }, { key: 'componentDidUpdate', value: function componentDidUpdate(prevProps, prevState) { this._renderDiffView(); if (this.state.filePath !== prevState.filePath) { this._scrollToFirstHighlightedLine(); this.props.diffModel.emitActiveBufferChangeModified(); } } }, { key: '_renderCommitView', value: _asyncToGenerator(function* () { var _props$diffModel$getState2 = this.props.diffModel.getState(); var commitMessage = _props$diffModel$getState2.commitMessage; var commitMode = _props$diffModel$getState2.commitMode; var commitModeState = _props$diffModel$getState2.commitModeState; var passes = yield (0, (_commonsNodePassesGK2 || _commonsNodePassesGK()).default)('nuclide_diff_commit_form'); var DiffComponent = undefined; if (passes) { // Try requiring private module try { // $FlowFB var _require = require('./fb/DiffViewCommitForm'); var DiffViewCommitForm = _require.DiffViewCommitForm; DiffComponent = DiffViewCommitForm; } catch (ex) { DiffComponent = (_DiffCommitView2 || _DiffCommitView()).default; } } else { DiffComponent = (_DiffCommitView2 || _DiffCommitView()).default; } (_reactForAtom2 || _reactForAtom()).ReactDOM.render((_reactForAtom2 || _reactForAtom()).React.createElement(DiffComponent, { commitMessage: commitMessage, commitMode: commitMode, commitModeState: commitModeState, // `diffModel` is acting as the action creator for commit view and needs to be passed so // methods can be called on it. diffModel: this.props.diffModel }), this._getPaneElement(this._bottomRightPane)); }) }, { key: '_renderPublishView', value: function _renderPublishView() { var diffModel = this.props.diffModel; var _diffModel$getState = diffModel.getState(); var publishMode = _diffModel$getState.publishMode; var publishModeState = _diffModel$getState.publishModeState; var publishMessage = _diffModel$getState.publishMessage; var headRevision = _diffModel$getState.headRevision; var component = (_reactForAtom2 || _reactForAtom()).ReactDOM.render((_reactForAtom2 || _reactForAtom()).React.createElement((_DiffPublishView2 || _DiffPublishView()).default, { publishModeState: publishModeState, message: publishMessage, publishMode: publishMode, headRevision: headRevision, diffModel: diffModel }), this._getPaneElement(this._bottomRightPane)); (0, (_assert2 || _assert()).default)(component instanceof (_DiffPublishView2 || _DiffPublishView()).default); this._publishComponent = component; } }, { key: '_renderTree', value: function _renderTree() { var diffModel = this.props.diffModel; var _diffModel$getState2 = diffModel.getState(); var selectedFileChanges = _diffModel$getState2.selectedFileChanges; var showNonHgRepos = _diffModel$getState2.showNonHgRepos; var _diffModel$getActiveFileState = diffModel.getActiveFileState(); var filePath = _diffModel$getActiveFileState.filePath; this._treeComponent = (_reactForAtom2 || _reactForAtom()).ReactDOM.render((_reactForAtom2 || _reactForAtom()).React.createElement( 'div', { className: 'nuclide-diff-view-tree padded' }, (_reactForAtom2 || _reactForAtom()).React.createElement((_DiffViewTree2 || _DiffViewTree()).default, { activeFilePath: filePath, fileChanges: selectedFileChanges, showNonHgRepos: showNonHgRepos, diffModel: diffModel }) ), this._getPaneElement(this._treePane)); } }, { key: '_renderEditors', value: function _renderEditors() { var _state2 = this.state; var filePath = _state2.filePath; var oldState = _state2.oldEditorState; var newState = _state2.newEditorState; var oldEditorComponent = (_reactForAtom2 || _reactForAtom()).ReactDOM.render((_reactForAtom2 || _reactForAtom()).React.createElement((_DiffViewEditorPane2 || _DiffViewEditorPane()).default, { headerTitle: oldState.revisionTitle, textBuffer: this._readonlyBuffer, filePath: filePath, offsets: oldState.offsets, highlightedLines: oldState.highlightedLines, textContent: oldState.text, inlineElements: oldState.inlineElements, readOnly: true, onChange: EMPTY_FUNCTION, onDidUpdateTextEditorElement: EMPTY_FUNCTION }), this._getPaneElement(this._oldEditorPane)); (0, (_assert2 || _assert()).default)(oldEditorComponent instanceof (_DiffViewEditorPane2 || _DiffViewEditorPane()).default); this._oldEditorComponent = oldEditorComponent; var textBuffer = (0, (_commonsAtomTextEditor2 || _commonsAtomTextEditor()).bufferForUri)(filePath); var newEditorComponent = (_reactForAtom2 || _reactForAtom()).ReactDOM.render((_reactForAtom2 || _reactForAtom()).React.createElement((_DiffViewEditorPane2 || _DiffViewEditorPane()).default, { headerTitle: newState.revisionTitle, textBuffer: textBuffer, filePath: filePath, offsets: newState.offsets, highlightedLines: newState.highlightedLines, inlineElements: newState.inlineElements, onDidUpdateTextEditorElement: this._onDidUpdateTextEditorElement, readOnly: false, onChange: this._onChangeNewTextEditor }), this._getPaneElement(this._newEditorPane)); (0, (_assert2 || _assert()).default)(newEditorComponent instanceof (_DiffViewEditorPane2 || _DiffViewEditorPane()).default); this._newEditorComponent = newEditorComponent; } }, { key: '_onDidUpdateTextEditorElement', value: function _onDidUpdateTextEditorElement() { this._setupSyncScroll(); } }, { key: '_renderTimelineView', value: function _renderTimelineView() { var component = (_reactForAtom2 || _reactForAtom()).ReactDOM.render((_reactForAtom2 || _reactForAtom()).React.createElement((_DiffTimelineView2 || _DiffTimelineView()).default, { diffModel: this.props.diffModel, onSelectionChange: this._onTimelineChangeRevision }), this._getPaneElement(this._bottomRightPane)); (0, (_assert2 || _assert()).default)(component instanceof (_DiffTimelineView2 || _DiffTimelineView()).default); this._timelineComponent = component; } }, { key: '_renderNavigation', value: function _renderNavigation() { var _state3 = this.state; var oldEditorState = _state3.oldEditorState; var newEditorState = _state3.newEditorState; var oldOffsets = oldEditorState.offsets; var oldLines = oldEditorState.highlightedLines; var oldContents = oldEditorState.text; var newOffsets = newEditorState.offsets; var newLines = newEditorState.highlightedLines; var newContents = newEditorState.text; var navigationPaneElement = this._getPaneElement(this._navigationPane); var component = (_reactForAtom2 || _reactForAtom()).ReactDOM.render((_reactForAtom2 || _reactForAtom()).React.createElement((_DiffNavigationBar2 || _DiffNavigationBar()).default, { elementHeight: navigationPaneElement.clientHeight, addedLines: newLines.added, newOffsets: newOffsets, newContents: newContents, removedLines: oldLines.removed, oldOffsets: oldOffsets, oldContents: oldContents, onClick: this._onNavigationClick }), navigationPaneElement); (0, (_assert2 || _assert()).default)(component instanceof (_DiffNavigationBar2 || _DiffNavigationBar()).default); this._navigationComponent = component; } }, { key: '_onNavigationClick', value: function _onNavigationClick(lineNumber, isAddedLine) { var textEditorComponent = isAddedLine ? this._newEditorComponent : this._oldEditorComponent; (0, (_assert2 || _assert()).default)(textEditorComponent, 'Diff View Navigation Error: Non valid text editor component'); var textEditor = textEditorComponent.getEditorModel(); textEditor.scrollToBufferPosition([lineNumber, 0]); } }, { key: '_getPaneElement', value: function _getPaneElement(pane) { return atom.views.getView(pane).querySelector('.item-views'); } }, { key: '_destroyPaneDisposable', value: function _destroyPaneDisposable(pane) { var _this3 = this; return new (_atom2 || _atom()).Disposable(function () { (_reactForAtom2 || _reactForAtom()).ReactDOM.unmountComponentAtNode((_reactForAtom2 || _reactForAtom()).ReactDOM.findDOMNode(_this3._getPaneElement(pane))); pane.destroy(); }); } }, { key: 'componentWillUnmount', value: function componentWillUnmount() { this._subscriptions.dispose(); } }, { key: 'render', value: function render() { var toolbarComponent = null; if (this.state.toolbarVisible) { var _state4 = this.state; var _oldEditorState = _state4.oldEditorState; var _newEditorState = _state4.newEditorState; toolbarComponent = (_reactForAtom2 || _reactForAtom()).React.createElement((_DiffViewToolbar2 || _DiffViewToolbar()).default, { filePath: this.state.filePath, newRevisionTitle: _newEditorState.revisionTitle, oldRevisionTitle: _oldEditorState.revisionTitle, onSwitchMode: this._onChangeMode, onSwitchToEditor: this._onSwitchToEditor }); } return (_reactForAtom2 || _reactForAtom()).React.createElement( 'div', { className: 'nuclide-diff-view-container' }, toolbarComponent, (_reactForAtom2 || _reactForAtom()).React.createElement('div', { className: 'nuclide-diff-view-component', ref: 'paneContainer' }) ); } }, { key: '_onSwitchToEditor', value: function _onSwitchToEditor() { var diffViewNode = (_reactForAtom2 || _reactForAtom()).ReactDOM.findDOMNode(this); (0, (_assert2 || _assert()).default)(diffViewNode, 'Diff View DOM needs to be attached to switch to editor mode'); atom.commands.dispatch(diffViewNode, 'nuclide-diff-view:switch-to-editor'); } }, { key: '_onChangeNewTextEditor', value: function _onChangeNewTextEditor(newContents) { this.props.diffModel.setNewContents(newContents); } }, { key: '_onTimelineChangeRevision', value: function _onTimelineChangeRevision(revision) { this.props.diffModel.setRevision(revision); } /** * Updates the line diff state on active file state change. */ }, { key: '_updateLineDiffState', value: function _updateLineDiffState(fileState) { var filePath = fileState.filePath; var oldContents = fileState.oldContents; var newContents = fileState.newContents; var inlineComponents = fileState.inlineComponents; var fromRevisionTitle = fileState.fromRevisionTitle; var toRevisionTitle = fileState.toRevisionTitle; var _ref = (0, (_diffUtils2 || _diffUtils()).computeDiff)(oldContents, newContents); var addedLines = _ref.addedLines; var removedLines = _ref.removedLines; var oldLineOffsets = _ref.oldLineOffsets; var newLineOffsets = _ref.newLineOffsets; // TODO(most): Sync the used comment vertical space on both editors. var oldEditorState = { revisionTitle: fromRevisionTitle, text: oldContents, offsets: oldLineOffsets, highlightedLines: { added: [], removed: removedLines }, inlineElements: inlineComponents || [] }; var newEditorState = { revisionTitle: toRevisionTitle, text: newContents, offsets: newLineOffsets, highlightedLines: { added: addedLines, removed: [] }, inlineElements: [] }; this.setState({ filePath: filePath, oldEditorState: oldEditorState, newEditorState: newEditorState }); } }]); return DiffViewComponent; })((_reactForAtom2 || _reactForAtom()).React.Component); module.exports = DiffViewComponent; // A bound function that when invoked will try to trigger the Diff View NUX