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.

583 lines (490 loc) 19.1 kB
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; /* * 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 _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } var _atom2; function _atom() { return _atom2 = require('atom'); } var _reactForAtom2; function _reactForAtom() { return _reactForAtom2 = require('react-for-atom'); } var _assert2; function _assert() { return _assert2 = _interopRequireDefault(require('assert')); } var _url2; function _url() { return _url2 = _interopRequireDefault(require('url')); } var _commonsAtomUiTreePath2; function _commonsAtomUiTreePath() { return _commonsAtomUiTreePath2 = _interopRequireDefault(require('../../commons-atom/ui-tree-path')); } var _nuclideHgGitBridge2; function _nuclideHgGitBridge() { return _nuclideHgGitBridge2 = require('../../nuclide-hg-git-bridge'); } var _constants2; function _constants() { return _constants2 = require('./constants'); } var _DiffViewElement2; function _DiffViewElement() { return _DiffViewElement2 = _interopRequireDefault(require('./DiffViewElement')); } var _DiffViewComponent2; function _DiffViewComponent() { return _DiffViewComponent2 = _interopRequireDefault(require('./DiffViewComponent')); } var _DiffViewModel2; function _DiffViewModel() { return _DiffViewModel2 = _interopRequireDefault(require('./DiffViewModel')); } var _nuclideAnalytics2; function _nuclideAnalytics() { return _nuclideAnalytics2 = require('../../nuclide-analytics'); } var diffViewModel = null; var activeDiffView = null; var tryTriggerNux = undefined; // This url style is the one Atom uses for the welcome and settings pages. var NUCLIDE_DIFF_VIEW_URI = 'atom://nuclide/diff-view'; var DIFF_VIEW_FILE_TREE_CONTEXT_MENU_PRIORITY = 1000; var COMMIT_FILE_TREE_CONTEXT_MENU_PRIORITY = 1100; var AMEND_FILE_TREE_CONTEXT_MENU_PRIORITY = 1200; var PUBLISH_FILE_TREE_CONTEXT_MENU_PRIORITY = 1300; // Diff View NUX constants. var NUX_DIFF_VIEW_ID = 4368; var NUX_DIFF_VIEW_NAME = 'nuclide_diff_view_nux'; var NUX_DIFF_VIEW_GK = 'mp_nuclide_diff_view_nux'; var uiProviders = []; var subscriptions = null; var cwdApi = null; function formatDiffViewUrl(diffEntityOptions_) { var diffEntityOptions = diffEntityOptions_; if (diffEntityOptions == null) { diffEntityOptions = { file: '' }; } return (_url2 || _url()).default.format({ protocol: 'atom', host: 'nuclide', pathname: 'diff-view', slashes: true, query: diffEntityOptions }); } // To add a View as an Atom workspace pane, we return `DiffViewElement` which extends `HTMLElement`. // This pattern is also followed with atom's TextEditor. function createView(diffEntityOptions, // A bound instance of the triggerNuxService that will try to trigger the Diff View NUX triggerNuxService) { if (activeDiffView) { activateDiffPath(diffEntityOptions); return activeDiffView.element; } var diffModel = getDiffViewModel(); diffModel.activate(); var hostElement = new (_DiffViewElement2 || _DiffViewElement()).default().initialize(diffModel, NUCLIDE_DIFF_VIEW_URI); var component = (_reactForAtom2 || _reactForAtom()).ReactDOM.render((_reactForAtom2 || _reactForAtom()).React.createElement((_DiffViewComponent2 || _DiffViewComponent()).default, { diffModel: diffModel, tryTriggerNux: triggerNuxService }), hostElement); activeDiffView = { component: component, element: hostElement }; activateDiffPath(diffEntityOptions); var destroySubscription = hostElement.onDidDestroy(function () { (_reactForAtom2 || _reactForAtom()).ReactDOM.unmountComponentAtNode(hostElement); diffModel.deactivate(); destroySubscription.dispose(); (0, (_assert2 || _assert()).default)(subscriptions); subscriptions.remove(destroySubscription); activeDiffView = null; }); (0, (_assert2 || _assert()).default)(subscriptions); subscriptions.add(new (_atom2 || _atom()).Disposable(function () { hostElement.destroy(); }), destroySubscription); (0, (_nuclideAnalytics2 || _nuclideAnalytics()).track)('diff-view-open'); return hostElement; } function getDiffViewModel() { if (diffViewModel == null) { diffViewModel = new (_DiffViewModel2 || _DiffViewModel()).default(); diffViewModel.setUiProviders(uiProviders); (0, (_assert2 || _assert()).default)(subscriptions); subscriptions.add(diffViewModel); } return diffViewModel; } function activateDiffPath(diffEntityOptions) { if (diffViewModel == null) { return; } if (!diffEntityOptions.file && !diffEntityOptions.directory && cwdApi != null) { var directory = cwdApi.getCwd(); if (directory != null) { diffEntityOptions.directory = directory.getPath(); } } diffViewModel.diffEntity(diffEntityOptions); } function diffActivePath(diffOptions) { var editor = atom.workspace.getActiveTextEditor(); if (editor == null) { atom.workspace.open(formatDiffViewUrl(diffOptions)); } else { atom.workspace.open(formatDiffViewUrl(_extends({ file: editor.getPath() || '' }, diffOptions))); } } function isActiveEditorDiffable() { var editor = atom.workspace.getActiveTextEditor(); if (editor == null) { return false; } return isPathDiffable(editor.getPath()); } function shouldDisplayDiffTreeItem(contextMenu) { var node = contextMenu.getSingleSelectedNode(); return node != null && isPathDiffable(node.uri); } function isPathDiffable(filePath) { if (filePath == null || filePath.length === 0) { return false; } var repository = (0, (_nuclideHgGitBridge2 || _nuclideHgGitBridge()).repositoryForPath)(filePath); return repository != null && repository.getType() === 'hg'; } // Listen for file tree context menu file item events to open the diff view. function addFileTreeCommands(commandName, diffOptions) { (0, (_assert2 || _assert()).default)(subscriptions); subscriptions.add(atom.commands.add('.tree-view .entry.file.list-item', commandName, function (event) { var filePath = (0, (_commonsAtomUiTreePath2 || _commonsAtomUiTreePath()).default)(event); atom.workspace.open(formatDiffViewUrl(_extends({ file: filePath || '' }, diffOptions))); })); subscriptions.add(atom.commands.add('.tree-view .entry.directory.list-nested-item > .list-item', commandName, function (event) { var directoryPath = (0, (_commonsAtomUiTreePath2 || _commonsAtomUiTreePath()).default)(event); atom.workspace.open(formatDiffViewUrl(_extends({ directory: directoryPath || '' }, diffOptions))); })); } function addActivePathCommands(commandName, diffOptions) { (0, (_assert2 || _assert()).default)(subscriptions); function onTargetCommand(event) { event.preventDefault(); event.stopPropagation(); diffActivePath(diffOptions); } subscriptions.add(atom.commands.add('atom-workspace', commandName, onTargetCommand)); // Listen for in-editor context menu item diff view open command. subscriptions.add(atom.commands.add('atom-text-editor', commandName, onTargetCommand)); } module.exports = Object.defineProperties({ activate: function activate(state) { var _this = this; subscriptions = new (_atom2 || _atom()).CompositeDisposable(); // Listen for menu item workspace diff view open command. addActivePathCommands('nuclide-diff-view:open'); addActivePathCommands('nuclide-diff-view:commit', { viewMode: (_constants2 || _constants()).DiffMode.COMMIT_MODE, commitMode: (_constants2 || _constants()).CommitMode.COMMIT }); addActivePathCommands('nuclide-diff-view:amend', { viewMode: (_constants2 || _constants()).DiffMode.COMMIT_MODE, commitMode: (_constants2 || _constants()).CommitMode.AMEND }); addActivePathCommands('nuclide-diff-view:publish', { viewMode: (_constants2 || _constants()).DiffMode.PUBLISH_MODE }); // Context Menu Items. subscriptions.add(atom.contextMenu.add({ 'atom-text-editor': [{ type: 'separator' }, { label: 'Source Control', submenu: [{ label: 'Open in Diff View', command: 'nuclide-diff-view:open' }, { label: 'Commit', command: 'nuclide-diff-view:commit' }, { label: 'Amend', command: 'nuclide-diff-view:amend' }, { label: 'Publish to Phabricator', command: 'nuclide-diff-view:publish' }], shouldDisplay: function shouldDisplay() { return isActiveEditorDiffable(); } }, { type: 'separator' }] })); // Listen for switching to editor mode for the active file. subscriptions.add(atom.commands.add('nuclide-diff-view', 'nuclide-diff-view:switch-to-editor', function () { var diffModel = getDiffViewModel(); var _diffModel$getActiveFileState = diffModel.getActiveFileState(); var filePath = _diffModel$getActiveFileState.filePath; if (filePath != null && filePath.length) { atom.workspace.open(filePath); } })); addFileTreeCommands('nuclide-diff-view:open-context'); addFileTreeCommands('nuclide-diff-view:commit-context', { viewMode: (_constants2 || _constants()).DiffMode.COMMIT_MODE, commitMode: (_constants2 || _constants()).CommitMode.COMMIT }); addFileTreeCommands('nuclide-diff-view:amend-context', { viewMode: (_constants2 || _constants()).DiffMode.COMMIT_MODE, commitMode: (_constants2 || _constants()).CommitMode.AMEND }); addFileTreeCommands('nuclide-diff-view:publish-context', { viewMode: (_constants2 || _constants()).DiffMode.PUBLISH_MODE }); // The Diff View will open its main UI in a tab, like Atom's preferences and welcome pages. subscriptions.add(atom.workspace.addOpener(function (uri) { if (uri.startsWith(NUCLIDE_DIFF_VIEW_URI)) { if (!require('semver').gte(atom.getVersion(), '1.6.1')) { throw new Error('Outdated Atom version<br/>\n' + '**Nuclide\'s Diff View require Atom 1.6.1 or later**'); } var _default$parse = (_url2 || _url()).default.parse(uri, true); var diffEntityOptions = _default$parse.query; return createView(diffEntityOptions, _this.triggerNux.bind(_this, NUX_DIFF_VIEW_ID)); } })); if (state == null || !state.visible) { return; } var activeFilePath = state.activeFilePath; var viewMode = state.viewMode; var commitMode = state.commitMode; // Wait for the source control providers to be ready: var restorationSubscriptions = new (_atom2 || _atom()).CompositeDisposable( // If it's a local directory, or if "nuclide-hg-repository" was activated // after "nuclide-diff-view": atom.packages.serviceHub.consume('atom.repository-provider', '^0.1.0', function () { tryRestoreActiveDiffView(); }), // If it's a remote directory, it should come on a path change event: atom.project.onDidChangePaths(function () { tryRestoreActiveDiffView(); })); subscriptions.add(restorationSubscriptions); function tryRestoreActiveDiffView() { // If there is no repository ready, it may be because it's a remote file, // or because "nuclide-hg-repository" hasn't loaded yet. var canRestoreActiveDiffView = activeFilePath ? isPathDiffable(activeFilePath) : atom.project.getDirectories().some(function (directory) { return isPathDiffable(directory.getPath()); }); if (canRestoreActiveDiffView) { restorationSubscriptions.dispose(); (0, (_assert2 || _assert()).default)(subscriptions); subscriptions.remove(restorationSubscriptions); atom.workspace.open(formatDiffViewUrl({ file: activeFilePath, viewMode: viewMode, commitMode: commitMode })); } } }, consumeToolBar: function consumeToolBar(getToolBar) { var toolBar = getToolBar('nuclide-diff-view'); var button = toolBar.addButton({ icon: 'git-branch', callback: 'nuclide-diff-view:open', tooltip: 'Open Diff View', priority: 300 }).element; button.classList.add('diff-view-count'); var diffModel = getDiffViewModel(); var lastCount = null; var updateToolbarCount = function updateToolbarCount() { var count = diffModel.getState().dirtyFileChanges.size; if (count !== lastCount) { button.classList.toggle('positive-count', count > 0); button.classList.toggle('max-count', count > 99); button.dataset.count = count === 0 ? '' : count > 99 ? '99+' : String(count); lastCount = count; } }; updateToolbarCount(); var toolBarSubscriptions = new (_atom2 || _atom()).CompositeDisposable(diffModel.onDidUpdateState(function () { updateToolbarCount(); }), new (_atom2 || _atom()).Disposable(function () { toolBar.removeItems(); })); (0, (_assert2 || _assert()).default)(subscriptions); subscriptions.add(toolBarSubscriptions); return toolBarSubscriptions; }, getHomeFragments: function getHomeFragments() { return { feature: { title: 'Diff View', icon: 'git-branch', description: (_reactForAtom2 || _reactForAtom()).React.createElement( 'span', null, 'Launches an editable side-by-side compare view across mercurial dirty and commits changes, allowing committing and pushing changes to phabricator.' ), command: 'nuclide-diff-view:open' }, priority: 3 }; }, serialize: function serialize() { if (!activeDiffView || !diffViewModel) { return { visible: false }; } var _diffViewModel$getActiveFileState = diffViewModel.getActiveFileState(); var filePath = _diffViewModel$getActiveFileState.filePath; var _diffViewModel$getState = diffViewModel.getState(); var viewMode = _diffViewModel$getState.viewMode; var commitMode = _diffViewModel$getState.commitMode; return { visible: true, activeFilePath: filePath, viewMode: viewMode, commitMode: commitMode }; }, deactivate: function deactivate() { uiProviders.splice(0); if (subscriptions != null) { subscriptions.dispose(); subscriptions = null; } if (diffViewModel != null) { diffViewModel.dispose(); diffViewModel = null; } activeDiffView = null; }, /** * The diff-view package can consume providers that return React components to * be rendered inline. * A uiProvider must have a method composeUiElements with the following spec: * @param filePath The path of the file the diff view is opened for * @return An array of InlineComments (defined above) to be rendered into the * diff view */ consumeUIProvider: function consumeUIProvider(provider) { uiProviders.push(provider); if (diffViewModel != null) { diffViewModel.setUiProviders(uiProviders); } return; }, consumeCwdApi: function consumeCwdApi(api) { cwdApi = api; }, addItemsToFileTreeContextMenu: function addItemsToFileTreeContextMenu(contextMenu) { (0, (_assert2 || _assert()).default)(subscriptions); var menuItemDescriptions = new (_atom2 || _atom()).CompositeDisposable(); menuItemDescriptions.add(contextMenu.addItemToSourceControlMenu({ label: 'Open in Diff View', command: 'nuclide-diff-view:open-context', shouldDisplay: function shouldDisplay() { return shouldDisplayDiffTreeItem(contextMenu); } }, DIFF_VIEW_FILE_TREE_CONTEXT_MENU_PRIORITY)); menuItemDescriptions.add(contextMenu.addItemToSourceControlMenu({ label: 'Commit', command: 'nuclide-diff-view:commit-context', shouldDisplay: function shouldDisplay() { return shouldDisplayDiffTreeItem(contextMenu); } }, COMMIT_FILE_TREE_CONTEXT_MENU_PRIORITY)); menuItemDescriptions.add(contextMenu.addItemToSourceControlMenu({ label: 'Amend', command: 'nuclide-diff-view:amend-context', shouldDisplay: function shouldDisplay() { return shouldDisplayDiffTreeItem(contextMenu); } }, AMEND_FILE_TREE_CONTEXT_MENU_PRIORITY)); menuItemDescriptions.add(contextMenu.addItemToSourceControlMenu({ label: 'Publish to Phabricator', command: 'nuclide-diff-view:publish-context', shouldDisplay: function shouldDisplay() { return shouldDisplayDiffTreeItem(contextMenu); } }, PUBLISH_FILE_TREE_CONTEXT_MENU_PRIORITY)); subscriptions.add(menuItemDescriptions); // We don't need to dispose of the menuItemDescriptions when the provider is disabled - // it needs to be handled by the provider itself. We only should remove it from the list // of the disposables we maintain. return new (_atom2 || _atom()).Disposable(function () { if (subscriptions != null) { subscriptions.remove(menuItemDescriptions); } }); }, triggerNux: function triggerNux(nuxID) { if (tryTriggerNux != null) { tryTriggerNux(nuxID); } }, consumeRegisterNuxService: function consumeRegisterNuxService(addNewNux) { var disposable = addNewNux(_createDiffViewNux()); (0, (_assert2 || _assert()).default)(subscriptions != null); subscriptions.add(disposable); return disposable; }, consumeTriggerNuxService: function consumeTriggerNuxService(tryTriggerNuxService) { tryTriggerNux = tryTriggerNuxService; module.exports.tryTriggerNux = tryTriggerNux; }, NUX_DIFF_VIEW_ID: NUX_DIFF_VIEW_ID, tryTriggerNux: tryTriggerNux }, { __testDiffView: { get: function get() { return activeDiffView; }, configurable: true, enumerable: true } }); function _createDiffViewNux() { var diffViewFilesNux = { content: 'View the list of newly added and modified files.', selector: '.nuclide-diff-view-tree', position: 'top' }; var diffViewTimelineNux = { content: 'Compare, commit and amend revisions!', selector: '.nuclide-diff-timeline', position: 'top' }; var diffViewEditButtonNux = { content: 'Want to make changes? Click here to open the file in an editor.', selector: '.nuclide-diff-view-goto-editor-button', position: 'left' }; var diffViewPhabricatorNux = { content: 'Publish your changes to Phabricator without leaving Nuclide!', selector: '.nuclide-diff-timeline .revision-timeline-wrap .btn', position: 'bottom' }; var diffViewNuxTour = { id: NUX_DIFF_VIEW_ID, name: NUX_DIFF_VIEW_NAME, gatekeeperID: NUX_DIFF_VIEW_GK, nuxList: [diffViewFilesNux, diffViewTimelineNux, diffViewEditButtonNux, diffViewPhabricatorNux] }; return diffViewNuxTour; }