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.

267 lines (242 loc) 10.4 kB
var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })(); 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; }; })(); /* * 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 _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 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'); } /** * A single delegate which handles events from the object. * * This is simpler than registering handlers using emitter events directly, as * there's less messy bookkeeping regarding lifetimes of the unregister * Disposable objects. */ /** * Handles displaying breakpoints and processing events for a single text * editor. */ var BreakpointDisplayController = (function () { function BreakpointDisplayController(delegate, breakpointStore, editor, debuggerActions) { _classCallCheck(this, BreakpointDisplayController); this._delegate = delegate; this._disposables = new (_atom2 || _atom()).CompositeDisposable(); this._breakpointStore = breakpointStore; this._debuggerActions = debuggerActions; this._editor = editor; this._markers = []; this._lastShadowBreakpointMarker = null; // Configure the gutter. var gutter = editor.addGutter({ name: 'nuclide-breakpoint', visible: false }); this._gutter = gutter; this._disposables.add(gutter.onDidDestroy(this._handleGutterDestroyed.bind(this)), editor.observeGutters(this._registerGutterMouseHandlers.bind(this)), this._breakpointStore.onNeedUIUpdate(this._handleBreakpointsChanged.bind(this)), this._editor.onDidDestroy(this._handleTextEditorDestroyed.bind(this))); this._update(); } _createClass(BreakpointDisplayController, [{ key: '_registerGutterMouseHandlers', value: function _registerGutterMouseHandlers(gutter) { var gutterView = atom.views.getView(gutter); var boundClickHandler = this._handleGutterClick.bind(this); var boundMouseMoveHandler = this._handleGutterMouseMove.bind(this); var boundMouseOutHandler = this._handleGutterMouseOut.bind(this); // Add mouse listeners gutter for setting breakpoints. gutterView.addEventListener('click', boundClickHandler); gutterView.addEventListener('mousemove', boundMouseMoveHandler); gutterView.addEventListener('mouseout', boundMouseOutHandler); this._disposables.add(new (_atom2 || _atom()).Disposable(function () { gutterView.removeEventListener('click', boundClickHandler); gutterView.removeEventListener('mousemove', boundMouseMoveHandler); gutterView.removeEventListener('mouseout', boundMouseOutHandler); })); } }, { key: 'dispose', value: function dispose() { this._disposables.dispose(); this._markers.forEach(function (marker) { return marker.destroy(); }); if (this._gutter) { this._gutter.destroy(); } } }, { key: 'getEditor', value: function getEditor() { return this._editor; } }, { key: '_handleTextEditorDestroyed', value: function _handleTextEditorDestroyed() { // Gutter.destroy seems to fail after text editor is destroyed, and // Gutter.onDidDestroy doesn't seem to be called in that case. this._gutter = null; this._delegate.handleTextEditorDestroyed(this); } }, { key: '_handleGutterDestroyed', value: function _handleGutterDestroyed() { // If gutter is destroyed by some outside force, ensure the gutter is not // destroyed again. this._gutter = null; } /** * Update the display with the current set of breakpoints for this editor. */ }, { key: '_update', value: function _update() { var gutter = this._gutter; if (gutter == null) { return; } var path = this._editor.getPath(); if (path == null) { return; } var breakpoints = this._breakpointStore.getBreakpointsForPath(path); // A mutable unhandled lines map. var unhandledLines = this._breakpointStore.getBreakpointLinesForPath(path); var markersToKeep = []; // Destroy markers that no longer correspond to breakpoints. this._markers.forEach(function (marker) { var line = marker.getStartBufferPosition().row; if (unhandledLines.has(line)) { markersToKeep.push(marker); unhandledLines.delete(line); } else { marker.destroy(); } }); // Add new markers for breakpoints without corresponding markers. for (var _ref3 of breakpoints) { var _ref2 = _slicedToArray(_ref3, 1); var line = _ref2[0]; if (!unhandledLines.has(line)) { // This line has been handled. continue; } var marker = this._createBreakpointMarkerAtLine(line, false); // isShadow marker.onDidChange(this._handleMarkerChange.bind(this)); markersToKeep.push(marker); } gutter.show(); this._markers = markersToKeep; } /** * Handler for marker movements due to text being edited. */ }, { key: '_handleMarkerChange', value: function _handleMarkerChange(event) { var path = this._editor.getPath(); if (!path) { return; } if (!event.isValid) { this._debuggerActions.deleteBreakpoint(path, event.newHeadBufferPosition.row); } else if (event.oldHeadBufferPosition.row !== event.newHeadBufferPosition.row) { this._debuggerActions.deleteBreakpoint(path, event.oldHeadBufferPosition.row); this._debuggerActions.addBreakpoint(path, event.newHeadBufferPosition.row); } } }, { key: '_handleBreakpointsChanged', value: function _handleBreakpointsChanged(path) { if (path === this._editor.getPath()) { this._update(); } } }, { key: '_handleGutterClick', value: function _handleGutterClick(event) { // Filter out clicks to the folding chevron. var FOLDING_CHEVRON_CLASS_NAME = 'icon-right'; var target = event.target; // classList isn't in the defs of HTMLElement... if (target.classList.contains(FOLDING_CHEVRON_CLASS_NAME)) { return; } var path = this._editor.getPath(); if (!path) { return; } this._debuggerActions.toggleBreakpoint(path, this._getCurrentMouseEventLine(event)); } }, { key: '_getCurrentMouseEventLine', value: function _getCurrentMouseEventLine(event) { // Beware, screenPositionForMouseEvent is not a public api and may change in future versions. // $FlowIssue var screenPos = atom.views.getView(this._editor).component.screenPositionForMouseEvent(event); var bufferPos = this._editor.bufferPositionForScreenPosition(screenPos); return bufferPos.row; } }, { key: '_handleGutterMouseMove', value: function _handleGutterMouseMove(event) { var curLine = this._getCurrentMouseEventLine(event); if (this._isLineOverLastShadowBreakpoint(curLine)) { return; } // User moves to a new line we need to delete the old shadow breakpoint // and create a new one. this._removeLastShadowBreakpoint(); this._createShadowBreakpointAtLine(this._editor, curLine); } }, { key: '_handleGutterMouseOut', value: function _handleGutterMouseOut(event) { this._removeLastShadowBreakpoint(); } }, { key: '_isLineOverLastShadowBreakpoint', value: function _isLineOverLastShadowBreakpoint(curLine) { var shadowBreakpointMarker = this._lastShadowBreakpointMarker; return shadowBreakpointMarker != null && shadowBreakpointMarker.getStartBufferPosition().row === curLine; } }, { key: '_removeLastShadowBreakpoint', value: function _removeLastShadowBreakpoint() { if (this._lastShadowBreakpointMarker != null) { this._lastShadowBreakpointMarker.destroy(); this._lastShadowBreakpointMarker = null; } } }, { key: '_createShadowBreakpointAtLine', value: function _createShadowBreakpointAtLine(editor, line) { this._lastShadowBreakpointMarker = this._createBreakpointMarkerAtLine(line, true); } }, { key: '_createBreakpointMarkerAtLine', // isShadow value: function _createBreakpointMarkerAtLine(line, isShadow) { var marker = this._editor.markBufferPosition([line, 0], { invalidate: 'never' }); var elem = document.createElement('a'); elem.className = isShadow ? 'nuclide-debugger-shadow-breakpoint-icon' : 'nuclide-debugger-breakpoint-icon'; (0, (_assert2 || _assert()).default)(this._gutter != null); this._gutter.decorateMarker(marker, { item: elem }); return marker; } }]); return BreakpointDisplayController; })(); module.exports = BreakpointDisplayController;