-
Notifications
You must be signed in to change notification settings - Fork 2.5k
/
plugin-vscode-init.ts
125 lines (106 loc) · 4.8 KB
/
plugin-vscode-init.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/********************************************************************************
* Copyright (C) 2018-2019 Red Hat, Inc.
*
* 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
********************************************************************************/
/* eslint-disable @typescript-eslint/no-explicit-any */
import * as theia from '@theia/plugin';
import { BackendInitializationFn, PluginAPIFactory, Plugin, emptyPlugin } from '@theia/plugin-ext';
export const VSCODE_DEFAULT_API_VERSION = '1.41.1';
/** Set up en as a default locale for VS Code extensions using vscode-nls */
process.env['VSCODE_NLS_CONFIG'] = JSON.stringify({ locale: 'en', availableLanguages: {} });
process.env['VSCODE_PID'] = process.env['THEIA_PARENT_PID'];
const pluginsApiImpl = new Map<string, typeof theia>();
const plugins = new Array<Plugin>();
let defaultApi: typeof theia;
let isLoadOverride = false;
let pluginApiFactory: PluginAPIFactory;
export enum ExtensionKind {
UI = 1,
Workspace = 2
}
export const doInitialization: BackendInitializationFn = (apiFactory: PluginAPIFactory, plugin: Plugin) => {
const vscode = Object.assign(apiFactory(plugin), { ExtensionKind });
// replace command API as it will send only the ID as a string parameter
const registerCommand = vscode.commands.registerCommand;
vscode.commands.registerCommand = function (command: theia.CommandDescription | string, handler?: <T>(...args: any[]) => T | Thenable<T>, thisArg?: any): any {
// use of the ID when registering commands
if (typeof command === 'string') {
const rawCommands = plugin.rawModel.contributes && plugin.rawModel.contributes.commands;
const commands = rawCommands ? Array.isArray(rawCommands) ? rawCommands : [rawCommands] : undefined;
if (handler && commands && commands.some(item => item.command === command)) {
return vscode.commands.registerHandler(command, handler, thisArg);
}
return registerCommand({ id: command }, handler, thisArg);
}
return registerCommand(command, handler, thisArg);
};
// use Theia plugin api instead vscode extensions
(<any>vscode).extensions = {
get all(): any[] {
return vscode.plugins.all.map(p => asExtension(p));
},
getExtension(pluginId: string): any | undefined {
return asExtension(vscode.plugins.getPlugin(pluginId));
},
get onDidChange(): theia.Event<void> {
return vscode.plugins.onDidChange;
}
};
// override the version for vscode to be a VSCode version
(<any>vscode).version = process.env['VSCODE_API_VERSION'] || VSCODE_DEFAULT_API_VERSION;
pluginsApiImpl.set(plugin.model.id, vscode);
plugins.push(plugin);
pluginApiFactory = apiFactory;
if (!isLoadOverride) {
overrideInternalLoad();
isLoadOverride = true;
}
};
function overrideInternalLoad(): void {
const module = require('module');
const vscodeModuleName = 'vscode';
// save original load method
const internalLoad = module._load;
// if we try to resolve theia module, return the filename entry to use cache.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
module._load = function (request: string, parent: any, isMain: {}): any {
if (request !== vscodeModuleName) {
return internalLoad.apply(this, arguments);
}
const plugin = findPlugin(parent.filename);
if (plugin) {
const apiImpl = pluginsApiImpl.get(plugin.model.id);
return apiImpl;
}
if (!defaultApi) {
console.warn(`Could not identify plugin for 'Theia' require call from ${parent.filename}`);
defaultApi = pluginApiFactory(emptyPlugin);
}
return defaultApi;
};
}
function findPlugin(filePath: string): Plugin | undefined {
return plugins.find(plugin => filePath.startsWith(plugin.pluginFolder));
}
function asExtension(plugin: any | undefined): any | undefined {
if (!plugin) {
return plugin;
}
if (plugin.pluginPath) {
plugin.extensionPath = plugin.pluginPath;
}
// stub as a local VS Code extension (not running on a remote workspace)
plugin.extensionKind = ExtensionKind.UI;
return plugin;
}