UNPKG

6.35 kBJavaScriptView Raw
1"use strict";
2// *****************************************************************************
3// Copyright (C) 2020 Red Hat, Inc. and others.
4//
5// This program and the accompanying materials are made available under the
6// terms of the Eclipse Public License v. 2.0 which is available at
7// http://www.eclipse.org/legal/epl-2.0.
8//
9// This Source Code may also be made available under the following Secondary
10// Licenses when the conditions for such availability set forth in the Eclipse
11// Public License v. 2.0 are satisfied: GNU General Public License, version 2
12// with the GNU Classpath Exception which is available at
13// https://www.gnu.org/software/classpath/license.html.
14//
15// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
16// *****************************************************************************
17Object.defineProperty(exports, "__esModule", { value: true });
18exports.DecorationsServiceImpl = exports.DecorationsService = void 0;
19const tslib_1 = require("tslib");
20const inversify_1 = require("inversify");
21const promise_util_1 = require("../common/promise-util");
22const common_1 = require("../common");
23const ternary_search_tree_1 = require("../common/ternary-search-tree");
24exports.DecorationsService = Symbol('DecorationsService');
25class DecorationDataRequest {
26 constructor(source, thenable) {
27 this.source = source;
28 this.thenable = thenable;
29 }
30}
31class DecorationProviderWrapper {
32 constructor(provider, onDidChangeDecorationsEmitter) {
33 this.provider = provider;
34 this.onDidChangeDecorationsEmitter = onDidChangeDecorationsEmitter;
35 this.decorations = new Map();
36 this.data = ternary_search_tree_1.TernarySearchTree.forUris(true);
37 this.disposable = this.provider.onDidChange(async (uris) => {
38 this.decorations.clear();
39 if (!uris) {
40 this.data.clear();
41 }
42 else {
43 for (const uri of uris) {
44 this.fetchData(uri);
45 const decoration = await provider.provideDecorations(uri, common_1.CancellationToken.None);
46 if (decoration) {
47 this.decorations.set(uri.toString(), decoration);
48 }
49 }
50 }
51 this.onDidChangeDecorationsEmitter.fire(this.decorations);
52 });
53 }
54 dispose() {
55 this.disposable.dispose();
56 this.data.clear();
57 }
58 knowsAbout(uri) {
59 return !!this.data.get(uri) || Boolean(this.data.findSuperstr(uri));
60 }
61 getOrRetrieve(uri, includeChildren, callback) {
62 let item = this.data.get(uri);
63 if (item === undefined) {
64 // unknown -> trigger request
65 item = this.fetchData(uri);
66 }
67 if (item && !(item instanceof DecorationDataRequest)) {
68 // found something (which isn't pending anymore)
69 callback(item, false);
70 }
71 if (includeChildren) {
72 // (resolved) children
73 const iter = this.data.findSuperstr(uri);
74 if (iter) {
75 let next = iter.next();
76 while (!next.done) {
77 const value = next.value;
78 if (value && !(value instanceof DecorationDataRequest)) {
79 callback(value, true);
80 }
81 next = iter.next();
82 }
83 }
84 }
85 }
86 fetchData(uri) {
87 // check for pending request and cancel it
88 const pendingRequest = this.data.get(uri);
89 if (pendingRequest instanceof DecorationDataRequest) {
90 pendingRequest.source.cancel();
91 this.data.delete(uri);
92 }
93 const source = new common_1.CancellationTokenSource();
94 const dataOrThenable = this.provider.provideDecorations(uri, source.token);
95 if (!(0, promise_util_1.isThenable)(dataOrThenable)) {
96 // sync -> we have a result now
97 return this.keepItem(uri, dataOrThenable);
98 }
99 else {
100 // async -> we have a result soon
101 const request = new DecorationDataRequest(source, Promise.resolve(dataOrThenable).then(data => {
102 if (this.data.get(uri) === request) {
103 this.keepItem(uri, data);
104 }
105 }).catch(err => {
106 if (!(err instanceof Error && err.name === 'Canceled' && err.message === 'Canceled') && this.data.get(uri) === request) {
107 this.data.delete(uri);
108 }
109 }));
110 this.data.set(uri, request);
111 return undefined;
112 }
113 }
114 keepItem(uri, data) {
115 const deco = data ? data : undefined;
116 this.data.set(uri, deco);
117 return deco;
118 }
119}
120let DecorationsServiceImpl = class DecorationsServiceImpl {
121 constructor() {
122 this.data = [];
123 this.onDidChangeDecorationsEmitter = new common_1.Emitter();
124 this.onDidChangeDecorations = this.onDidChangeDecorationsEmitter.event;
125 }
126 dispose() {
127 this.onDidChangeDecorationsEmitter.dispose();
128 }
129 registerDecorationsProvider(provider) {
130 const wrapper = new DecorationProviderWrapper(provider, this.onDidChangeDecorationsEmitter);
131 this.data.push(wrapper);
132 return common_1.Disposable.create(() => {
133 // fire event that says 'yes' for any resource
134 // known to this provider. then dispose and remove it.
135 this.data.splice(this.data.indexOf(wrapper), 1);
136 this.onDidChangeDecorationsEmitter.fire(new Map());
137 wrapper.dispose();
138 });
139 }
140 getDecoration(uri, includeChildren) {
141 const data = [];
142 let containsChildren = false;
143 for (const wrapper of this.data) {
144 wrapper.getOrRetrieve(uri, includeChildren, (deco, isChild) => {
145 if (!isChild || deco.bubble) {
146 data.push(deco);
147 containsChildren = isChild || containsChildren;
148 }
149 });
150 }
151 return data;
152 }
153};
154DecorationsServiceImpl = (0, tslib_1.__decorate)([
155 (0, inversify_1.injectable)()
156], DecorationsServiceImpl);
157exports.DecorationsServiceImpl = DecorationsServiceImpl;
158//# sourceMappingURL=decorations-service.js.map
\No newline at end of file