@theia/core
Version:
Theia is a cloud & desktop IDE framework implemented in TypeScript.
288 lines • 10.6 kB
JavaScript
"use strict";
// *****************************************************************************
// Copyright (C) 2017 TypeFox and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
// *****************************************************************************
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 });
exports.TreeImpl = exports.CompositeTreeNode = exports.TreeNode = exports.Tree = void 0;
const inversify_1 = require("inversify");
const event_1 = require("../../common/event");
const disposable_1 = require("../../common/disposable");
const cancellation_1 = require("../../common/cancellation");
const promise_util_1 = require("../../common/promise-util");
const common_1 = require("../../common");
exports.Tree = Symbol('Tree');
var TreeNode;
(function (TreeNode) {
function is(node) {
return (0, common_1.isObject)(node) && 'id' in node && 'parent' in node;
}
TreeNode.is = is;
function equals(left, right) {
return left === right || (!!left && !!right && left.id === right.id);
}
TreeNode.equals = equals;
function isVisible(node) {
return !!node && (node.visible === undefined || node.visible);
}
TreeNode.isVisible = isVisible;
})(TreeNode = exports.TreeNode || (exports.TreeNode = {}));
var CompositeTreeNode;
(function (CompositeTreeNode) {
function is(node) {
return (0, common_1.isObject)(node) && 'children' in node;
}
CompositeTreeNode.is = is;
function getFirstChild(parent) {
return parent.children[0];
}
CompositeTreeNode.getFirstChild = getFirstChild;
function getLastChild(parent) {
return parent.children[parent.children.length - 1];
}
CompositeTreeNode.getLastChild = getLastChild;
function isAncestor(parent, child) {
if (!child) {
return false;
}
if (TreeNode.equals(parent, child.parent)) {
return true;
}
return isAncestor(parent, child.parent);
}
CompositeTreeNode.isAncestor = isAncestor;
function indexOf(parent, node) {
if (!node) {
return -1;
}
return parent.children.findIndex(child => TreeNode.equals(node, child));
}
CompositeTreeNode.indexOf = indexOf;
function addChildren(parent, children) {
for (const child of children) {
addChild(parent, child);
}
return parent;
}
CompositeTreeNode.addChildren = addChildren;
function addChild(parent, child) {
const children = parent.children;
const index = children.findIndex(value => value.id === child.id);
if (index !== -1) {
children.splice(index, 1, child);
setParent(child, index, parent);
}
else {
children.push(child);
setParent(child, parent.children.length - 1, parent);
}
return parent;
}
CompositeTreeNode.addChild = addChild;
function removeChild(parent, child) {
const children = parent.children;
const index = children.findIndex(value => value.id === child.id);
if (index === -1) {
return;
}
children.splice(index, 1);
const { previousSibling, nextSibling } = child;
if (previousSibling) {
Object.assign(previousSibling, { nextSibling });
}
if (nextSibling) {
Object.assign(nextSibling, { previousSibling });
}
}
CompositeTreeNode.removeChild = removeChild;
function setParent(child, index, parent) {
const previousSibling = parent.children[index - 1];
const nextSibling = parent.children[index + 1];
Object.assign(child, { parent, previousSibling, nextSibling });
if (previousSibling) {
Object.assign(previousSibling, { nextSibling: child });
}
if (nextSibling) {
Object.assign(nextSibling, { previousSibling: child });
}
}
CompositeTreeNode.setParent = setParent;
})(CompositeTreeNode = exports.CompositeTreeNode || (exports.CompositeTreeNode = {}));
/**
* A default implementation of the tree.
*/
let TreeImpl = class TreeImpl {
constructor() {
this.onChangedEmitter = new event_1.Emitter();
this.onNodeRefreshedEmitter = new event_1.Emitter();
this.toDispose = new disposable_1.DisposableCollection();
this.onDidChangeBusyEmitter = new event_1.Emitter();
this.onDidChangeBusy = this.onDidChangeBusyEmitter.event;
this.nodes = {};
this.toDisposeOnSetRoot = new disposable_1.DisposableCollection();
this.toDispose.push(this.onChangedEmitter);
this.toDispose.push(this.onNodeRefreshedEmitter);
this.toDispose.push(this.onDidChangeBusyEmitter);
}
dispose() {
this.nodes = {};
this.toDispose.dispose();
}
get root() {
return this._root;
}
set root(root) {
this.toDisposeOnSetRoot.dispose();
const cancelRefresh = new cancellation_1.CancellationTokenSource();
this.toDisposeOnSetRoot.push(cancelRefresh);
this.nodes = {};
this._root = root;
this.addNode(root);
this.refresh(undefined, cancelRefresh.token);
}
get onChanged() {
return this.onChangedEmitter.event;
}
fireChanged() {
this.onChangedEmitter.fire(undefined);
}
get onNodeRefreshed() {
return this.onNodeRefreshedEmitter.event;
}
async fireNodeRefreshed(parent) {
await event_1.WaitUntilEvent.fire(this.onNodeRefreshedEmitter, parent);
this.fireChanged();
}
getNode(id) {
return id !== undefined ? this.nodes[id] : undefined;
}
validateNode(node) {
const id = !!node ? node.id : undefined;
return this.getNode(id);
}
async refresh(raw, cancellationToken) {
const parent = !raw ? this._root : this.validateNode(raw);
let result;
if (CompositeTreeNode.is(parent)) {
const busySource = new cancellation_1.CancellationTokenSource();
this.doMarkAsBusy(parent, 800, busySource.token);
try {
result = parent;
const children = await this.resolveChildren(parent);
if (cancellationToken === null || cancellationToken === void 0 ? void 0 : cancellationToken.isCancellationRequested) {
return;
}
result = await this.setChildren(parent, children);
if (cancellationToken === null || cancellationToken === void 0 ? void 0 : cancellationToken.isCancellationRequested) {
return;
}
}
finally {
busySource.cancel();
}
}
this.fireChanged();
return result;
}
resolveChildren(parent) {
return Promise.resolve(Array.from(parent.children));
}
async setChildren(parent, children) {
const root = this.getRootNode(parent);
if (this.nodes[root.id] && this.nodes[root.id] !== root) {
console.error(`Child node '${parent.id}' does not belong to this '${root.id}' tree.`);
return undefined;
}
this.removeNode(parent);
parent.children = children;
this.addNode(parent);
await this.fireNodeRefreshed(parent);
return parent;
}
removeNode(node) {
if (CompositeTreeNode.is(node)) {
node.children.forEach(child => this.removeNode(child));
}
if (node) {
delete this.nodes[node.id];
}
}
getRootNode(node) {
if (node.parent === undefined) {
return node;
}
else {
return this.getRootNode(node.parent);
}
}
addNode(node) {
if (node) {
this.nodes[node.id] = node;
}
if (CompositeTreeNode.is(node)) {
const { children } = node;
children.forEach((child, index) => {
CompositeTreeNode.setParent(child, index, node);
this.addNode(child);
});
}
}
async markAsBusy(raw, ms, token) {
const node = this.validateNode(raw);
if (node) {
await this.doMarkAsBusy(node, ms, token);
}
}
async doMarkAsBusy(node, ms, token) {
try {
await (0, promise_util_1.timeout)(ms, token);
this.doSetBusy(node);
token.onCancellationRequested(() => this.doResetBusy(node));
}
catch (_a) {
/* no-op */
}
}
doSetBusy(node) {
const oldBusy = node.busy || 0;
node.busy = oldBusy + 1;
if (oldBusy === 0) {
this.onDidChangeBusyEmitter.fire(node);
}
}
doResetBusy(node) {
const oldBusy = node.busy || 0;
if (oldBusy > 0) {
node.busy = oldBusy - 1;
if (node.busy === 0) {
this.onDidChangeBusyEmitter.fire(node);
}
}
}
};
TreeImpl = __decorate([
(0, inversify_1.injectable)(),
__metadata("design:paramtypes", [])
], TreeImpl);
exports.TreeImpl = TreeImpl;
//# sourceMappingURL=tree.js.map