feat: 添加vscode编辑器
This commit is contained in:
@@ -0,0 +1,439 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { transformErrorForSerialization } from '../errors.js';
|
||||
import { Emitter } from '../event.js';
|
||||
import { Disposable } from '../lifecycle.js';
|
||||
import { globals, isWeb } from '../platform.js';
|
||||
import * as types from '../types.js';
|
||||
import * as strings from '../strings.js';
|
||||
const INITIALIZE = '$initialize';
|
||||
let webWorkerWarningLogged = false;
|
||||
export function logOnceWebWorkerWarning(err) {
|
||||
if (!isWeb) {
|
||||
// running tests
|
||||
return;
|
||||
}
|
||||
if (!webWorkerWarningLogged) {
|
||||
webWorkerWarningLogged = true;
|
||||
console.warn('Could not create web worker(s). Falling back to loading web worker code in main thread, which might cause UI freezes. Please see https://github.com/microsoft/monaco-editor#faq');
|
||||
}
|
||||
console.warn(err.message);
|
||||
}
|
||||
class RequestMessage {
|
||||
constructor(vsWorker, req, method, args) {
|
||||
this.vsWorker = vsWorker;
|
||||
this.req = req;
|
||||
this.method = method;
|
||||
this.args = args;
|
||||
this.type = 0 /* MessageType.Request */;
|
||||
}
|
||||
}
|
||||
class ReplyMessage {
|
||||
constructor(vsWorker, seq, res, err) {
|
||||
this.vsWorker = vsWorker;
|
||||
this.seq = seq;
|
||||
this.res = res;
|
||||
this.err = err;
|
||||
this.type = 1 /* MessageType.Reply */;
|
||||
}
|
||||
}
|
||||
class SubscribeEventMessage {
|
||||
constructor(vsWorker, req, eventName, arg) {
|
||||
this.vsWorker = vsWorker;
|
||||
this.req = req;
|
||||
this.eventName = eventName;
|
||||
this.arg = arg;
|
||||
this.type = 2 /* MessageType.SubscribeEvent */;
|
||||
}
|
||||
}
|
||||
class EventMessage {
|
||||
constructor(vsWorker, req, event) {
|
||||
this.vsWorker = vsWorker;
|
||||
this.req = req;
|
||||
this.event = event;
|
||||
this.type = 3 /* MessageType.Event */;
|
||||
}
|
||||
}
|
||||
class UnsubscribeEventMessage {
|
||||
constructor(vsWorker, req) {
|
||||
this.vsWorker = vsWorker;
|
||||
this.req = req;
|
||||
this.type = 4 /* MessageType.UnsubscribeEvent */;
|
||||
}
|
||||
}
|
||||
class SimpleWorkerProtocol {
|
||||
constructor(handler) {
|
||||
this._workerId = -1;
|
||||
this._handler = handler;
|
||||
this._lastSentReq = 0;
|
||||
this._pendingReplies = Object.create(null);
|
||||
this._pendingEmitters = new Map();
|
||||
this._pendingEvents = new Map();
|
||||
}
|
||||
setWorkerId(workerId) {
|
||||
this._workerId = workerId;
|
||||
}
|
||||
sendMessage(method, args) {
|
||||
const req = String(++this._lastSentReq);
|
||||
return new Promise((resolve, reject) => {
|
||||
this._pendingReplies[req] = {
|
||||
resolve: resolve,
|
||||
reject: reject
|
||||
};
|
||||
this._send(new RequestMessage(this._workerId, req, method, args));
|
||||
});
|
||||
}
|
||||
listen(eventName, arg) {
|
||||
let req = null;
|
||||
const emitter = new Emitter({
|
||||
onFirstListenerAdd: () => {
|
||||
req = String(++this._lastSentReq);
|
||||
this._pendingEmitters.set(req, emitter);
|
||||
this._send(new SubscribeEventMessage(this._workerId, req, eventName, arg));
|
||||
},
|
||||
onLastListenerRemove: () => {
|
||||
this._pendingEmitters.delete(req);
|
||||
this._send(new UnsubscribeEventMessage(this._workerId, req));
|
||||
req = null;
|
||||
}
|
||||
});
|
||||
return emitter.event;
|
||||
}
|
||||
handleMessage(message) {
|
||||
if (!message || !message.vsWorker) {
|
||||
return;
|
||||
}
|
||||
if (this._workerId !== -1 && message.vsWorker !== this._workerId) {
|
||||
return;
|
||||
}
|
||||
this._handleMessage(message);
|
||||
}
|
||||
_handleMessage(msg) {
|
||||
switch (msg.type) {
|
||||
case 1 /* MessageType.Reply */:
|
||||
return this._handleReplyMessage(msg);
|
||||
case 0 /* MessageType.Request */:
|
||||
return this._handleRequestMessage(msg);
|
||||
case 2 /* MessageType.SubscribeEvent */:
|
||||
return this._handleSubscribeEventMessage(msg);
|
||||
case 3 /* MessageType.Event */:
|
||||
return this._handleEventMessage(msg);
|
||||
case 4 /* MessageType.UnsubscribeEvent */:
|
||||
return this._handleUnsubscribeEventMessage(msg);
|
||||
}
|
||||
}
|
||||
_handleReplyMessage(replyMessage) {
|
||||
if (!this._pendingReplies[replyMessage.seq]) {
|
||||
console.warn('Got reply to unknown seq');
|
||||
return;
|
||||
}
|
||||
const reply = this._pendingReplies[replyMessage.seq];
|
||||
delete this._pendingReplies[replyMessage.seq];
|
||||
if (replyMessage.err) {
|
||||
let err = replyMessage.err;
|
||||
if (replyMessage.err.$isError) {
|
||||
err = new Error();
|
||||
err.name = replyMessage.err.name;
|
||||
err.message = replyMessage.err.message;
|
||||
err.stack = replyMessage.err.stack;
|
||||
}
|
||||
reply.reject(err);
|
||||
return;
|
||||
}
|
||||
reply.resolve(replyMessage.res);
|
||||
}
|
||||
_handleRequestMessage(requestMessage) {
|
||||
const req = requestMessage.req;
|
||||
const result = this._handler.handleMessage(requestMessage.method, requestMessage.args);
|
||||
result.then((r) => {
|
||||
this._send(new ReplyMessage(this._workerId, req, r, undefined));
|
||||
}, (e) => {
|
||||
if (e.detail instanceof Error) {
|
||||
// Loading errors have a detail property that points to the actual error
|
||||
e.detail = transformErrorForSerialization(e.detail);
|
||||
}
|
||||
this._send(new ReplyMessage(this._workerId, req, undefined, transformErrorForSerialization(e)));
|
||||
});
|
||||
}
|
||||
_handleSubscribeEventMessage(msg) {
|
||||
const req = msg.req;
|
||||
const disposable = this._handler.handleEvent(msg.eventName, msg.arg)((event) => {
|
||||
this._send(new EventMessage(this._workerId, req, event));
|
||||
});
|
||||
this._pendingEvents.set(req, disposable);
|
||||
}
|
||||
_handleEventMessage(msg) {
|
||||
if (!this._pendingEmitters.has(msg.req)) {
|
||||
console.warn('Got event for unknown req');
|
||||
return;
|
||||
}
|
||||
this._pendingEmitters.get(msg.req).fire(msg.event);
|
||||
}
|
||||
_handleUnsubscribeEventMessage(msg) {
|
||||
if (!this._pendingEvents.has(msg.req)) {
|
||||
console.warn('Got unsubscribe for unknown req');
|
||||
return;
|
||||
}
|
||||
this._pendingEvents.get(msg.req).dispose();
|
||||
this._pendingEvents.delete(msg.req);
|
||||
}
|
||||
_send(msg) {
|
||||
const transfer = [];
|
||||
if (msg.type === 0 /* MessageType.Request */) {
|
||||
for (let i = 0; i < msg.args.length; i++) {
|
||||
if (msg.args[i] instanceof ArrayBuffer) {
|
||||
transfer.push(msg.args[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (msg.type === 1 /* MessageType.Reply */) {
|
||||
if (msg.res instanceof ArrayBuffer) {
|
||||
transfer.push(msg.res);
|
||||
}
|
||||
}
|
||||
this._handler.sendMessage(msg, transfer);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Main thread side
|
||||
*/
|
||||
export class SimpleWorkerClient extends Disposable {
|
||||
constructor(workerFactory, moduleId, host) {
|
||||
super();
|
||||
let lazyProxyReject = null;
|
||||
this._worker = this._register(workerFactory.create('vs/base/common/worker/simpleWorker', (msg) => {
|
||||
this._protocol.handleMessage(msg);
|
||||
}, (err) => {
|
||||
// in Firefox, web workers fail lazily :(
|
||||
// we will reject the proxy
|
||||
lazyProxyReject === null || lazyProxyReject === void 0 ? void 0 : lazyProxyReject(err);
|
||||
}));
|
||||
this._protocol = new SimpleWorkerProtocol({
|
||||
sendMessage: (msg, transfer) => {
|
||||
this._worker.postMessage(msg, transfer);
|
||||
},
|
||||
handleMessage: (method, args) => {
|
||||
if (typeof host[method] !== 'function') {
|
||||
return Promise.reject(new Error('Missing method ' + method + ' on main thread host.'));
|
||||
}
|
||||
try {
|
||||
return Promise.resolve(host[method].apply(host, args));
|
||||
}
|
||||
catch (e) {
|
||||
return Promise.reject(e);
|
||||
}
|
||||
},
|
||||
handleEvent: (eventName, arg) => {
|
||||
if (propertyIsDynamicEvent(eventName)) {
|
||||
const event = host[eventName].call(host, arg);
|
||||
if (typeof event !== 'function') {
|
||||
throw new Error(`Missing dynamic event ${eventName} on main thread host.`);
|
||||
}
|
||||
return event;
|
||||
}
|
||||
if (propertyIsEvent(eventName)) {
|
||||
const event = host[eventName];
|
||||
if (typeof event !== 'function') {
|
||||
throw new Error(`Missing event ${eventName} on main thread host.`);
|
||||
}
|
||||
return event;
|
||||
}
|
||||
throw new Error(`Malformed event name ${eventName}`);
|
||||
}
|
||||
});
|
||||
this._protocol.setWorkerId(this._worker.getId());
|
||||
// Gather loader configuration
|
||||
let loaderConfiguration = null;
|
||||
if (typeof globals.require !== 'undefined' && typeof globals.require.getConfig === 'function') {
|
||||
// Get the configuration from the Monaco AMD Loader
|
||||
loaderConfiguration = globals.require.getConfig();
|
||||
}
|
||||
else if (typeof globals.requirejs !== 'undefined') {
|
||||
// Get the configuration from requirejs
|
||||
loaderConfiguration = globals.requirejs.s.contexts._.config;
|
||||
}
|
||||
const hostMethods = types.getAllMethodNames(host);
|
||||
// Send initialize message
|
||||
this._onModuleLoaded = this._protocol.sendMessage(INITIALIZE, [
|
||||
this._worker.getId(),
|
||||
JSON.parse(JSON.stringify(loaderConfiguration)),
|
||||
moduleId,
|
||||
hostMethods,
|
||||
]);
|
||||
// Create proxy to loaded code
|
||||
const proxyMethodRequest = (method, args) => {
|
||||
return this._request(method, args);
|
||||
};
|
||||
const proxyListen = (eventName, arg) => {
|
||||
return this._protocol.listen(eventName, arg);
|
||||
};
|
||||
this._lazyProxy = new Promise((resolve, reject) => {
|
||||
lazyProxyReject = reject;
|
||||
this._onModuleLoaded.then((availableMethods) => {
|
||||
resolve(createProxyObject(availableMethods, proxyMethodRequest, proxyListen));
|
||||
}, (e) => {
|
||||
reject(e);
|
||||
this._onError('Worker failed to load ' + moduleId, e);
|
||||
});
|
||||
});
|
||||
}
|
||||
getProxyObject() {
|
||||
return this._lazyProxy;
|
||||
}
|
||||
_request(method, args) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this._onModuleLoaded.then(() => {
|
||||
this._protocol.sendMessage(method, args).then(resolve, reject);
|
||||
}, reject);
|
||||
});
|
||||
}
|
||||
_onError(message, error) {
|
||||
console.error(message);
|
||||
console.info(error);
|
||||
}
|
||||
}
|
||||
function propertyIsEvent(name) {
|
||||
// Assume a property is an event if it has a form of "onSomething"
|
||||
return name[0] === 'o' && name[1] === 'n' && strings.isUpperAsciiLetter(name.charCodeAt(2));
|
||||
}
|
||||
function propertyIsDynamicEvent(name) {
|
||||
// Assume a property is a dynamic event (a method that returns an event) if it has a form of "onDynamicSomething"
|
||||
return /^onDynamic/.test(name) && strings.isUpperAsciiLetter(name.charCodeAt(9));
|
||||
}
|
||||
function createProxyObject(methodNames, invoke, proxyListen) {
|
||||
const createProxyMethod = (method) => {
|
||||
return function () {
|
||||
const args = Array.prototype.slice.call(arguments, 0);
|
||||
return invoke(method, args);
|
||||
};
|
||||
};
|
||||
const createProxyDynamicEvent = (eventName) => {
|
||||
return function (arg) {
|
||||
return proxyListen(eventName, arg);
|
||||
};
|
||||
};
|
||||
const result = {};
|
||||
for (const methodName of methodNames) {
|
||||
if (propertyIsDynamicEvent(methodName)) {
|
||||
result[methodName] = createProxyDynamicEvent(methodName);
|
||||
continue;
|
||||
}
|
||||
if (propertyIsEvent(methodName)) {
|
||||
result[methodName] = proxyListen(methodName, undefined);
|
||||
continue;
|
||||
}
|
||||
result[methodName] = createProxyMethod(methodName);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Worker side
|
||||
*/
|
||||
export class SimpleWorkerServer {
|
||||
constructor(postMessage, requestHandlerFactory) {
|
||||
this._requestHandlerFactory = requestHandlerFactory;
|
||||
this._requestHandler = null;
|
||||
this._protocol = new SimpleWorkerProtocol({
|
||||
sendMessage: (msg, transfer) => {
|
||||
postMessage(msg, transfer);
|
||||
},
|
||||
handleMessage: (method, args) => this._handleMessage(method, args),
|
||||
handleEvent: (eventName, arg) => this._handleEvent(eventName, arg)
|
||||
});
|
||||
}
|
||||
onmessage(msg) {
|
||||
this._protocol.handleMessage(msg);
|
||||
}
|
||||
_handleMessage(method, args) {
|
||||
if (method === INITIALIZE) {
|
||||
return this.initialize(args[0], args[1], args[2], args[3]);
|
||||
}
|
||||
if (!this._requestHandler || typeof this._requestHandler[method] !== 'function') {
|
||||
return Promise.reject(new Error('Missing requestHandler or method: ' + method));
|
||||
}
|
||||
try {
|
||||
return Promise.resolve(this._requestHandler[method].apply(this._requestHandler, args));
|
||||
}
|
||||
catch (e) {
|
||||
return Promise.reject(e);
|
||||
}
|
||||
}
|
||||
_handleEvent(eventName, arg) {
|
||||
if (!this._requestHandler) {
|
||||
throw new Error(`Missing requestHandler`);
|
||||
}
|
||||
if (propertyIsDynamicEvent(eventName)) {
|
||||
const event = this._requestHandler[eventName].call(this._requestHandler, arg);
|
||||
if (typeof event !== 'function') {
|
||||
throw new Error(`Missing dynamic event ${eventName} on request handler.`);
|
||||
}
|
||||
return event;
|
||||
}
|
||||
if (propertyIsEvent(eventName)) {
|
||||
const event = this._requestHandler[eventName];
|
||||
if (typeof event !== 'function') {
|
||||
throw new Error(`Missing event ${eventName} on request handler.`);
|
||||
}
|
||||
return event;
|
||||
}
|
||||
throw new Error(`Malformed event name ${eventName}`);
|
||||
}
|
||||
initialize(workerId, loaderConfig, moduleId, hostMethods) {
|
||||
this._protocol.setWorkerId(workerId);
|
||||
const proxyMethodRequest = (method, args) => {
|
||||
return this._protocol.sendMessage(method, args);
|
||||
};
|
||||
const proxyListen = (eventName, arg) => {
|
||||
return this._protocol.listen(eventName, arg);
|
||||
};
|
||||
const hostProxy = createProxyObject(hostMethods, proxyMethodRequest, proxyListen);
|
||||
if (this._requestHandlerFactory) {
|
||||
// static request handler
|
||||
this._requestHandler = this._requestHandlerFactory(hostProxy);
|
||||
return Promise.resolve(types.getAllMethodNames(this._requestHandler));
|
||||
}
|
||||
if (loaderConfig) {
|
||||
// Remove 'baseUrl', handling it is beyond scope for now
|
||||
if (typeof loaderConfig.baseUrl !== 'undefined') {
|
||||
delete loaderConfig['baseUrl'];
|
||||
}
|
||||
if (typeof loaderConfig.paths !== 'undefined') {
|
||||
if (typeof loaderConfig.paths.vs !== 'undefined') {
|
||||
delete loaderConfig.paths['vs'];
|
||||
}
|
||||
}
|
||||
if (typeof loaderConfig.trustedTypesPolicy !== undefined) {
|
||||
// don't use, it has been destroyed during serialize
|
||||
delete loaderConfig['trustedTypesPolicy'];
|
||||
}
|
||||
// Since this is in a web worker, enable catching errors
|
||||
loaderConfig.catchError = true;
|
||||
globals.require.config(loaderConfig);
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
// Use the global require to be sure to get the global config
|
||||
// ESM-comment-begin
|
||||
// const req = (globals.require || require);
|
||||
// ESM-comment-end
|
||||
// ESM-uncomment-begin
|
||||
const req = globals.require;
|
||||
// ESM-uncomment-end
|
||||
req([moduleId], (module) => {
|
||||
this._requestHandler = module.create(hostProxy);
|
||||
if (!this._requestHandler) {
|
||||
reject(new Error(`No RequestHandler!`));
|
||||
return;
|
||||
}
|
||||
resolve(types.getAllMethodNames(this._requestHandler));
|
||||
}, reject);
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Called on the worker side
|
||||
*/
|
||||
export function create(postMessage) {
|
||||
return new SimpleWorkerServer(postMessage, null);
|
||||
}
|
||||
Reference in New Issue
Block a user