alm
Version:
The best IDE for TypeScript
236 lines (235 loc) • 10.4 kB
JavaScript
;
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Provides a new overview of the cotents of the file, *semantically*
*/
/** imports */
var ui = require("../../ui");
var csx = require("../../base/csx");
var React = require("react");
var ReactDOM = require("react-dom");
var state = require("../../state/state");
var react_redux_1 = require("react-redux");
var utils = require("../../../common/utils");
var socketClient_1 = require("../../../socket/socketClient");
var commands = require("../../commands/commands");
var typestyle = require("typestyle");
var styles = require("../../styles/styles");
var pure_1 = require("../../../common/pure");
var monacoUtils_1 = require("../../monaco/monacoUtils");
var SemanticViewStyles;
(function (SemanticViewStyles) {
SemanticViewStyles.root = {
padding: '5px',
background: '#343333',
// Font
color: '#BBB',
fontSize: '.6rem',
fontWeight: 'bold',
// Overflow
overflow: 'auto',
// Limit width
maxWidth: '200px',
opacity: '0.7',
transition: 'opacity .2s',
':hover': {
opacity: '1'
}
};
SemanticViewStyles.nodeClass = typestyle.style(csx.extend(styles.ellipsis, {
paddingTop: '2px',
paddingBottom: '3px',
paddingLeft: '2px',
paddingRight: '2px',
// Border which merges with the top
marginTop: '-1px',
border: '1px solid transparent',
cursor: 'pointer',
'-webkit-user-select': 'none',
transition: 'background .2s',
'&:hover': {
backgroundColor: '#555'
}
}));
SemanticViewStyles.selectedNodeClass = typestyle.style({
border: '1px solid grey',
backgroundColor: styles.blackHighlightColor,
$nest: {
'&:hover': {
backgroundColor: styles.blackHighlightColor
}
}
});
})(SemanticViewStyles || (SemanticViewStyles = {}));
var SemanticView = /** @class */ (function (_super) {
__extends(SemanticView, _super);
function SemanticView(props) {
var _this = _super.call(this, props) || this;
_this.handleCursorActivity = utils.debounce(function (editor) {
if (editor === void 0) { editor = _this.props.editor; }
if (!editor)
return; // Still loading or maybe unloaded
if (!state.inActiveProjectFilePath(_this.props.filePath))
return;
if (_this.isUnmounted)
return;
if (!_this.props.showSemanticView)
return;
var sel = editor.getSelection();
var cursor = { line: sel.startLineNumber - 1, ch: sel.startColumn - 1 };
/** If first call OR cursor moved */
if (!_this.state.cursor || (_this.state.cursor && _this.state.cursor.line !== cursor.line)) {
_this.setState({ cursor: cursor });
_this.afterComponentDidUpdate(function () {
// Scroll to select node in view if any
var ref = _this.refs[_this.selectedRef];
if (ref) {
ref.scrollIntoViewIfNeeded(true);
}
});
}
}, 1000);
_this.gotoNode = function (node) {
var cursor = { line: node.start.line, ch: node.start.ch };
var editor = _this.props.editor;
monacoUtils_1.gotoPosition({ editor: editor, position: cursor });
editor.focus();
_this.setState({ cursor: cursor });
};
/** Constantly incrementing so that this points to the last (deepest) selected node :) */
_this.selectedRef = 0;
_this.isSelected = function (node) {
if (!_this.state.cursor)
return '';
var cursor = _this.state.cursor;
if (node.start.line <= cursor.line && node.end.line >= cursor.line) {
_this.selectedRef++;
return SemanticViewStyles.selectedNodeClass;
}
return '';
};
/** If the tree changes its width we need to relayout the editor */
_this.lastWidth = 0;
/** Loads the tree data */
_this.reloadData = function () {
if (!_this.props.filePath)
return;
if (!state.inActiveProjectFilePath(_this.props.filePath))
return;
socketClient_1.server.getSemanticTree({ filePath: _this.props.filePath }).then(function (res) {
_this.afterComponentDidUpdate(function () {
// also relayout the editor if the last width is not the same as new width
var newWidth = ReactDOM.findDOMNode(_this).clientWidth;
if (_this.lastWidth !== newWidth) {
_this.relayoutEditor();
_this.lastWidth = newWidth;
}
});
_this.setState({ tree: res.nodes });
});
};
_this.state = {
tree: []
};
return _this;
}
SemanticView.prototype.shouldComponentUpdate = function () {
return pure_1.shouldComponentUpdate.apply(this, arguments);
};
SemanticView.prototype.componentWillUnmount = function () {
_super.prototype.componentWillUnmount.call(this);
};
SemanticView.prototype.componentWillReceiveProps = function (props) {
var _this = this;
if (props.showSemanticView && !this.props.showSemanticView) {
this.handleCursorActivity();
}
if (!this.props.editor && props.editor) {
/** Initial data load */
var sel = props.editor.getSelection();
var cursor = { line: sel.startLineNumber - 1, ch: sel.endLineNumber - 1 };
this.setState({ cursor: cursor });
this.reloadData();
var reloadDataDebounced_1 = utils.debounce(this.reloadData, 3000);
this.disposible.add(commands.fileContentsChanged.on(function (e) {
if (e.filePath === props.filePath && _this.props.showSemanticView) {
reloadDataDebounced_1();
}
}));
this.disposible.add(state.subscribeSub((function (s) { return s.showSemanticView; }), function (showSemanticView) {
if (showSemanticView) {
reloadDataDebounced_1();
}
}));
this.handleCursorActivity(props.editor);
this.disposible.add(props.editor.onDidChangeCursorSelection(function () { return _this.handleCursorActivity(); }));
}
/**
* If just hidden and we have an editor, then the editor needs resizing
*/
if (!props.showSemanticView && this.props.showSemanticView && this.props.editor) {
this.afterComponentDidUpdate(function () {
_this.relayoutEditor();
});
}
};
SemanticView.prototype.render = function () {
var _this = this;
if (!this.props.showSemanticView || !this.state.cursor) {
return React.createElement("div", null);
}
if (!state.inActiveProjectFilePath(this.props.filePath)) {
return React.createElement("div", null);
}
return React.createElement("div", { style: SemanticViewStyles.root }, this.state.tree.map(function (node) { return _this.renderNode(node, 0); }));
};
SemanticView.prototype.renderNode = function (node, indent) {
var _this = this;
var isSelected = this.isSelected(node);
var color = ui.kindToColor(node.kind);
var ref = isSelected ? this.selectedRef.toString() : null;
return [React.createElement("div", { ref: ref, key: node.text, className: SemanticViewStyles.nodeClass + ' ' + isSelected, style: { color: color }, onClick: function (event) { _this.gotoNode(node); event.stopPropagation(); }, "data-start": node.start.line, "data-end": node.end.line },
ui.indent(indent),
React.createElement("span", { style: { fontFamily: 'FontAwesome' } }, this.getIconForKind(node.kind)),
" ",
node.text)].concat(node.subNodes.map(function (sn) { return _this.renderNode(sn, indent + 1); }));
};
SemanticView.prototype.getIconForKind = function (kind) {
return ui.kindToIcon(kind);
};
SemanticView.prototype.relayoutEditor = function () {
// We store `top` (and restore it) otherwise the editor jumps around a bit after relayout.
var top = this.props.editor.getScrollTop();
this.props.editor.layout();
this.props.editor.setScrollTop(top);
};
SemanticView = __decorate([
react_redux_1.connect(function (state) {
return {
showSemanticView: state.showSemanticView,
};
}),
__metadata("design:paramtypes", [Object])
], SemanticView);
return SemanticView;
}(ui.BaseComponent));
exports.SemanticView = SemanticView;