1 | import { from, Subject } from 'rxjs';
|
2 | import { filter, map, mergeMap } from 'rxjs/operators';
|
3 | import { Controller as BaseController } from 'sourcegraph/module/client/controller';
|
4 | import { MessageType } from 'sourcegraph/module/protocol';
|
5 | import { BrowserConsoleTracer, Trace } from 'sourcegraph/module/protocol/jsonrpc2/trace';
|
6 | import { ExtensionStatus } from '../app/ExtensionStatus';
|
7 | import { asError, isErrorLike } from '../errors';
|
8 | import { isExtensionEnabled } from '../extensions/extension';
|
9 | import { registerBuiltinClientCommands, updateConfiguration } from './clientCommands';
|
10 | import { log } from './log';
|
11 |
|
12 |
|
13 |
|
14 | export class Controller extends BaseController {
|
15 | constructor() {
|
16 | super(...arguments);
|
17 | |
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 | this.notifications = new Subject();
|
24 | }
|
25 | |
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 | executeCommand(params) {
|
34 | return this.registries.commands.executeCommand(params).catch(err => {
|
35 | this.notifications.next({ message: err, type: MessageType.Error, source: params.command });
|
36 | return Promise.reject(err);
|
37 | });
|
38 | }
|
39 | }
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 | function environmentFilter(nextEnvironment) {
|
47 | return Object.assign({}, nextEnvironment, { extensions: nextEnvironment.extensions &&
|
48 | nextEnvironment.extensions.filter(x => {
|
49 | try {
|
50 | if (!isExtensionEnabled(nextEnvironment.configuration.merged, x.id)) {
|
51 | return false;
|
52 | }
|
53 | else if (!x.manifest) {
|
54 | console.warn(`Extension ${x.id} was not found. Remove it from settings to suppress this warning.`);
|
55 | return false;
|
56 | }
|
57 | else if (isErrorLike(x.manifest)) {
|
58 | console.warn(asError(x.manifest));
|
59 | return false;
|
60 | }
|
61 | else if (!x.manifest.activationEvents) {
|
62 | console.warn(`Extension ${x.id} has no activation events, so it will never be activated.`);
|
63 | return false;
|
64 | }
|
65 | const visibleTextDocumentLanguages = nextEnvironment.visibleTextDocuments
|
66 | ? nextEnvironment.visibleTextDocuments.map(({ languageId }) => languageId)
|
67 | : [];
|
68 | return x.manifest.activationEvents.some(e => e === '*' || visibleTextDocumentLanguages.some(l => e === `onLanguage:${l}`));
|
69 | }
|
70 | catch (err) {
|
71 | console.error(err);
|
72 | }
|
73 | return false;
|
74 | }) });
|
75 | }
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 | export function createController(context, createMessageTransports) {
|
86 | const controller = new Controller({
|
87 | clientOptions: (_key, extension) => ({
|
88 | createMessageTransports: () => createMessageTransports(extension),
|
89 | }),
|
90 | environmentFilter,
|
91 | });
|
92 |
|
93 |
|
94 |
|
95 | controller.clientEntries.subscribe(entries => {
|
96 | const traceEnabled = localStorage.getItem(ExtensionStatus.TRACE_STORAGE_KEY) !== null;
|
97 | for (const e of entries) {
|
98 | e.connection
|
99 | .then(c => c.trace(traceEnabled ? Trace.Verbose : Trace.Off, new BrowserConsoleTracer(e.key.id)))
|
100 | .catch(err => console.error(err));
|
101 | }
|
102 | });
|
103 | registerBuiltinClientCommands(context, controller);
|
104 | registerExtensionContributions(controller);
|
105 |
|
106 | controller.showMessages.subscribe(({ message, type }) => controller.notifications.next({ message, type }));
|
107 | function messageFromExtension(message) {
|
108 | return `From extension:\n\n${message}`;
|
109 | }
|
110 | controller.showMessageRequests.subscribe(({ message, actions, resolve }) => {
|
111 | if (!actions || actions.length === 0) {
|
112 | alert(messageFromExtension(message));
|
113 | resolve(null);
|
114 | return;
|
115 | }
|
116 | const value = prompt(messageFromExtension(`${message}\n\nValid responses: ${actions.map(({ title }) => JSON.stringify(title)).join(', ')}`), actions[0].title);
|
117 | resolve(actions.find(a => a.title === value) || null);
|
118 | });
|
119 | controller.showInputs.subscribe(({ message, defaultValue, resolve }) => resolve(prompt(messageFromExtension(message), defaultValue)));
|
120 | controller.configurationUpdates
|
121 | .pipe(mergeMap(params => {
|
122 | const update = updateConfiguration(context, params);
|
123 | params.resolve(update);
|
124 | return from(update);
|
125 | }))
|
126 | .subscribe(undefined, err => console.error(err));
|
127 |
|
128 | controller.logMessages.subscribe(({ message }) => {
|
129 | log('info', 'EXT', message);
|
130 | });
|
131 |
|
132 | const DEBUG = true;
|
133 | if (DEBUG) {
|
134 |
|
135 | const LOG_ENVIRONMENT = false;
|
136 | if (LOG_ENVIRONMENT) {
|
137 | controller.environment.subscribe(environment => log('info', 'env', environment));
|
138 | }
|
139 |
|
140 |
|
141 | window.sx = controller;
|
142 |
|
143 |
|
144 | controller.environment.subscribe(v => (window.sxenv = v)).unsubscribe();
|
145 | }
|
146 | return controller;
|
147 | }
|
148 |
|
149 |
|
150 |
|
151 |
|
152 |
|
153 | function registerExtensionContributions(controller) {
|
154 | const contributions = controller.environment.pipe(map(({ extensions }) => extensions), filter((extensions) => !!extensions), map(extensions => extensions
|
155 | .map(({ manifest }) => manifest)
|
156 | .filter((manifest) => manifest !== null && !isErrorLike(manifest))
|
157 | .map(({ contributes }) => contributes)
|
158 | .filter((contributions) => !!contributions)));
|
159 | return controller.registries.contribution.registerContributions({
|
160 | contributions,
|
161 | });
|
162 | }
|
163 |
|
\ | No newline at end of file |